@brookmind/ai-toolkit 1.2.0 → 1.2.1

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 (46) hide show
  1. package/dist/__tests__/constants.test.d.ts +2 -0
  2. package/dist/__tests__/constants.test.d.ts.map +1 -0
  3. package/dist/__tests__/constants.test.js +102 -0
  4. package/dist/__tests__/constants.test.js.map +1 -0
  5. package/dist/__tests__/index.test.js +2 -102
  6. package/dist/__tests__/index.test.js.map +1 -1
  7. package/dist/__tests__/integration/installer.test.d.ts +2 -0
  8. package/dist/__tests__/integration/installer.test.d.ts.map +1 -0
  9. package/dist/__tests__/integration/installer.test.js +425 -0
  10. package/dist/__tests__/integration/installer.test.js.map +1 -0
  11. package/dist/__tests__/services/installers.test.d.ts +2 -0
  12. package/dist/__tests__/services/installers.test.d.ts.map +1 -0
  13. package/dist/__tests__/services/installers.test.js +222 -0
  14. package/dist/__tests__/services/installers.test.js.map +1 -0
  15. package/dist/__tests__/services/opencode.test.d.ts +2 -0
  16. package/dist/__tests__/services/opencode.test.d.ts.map +1 -0
  17. package/dist/__tests__/services/opencode.test.js +120 -0
  18. package/dist/__tests__/services/opencode.test.js.map +1 -0
  19. package/dist/__tests__/ui/categorize.test.d.ts +2 -0
  20. package/dist/__tests__/ui/categorize.test.d.ts.map +1 -0
  21. package/dist/__tests__/ui/categorize.test.js +194 -0
  22. package/dist/__tests__/ui/categorize.test.js.map +1 -0
  23. package/dist/__tests__/ui/choices.test.d.ts +2 -0
  24. package/dist/__tests__/ui/choices.test.d.ts.map +1 -0
  25. package/dist/__tests__/ui/choices.test.js +180 -0
  26. package/dist/__tests__/ui/choices.test.js.map +1 -0
  27. package/dist/__tests__/ui/display.test.d.ts +2 -0
  28. package/dist/__tests__/ui/display.test.d.ts.map +1 -0
  29. package/dist/__tests__/ui/display.test.js +142 -0
  30. package/dist/__tests__/ui/display.test.js.map +1 -0
  31. package/dist/__tests__/utils/fs.test.d.ts +2 -0
  32. package/dist/__tests__/utils/fs.test.d.ts.map +1 -0
  33. package/dist/__tests__/utils/fs.test.js +142 -0
  34. package/dist/__tests__/utils/fs.test.js.map +1 -0
  35. package/dist/__tests__/utils/terminal.test.d.ts +2 -0
  36. package/dist/__tests__/utils/terminal.test.d.ts.map +1 -0
  37. package/dist/__tests__/utils/terminal.test.js +97 -0
  38. package/dist/__tests__/utils/terminal.test.js.map +1 -0
  39. package/dist/constants.d.ts +1 -0
  40. package/dist/constants.d.ts.map +1 -1
  41. package/dist/constants.js +1 -0
  42. package/dist/constants.js.map +1 -1
  43. package/dist/ui/display.d.ts.map +1 -1
  44. package/dist/ui/display.js +3 -1
  45. package/dist/ui/display.js.map +1 -1
  46. package/package.json +3 -1
@@ -0,0 +1,222 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ vi.mock('fs/promises', async () => {
3
+ const actual = await vi.importActual('fs/promises');
4
+ return {
5
+ ...actual,
6
+ cp: vi.fn(),
7
+ mkdir: vi.fn(),
8
+ readFile: vi.fn(),
9
+ writeFile: vi.fn(),
10
+ };
11
+ });
12
+ vi.mock('../../constants.js', () => {
13
+ const testDir = '/tmp/ai-toolkit-test';
14
+ return {
15
+ OPENCODE_DIR: `${testDir}/opencode`,
16
+ OPENCODE_CONFIG: `${testDir}/opencode/opencode.json`,
17
+ TOOLS_DIR: `${testDir}/tools`,
18
+ };
19
+ });
20
+ vi.mock('../../utils/fs.js', () => ({
21
+ exists: vi.fn(),
22
+ readJsonConfig: vi.fn(),
23
+ }));
24
+ describe('services/installers', () => {
25
+ let mockCp;
26
+ let mockMkdir;
27
+ let mockReadFile;
28
+ let mockWriteFile;
29
+ let mockExists;
30
+ let mockReadJsonConfig;
31
+ beforeEach(async () => {
32
+ vi.resetAllMocks();
33
+ const fsPromises = await import('fs/promises');
34
+ mockCp = fsPromises.cp;
35
+ mockMkdir = fsPromises.mkdir;
36
+ mockReadFile = fsPromises.readFile;
37
+ mockWriteFile = fsPromises.writeFile;
38
+ const fsUtils = await import('../../utils/fs.js');
39
+ mockExists = fsUtils.exists;
40
+ mockReadJsonConfig = fsUtils.readJsonConfig;
41
+ mockMkdir.mockResolvedValue(undefined);
42
+ mockCp.mockResolvedValue(undefined);
43
+ mockWriteFile.mockResolvedValue(undefined);
44
+ mockReadFile.mockResolvedValue('{}');
45
+ mockExists.mockResolvedValue(false);
46
+ mockReadJsonConfig.mockResolvedValue({});
47
+ });
48
+ afterEach(() => {
49
+ vi.clearAllMocks();
50
+ });
51
+ describe('installAgents', () => {
52
+ it('should do nothing when agents array is empty', async () => {
53
+ const { installAgents } = await import('../../services/installers.js');
54
+ await installAgents([]);
55
+ expect(mockMkdir).not.toHaveBeenCalled();
56
+ expect(mockCp).not.toHaveBeenCalled();
57
+ });
58
+ it('should create directory and copy agent files', async () => {
59
+ const { installAgents } = await import('../../services/installers.js');
60
+ await installAgents(['test-agent']);
61
+ expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('opencode/agent'), {
62
+ recursive: true,
63
+ });
64
+ expect(mockCp).toHaveBeenCalledWith(expect.stringContaining('tools/agents/test-agent.md'), expect.stringContaining('opencode/agent/test-agent.md'));
65
+ });
66
+ it('should install multiple agents', async () => {
67
+ const { installAgents } = await import('../../services/installers.js');
68
+ await installAgents(['agent1', 'agent2', 'agent3']);
69
+ expect(mockCp).toHaveBeenCalledTimes(3);
70
+ });
71
+ });
72
+ describe('installSkills', () => {
73
+ it('should do nothing when skills array is empty', async () => {
74
+ const { installSkills } = await import('../../services/installers.js');
75
+ await installSkills([]);
76
+ expect(mockMkdir).not.toHaveBeenCalled();
77
+ expect(mockCp).not.toHaveBeenCalled();
78
+ });
79
+ it('should create directory and copy skill folder', async () => {
80
+ const { installSkills } = await import('../../services/installers.js');
81
+ await installSkills(['test-skill']);
82
+ expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('opencode/skill'), {
83
+ recursive: true,
84
+ });
85
+ expect(mockCp).toHaveBeenCalledWith(expect.stringContaining('tools/skills/test-skill'), expect.stringContaining('opencode/skill/test-skill'), { recursive: true, force: true });
86
+ });
87
+ it('should install multiple skills', async () => {
88
+ const { installSkills } = await import('../../services/installers.js');
89
+ await installSkills(['skill1', 'skill2']);
90
+ expect(mockCp).toHaveBeenCalledTimes(2);
91
+ });
92
+ });
93
+ describe('installCommands', () => {
94
+ it('should do nothing when commands array is empty', async () => {
95
+ const { installCommands } = await import('../../services/installers.js');
96
+ await installCommands([]);
97
+ expect(mockMkdir).not.toHaveBeenCalled();
98
+ expect(mockCp).not.toHaveBeenCalled();
99
+ });
100
+ it('should create directory and copy command files', async () => {
101
+ const { installCommands } = await import('../../services/installers.js');
102
+ await installCommands(['test-cmd']);
103
+ expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('opencode/command'), {
104
+ recursive: true,
105
+ });
106
+ expect(mockCp).toHaveBeenCalledWith(expect.stringContaining('tools/commands/test-cmd.md'), expect.stringContaining('opencode/command/test-cmd.md'));
107
+ });
108
+ it('should install multiple commands', async () => {
109
+ const { installCommands } = await import('../../services/installers.js');
110
+ await installCommands(['cmd1', 'cmd2']);
111
+ expect(mockCp).toHaveBeenCalledTimes(2);
112
+ });
113
+ });
114
+ describe('installMcps', () => {
115
+ it('should do nothing when mcps array is empty', async () => {
116
+ const { installMcps } = await import('../../services/installers.js');
117
+ await installMcps([]);
118
+ expect(mockWriteFile).not.toHaveBeenCalled();
119
+ });
120
+ it('should create mcp section if it does not exist', async () => {
121
+ const { installMcps } = await import('../../services/installers.js');
122
+ mockReadJsonConfig
123
+ .mockResolvedValueOnce({}) // OPENCODE_CONFIG
124
+ .mockResolvedValueOnce({ mcpServers: { 'test-server': { command: 'test' } } }); // MCP config
125
+ await installMcps(['test-mcp']);
126
+ expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining('opencode.json'), expect.stringContaining('"test-server"'));
127
+ });
128
+ it('should merge servers into existing mcp section', async () => {
129
+ const { installMcps } = await import('../../services/installers.js');
130
+ mockReadJsonConfig
131
+ .mockResolvedValueOnce({ mcp: { 'existing-server': {} } })
132
+ .mockResolvedValueOnce({ mcpServers: { 'new-server': {} } });
133
+ await installMcps(['test-mcp']);
134
+ expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining('opencode.json'), expect.stringMatching(/"existing-server".*"new-server"|"new-server".*"existing-server"/s));
135
+ });
136
+ it('should handle mcps without servers', async () => {
137
+ const { installMcps } = await import('../../services/installers.js');
138
+ mockReadJsonConfig.mockResolvedValueOnce({}).mockResolvedValueOnce({}); // No mcpServers
139
+ await installMcps(['test-mcp']);
140
+ expect(mockWriteFile).toHaveBeenCalled();
141
+ });
142
+ it('should install multiple mcps', async () => {
143
+ const { installMcps } = await import('../../services/installers.js');
144
+ mockReadJsonConfig
145
+ .mockResolvedValueOnce({})
146
+ .mockResolvedValueOnce({ mcpServers: { server1: {} } })
147
+ .mockResolvedValueOnce({ mcpServers: { server2: {} } });
148
+ await installMcps(['mcp1', 'mcp2']);
149
+ expect(mockWriteFile).toHaveBeenCalled();
150
+ });
151
+ });
152
+ describe('installTheme', () => {
153
+ it('should copy theme and update config when theme source exists', async () => {
154
+ const { installTheme } = await import('../../services/installers.js');
155
+ mockExists.mockResolvedValue(true);
156
+ mockReadJsonConfig.mockResolvedValue({});
157
+ await installTheme();
158
+ expect(mockMkdir).toHaveBeenCalledWith(expect.stringContaining('opencode/themes'), {
159
+ recursive: true,
160
+ });
161
+ expect(mockCp).toHaveBeenCalledWith(expect.stringContaining('themes/claude-vivid.json'), expect.stringContaining('opencode/themes/claude-vivid.json'));
162
+ expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining('opencode.json'), expect.stringContaining('claude-vivid'));
163
+ });
164
+ it('should not update config if theme source does not exist', async () => {
165
+ const { installTheme } = await import('../../services/installers.js');
166
+ mockExists.mockResolvedValue(false);
167
+ await installTheme();
168
+ expect(mockCp).not.toHaveBeenCalled();
169
+ expect(mockWriteFile).not.toHaveBeenCalled();
170
+ });
171
+ });
172
+ describe('isThemeInstalled', () => {
173
+ it('should return true when theme exists', async () => {
174
+ const { isThemeInstalled } = await import('../../services/installers.js');
175
+ mockExists.mockResolvedValue(true);
176
+ const result = await isThemeInstalled('claude-vivid');
177
+ expect(result).toBe(true);
178
+ expect(mockExists).toHaveBeenCalledWith(expect.stringContaining('opencode/themes/claude-vivid.json'));
179
+ });
180
+ it('should return false when theme does not exist', async () => {
181
+ const { isThemeInstalled } = await import('../../services/installers.js');
182
+ mockExists.mockResolvedValue(false);
183
+ const result = await isThemeInstalled('nonexistent');
184
+ expect(result).toBe(false);
185
+ });
186
+ });
187
+ describe('getInstalledMcps', () => {
188
+ it('should return empty set when config does not exist', async () => {
189
+ const { getInstalledMcps } = await import('../../services/installers.js');
190
+ mockReadFile.mockRejectedValue(new Error('ENOENT'));
191
+ const result = await getInstalledMcps();
192
+ expect(result).toEqual(new Set());
193
+ });
194
+ it('should return empty set when config has no mcp section', async () => {
195
+ const { getInstalledMcps } = await import('../../services/installers.js');
196
+ mockReadFile.mockResolvedValue(JSON.stringify({ theme: 'test' }));
197
+ const result = await getInstalledMcps();
198
+ expect(result).toEqual(new Set());
199
+ });
200
+ it('should return server names from mcp section', async () => {
201
+ const { getInstalledMcps } = await import('../../services/installers.js');
202
+ mockReadFile.mockResolvedValue(JSON.stringify({
203
+ mcp: { server1: {}, server2: {} },
204
+ }));
205
+ const result = await getInstalledMcps();
206
+ expect(result).toEqual(new Set(['server1', 'server2']));
207
+ });
208
+ it('should return empty set on JSON parse error', async () => {
209
+ const { getInstalledMcps } = await import('../../services/installers.js');
210
+ mockReadFile.mockResolvedValue('invalid json');
211
+ const result = await getInstalledMcps();
212
+ expect(result).toEqual(new Set());
213
+ });
214
+ it('should handle empty mcp section', async () => {
215
+ const { getInstalledMcps } = await import('../../services/installers.js');
216
+ mockReadFile.mockResolvedValue(JSON.stringify({ mcp: {} }));
217
+ const result = await getInstalledMcps();
218
+ expect(result).toEqual(new Set());
219
+ });
220
+ });
221
+ });
222
+ //# sourceMappingURL=installers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installers.test.js","sourceRoot":"","sources":["../../../src/__tests__/services/installers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=opencode.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/services/opencode.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { exec } from 'child_process';
3
+ import { isOpenCodeInstalled, installOpenCode } from '../../services/opencode.js';
4
+ vi.mock('child_process', () => ({
5
+ exec: vi.fn(),
6
+ }));
7
+ vi.mock('../../utils/fs.js', () => ({
8
+ exists: vi.fn(),
9
+ }));
10
+ vi.mock('ora', () => ({
11
+ default: vi.fn(() => ({
12
+ start: vi.fn().mockReturnThis(),
13
+ succeed: vi.fn().mockReturnThis(),
14
+ fail: vi.fn().mockReturnThis(),
15
+ })),
16
+ }));
17
+ describe('services/opencode', () => {
18
+ let mockExec;
19
+ let mockExists;
20
+ let mockOra;
21
+ let consoleLogSpy;
22
+ beforeEach(async () => {
23
+ vi.resetAllMocks();
24
+ mockExec = exec;
25
+ const fsModule = await import('../../utils/fs.js');
26
+ mockExists = fsModule.exists;
27
+ const oraModule = await import('ora');
28
+ mockOra = oraModule.default;
29
+ consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
30
+ });
31
+ afterEach(() => {
32
+ consoleLogSpy.mockRestore();
33
+ });
34
+ describe('isOpenCodeInstalled', () => {
35
+ it('should return true when which opencode succeeds', async () => {
36
+ mockExec.mockImplementation((_cmd, callback) => {
37
+ if (callback) {
38
+ callback(null, { stdout: '/usr/local/bin/opencode', stderr: '' });
39
+ }
40
+ return undefined;
41
+ });
42
+ const result = await isOpenCodeInstalled();
43
+ expect(result).toBe(true);
44
+ });
45
+ it('should check directory when which fails', async () => {
46
+ mockExec.mockImplementation((_cmd, callback) => {
47
+ if (callback) {
48
+ callback(new Error('not found'), { stdout: '', stderr: '' });
49
+ }
50
+ return undefined;
51
+ });
52
+ mockExists.mockResolvedValue(true);
53
+ const result = await isOpenCodeInstalled();
54
+ expect(result).toBe(true);
55
+ expect(mockExists).toHaveBeenCalled();
56
+ });
57
+ it('should return false when both which and directory check fail', async () => {
58
+ mockExec.mockImplementation((_cmd, callback) => {
59
+ if (callback) {
60
+ callback(new Error('not found'), { stdout: '', stderr: '' });
61
+ }
62
+ return undefined;
63
+ });
64
+ mockExists.mockResolvedValue(false);
65
+ const result = await isOpenCodeInstalled();
66
+ expect(result).toBe(false);
67
+ });
68
+ });
69
+ describe('installOpenCode', () => {
70
+ it('should install successfully and show spinner', async () => {
71
+ const spinnerMock = {
72
+ start: vi.fn().mockReturnThis(),
73
+ succeed: vi.fn().mockReturnThis(),
74
+ fail: vi.fn().mockReturnThis(),
75
+ };
76
+ mockOra.mockReturnValue(spinnerMock);
77
+ mockExec.mockImplementation((_cmd, _options, callback) => {
78
+ if (callback) {
79
+ callback(null, { stdout: 'success', stderr: '' });
80
+ }
81
+ return undefined;
82
+ });
83
+ await installOpenCode();
84
+ expect(spinnerMock.start).toHaveBeenCalled();
85
+ expect(spinnerMock.succeed).toHaveBeenCalledWith('OpenCode installed successfully!');
86
+ });
87
+ it('should fail and throw error on installation failure', async () => {
88
+ const spinnerMock = {
89
+ start: vi.fn().mockReturnThis(),
90
+ succeed: vi.fn().mockReturnThis(),
91
+ fail: vi.fn().mockReturnThis(),
92
+ };
93
+ mockOra.mockReturnValue(spinnerMock);
94
+ mockExec.mockImplementation((_cmd, _options, callback) => {
95
+ if (callback) {
96
+ callback(new Error('curl failed'), { stdout: '', stderr: '' });
97
+ }
98
+ return undefined;
99
+ });
100
+ await expect(installOpenCode()).rejects.toThrow('Failed to install OpenCode: curl failed');
101
+ expect(spinnerMock.fail).toHaveBeenCalledWith('Installation failed');
102
+ });
103
+ it('should handle non-Error exceptions', async () => {
104
+ const spinnerMock = {
105
+ start: vi.fn().mockReturnThis(),
106
+ succeed: vi.fn().mockReturnThis(),
107
+ fail: vi.fn().mockReturnThis(),
108
+ };
109
+ mockOra.mockReturnValue(spinnerMock);
110
+ mockExec.mockImplementation((_cmd, _options, callback) => {
111
+ if (callback) {
112
+ callback('string error', { stdout: '', stderr: '' });
113
+ }
114
+ return undefined;
115
+ });
116
+ await expect(installOpenCode()).rejects.toThrow('Failed to install OpenCode: string error');
117
+ });
118
+ });
119
+ });
120
+ //# sourceMappingURL=opencode.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.test.js","sourceRoot":"","sources":["../../../src/__tests__/services/opencode.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=categorize.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categorize.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/ui/categorize.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,194 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { categorizeAgents, categorizeSkills, categorizeCommands, categorizeMcps, } from '../../ui/categorize.js';
3
+ vi.mock('../../utils/fs.js', () => ({
4
+ exists: vi.fn(),
5
+ readJsonConfig: vi.fn(),
6
+ }));
7
+ vi.mock('../../services/installers.js', () => ({
8
+ getInstalledMcps: vi.fn(),
9
+ }));
10
+ vi.mock('../../constants.js', async (importOriginal) => {
11
+ const original = await importOriginal();
12
+ return {
13
+ ...original,
14
+ MCP_DISPLAY_NAMES: {
15
+ 'pg-aiguide': 'postgres-mcp',
16
+ },
17
+ OPENCODE_DIR: '/fake/opencode',
18
+ TOOLS_DIR: '/fake/tools',
19
+ };
20
+ });
21
+ describe('ui/categorize', () => {
22
+ let mockExists;
23
+ let mockReadJsonConfig;
24
+ let mockGetInstalledMcps;
25
+ beforeEach(async () => {
26
+ vi.resetAllMocks();
27
+ const fsModule = await import('../../utils/fs.js');
28
+ mockExists = fsModule.exists;
29
+ mockReadJsonConfig = fsModule.readJsonConfig;
30
+ const installersModule = await import('../../services/installers.js');
31
+ mockGetInstalledMcps = installersModule.getInstalledMcps;
32
+ mockExists.mockResolvedValue(false);
33
+ mockReadJsonConfig.mockResolvedValue({});
34
+ mockGetInstalledMcps.mockResolvedValue(new Set());
35
+ });
36
+ afterEach(() => {
37
+ vi.clearAllMocks();
38
+ });
39
+ describe('categorizeAgents', () => {
40
+ it('should return empty arrays for empty agents', async () => {
41
+ const result = await categorizeAgents([]);
42
+ expect(result).toEqual({ new: [], update: [] });
43
+ });
44
+ it('should categorize all as new when none installed', async () => {
45
+ mockExists.mockResolvedValue(false);
46
+ const result = await categorizeAgents(['agent1', 'agent2']);
47
+ expect(result.new).toEqual(['agent1', 'agent2']);
48
+ expect(result.update).toEqual([]);
49
+ });
50
+ it('should categorize all as update when all installed', async () => {
51
+ mockExists.mockResolvedValue(true);
52
+ const result = await categorizeAgents(['agent1', 'agent2']);
53
+ expect(result.new).toEqual([]);
54
+ expect(result.update).toEqual(['agent1', 'agent2']);
55
+ });
56
+ it('should categorize mixed new and update', async () => {
57
+ mockExists.mockResolvedValueOnce(false).mockResolvedValueOnce(true);
58
+ const result = await categorizeAgents(['agent1', 'agent2']);
59
+ expect(result.new).toEqual(['agent1']);
60
+ expect(result.update).toEqual(['agent2']);
61
+ });
62
+ it('should check correct path for agents', async () => {
63
+ mockExists.mockResolvedValue(false);
64
+ await categorizeAgents(['test-agent']);
65
+ expect(mockExists).toHaveBeenCalledWith('/fake/opencode/agent/test-agent.md');
66
+ });
67
+ });
68
+ describe('categorizeSkills', () => {
69
+ it('should return empty arrays for empty skills', async () => {
70
+ const result = await categorizeSkills([]);
71
+ expect(result).toEqual({ new: [], update: [] });
72
+ });
73
+ it('should categorize all as new when none installed', async () => {
74
+ mockExists.mockResolvedValue(false);
75
+ const result = await categorizeSkills(['skill1', 'skill2']);
76
+ expect(result.new).toEqual(['skill1', 'skill2']);
77
+ expect(result.update).toEqual([]);
78
+ });
79
+ it('should categorize all as update when all installed', async () => {
80
+ mockExists.mockResolvedValue(true);
81
+ const result = await categorizeSkills(['skill1', 'skill2']);
82
+ expect(result.new).toEqual([]);
83
+ expect(result.update).toEqual(['skill1', 'skill2']);
84
+ });
85
+ it('should categorize mixed new and update', async () => {
86
+ mockExists.mockResolvedValueOnce(true).mockResolvedValueOnce(false);
87
+ const result = await categorizeSkills(['skill1', 'skill2']);
88
+ expect(result.new).toEqual(['skill2']);
89
+ expect(result.update).toEqual(['skill1']);
90
+ });
91
+ it('should check correct path for skills (directory, not .md)', async () => {
92
+ mockExists.mockResolvedValue(false);
93
+ await categorizeSkills(['test-skill']);
94
+ expect(mockExists).toHaveBeenCalledWith('/fake/opencode/skill/test-skill');
95
+ });
96
+ });
97
+ describe('categorizeCommands', () => {
98
+ it('should return empty arrays for empty commands', async () => {
99
+ const result = await categorizeCommands([]);
100
+ expect(result).toEqual({ new: [], update: [] });
101
+ });
102
+ it('should categorize all as new when none installed', async () => {
103
+ mockExists.mockResolvedValue(false);
104
+ const result = await categorizeCommands(['cmd1', 'cmd2']);
105
+ expect(result.new).toEqual(['cmd1', 'cmd2']);
106
+ expect(result.update).toEqual([]);
107
+ });
108
+ it('should categorize all as update when all installed', async () => {
109
+ mockExists.mockResolvedValue(true);
110
+ const result = await categorizeCommands(['cmd1', 'cmd2']);
111
+ expect(result.new).toEqual([]);
112
+ expect(result.update).toEqual(['cmd1', 'cmd2']);
113
+ });
114
+ it('should categorize mixed new and update', async () => {
115
+ mockExists
116
+ .mockResolvedValueOnce(false)
117
+ .mockResolvedValueOnce(true)
118
+ .mockResolvedValueOnce(false);
119
+ const result = await categorizeCommands(['cmd1', 'cmd2', 'cmd3']);
120
+ expect(result.new).toEqual(['cmd1', 'cmd3']);
121
+ expect(result.update).toEqual(['cmd2']);
122
+ });
123
+ it('should check correct path for commands', async () => {
124
+ mockExists.mockResolvedValue(false);
125
+ await categorizeCommands(['test-cmd']);
126
+ expect(mockExists).toHaveBeenCalledWith('/fake/opencode/command/test-cmd.md');
127
+ });
128
+ });
129
+ describe('categorizeMcps', () => {
130
+ it('should return empty arrays for empty mcps', async () => {
131
+ const result = await categorizeMcps([]);
132
+ expect(result).toEqual({ new: [], update: [] });
133
+ });
134
+ it('should categorize all as new when none installed', async () => {
135
+ mockGetInstalledMcps.mockResolvedValue(new Set());
136
+ mockReadJsonConfig.mockResolvedValue({
137
+ mcpServers: { server1: {} },
138
+ });
139
+ const result = await categorizeMcps(['mcp1', 'mcp2']);
140
+ expect(result.new).toHaveLength(2);
141
+ expect(result.update).toEqual([]);
142
+ });
143
+ it('should categorize all as update when all installed', async () => {
144
+ mockGetInstalledMcps.mockResolvedValue(new Set(['server1', 'server2']));
145
+ mockReadJsonConfig
146
+ .mockResolvedValueOnce({ mcpServers: { server1: {} } })
147
+ .mockResolvedValueOnce({ mcpServers: { server2: {} } });
148
+ const result = await categorizeMcps(['mcp1', 'mcp2']);
149
+ expect(result.new).toEqual([]);
150
+ expect(result.update).toHaveLength(2);
151
+ });
152
+ it('should categorize mixed new and update', async () => {
153
+ mockGetInstalledMcps.mockResolvedValue(new Set(['server1']));
154
+ mockReadJsonConfig
155
+ .mockResolvedValueOnce({ mcpServers: { server1: {} } })
156
+ .mockResolvedValueOnce({ mcpServers: { server2: {} } });
157
+ const result = await categorizeMcps(['mcp1', 'mcp2']);
158
+ expect(result.new).toHaveLength(1);
159
+ expect(result.update).toHaveLength(1);
160
+ });
161
+ it('should use display name from MCP_DISPLAY_NAMES', async () => {
162
+ mockGetInstalledMcps.mockResolvedValue(new Set());
163
+ mockReadJsonConfig.mockResolvedValue({
164
+ mcpServers: { 'pg-server': {} },
165
+ });
166
+ const result = await categorizeMcps(['pg-aiguide']);
167
+ expect(result.new).toEqual(['postgres-mcp']);
168
+ });
169
+ it('should use mcp name when not in MCP_DISPLAY_NAMES', async () => {
170
+ mockGetInstalledMcps.mockResolvedValue(new Set());
171
+ mockReadJsonConfig.mockResolvedValue({
172
+ mcpServers: { server: {} },
173
+ });
174
+ const result = await categorizeMcps(['custom-mcp']);
175
+ expect(result.new).toEqual(['custom-mcp']);
176
+ });
177
+ it('should handle mcps without servers', async () => {
178
+ mockGetInstalledMcps.mockResolvedValue(new Set(['existing']));
179
+ mockReadJsonConfig.mockResolvedValue({});
180
+ const result = await categorizeMcps(['no-servers']);
181
+ expect(result.new).toEqual(['no-servers']);
182
+ expect(result.update).toEqual([]);
183
+ });
184
+ it('should check server installation by server name', async () => {
185
+ mockGetInstalledMcps.mockResolvedValue(new Set(['exact-server-name']));
186
+ mockReadJsonConfig.mockResolvedValue({
187
+ mcpServers: { 'exact-server-name': { cmd: 'test' } },
188
+ });
189
+ const result = await categorizeMcps(['test-mcp']);
190
+ expect(result.update).toEqual(['test-mcp']);
191
+ });
192
+ });
193
+ });
194
+ //# sourceMappingURL=categorize.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"categorize.test.js","sourceRoot":"","sources":["../../../src/__tests__/ui/categorize.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=choices.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"choices.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/ui/choices.test.ts"],"names":[],"mappings":""}