@cleocode/adapters 2.0.0

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 (217) hide show
  1. package/dist/index.d.ts +27 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +1927 -0
  4. package/dist/index.js.map +7 -0
  5. package/dist/providers/claude-code/adapter.d.ts +75 -0
  6. package/dist/providers/claude-code/adapter.d.ts.map +1 -0
  7. package/dist/providers/claude-code/adapter.js +154 -0
  8. package/dist/providers/claude-code/adapter.js.map +1 -0
  9. package/dist/providers/claude-code/context-monitor.d.ts +24 -0
  10. package/dist/providers/claude-code/context-monitor.d.ts.map +1 -0
  11. package/dist/providers/claude-code/context-monitor.js +148 -0
  12. package/dist/providers/claude-code/context-monitor.js.map +1 -0
  13. package/dist/providers/claude-code/hooks.d.ts +59 -0
  14. package/dist/providers/claude-code/hooks.d.ts.map +1 -0
  15. package/dist/providers/claude-code/hooks.js +77 -0
  16. package/dist/providers/claude-code/hooks.js.map +1 -0
  17. package/dist/providers/claude-code/index.d.ts +24 -0
  18. package/dist/providers/claude-code/index.d.ts.map +1 -0
  19. package/dist/providers/claude-code/index.js +26 -0
  20. package/dist/providers/claude-code/index.js.map +1 -0
  21. package/dist/providers/claude-code/install.d.ts +75 -0
  22. package/dist/providers/claude-code/install.d.ts.map +1 -0
  23. package/dist/providers/claude-code/install.js +237 -0
  24. package/dist/providers/claude-code/install.js.map +1 -0
  25. package/dist/providers/claude-code/paths.d.ts +24 -0
  26. package/dist/providers/claude-code/paths.d.ts.map +1 -0
  27. package/dist/providers/claude-code/paths.js +33 -0
  28. package/dist/providers/claude-code/paths.js.map +1 -0
  29. package/dist/providers/claude-code/spawn.d.ts +60 -0
  30. package/dist/providers/claude-code/spawn.d.ts.map +1 -0
  31. package/dist/providers/claude-code/spawn.js +160 -0
  32. package/dist/providers/claude-code/spawn.js.map +1 -0
  33. package/dist/providers/claude-code/statusline.d.ts +24 -0
  34. package/dist/providers/claude-code/statusline.d.ts.map +1 -0
  35. package/dist/providers/claude-code/statusline.js +85 -0
  36. package/dist/providers/claude-code/statusline.js.map +1 -0
  37. package/dist/providers/claude-code/task-sync.d.ts +27 -0
  38. package/dist/providers/claude-code/task-sync.d.ts.map +1 -0
  39. package/dist/providers/claude-code/task-sync.js +124 -0
  40. package/dist/providers/claude-code/task-sync.js.map +1 -0
  41. package/dist/providers/claude-code/transport.d.ts +14 -0
  42. package/dist/providers/claude-code/transport.d.ts.map +1 -0
  43. package/dist/providers/claude-code/transport.js +18 -0
  44. package/dist/providers/claude-code/transport.js.map +1 -0
  45. package/dist/providers/cursor/adapter.d.ts +62 -0
  46. package/dist/providers/cursor/adapter.d.ts.map +1 -0
  47. package/dist/providers/cursor/adapter.js +124 -0
  48. package/dist/providers/cursor/adapter.js.map +1 -0
  49. package/dist/providers/cursor/hooks.d.ts +48 -0
  50. package/dist/providers/cursor/hooks.d.ts.map +1 -0
  51. package/dist/providers/cursor/hooks.js +55 -0
  52. package/dist/providers/cursor/hooks.js.map +1 -0
  53. package/dist/providers/cursor/index.d.ts +19 -0
  54. package/dist/providers/cursor/index.d.ts.map +1 -0
  55. package/dist/providers/cursor/index.js +21 -0
  56. package/dist/providers/cursor/index.js.map +1 -0
  57. package/dist/providers/cursor/install.d.ts +94 -0
  58. package/dist/providers/cursor/install.d.ts.map +1 -0
  59. package/dist/providers/cursor/install.js +241 -0
  60. package/dist/providers/cursor/install.js.map +1 -0
  61. package/dist/providers/cursor/spawn.d.ts +50 -0
  62. package/dist/providers/cursor/spawn.d.ts.map +1 -0
  63. package/dist/providers/cursor/spawn.js +59 -0
  64. package/dist/providers/cursor/spawn.js.map +1 -0
  65. package/dist/providers/opencode/adapter.d.ts +67 -0
  66. package/dist/providers/opencode/adapter.d.ts.map +1 -0
  67. package/dist/providers/opencode/adapter.js +144 -0
  68. package/dist/providers/opencode/adapter.js.map +1 -0
  69. package/dist/providers/opencode/hooks.d.ts +66 -0
  70. package/dist/providers/opencode/hooks.d.ts.map +1 -0
  71. package/dist/providers/opencode/hooks.js +89 -0
  72. package/dist/providers/opencode/hooks.js.map +1 -0
  73. package/dist/providers/opencode/index.d.ts +20 -0
  74. package/dist/providers/opencode/index.d.ts.map +1 -0
  75. package/dist/providers/opencode/index.js +22 -0
  76. package/dist/providers/opencode/index.js.map +1 -0
  77. package/dist/providers/opencode/install.d.ts +65 -0
  78. package/dist/providers/opencode/install.d.ts.map +1 -0
  79. package/dist/providers/opencode/install.js +183 -0
  80. package/dist/providers/opencode/install.js.map +1 -0
  81. package/dist/providers/opencode/spawn.d.ts +72 -0
  82. package/dist/providers/opencode/spawn.d.ts.map +1 -0
  83. package/dist/providers/opencode/spawn.js +219 -0
  84. package/dist/providers/opencode/spawn.js.map +1 -0
  85. package/dist/registry.d.ts +36 -0
  86. package/dist/registry.d.ts.map +1 -0
  87. package/dist/registry.js +55 -0
  88. package/dist/registry.js.map +1 -0
  89. package/package.json +32 -0
  90. package/src/index.d.ts +27 -0
  91. package/src/index.d.ts.map +1 -0
  92. package/src/index.js +28 -0
  93. package/src/index.js.map +1 -0
  94. package/src/index.ts +37 -0
  95. package/src/providers/claude-code/__tests__/adapter.test.d.ts +7 -0
  96. package/src/providers/claude-code/__tests__/adapter.test.d.ts.map +1 -0
  97. package/src/providers/claude-code/__tests__/adapter.test.js +249 -0
  98. package/src/providers/claude-code/__tests__/adapter.test.js.map +1 -0
  99. package/src/providers/claude-code/__tests__/adapter.test.ts +291 -0
  100. package/src/providers/claude-code/adapter.d.ts +75 -0
  101. package/src/providers/claude-code/adapter.d.ts.map +1 -0
  102. package/src/providers/claude-code/adapter.js +154 -0
  103. package/src/providers/claude-code/adapter.js.map +1 -0
  104. package/src/providers/claude-code/adapter.ts +175 -0
  105. package/src/providers/claude-code/context-monitor.d.ts +24 -0
  106. package/src/providers/claude-code/context-monitor.d.ts.map +1 -0
  107. package/src/providers/claude-code/context-monitor.js +148 -0
  108. package/src/providers/claude-code/context-monitor.js.map +1 -0
  109. package/src/providers/claude-code/context-monitor.ts +175 -0
  110. package/src/providers/claude-code/hooks.d.ts +59 -0
  111. package/src/providers/claude-code/hooks.d.ts.map +1 -0
  112. package/src/providers/claude-code/hooks.js +77 -0
  113. package/src/providers/claude-code/hooks.js.map +1 -0
  114. package/src/providers/claude-code/hooks.ts +85 -0
  115. package/src/providers/claude-code/index.d.ts +24 -0
  116. package/src/providers/claude-code/index.d.ts.map +1 -0
  117. package/src/providers/claude-code/index.js +26 -0
  118. package/src/providers/claude-code/index.js.map +1 -0
  119. package/src/providers/claude-code/index.ts +33 -0
  120. package/src/providers/claude-code/install.d.ts +75 -0
  121. package/src/providers/claude-code/install.d.ts.map +1 -0
  122. package/src/providers/claude-code/install.js +237 -0
  123. package/src/providers/claude-code/install.js.map +1 -0
  124. package/src/providers/claude-code/install.ts +267 -0
  125. package/src/providers/claude-code/manifest.json +26 -0
  126. package/src/providers/claude-code/paths.d.ts +24 -0
  127. package/src/providers/claude-code/paths.d.ts.map +1 -0
  128. package/src/providers/claude-code/paths.js +33 -0
  129. package/src/providers/claude-code/paths.js.map +1 -0
  130. package/src/providers/claude-code/paths.ts +38 -0
  131. package/src/providers/claude-code/spawn.d.ts +60 -0
  132. package/src/providers/claude-code/spawn.d.ts.map +1 -0
  133. package/src/providers/claude-code/spawn.js +160 -0
  134. package/src/providers/claude-code/spawn.js.map +1 -0
  135. package/src/providers/claude-code/spawn.ts +178 -0
  136. package/src/providers/claude-code/statusline.d.ts +24 -0
  137. package/src/providers/claude-code/statusline.d.ts.map +1 -0
  138. package/src/providers/claude-code/statusline.js +85 -0
  139. package/src/providers/claude-code/statusline.js.map +1 -0
  140. package/src/providers/claude-code/statusline.ts +99 -0
  141. package/src/providers/claude-code/task-sync.d.ts +27 -0
  142. package/src/providers/claude-code/task-sync.d.ts.map +1 -0
  143. package/src/providers/claude-code/task-sync.js +124 -0
  144. package/src/providers/claude-code/task-sync.js.map +1 -0
  145. package/src/providers/claude-code/task-sync.ts +158 -0
  146. package/src/providers/claude-code/transport.d.ts +14 -0
  147. package/src/providers/claude-code/transport.d.ts.map +1 -0
  148. package/src/providers/claude-code/transport.js +18 -0
  149. package/src/providers/claude-code/transport.js.map +1 -0
  150. package/src/providers/claude-code/transport.ts +21 -0
  151. package/src/providers/cursor/__tests__/adapter.test.d.ts +7 -0
  152. package/src/providers/cursor/__tests__/adapter.test.d.ts.map +1 -0
  153. package/src/providers/cursor/__tests__/adapter.test.js +246 -0
  154. package/src/providers/cursor/__tests__/adapter.test.js.map +1 -0
  155. package/src/providers/cursor/__tests__/adapter.test.ts +291 -0
  156. package/src/providers/cursor/adapter.d.ts +62 -0
  157. package/src/providers/cursor/adapter.d.ts.map +1 -0
  158. package/src/providers/cursor/adapter.js +124 -0
  159. package/src/providers/cursor/adapter.js.map +1 -0
  160. package/src/providers/cursor/adapter.ts +145 -0
  161. package/src/providers/cursor/hooks.d.ts +48 -0
  162. package/src/providers/cursor/hooks.d.ts.map +1 -0
  163. package/src/providers/cursor/hooks.js +55 -0
  164. package/src/providers/cursor/hooks.js.map +1 -0
  165. package/src/providers/cursor/hooks.ts +61 -0
  166. package/src/providers/cursor/index.d.ts +19 -0
  167. package/src/providers/cursor/index.d.ts.map +1 -0
  168. package/src/providers/cursor/index.js +21 -0
  169. package/src/providers/cursor/index.js.map +1 -0
  170. package/src/providers/cursor/index.ts +24 -0
  171. package/src/providers/cursor/install.d.ts +94 -0
  172. package/src/providers/cursor/install.d.ts.map +1 -0
  173. package/src/providers/cursor/install.js +241 -0
  174. package/src/providers/cursor/install.js.map +1 -0
  175. package/src/providers/cursor/install.ts +271 -0
  176. package/src/providers/cursor/manifest.json +26 -0
  177. package/src/providers/cursor/spawn.d.ts +50 -0
  178. package/src/providers/cursor/spawn.d.ts.map +1 -0
  179. package/src/providers/cursor/spawn.js +59 -0
  180. package/src/providers/cursor/spawn.js.map +1 -0
  181. package/src/providers/cursor/spawn.ts +66 -0
  182. package/src/providers/opencode/__tests__/adapter.test.d.ts +7 -0
  183. package/src/providers/opencode/__tests__/adapter.test.d.ts.map +1 -0
  184. package/src/providers/opencode/__tests__/adapter.test.js +263 -0
  185. package/src/providers/opencode/__tests__/adapter.test.js.map +1 -0
  186. package/src/providers/opencode/__tests__/adapter.test.ts +309 -0
  187. package/src/providers/opencode/adapter.d.ts +67 -0
  188. package/src/providers/opencode/adapter.d.ts.map +1 -0
  189. package/src/providers/opencode/adapter.js +144 -0
  190. package/src/providers/opencode/adapter.js.map +1 -0
  191. package/src/providers/opencode/adapter.ts +165 -0
  192. package/src/providers/opencode/hooks.d.ts +66 -0
  193. package/src/providers/opencode/hooks.d.ts.map +1 -0
  194. package/src/providers/opencode/hooks.js +89 -0
  195. package/src/providers/opencode/hooks.js.map +1 -0
  196. package/src/providers/opencode/hooks.ts +97 -0
  197. package/src/providers/opencode/index.d.ts +20 -0
  198. package/src/providers/opencode/index.d.ts.map +1 -0
  199. package/src/providers/opencode/index.js +22 -0
  200. package/src/providers/opencode/index.js.map +1 -0
  201. package/src/providers/opencode/index.ts +25 -0
  202. package/src/providers/opencode/install.d.ts +65 -0
  203. package/src/providers/opencode/install.d.ts.map +1 -0
  204. package/src/providers/opencode/install.js +183 -0
  205. package/src/providers/opencode/install.js.map +1 -0
  206. package/src/providers/opencode/install.ts +206 -0
  207. package/src/providers/opencode/manifest.json +26 -0
  208. package/src/providers/opencode/spawn.d.ts +72 -0
  209. package/src/providers/opencode/spawn.d.ts.map +1 -0
  210. package/src/providers/opencode/spawn.js +219 -0
  211. package/src/providers/opencode/spawn.js.map +1 -0
  212. package/src/providers/opencode/spawn.ts +253 -0
  213. package/src/registry.d.ts +36 -0
  214. package/src/registry.d.ts.map +1 -0
  215. package/src/registry.js +55 -0
  216. package/src/registry.js.map +1 -0
  217. package/src/registry.ts +81 -0
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Tests for the OpenCode adapter package.
3
+ *
4
+ * @task T5240
5
+ */
6
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
7
+ import { OpenCodeAdapter } from '../adapter.js';
8
+ import { OpenCodeHookProvider } from '../hooks.js';
9
+ import { OpenCodeSpawnProvider } from '../spawn.js';
10
+ import { OpenCodeInstallProvider } from '../install.js';
11
+ // Mock child_process for health check and spawn tests
12
+ vi.mock('node:child_process', () => ({
13
+ exec: vi.fn(),
14
+ execFile: vi.fn(),
15
+ spawn: vi.fn(() => ({
16
+ pid: 12345,
17
+ unref: vi.fn(),
18
+ on: vi.fn(),
19
+ })),
20
+ }));
21
+ vi.mock('node:util', async (importOriginal) => {
22
+ const actual = await importOriginal();
23
+ return {
24
+ ...actual,
25
+ promisify: () => {
26
+ // Return a mock for exec that simulates 'which opencode' succeeding
27
+ return vi.fn().mockResolvedValue({ stdout: '/usr/local/bin/opencode', stderr: '' });
28
+ },
29
+ };
30
+ });
31
+ vi.mock('node:fs', async (importOriginal) => {
32
+ const actual = await importOriginal();
33
+ return {
34
+ ...actual,
35
+ existsSync: vi.fn((path) => {
36
+ if (typeof path === 'string' && path.includes('.opencode'))
37
+ return true;
38
+ if (typeof path === 'string' && path.includes('AGENTS.md'))
39
+ return false;
40
+ return false;
41
+ }),
42
+ readFileSync: vi.fn(() => '{}'),
43
+ writeFileSync: vi.fn(),
44
+ mkdirSync: vi.fn(),
45
+ };
46
+ });
47
+ vi.mock('node:fs/promises', () => ({
48
+ writeFile: vi.fn().mockResolvedValue(undefined),
49
+ readFile: vi.fn().mockRejectedValue(new Error('ENOENT')),
50
+ mkdir: vi.fn().mockResolvedValue(undefined),
51
+ unlink: vi.fn().mockResolvedValue(undefined),
52
+ }));
53
+ describe('OpenCodeAdapter', () => {
54
+ let adapter;
55
+ beforeEach(() => {
56
+ adapter = new OpenCodeAdapter();
57
+ });
58
+ afterEach(async () => {
59
+ if (adapter.isInitialized()) {
60
+ await adapter.dispose();
61
+ }
62
+ vi.restoreAllMocks();
63
+ });
64
+ describe('identity', () => {
65
+ it('has correct id', () => {
66
+ expect(adapter.id).toBe('opencode');
67
+ });
68
+ it('has correct name', () => {
69
+ expect(adapter.name).toBe('OpenCode');
70
+ });
71
+ it('has correct version', () => {
72
+ expect(adapter.version).toBe('1.0.0');
73
+ });
74
+ });
75
+ describe('capabilities', () => {
76
+ it('supports hooks', () => {
77
+ expect(adapter.capabilities.supportsHooks).toBe(true);
78
+ });
79
+ it('supports spawn', () => {
80
+ expect(adapter.capabilities.supportsSpawn).toBe(true);
81
+ });
82
+ it('supports install', () => {
83
+ expect(adapter.capabilities.supportsInstall).toBe(true);
84
+ });
85
+ it('supports MCP', () => {
86
+ expect(adapter.capabilities.supportsMcp).toBe(true);
87
+ });
88
+ it('supports instruction files with AGENTS.md pattern', () => {
89
+ expect(adapter.capabilities.supportsInstructionFiles).toBe(true);
90
+ expect(adapter.capabilities.instructionFilePattern).toBe('AGENTS.md');
91
+ });
92
+ it('declares expected hook events', () => {
93
+ expect(adapter.capabilities.supportedHookEvents).toContain('onSessionStart');
94
+ expect(adapter.capabilities.supportedHookEvents).toContain('onSessionEnd');
95
+ expect(adapter.capabilities.supportedHookEvents).toContain('onToolStart');
96
+ expect(adapter.capabilities.supportedHookEvents).toContain('onToolComplete');
97
+ expect(adapter.capabilities.supportedHookEvents).toContain('onError');
98
+ expect(adapter.capabilities.supportedHookEvents).toContain('onPromptSubmit');
99
+ });
100
+ it('supports 6 hook events', () => {
101
+ expect(adapter.capabilities.supportedHookEvents).toHaveLength(6);
102
+ });
103
+ });
104
+ describe('sub-providers', () => {
105
+ it('provides a hook provider', () => {
106
+ expect(adapter.hooks).toBeInstanceOf(OpenCodeHookProvider);
107
+ });
108
+ it('provides a spawn provider', () => {
109
+ expect(adapter.spawn).toBeInstanceOf(OpenCodeSpawnProvider);
110
+ });
111
+ it('provides an install provider', () => {
112
+ expect(adapter.install).toBeInstanceOf(OpenCodeInstallProvider);
113
+ });
114
+ });
115
+ describe('initialize', () => {
116
+ it('sets initialized state', async () => {
117
+ expect(adapter.isInitialized()).toBe(false);
118
+ await adapter.initialize('/tmp/test-project');
119
+ expect(adapter.isInitialized()).toBe(true);
120
+ });
121
+ it('stores project directory', async () => {
122
+ await adapter.initialize('/tmp/test-project');
123
+ expect(adapter.getProjectDir()).toBe('/tmp/test-project');
124
+ });
125
+ });
126
+ describe('dispose', () => {
127
+ it('resets initialized state', async () => {
128
+ await adapter.initialize('/tmp/test-project');
129
+ await adapter.dispose();
130
+ expect(adapter.isInitialized()).toBe(false);
131
+ expect(adapter.getProjectDir()).toBeNull();
132
+ });
133
+ });
134
+ describe('healthCheck', () => {
135
+ it('returns unhealthy when not initialized', async () => {
136
+ const status = await adapter.healthCheck();
137
+ expect(status.healthy).toBe(false);
138
+ expect(status.provider).toBe('opencode');
139
+ expect(status.details?.error).toBe('Adapter not initialized');
140
+ });
141
+ it('returns health status with provider id', async () => {
142
+ await adapter.initialize('/tmp/test-project');
143
+ const status = await adapter.healthCheck();
144
+ expect(status.provider).toBe('opencode');
145
+ expect(typeof status.healthy).toBe('boolean');
146
+ });
147
+ });
148
+ });
149
+ describe('OpenCodeHookProvider', () => {
150
+ let hooks;
151
+ beforeEach(() => {
152
+ hooks = new OpenCodeHookProvider();
153
+ });
154
+ describe('mapProviderEvent', () => {
155
+ it('maps session.start to onSessionStart', () => {
156
+ expect(hooks.mapProviderEvent('session.start')).toBe('onSessionStart');
157
+ });
158
+ it('maps session.end to onSessionEnd', () => {
159
+ expect(hooks.mapProviderEvent('session.end')).toBe('onSessionEnd');
160
+ });
161
+ it('maps tool.start to onToolStart', () => {
162
+ expect(hooks.mapProviderEvent('tool.start')).toBe('onToolStart');
163
+ });
164
+ it('maps tool.complete to onToolComplete', () => {
165
+ expect(hooks.mapProviderEvent('tool.complete')).toBe('onToolComplete');
166
+ });
167
+ it('maps error to onError', () => {
168
+ expect(hooks.mapProviderEvent('error')).toBe('onError');
169
+ });
170
+ it('maps prompt.submit to onPromptSubmit', () => {
171
+ expect(hooks.mapProviderEvent('prompt.submit')).toBe('onPromptSubmit');
172
+ });
173
+ it('returns null for unknown events', () => {
174
+ expect(hooks.mapProviderEvent('UnknownEvent')).toBeNull();
175
+ expect(hooks.mapProviderEvent('')).toBeNull();
176
+ });
177
+ });
178
+ describe('registerNativeHooks', () => {
179
+ it('marks hooks as registered', async () => {
180
+ expect(hooks.isRegistered()).toBe(false);
181
+ await hooks.registerNativeHooks('/tmp/project');
182
+ expect(hooks.isRegistered()).toBe(true);
183
+ });
184
+ });
185
+ describe('unregisterNativeHooks', () => {
186
+ it('marks hooks as unregistered', async () => {
187
+ await hooks.registerNativeHooks('/tmp/project');
188
+ await hooks.unregisterNativeHooks();
189
+ expect(hooks.isRegistered()).toBe(false);
190
+ });
191
+ });
192
+ describe('getEventMap', () => {
193
+ it('returns all mapped events', () => {
194
+ const map = hooks.getEventMap();
195
+ expect(Object.keys(map)).toHaveLength(6);
196
+ expect(map['session.start']).toBe('onSessionStart');
197
+ expect(map['session.end']).toBe('onSessionEnd');
198
+ expect(map['tool.start']).toBe('onToolStart');
199
+ expect(map['tool.complete']).toBe('onToolComplete');
200
+ expect(map['error']).toBe('onError');
201
+ expect(map['prompt.submit']).toBe('onPromptSubmit');
202
+ });
203
+ });
204
+ });
205
+ describe('OpenCodeSpawnProvider', () => {
206
+ let spawn;
207
+ beforeEach(() => {
208
+ spawn = new OpenCodeSpawnProvider();
209
+ });
210
+ describe('canSpawn', () => {
211
+ it('returns a boolean', async () => {
212
+ const result = await spawn.canSpawn();
213
+ expect(typeof result).toBe('boolean');
214
+ });
215
+ });
216
+ describe('listRunning', () => {
217
+ it('returns empty array when no processes spawned', async () => {
218
+ const running = await spawn.listRunning();
219
+ expect(running).toEqual([]);
220
+ });
221
+ });
222
+ describe('terminate', () => {
223
+ it('handles non-existent instance gracefully', async () => {
224
+ await expect(spawn.terminate('non-existent')).resolves.toBeUndefined();
225
+ });
226
+ });
227
+ });
228
+ describe('OpenCodeInstallProvider', () => {
229
+ let installProvider;
230
+ beforeEach(() => {
231
+ installProvider = new OpenCodeInstallProvider();
232
+ });
233
+ describe('isInstalled', () => {
234
+ it('returns a boolean', async () => {
235
+ const result = await installProvider.isInstalled();
236
+ expect(typeof result).toBe('boolean');
237
+ });
238
+ });
239
+ describe('install', () => {
240
+ it('returns a success result', async () => {
241
+ const result = await installProvider.install({
242
+ projectDir: '/tmp/test-project',
243
+ });
244
+ expect(result.success).toBe(true);
245
+ expect(result.installedAt).toBeTruthy();
246
+ expect(typeof result.instructionFileUpdated).toBe('boolean');
247
+ expect(typeof result.mcpRegistered).toBe('boolean');
248
+ });
249
+ it('registers MCP when mcpServerPath provided', async () => {
250
+ const result = await installProvider.install({
251
+ projectDir: '/tmp/test-project',
252
+ mcpServerPath: '/path/to/mcp-server.js',
253
+ });
254
+ expect(result.mcpRegistered).toBe(true);
255
+ });
256
+ });
257
+ describe('uninstall', () => {
258
+ it('handles uninstall when not installed', async () => {
259
+ await expect(installProvider.uninstall()).resolves.toBeUndefined();
260
+ });
261
+ });
262
+ });
263
+ //# sourceMappingURL=adapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.test.js","sourceRoot":"","sources":["adapter.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Tests for the OpenCode adapter package.
3
+ *
4
+ * @task T5240
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
8
+ import { OpenCodeAdapter } from '../adapter.js';
9
+ import { OpenCodeHookProvider } from '../hooks.js';
10
+ import { OpenCodeSpawnProvider } from '../spawn.js';
11
+ import { OpenCodeInstallProvider } from '../install.js';
12
+
13
+ // Mock child_process for health check and spawn tests
14
+ vi.mock('node:child_process', () => ({
15
+ exec: vi.fn(),
16
+ execFile: vi.fn(),
17
+ spawn: vi.fn(() => ({
18
+ pid: 12345,
19
+ unref: vi.fn(),
20
+ on: vi.fn(),
21
+ })),
22
+ }));
23
+
24
+ vi.mock('node:util', async (importOriginal) => {
25
+ const actual = await importOriginal<typeof import('node:util')>();
26
+ return {
27
+ ...actual,
28
+ promisify: () => {
29
+ // Return a mock for exec that simulates 'which opencode' succeeding
30
+ return vi.fn().mockResolvedValue({ stdout: '/usr/local/bin/opencode', stderr: '' });
31
+ },
32
+ };
33
+ });
34
+
35
+ vi.mock('node:fs', async (importOriginal) => {
36
+ const actual = await importOriginal<typeof import('node:fs')>();
37
+ return {
38
+ ...actual,
39
+ existsSync: vi.fn((path: string) => {
40
+ if (typeof path === 'string' && path.includes('.opencode')) return true;
41
+ if (typeof path === 'string' && path.includes('AGENTS.md')) return false;
42
+ return false;
43
+ }),
44
+ readFileSync: vi.fn(() => '{}'),
45
+ writeFileSync: vi.fn(),
46
+ mkdirSync: vi.fn(),
47
+ };
48
+ });
49
+
50
+ vi.mock('node:fs/promises', () => ({
51
+ writeFile: vi.fn().mockResolvedValue(undefined),
52
+ readFile: vi.fn().mockRejectedValue(new Error('ENOENT')),
53
+ mkdir: vi.fn().mockResolvedValue(undefined),
54
+ unlink: vi.fn().mockResolvedValue(undefined),
55
+ }));
56
+
57
+ describe('OpenCodeAdapter', () => {
58
+ let adapter: OpenCodeAdapter;
59
+
60
+ beforeEach(() => {
61
+ adapter = new OpenCodeAdapter();
62
+ });
63
+
64
+ afterEach(async () => {
65
+ if (adapter.isInitialized()) {
66
+ await adapter.dispose();
67
+ }
68
+ vi.restoreAllMocks();
69
+ });
70
+
71
+ describe('identity', () => {
72
+ it('has correct id', () => {
73
+ expect(adapter.id).toBe('opencode');
74
+ });
75
+
76
+ it('has correct name', () => {
77
+ expect(adapter.name).toBe('OpenCode');
78
+ });
79
+
80
+ it('has correct version', () => {
81
+ expect(adapter.version).toBe('1.0.0');
82
+ });
83
+ });
84
+
85
+ describe('capabilities', () => {
86
+ it('supports hooks', () => {
87
+ expect(adapter.capabilities.supportsHooks).toBe(true);
88
+ });
89
+
90
+ it('supports spawn', () => {
91
+ expect(adapter.capabilities.supportsSpawn).toBe(true);
92
+ });
93
+
94
+ it('supports install', () => {
95
+ expect(adapter.capabilities.supportsInstall).toBe(true);
96
+ });
97
+
98
+ it('supports MCP', () => {
99
+ expect(adapter.capabilities.supportsMcp).toBe(true);
100
+ });
101
+
102
+ it('supports instruction files with AGENTS.md pattern', () => {
103
+ expect(adapter.capabilities.supportsInstructionFiles).toBe(true);
104
+ expect(adapter.capabilities.instructionFilePattern).toBe('AGENTS.md');
105
+ });
106
+
107
+ it('declares expected hook events', () => {
108
+ expect(adapter.capabilities.supportedHookEvents).toContain('onSessionStart');
109
+ expect(adapter.capabilities.supportedHookEvents).toContain('onSessionEnd');
110
+ expect(adapter.capabilities.supportedHookEvents).toContain('onToolStart');
111
+ expect(adapter.capabilities.supportedHookEvents).toContain('onToolComplete');
112
+ expect(adapter.capabilities.supportedHookEvents).toContain('onError');
113
+ expect(adapter.capabilities.supportedHookEvents).toContain('onPromptSubmit');
114
+ });
115
+
116
+ it('supports 6 hook events', () => {
117
+ expect(adapter.capabilities.supportedHookEvents).toHaveLength(6);
118
+ });
119
+ });
120
+
121
+ describe('sub-providers', () => {
122
+ it('provides a hook provider', () => {
123
+ expect(adapter.hooks).toBeInstanceOf(OpenCodeHookProvider);
124
+ });
125
+
126
+ it('provides a spawn provider', () => {
127
+ expect(adapter.spawn).toBeInstanceOf(OpenCodeSpawnProvider);
128
+ });
129
+
130
+ it('provides an install provider', () => {
131
+ expect(adapter.install).toBeInstanceOf(OpenCodeInstallProvider);
132
+ });
133
+ });
134
+
135
+ describe('initialize', () => {
136
+ it('sets initialized state', async () => {
137
+ expect(adapter.isInitialized()).toBe(false);
138
+ await adapter.initialize('/tmp/test-project');
139
+ expect(adapter.isInitialized()).toBe(true);
140
+ });
141
+
142
+ it('stores project directory', async () => {
143
+ await adapter.initialize('/tmp/test-project');
144
+ expect(adapter.getProjectDir()).toBe('/tmp/test-project');
145
+ });
146
+ });
147
+
148
+ describe('dispose', () => {
149
+ it('resets initialized state', async () => {
150
+ await adapter.initialize('/tmp/test-project');
151
+ await adapter.dispose();
152
+ expect(adapter.isInitialized()).toBe(false);
153
+ expect(adapter.getProjectDir()).toBeNull();
154
+ });
155
+ });
156
+
157
+ describe('healthCheck', () => {
158
+ it('returns unhealthy when not initialized', async () => {
159
+ const status = await adapter.healthCheck();
160
+ expect(status.healthy).toBe(false);
161
+ expect(status.provider).toBe('opencode');
162
+ expect(status.details?.error).toBe('Adapter not initialized');
163
+ });
164
+
165
+ it('returns health status with provider id', async () => {
166
+ await adapter.initialize('/tmp/test-project');
167
+ const status = await adapter.healthCheck();
168
+ expect(status.provider).toBe('opencode');
169
+ expect(typeof status.healthy).toBe('boolean');
170
+ });
171
+ });
172
+ });
173
+
174
+ describe('OpenCodeHookProvider', () => {
175
+ let hooks: OpenCodeHookProvider;
176
+
177
+ beforeEach(() => {
178
+ hooks = new OpenCodeHookProvider();
179
+ });
180
+
181
+ describe('mapProviderEvent', () => {
182
+ it('maps session.start to onSessionStart', () => {
183
+ expect(hooks.mapProviderEvent('session.start')).toBe('onSessionStart');
184
+ });
185
+
186
+ it('maps session.end to onSessionEnd', () => {
187
+ expect(hooks.mapProviderEvent('session.end')).toBe('onSessionEnd');
188
+ });
189
+
190
+ it('maps tool.start to onToolStart', () => {
191
+ expect(hooks.mapProviderEvent('tool.start')).toBe('onToolStart');
192
+ });
193
+
194
+ it('maps tool.complete to onToolComplete', () => {
195
+ expect(hooks.mapProviderEvent('tool.complete')).toBe('onToolComplete');
196
+ });
197
+
198
+ it('maps error to onError', () => {
199
+ expect(hooks.mapProviderEvent('error')).toBe('onError');
200
+ });
201
+
202
+ it('maps prompt.submit to onPromptSubmit', () => {
203
+ expect(hooks.mapProviderEvent('prompt.submit')).toBe('onPromptSubmit');
204
+ });
205
+
206
+ it('returns null for unknown events', () => {
207
+ expect(hooks.mapProviderEvent('UnknownEvent')).toBeNull();
208
+ expect(hooks.mapProviderEvent('')).toBeNull();
209
+ });
210
+ });
211
+
212
+ describe('registerNativeHooks', () => {
213
+ it('marks hooks as registered', async () => {
214
+ expect(hooks.isRegistered()).toBe(false);
215
+ await hooks.registerNativeHooks('/tmp/project');
216
+ expect(hooks.isRegistered()).toBe(true);
217
+ });
218
+ });
219
+
220
+ describe('unregisterNativeHooks', () => {
221
+ it('marks hooks as unregistered', async () => {
222
+ await hooks.registerNativeHooks('/tmp/project');
223
+ await hooks.unregisterNativeHooks();
224
+ expect(hooks.isRegistered()).toBe(false);
225
+ });
226
+ });
227
+
228
+ describe('getEventMap', () => {
229
+ it('returns all mapped events', () => {
230
+ const map = hooks.getEventMap();
231
+ expect(Object.keys(map)).toHaveLength(6);
232
+ expect(map['session.start']).toBe('onSessionStart');
233
+ expect(map['session.end']).toBe('onSessionEnd');
234
+ expect(map['tool.start']).toBe('onToolStart');
235
+ expect(map['tool.complete']).toBe('onToolComplete');
236
+ expect(map['error']).toBe('onError');
237
+ expect(map['prompt.submit']).toBe('onPromptSubmit');
238
+ });
239
+ });
240
+ });
241
+
242
+ describe('OpenCodeSpawnProvider', () => {
243
+ let spawn: OpenCodeSpawnProvider;
244
+
245
+ beforeEach(() => {
246
+ spawn = new OpenCodeSpawnProvider();
247
+ });
248
+
249
+ describe('canSpawn', () => {
250
+ it('returns a boolean', async () => {
251
+ const result = await spawn.canSpawn();
252
+ expect(typeof result).toBe('boolean');
253
+ });
254
+ });
255
+
256
+ describe('listRunning', () => {
257
+ it('returns empty array when no processes spawned', async () => {
258
+ const running = await spawn.listRunning();
259
+ expect(running).toEqual([]);
260
+ });
261
+ });
262
+
263
+ describe('terminate', () => {
264
+ it('handles non-existent instance gracefully', async () => {
265
+ await expect(spawn.terminate('non-existent')).resolves.toBeUndefined();
266
+ });
267
+ });
268
+ });
269
+
270
+ describe('OpenCodeInstallProvider', () => {
271
+ let installProvider: OpenCodeInstallProvider;
272
+
273
+ beforeEach(() => {
274
+ installProvider = new OpenCodeInstallProvider();
275
+ });
276
+
277
+ describe('isInstalled', () => {
278
+ it('returns a boolean', async () => {
279
+ const result = await installProvider.isInstalled();
280
+ expect(typeof result).toBe('boolean');
281
+ });
282
+ });
283
+
284
+ describe('install', () => {
285
+ it('returns a success result', async () => {
286
+ const result = await installProvider.install({
287
+ projectDir: '/tmp/test-project',
288
+ });
289
+ expect(result.success).toBe(true);
290
+ expect(result.installedAt).toBeTruthy();
291
+ expect(typeof result.instructionFileUpdated).toBe('boolean');
292
+ expect(typeof result.mcpRegistered).toBe('boolean');
293
+ });
294
+
295
+ it('registers MCP when mcpServerPath provided', async () => {
296
+ const result = await installProvider.install({
297
+ projectDir: '/tmp/test-project',
298
+ mcpServerPath: '/path/to/mcp-server.js',
299
+ });
300
+ expect(result.mcpRegistered).toBe(true);
301
+ });
302
+ });
303
+
304
+ describe('uninstall', () => {
305
+ it('handles uninstall when not installed', async () => {
306
+ await expect(installProvider.uninstall()).resolves.toBeUndefined();
307
+ });
308
+ });
309
+ });
@@ -0,0 +1,67 @@
1
+ /**
2
+ * OpenCode Adapter
3
+ *
4
+ * Main CLEOProviderAdapter implementation for OpenCode AI coding assistant.
5
+ * Provides spawn, hooks, and install capabilities for CLEO integration.
6
+ *
7
+ * @task T5240
8
+ */
9
+ import type { AdapterCapabilities, AdapterHealthStatus, CLEOProviderAdapter } from '@cleocode/contracts';
10
+ import { OpenCodeHookProvider } from './hooks.js';
11
+ import { OpenCodeInstallProvider } from './install.js';
12
+ import { OpenCodeSpawnProvider } from './spawn.js';
13
+ /**
14
+ * CLEO provider adapter for OpenCode AI coding assistant.
15
+ *
16
+ * Bridges CLEO's adapter system with OpenCode's native capabilities:
17
+ * - Hooks: Maps OpenCode events (session.start, tool.complete, etc.) to CAAMP events
18
+ * - Spawn: Launches subagent processes via the `opencode` CLI
19
+ * - Install: Registers MCP server in .opencode/config.json and ensures AGENTS.md references
20
+ */
21
+ export declare class OpenCodeAdapter implements CLEOProviderAdapter {
22
+ readonly id = "opencode";
23
+ readonly name = "OpenCode";
24
+ readonly version = "1.0.0";
25
+ capabilities: AdapterCapabilities;
26
+ hooks: OpenCodeHookProvider;
27
+ spawn: OpenCodeSpawnProvider;
28
+ install: OpenCodeInstallProvider;
29
+ private projectDir;
30
+ private initialized;
31
+ constructor();
32
+ /**
33
+ * Initialize the adapter for a given project directory.
34
+ *
35
+ * Validates the environment by checking for the OpenCode CLI
36
+ * and OpenCode configuration directory.
37
+ *
38
+ * @param projectDir - Root directory of the project
39
+ */
40
+ initialize(projectDir: string): Promise<void>;
41
+ /**
42
+ * Dispose the adapter and clean up resources.
43
+ *
44
+ * Unregisters hooks and releases any tracked state.
45
+ */
46
+ dispose(): Promise<void>;
47
+ /**
48
+ * Run a health check to verify OpenCode is accessible.
49
+ *
50
+ * Checks:
51
+ * 1. Adapter has been initialized
52
+ * 2. OpenCode CLI is available in PATH
53
+ * 3. .opencode/ configuration directory exists in the project
54
+ *
55
+ * @returns Health status with details about each check
56
+ */
57
+ healthCheck(): Promise<AdapterHealthStatus>;
58
+ /**
59
+ * Check whether the adapter has been initialized.
60
+ */
61
+ isInitialized(): boolean;
62
+ /**
63
+ * Get the project directory this adapter was initialized with.
64
+ */
65
+ getProjectDir(): string | null;
66
+ }
67
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAInD;;;;;;;GAOG;AACH,qBAAa,eAAgB,YAAW,mBAAmB;IACzD,QAAQ,CAAC,EAAE,cAAc;IACzB,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,OAAO,WAAW;IAE3B,YAAY,EAAE,mBAAmB,CAoB/B;IAEF,KAAK,EAAE,oBAAoB,CAAC;IAC5B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,EAAE,uBAAuB,CAAC;IAEjC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,WAAW,CAAS;;IAQ5B;;;;;;;OAOG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;;;;;;OASG;IACG,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IA2CjD;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;CAG/B"}