@vibescope/mcp-server 0.0.1 → 0.1.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 (170) hide show
  1. package/README.md +113 -98
  2. package/dist/api-client.d.ts +1114 -0
  3. package/dist/api-client.js +698 -0
  4. package/dist/cli.d.ts +1 -6
  5. package/dist/cli.js +39 -240
  6. package/dist/config/tool-categories.d.ts +31 -0
  7. package/dist/config/tool-categories.js +253 -0
  8. package/dist/handlers/blockers.js +57 -58
  9. package/dist/handlers/bodies-of-work.d.ts +2 -0
  10. package/dist/handlers/bodies-of-work.js +106 -476
  11. package/dist/handlers/cost.d.ts +1 -0
  12. package/dist/handlers/cost.js +35 -113
  13. package/dist/handlers/decisions.d.ts +2 -0
  14. package/dist/handlers/decisions.js +28 -27
  15. package/dist/handlers/deployment.js +112 -828
  16. package/dist/handlers/discovery.js +31 -0
  17. package/dist/handlers/fallback.d.ts +2 -0
  18. package/dist/handlers/fallback.js +39 -134
  19. package/dist/handlers/findings.js +43 -67
  20. package/dist/handlers/git-issues.d.ts +9 -13
  21. package/dist/handlers/git-issues.js +80 -225
  22. package/dist/handlers/ideas.d.ts +3 -0
  23. package/dist/handlers/ideas.js +53 -134
  24. package/dist/handlers/index.d.ts +2 -0
  25. package/dist/handlers/index.js +6 -0
  26. package/dist/handlers/milestones.d.ts +2 -0
  27. package/dist/handlers/milestones.js +51 -98
  28. package/dist/handlers/organizations.js +79 -275
  29. package/dist/handlers/progress.d.ts +2 -0
  30. package/dist/handlers/progress.js +25 -123
  31. package/dist/handlers/project.js +42 -221
  32. package/dist/handlers/requests.d.ts +2 -0
  33. package/dist/handlers/requests.js +23 -83
  34. package/dist/handlers/session.js +99 -585
  35. package/dist/handlers/sprints.d.ts +32 -0
  36. package/dist/handlers/sprints.js +274 -0
  37. package/dist/handlers/tasks.d.ts +7 -10
  38. package/dist/handlers/tasks.js +230 -900
  39. package/dist/handlers/tool-docs.d.ts +8 -0
  40. package/dist/handlers/tool-docs.js +657 -0
  41. package/dist/handlers/types.d.ts +11 -3
  42. package/dist/handlers/validation.d.ts +1 -1
  43. package/dist/handlers/validation.js +26 -153
  44. package/dist/index.js +473 -160
  45. package/dist/knowledge.js +106 -9
  46. package/dist/tools.js +4 -0
  47. package/dist/validators.d.ts +21 -0
  48. package/dist/validators.js +91 -0
  49. package/package.json +2 -3
  50. package/src/api-client.ts +1752 -0
  51. package/src/cli.test.ts +128 -302
  52. package/src/cli.ts +41 -285
  53. package/src/handlers/__test-setup__.ts +210 -0
  54. package/src/handlers/__test-utils__.ts +4 -134
  55. package/src/handlers/blockers.test.ts +114 -124
  56. package/src/handlers/blockers.ts +68 -70
  57. package/src/handlers/bodies-of-work.test.ts +236 -831
  58. package/src/handlers/bodies-of-work.ts +194 -525
  59. package/src/handlers/cost.test.ts +149 -113
  60. package/src/handlers/cost.ts +44 -132
  61. package/src/handlers/decisions.test.ts +111 -209
  62. package/src/handlers/decisions.ts +35 -27
  63. package/src/handlers/deployment.test.ts +193 -239
  64. package/src/handlers/deployment.ts +140 -895
  65. package/src/handlers/discovery.test.ts +20 -67
  66. package/src/handlers/discovery.ts +32 -0
  67. package/src/handlers/fallback.test.ts +128 -361
  68. package/src/handlers/fallback.ts +62 -148
  69. package/src/handlers/findings.test.ts +127 -345
  70. package/src/handlers/findings.ts +49 -66
  71. package/src/handlers/git-issues.test.ts +623 -0
  72. package/src/handlers/git-issues.ts +174 -0
  73. package/src/handlers/ideas.test.ts +229 -343
  74. package/src/handlers/ideas.ts +69 -143
  75. package/src/handlers/index.ts +6 -0
  76. package/src/handlers/milestones.test.ts +167 -281
  77. package/src/handlers/milestones.ts +54 -93
  78. package/src/handlers/organizations.test.ts +275 -467
  79. package/src/handlers/organizations.ts +84 -294
  80. package/src/handlers/progress.test.ts +112 -218
  81. package/src/handlers/progress.ts +29 -142
  82. package/src/handlers/project.test.ts +203 -226
  83. package/src/handlers/project.ts +48 -238
  84. package/src/handlers/requests.test.ts +74 -342
  85. package/src/handlers/requests.ts +25 -83
  86. package/src/handlers/session.test.ts +241 -206
  87. package/src/handlers/session.ts +110 -657
  88. package/src/handlers/sprints.test.ts +711 -0
  89. package/src/handlers/sprints.ts +497 -0
  90. package/src/handlers/tasks.test.ts +608 -353
  91. package/src/handlers/tasks.ts +248 -1025
  92. package/src/handlers/types.ts +12 -4
  93. package/src/handlers/validation.test.ts +189 -572
  94. package/src/handlers/validation.ts +29 -166
  95. package/src/index.ts +473 -184
  96. package/src/knowledge.ts +107 -9
  97. package/src/tools.ts +2506 -0
  98. package/src/validators.test.ts +223 -223
  99. package/src/validators.ts +127 -0
  100. package/tsconfig.json +1 -1
  101. package/vitest.config.ts +14 -13
  102. package/dist/cli.test.d.ts +0 -1
  103. package/dist/cli.test.js +0 -367
  104. package/dist/handlers/__test-utils__.d.ts +0 -72
  105. package/dist/handlers/__test-utils__.js +0 -176
  106. package/dist/handlers/checkouts.d.ts +0 -37
  107. package/dist/handlers/checkouts.js +0 -377
  108. package/dist/handlers/knowledge-query.d.ts +0 -22
  109. package/dist/handlers/knowledge-query.js +0 -253
  110. package/dist/handlers/knowledge.d.ts +0 -12
  111. package/dist/handlers/knowledge.js +0 -108
  112. package/dist/handlers/roles.d.ts +0 -30
  113. package/dist/handlers/roles.js +0 -281
  114. package/dist/handlers/tasks.test.d.ts +0 -1
  115. package/dist/handlers/tasks.test.js +0 -431
  116. package/dist/utils.test.d.ts +0 -1
  117. package/dist/utils.test.js +0 -532
  118. package/dist/validators.test.d.ts +0 -1
  119. package/dist/validators.test.js +0 -176
  120. package/src/tmpclaude-0078-cwd +0 -1
  121. package/src/tmpclaude-0ee1-cwd +0 -1
  122. package/src/tmpclaude-2dd5-cwd +0 -1
  123. package/src/tmpclaude-344c-cwd +0 -1
  124. package/src/tmpclaude-3860-cwd +0 -1
  125. package/src/tmpclaude-4b63-cwd +0 -1
  126. package/src/tmpclaude-5c73-cwd +0 -1
  127. package/src/tmpclaude-5ee3-cwd +0 -1
  128. package/src/tmpclaude-6795-cwd +0 -1
  129. package/src/tmpclaude-709e-cwd +0 -1
  130. package/src/tmpclaude-9839-cwd +0 -1
  131. package/src/tmpclaude-d829-cwd +0 -1
  132. package/src/tmpclaude-e072-cwd +0 -1
  133. package/src/tmpclaude-f6ee-cwd +0 -1
  134. package/tmpclaude-0439-cwd +0 -1
  135. package/tmpclaude-132f-cwd +0 -1
  136. package/tmpclaude-15bb-cwd +0 -1
  137. package/tmpclaude-165a-cwd +0 -1
  138. package/tmpclaude-1ba9-cwd +0 -1
  139. package/tmpclaude-21a3-cwd +0 -1
  140. package/tmpclaude-2a38-cwd +0 -1
  141. package/tmpclaude-2adf-cwd +0 -1
  142. package/tmpclaude-2f56-cwd +0 -1
  143. package/tmpclaude-3626-cwd +0 -1
  144. package/tmpclaude-3727-cwd +0 -1
  145. package/tmpclaude-40bc-cwd +0 -1
  146. package/tmpclaude-436f-cwd +0 -1
  147. package/tmpclaude-4783-cwd +0 -1
  148. package/tmpclaude-4b6d-cwd +0 -1
  149. package/tmpclaude-4ba4-cwd +0 -1
  150. package/tmpclaude-51e6-cwd +0 -1
  151. package/tmpclaude-5ecf-cwd +0 -1
  152. package/tmpclaude-6f97-cwd +0 -1
  153. package/tmpclaude-7fb2-cwd +0 -1
  154. package/tmpclaude-825c-cwd +0 -1
  155. package/tmpclaude-8baf-cwd +0 -1
  156. package/tmpclaude-8d9f-cwd +0 -1
  157. package/tmpclaude-975c-cwd +0 -1
  158. package/tmpclaude-9983-cwd +0 -1
  159. package/tmpclaude-a045-cwd +0 -1
  160. package/tmpclaude-ac4a-cwd +0 -1
  161. package/tmpclaude-b593-cwd +0 -1
  162. package/tmpclaude-b891-cwd +0 -1
  163. package/tmpclaude-c032-cwd +0 -1
  164. package/tmpclaude-cf43-cwd +0 -1
  165. package/tmpclaude-d040-cwd +0 -1
  166. package/tmpclaude-dcdd-cwd +0 -1
  167. package/tmpclaude-dcee-cwd +0 -1
  168. package/tmpclaude-e16b-cwd +0 -1
  169. package/tmpclaude-ecd2-cwd +0 -1
  170. package/tmpclaude-f48d-cwd +0 -1
@@ -1,6 +1,4 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import type { SupabaseClient } from '@supabase/supabase-js';
3
- import type { HandlerContext, TokenUsage } from './types.js';
4
2
  import {
5
3
  startFallbackActivity,
6
4
  stopFallbackActivity,
@@ -8,118 +6,8 @@ import {
8
6
  getActivitySchedules,
9
7
  } from './fallback.js';
10
8
  import { ValidationError } from '../validators.js';
11
-
12
- // ============================================================================
13
- // Test Utilities
14
- // ============================================================================
15
-
16
- function createMockSupabase(overrides: {
17
- selectResult?: { data: unknown; error: unknown };
18
- insertResult?: { data: unknown; error: unknown };
19
- updateResult?: { data: unknown; error: unknown };
20
- deleteResult?: { data: unknown; error: unknown };
21
- } = {}) {
22
- const defaultResult = { data: null, error: null };
23
- let currentOperation = 'select';
24
- let insertThenSelect = false;
25
-
26
- const mock = {
27
- from: vi.fn().mockReturnThis(),
28
- select: vi.fn(() => {
29
- if (currentOperation === 'insert') {
30
- insertThenSelect = true;
31
- } else {
32
- currentOperation = 'select';
33
- insertThenSelect = false;
34
- }
35
- return mock;
36
- }),
37
- insert: vi.fn(() => {
38
- currentOperation = 'insert';
39
- insertThenSelect = false;
40
- return mock;
41
- }),
42
- update: vi.fn(() => {
43
- currentOperation = 'update';
44
- insertThenSelect = false;
45
- return mock;
46
- }),
47
- delete: vi.fn(() => {
48
- currentOperation = 'delete';
49
- insertThenSelect = false;
50
- return mock;
51
- }),
52
- eq: vi.fn().mockReturnThis(),
53
- neq: vi.fn().mockReturnThis(),
54
- in: vi.fn().mockReturnThis(),
55
- is: vi.fn().mockReturnThis(),
56
- not: vi.fn().mockReturnThis(),
57
- or: vi.fn().mockReturnThis(),
58
- gt: vi.fn().mockReturnThis(),
59
- gte: vi.fn().mockReturnThis(),
60
- lte: vi.fn().mockReturnThis(),
61
- lt: vi.fn().mockReturnThis(),
62
- order: vi.fn().mockReturnThis(),
63
- limit: vi.fn().mockReturnThis(),
64
- single: vi.fn(() => {
65
- if (currentOperation === 'insert' || insertThenSelect) {
66
- return Promise.resolve(overrides.insertResult ?? defaultResult);
67
- }
68
- if (currentOperation === 'select') {
69
- return Promise.resolve(overrides.selectResult ?? defaultResult);
70
- }
71
- if (currentOperation === 'update') {
72
- return Promise.resolve(overrides.updateResult ?? defaultResult);
73
- }
74
- return Promise.resolve(defaultResult);
75
- }),
76
- maybeSingle: vi.fn(() => {
77
- return Promise.resolve(overrides.selectResult ?? defaultResult);
78
- }),
79
- then: vi.fn((resolve: (value: unknown) => void) => {
80
- if (currentOperation === 'insert' || insertThenSelect) {
81
- return Promise.resolve(overrides.insertResult ?? defaultResult).then(resolve);
82
- }
83
- if (currentOperation === 'select') {
84
- return Promise.resolve(overrides.selectResult ?? defaultResult).then(resolve);
85
- }
86
- if (currentOperation === 'update') {
87
- return Promise.resolve(overrides.updateResult ?? defaultResult).then(resolve);
88
- }
89
- if (currentOperation === 'delete') {
90
- return Promise.resolve(overrides.deleteResult ?? defaultResult).then(resolve);
91
- }
92
- return Promise.resolve(defaultResult).then(resolve);
93
- }),
94
- };
95
-
96
- return mock as unknown as SupabaseClient;
97
- }
98
-
99
- function createMockContext(
100
- supabase: SupabaseClient,
101
- options: { sessionId?: string | null } = {}
102
- ): HandlerContext {
103
- const defaultTokenUsage: TokenUsage = {
104
- callCount: 5,
105
- totalTokens: 2500,
106
- byTool: {},
107
- };
108
-
109
- const sessionId = 'sessionId' in options ? options.sessionId : 'session-123';
110
-
111
- return {
112
- supabase,
113
- auth: { userId: 'user-123', apiKeyId: 'api-key-123' },
114
- session: {
115
- instanceId: 'instance-abc',
116
- currentSessionId: sessionId,
117
- currentPersona: 'Wave',
118
- tokenUsage: defaultTokenUsage,
119
- },
120
- updateSession: vi.fn(),
121
- };
122
- }
9
+ import { createMockContext } from './__test-utils__.js';
10
+ import { mockApiClient } from './__test-setup__.js';
123
11
 
124
12
  // ============================================================================
125
13
  // startFallbackActivity Tests
@@ -129,8 +17,7 @@ describe('startFallbackActivity', () => {
129
17
  beforeEach(() => vi.clearAllMocks());
130
18
 
131
19
  it('should throw error for missing project_id', async () => {
132
- const supabase = createMockSupabase();
133
- const ctx = createMockContext(supabase);
20
+ const ctx = createMockContext();
134
21
 
135
22
  await expect(
136
23
  startFallbackActivity({ activity: 'code_review' }, ctx)
@@ -138,8 +25,7 @@ describe('startFallbackActivity', () => {
138
25
  });
139
26
 
140
27
  it('should throw error for invalid project_id UUID', async () => {
141
- const supabase = createMockSupabase();
142
- const ctx = createMockContext(supabase);
28
+ const ctx = createMockContext();
143
29
 
144
30
  await expect(
145
31
  startFallbackActivity({ project_id: 'invalid', activity: 'code_review' }, ctx)
@@ -147,8 +33,7 @@ describe('startFallbackActivity', () => {
147
33
  });
148
34
 
149
35
  it('should throw error for missing activity', async () => {
150
- const supabase = createMockSupabase();
151
- const ctx = createMockContext(supabase);
36
+ const ctx = createMockContext();
152
37
 
153
38
  await expect(
154
39
  startFallbackActivity({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
@@ -156,8 +41,7 @@ describe('startFallbackActivity', () => {
156
41
  });
157
42
 
158
43
  it('should throw error for invalid activity type', async () => {
159
- const supabase = createMockSupabase();
160
- const ctx = createMockContext(supabase);
44
+ const ctx = createMockContext();
161
45
 
162
46
  await expect(
163
47
  startFallbackActivity({
@@ -168,10 +52,11 @@ describe('startFallbackActivity', () => {
168
52
  });
169
53
 
170
54
  it('should start fallback activity successfully', async () => {
171
- const supabase = createMockSupabase({
172
- updateResult: { data: null, error: null },
55
+ mockApiClient.startFallbackActivity.mockResolvedValue({
56
+ ok: true,
57
+ data: { message: 'Started code_review' },
173
58
  });
174
- const ctx = createMockContext(supabase);
59
+ const ctx = createMockContext();
175
60
 
176
61
  const result = await startFallbackActivity(
177
62
  {
@@ -188,11 +73,12 @@ describe('startFallbackActivity', () => {
188
73
  expect((result.result as { title: string }).title).toBeDefined();
189
74
  });
190
75
 
191
- it('should update agent_sessions with fallback activity', async () => {
192
- const supabase = createMockSupabase({
193
- updateResult: { data: null, error: null },
76
+ it('should call API client with correct parameters', async () => {
77
+ mockApiClient.startFallbackActivity.mockResolvedValue({
78
+ ok: true,
79
+ data: { message: 'Started' },
194
80
  });
195
- const ctx = createMockContext(supabase, { sessionId: 'my-session' });
81
+ const ctx = createMockContext({ sessionId: 'my-session' });
196
82
 
197
83
  await startFallbackActivity(
198
84
  {
@@ -202,15 +88,11 @@ describe('startFallbackActivity', () => {
202
88
  ctx
203
89
  );
204
90
 
205
- expect(supabase.from).toHaveBeenCalledWith('agent_sessions');
206
- expect(supabase.update).toHaveBeenCalledWith(
207
- expect.objectContaining({
208
- current_fallback_activity: 'security_review',
209
- current_task_id: null,
210
- status: 'active',
211
- })
91
+ expect(mockApiClient.startFallbackActivity).toHaveBeenCalledWith(
92
+ '123e4567-e89b-12d3-a456-426614174000',
93
+ 'security_review',
94
+ 'my-session'
212
95
  );
213
- expect(supabase.eq).toHaveBeenCalledWith('id', 'my-session');
214
96
  });
215
97
 
216
98
  it('should accept all valid activity types', async () => {
@@ -228,10 +110,11 @@ describe('startFallbackActivity', () => {
228
110
  ];
229
111
 
230
112
  for (const activity of validActivities) {
231
- const supabase = createMockSupabase({
232
- updateResult: { data: null, error: null },
113
+ mockApiClient.startFallbackActivity.mockResolvedValue({
114
+ ok: true,
115
+ data: { message: `Started ${activity}` },
233
116
  });
234
- const ctx = createMockContext(supabase);
117
+ const ctx = createMockContext();
235
118
 
236
119
  const result = await startFallbackActivity(
237
120
  {
@@ -248,25 +131,19 @@ describe('startFallbackActivity', () => {
248
131
  }
249
132
  });
250
133
 
251
- it('should throw error when update fails', async () => {
252
- const supabase = createMockSupabase();
253
- const ctx = createMockContext(supabase);
254
-
255
- // Override update to return error
256
- vi.mocked(supabase.from('').update).mockReturnValue({
257
- ...supabase,
258
- eq: vi.fn().mockReturnValue({
259
- then: (resolve: (val: unknown) => void) =>
260
- Promise.resolve({ data: null, error: { message: 'Update failed' } }).then(resolve),
261
- }),
262
- } as unknown as ReturnType<SupabaseClient['from']>);
134
+ it('should throw error when API call fails', async () => {
135
+ mockApiClient.startFallbackActivity.mockResolvedValue({
136
+ ok: false,
137
+ error: 'Failed to start activity',
138
+ });
139
+ const ctx = createMockContext();
263
140
 
264
141
  await expect(
265
142
  startFallbackActivity({
266
143
  project_id: '123e4567-e89b-12d3-a456-426614174000',
267
144
  activity: 'code_review',
268
145
  }, ctx)
269
- ).rejects.toThrow();
146
+ ).rejects.toThrow('Failed to start fallback activity');
270
147
  });
271
148
  });
272
149
 
@@ -278,46 +155,25 @@ describe('stopFallbackActivity', () => {
278
155
  beforeEach(() => vi.clearAllMocks());
279
156
 
280
157
  it('should throw error for missing project_id', async () => {
281
- const supabase = createMockSupabase();
282
- const ctx = createMockContext(supabase);
158
+ const ctx = createMockContext();
283
159
 
284
160
  await expect(stopFallbackActivity({}, ctx)).rejects.toThrow(ValidationError);
285
161
  });
286
162
 
287
163
  it('should throw error for invalid project_id UUID', async () => {
288
- const supabase = createMockSupabase();
289
- const ctx = createMockContext(supabase);
164
+ const ctx = createMockContext();
290
165
 
291
166
  await expect(
292
167
  stopFallbackActivity({ project_id: 'invalid' }, ctx)
293
168
  ).rejects.toThrow(ValidationError);
294
169
  });
295
170
 
296
- it('should stop fallback activity successfully when activity exists', async () => {
297
- const supabase = createMockSupabase({
298
- selectResult: { data: { current_fallback_activity: 'code_review' }, error: null },
299
- insertResult: { data: null, error: null },
300
- updateResult: { data: null, error: null },
171
+ it('should stop fallback activity successfully', async () => {
172
+ mockApiClient.stopFallbackActivity.mockResolvedValue({
173
+ ok: true,
174
+ data: { success: true },
301
175
  });
302
- const ctx = createMockContext(supabase);
303
-
304
- const result = await stopFallbackActivity(
305
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
306
- ctx
307
- );
308
-
309
- expect(result.result).toMatchObject({
310
- success: true,
311
- });
312
- expect((result.result as { message: string }).message).toContain('code_review');
313
- });
314
-
315
- it('should stop fallback activity when no activity was active', async () => {
316
- const supabase = createMockSupabase({
317
- selectResult: { data: { current_fallback_activity: null }, error: null },
318
- updateResult: { data: null, error: null },
319
- });
320
- const ctx = createMockContext(supabase);
176
+ const ctx = createMockContext();
321
177
 
322
178
  const result = await stopFallbackActivity(
323
179
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
@@ -330,13 +186,12 @@ describe('stopFallbackActivity', () => {
330
186
  });
331
187
  });
332
188
 
333
- it('should include summary in history when provided', async () => {
334
- const supabase = createMockSupabase({
335
- selectResult: { data: { current_fallback_activity: 'code_review' }, error: null },
336
- insertResult: { data: null, error: null },
337
- updateResult: { data: null, error: null },
189
+ it('should call API client with summary when provided', async () => {
190
+ mockApiClient.stopFallbackActivity.mockResolvedValue({
191
+ ok: true,
192
+ data: { success: true },
338
193
  });
339
- const ctx = createMockContext(supabase);
194
+ const ctx = createMockContext({ sessionId: 'my-session' });
340
195
 
341
196
  await stopFallbackActivity(
342
197
  {
@@ -346,32 +201,25 @@ describe('stopFallbackActivity', () => {
346
201
  ctx
347
202
  );
348
203
 
349
- expect(supabase.from).toHaveBeenCalledWith('background_activity_history');
350
- expect(supabase.insert).toHaveBeenCalledWith(
351
- expect.objectContaining({
352
- summary: 'Reviewed 5 files, found 3 issues',
353
- })
204
+ expect(mockApiClient.stopFallbackActivity).toHaveBeenCalledWith(
205
+ '123e4567-e89b-12d3-a456-426614174000',
206
+ 'Reviewed 5 files, found 3 issues',
207
+ 'my-session'
354
208
  );
355
209
  });
356
210
 
357
- it('should clear session fallback activity', async () => {
358
- const supabase = createMockSupabase({
359
- selectResult: { data: { current_fallback_activity: null }, error: null },
360
- updateResult: { data: null, error: null },
211
+ it('should throw error when API call fails', async () => {
212
+ mockApiClient.stopFallbackActivity.mockResolvedValue({
213
+ ok: false,
214
+ error: 'Failed to stop activity',
361
215
  });
362
- const ctx = createMockContext(supabase, { sessionId: 'my-session' });
363
-
364
- await stopFallbackActivity(
365
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
366
- ctx
367
- );
216
+ const ctx = createMockContext();
368
217
 
369
- expect(supabase.update).toHaveBeenCalledWith(
370
- expect.objectContaining({
371
- current_fallback_activity: null,
372
- status: 'idle',
373
- })
374
- );
218
+ await expect(
219
+ stopFallbackActivity({
220
+ project_id: '123e4567-e89b-12d3-a456-426614174000',
221
+ }, ctx)
222
+ ).rejects.toThrow('Failed to stop fallback activity');
375
223
  });
376
224
  });
377
225
 
@@ -383,15 +231,13 @@ describe('getActivityHistory', () => {
383
231
  beforeEach(() => vi.clearAllMocks());
384
232
 
385
233
  it('should throw error for missing project_id', async () => {
386
- const supabase = createMockSupabase();
387
- const ctx = createMockContext(supabase);
234
+ const ctx = createMockContext();
388
235
 
389
236
  await expect(getActivityHistory({}, ctx)).rejects.toThrow(ValidationError);
390
237
  });
391
238
 
392
239
  it('should throw error for invalid project_id UUID', async () => {
393
- const supabase = createMockSupabase();
394
- const ctx = createMockContext(supabase);
240
+ const ctx = createMockContext();
395
241
 
396
242
  await expect(
397
243
  getActivityHistory({ project_id: 'invalid' }, ctx)
@@ -399,10 +245,15 @@ describe('getActivityHistory', () => {
399
245
  });
400
246
 
401
247
  it('should return empty history when no activities', async () => {
402
- const supabase = createMockSupabase({
403
- selectResult: { data: [], error: null },
248
+ mockApiClient.proxy.mockResolvedValue({
249
+ ok: true,
250
+ data: {
251
+ history: [],
252
+ latest_by_type: {},
253
+ count: 0,
254
+ },
404
255
  });
405
- const ctx = createMockContext(supabase);
256
+ const ctx = createMockContext();
406
257
 
407
258
  const result = await getActivityHistory(
408
259
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
@@ -415,28 +266,31 @@ describe('getActivityHistory', () => {
415
266
  });
416
267
  });
417
268
 
418
- it('should return activity history', async () => {
269
+ it('should return activity history from API', async () => {
419
270
  const mockHistory = [
420
271
  {
421
272
  id: 'h1',
422
273
  activity_type: 'code_review',
423
274
  completed_at: '2025-01-14T10:00:00Z',
424
275
  summary: 'Reviewed auth module',
425
- agent_sessions: { agent_name: 'Wave' },
426
276
  },
427
277
  {
428
278
  id: 'h2',
429
279
  activity_type: 'security_review',
430
280
  completed_at: '2025-01-14T09:00:00Z',
431
281
  summary: null,
432
- agent_sessions: { agent_name: 'Glitch' },
433
282
  },
434
283
  ];
435
284
 
436
- const supabase = createMockSupabase({
437
- selectResult: { data: mockHistory, error: null },
285
+ mockApiClient.proxy.mockResolvedValue({
286
+ ok: true,
287
+ data: {
288
+ history: mockHistory,
289
+ latest_by_type: { code_review: mockHistory[0] },
290
+ count: 2,
291
+ },
438
292
  });
439
- const ctx = createMockContext(supabase);
293
+ const ctx = createMockContext();
440
294
 
441
295
  const result = await getActivityHistory(
442
296
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
@@ -447,83 +301,42 @@ describe('getActivityHistory', () => {
447
301
  expect((result.result as { count: number }).count).toBe(2);
448
302
  });
449
303
 
450
- it('should include latest_by_type in response', async () => {
451
- const mockHistory = [
452
- {
453
- id: 'h1',
454
- activity_type: 'code_review',
455
- completed_at: '2025-01-14T10:00:00Z',
456
- agent_sessions: null,
457
- },
458
- {
459
- id: 'h2',
460
- activity_type: 'code_review',
461
- completed_at: '2025-01-14T09:00:00Z',
462
- agent_sessions: null,
463
- },
464
- ];
465
-
466
- const supabase = createMockSupabase({
467
- selectResult: { data: mockHistory, error: null },
304
+ it('should call API proxy with correct parameters', async () => {
305
+ mockApiClient.proxy.mockResolvedValue({
306
+ ok: true,
307
+ data: { history: [], count: 0 },
468
308
  });
469
- const ctx = createMockContext(supabase);
470
-
471
- const result = await getActivityHistory(
472
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
473
- ctx
474
- );
475
-
476
- const latestByType = (result.result as { latest_by_type: Record<string, unknown> }).latest_by_type;
477
- expect(latestByType['code_review']).toBeDefined();
478
- expect((latestByType['code_review'] as { id: string }).id).toBe('h1');
479
- });
480
-
481
- it('should filter by activity_type when provided', async () => {
482
- const supabase = createMockSupabase({
483
- selectResult: { data: [], error: null },
484
- });
485
- const ctx = createMockContext(supabase);
309
+ const ctx = createMockContext();
486
310
 
487
311
  await getActivityHistory(
488
312
  {
489
313
  project_id: '123e4567-e89b-12d3-a456-426614174000',
490
314
  activity_type: 'security_review',
315
+ limit: 10,
491
316
  },
492
317
  ctx
493
318
  );
494
319
 
495
- expect(supabase.eq).toHaveBeenCalledWith('activity_type', 'security_review');
496
- });
497
-
498
- it('should respect limit parameter', async () => {
499
- const supabase = createMockSupabase({
500
- selectResult: { data: [], error: null },
501
- });
502
- const ctx = createMockContext(supabase);
503
-
504
- await getActivityHistory(
320
+ expect(mockApiClient.proxy).toHaveBeenCalledWith(
321
+ 'get_activity_history',
505
322
  {
506
323
  project_id: '123e4567-e89b-12d3-a456-426614174000',
324
+ activity_type: 'security_review',
507
325
  limit: 10,
508
- },
509
- ctx
326
+ }
510
327
  );
511
-
512
- expect(supabase.limit).toHaveBeenCalledWith(10);
513
328
  });
514
329
 
515
- it('should query background_activity_history table', async () => {
516
- const supabase = createMockSupabase({
517
- selectResult: { data: [], error: null },
330
+ it('should throw error when API call fails', async () => {
331
+ mockApiClient.proxy.mockResolvedValue({
332
+ ok: false,
333
+ error: 'Query failed',
518
334
  });
519
- const ctx = createMockContext(supabase);
335
+ const ctx = createMockContext();
520
336
 
521
- await getActivityHistory(
522
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
523
- ctx
524
- );
525
-
526
- expect(supabase.from).toHaveBeenCalledWith('background_activity_history');
337
+ await expect(
338
+ getActivityHistory({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
339
+ ).rejects.toThrow('Failed to get activity history');
527
340
  });
528
341
  });
529
342
 
@@ -535,15 +348,13 @@ describe('getActivitySchedules', () => {
535
348
  beforeEach(() => vi.clearAllMocks());
536
349
 
537
350
  it('should throw error for missing project_id', async () => {
538
- const supabase = createMockSupabase();
539
- const ctx = createMockContext(supabase);
351
+ const ctx = createMockContext();
540
352
 
541
353
  await expect(getActivitySchedules({}, ctx)).rejects.toThrow(ValidationError);
542
354
  });
543
355
 
544
356
  it('should throw error for invalid project_id UUID', async () => {
545
- const supabase = createMockSupabase();
546
- const ctx = createMockContext(supabase);
357
+ const ctx = createMockContext();
547
358
 
548
359
  await expect(
549
360
  getActivitySchedules({ project_id: 'invalid' }, ctx)
@@ -551,10 +362,15 @@ describe('getActivitySchedules', () => {
551
362
  });
552
363
 
553
364
  it('should return empty schedules when none exist', async () => {
554
- const supabase = createMockSupabase({
555
- selectResult: { data: [], error: null },
365
+ mockApiClient.proxy.mockResolvedValue({
366
+ ok: true,
367
+ data: {
368
+ schedules: [],
369
+ due_activities: [],
370
+ count: 0,
371
+ },
556
372
  });
557
- const ctx = createMockContext(supabase);
373
+ const ctx = createMockContext();
558
374
 
559
375
  const result = await getActivitySchedules(
560
376
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
@@ -568,7 +384,7 @@ describe('getActivitySchedules', () => {
568
384
  });
569
385
  });
570
386
 
571
- it('should return activity schedules', async () => {
387
+ it('should return activity schedules from API', async () => {
572
388
  const mockSchedules = [
573
389
  {
574
390
  id: 's1',
@@ -586,10 +402,15 @@ describe('getActivitySchedules', () => {
586
402
  },
587
403
  ];
588
404
 
589
- const supabase = createMockSupabase({
590
- selectResult: { data: mockSchedules, error: null },
405
+ mockApiClient.proxy.mockResolvedValue({
406
+ ok: true,
407
+ data: {
408
+ schedules: mockSchedules,
409
+ due_activities: ['code_review'],
410
+ count: 2,
411
+ },
591
412
  });
592
- const ctx = createMockContext(supabase);
413
+ const ctx = createMockContext();
593
414
 
594
415
  const result = await getActivitySchedules(
595
416
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
@@ -598,90 +419,36 @@ describe('getActivitySchedules', () => {
598
419
 
599
420
  expect((result.result as { schedules: unknown[] }).schedules).toHaveLength(2);
600
421
  expect((result.result as { count: number }).count).toBe(2);
422
+ expect((result.result as { due_activities: string[] }).due_activities).toContain('code_review');
601
423
  });
602
424
 
603
- it('should identify due activities', async () => {
604
- const pastDate = new Date(Date.now() - 3600000).toISOString(); // 1 hour ago
605
- const futureDate = new Date(Date.now() + 3600000).toISOString(); // 1 hour from now
606
-
607
- const mockSchedules = [
608
- {
609
- id: 's1',
610
- activity_type: 'code_review',
611
- enabled: true,
612
- next_run_at: pastDate, // Due
613
- },
614
- {
615
- id: 's2',
616
- activity_type: 'security_review',
617
- enabled: true,
618
- next_run_at: futureDate, // Not due
619
- },
620
- {
621
- id: 's3',
622
- activity_type: 'test_coverage',
623
- enabled: false, // Disabled
624
- next_run_at: pastDate,
625
- },
626
- ];
627
-
628
- const supabase = createMockSupabase({
629
- selectResult: { data: mockSchedules, error: null },
630
- });
631
- const ctx = createMockContext(supabase);
632
-
633
- const result = await getActivitySchedules(
634
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
635
- ctx
636
- );
637
-
638
- const dueActivities = (result.result as { due_activities: string[] }).due_activities;
639
- expect(dueActivities).toContain('code_review');
640
- expect(dueActivities).not.toContain('security_review');
641
- expect(dueActivities).not.toContain('test_coverage');
642
- });
643
-
644
- it('should query background_activity_schedules table', async () => {
645
- const supabase = createMockSupabase({
646
- selectResult: { data: [], error: null },
425
+ it('should call API proxy with correct parameters', async () => {
426
+ mockApiClient.proxy.mockResolvedValue({
427
+ ok: true,
428
+ data: { schedules: [], due_activities: [], count: 0 },
647
429
  });
648
- const ctx = createMockContext(supabase);
430
+ const ctx = createMockContext();
649
431
 
650
432
  await getActivitySchedules(
651
433
  { project_id: '123e4567-e89b-12d3-a456-426614174000' },
652
434
  ctx
653
435
  );
654
436
 
655
- expect(supabase.from).toHaveBeenCalledWith('background_activity_schedules');
656
- });
657
-
658
- it('should order schedules by activity_type', async () => {
659
- const supabase = createMockSupabase({
660
- selectResult: { data: [], error: null },
661
- });
662
- const ctx = createMockContext(supabase);
663
-
664
- await getActivitySchedules(
665
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
666
- ctx
437
+ expect(mockApiClient.proxy).toHaveBeenCalledWith(
438
+ 'get_activity_schedules',
439
+ { project_id: '123e4567-e89b-12d3-a456-426614174000' }
667
440
  );
668
-
669
- expect(supabase.order).toHaveBeenCalledWith('activity_type');
670
441
  });
671
442
 
672
- it('should throw error when query fails', async () => {
673
- const supabase = createMockSupabase();
674
- const ctx = createMockContext(supabase);
675
-
676
- // Override to return error
677
- vi.mocked(supabase.from('').select).mockReturnValue({
678
- ...supabase,
679
- then: (resolve: (val: unknown) => void) =>
680
- Promise.resolve({ data: null, error: { message: 'Query failed' } }).then(resolve),
681
- } as unknown as ReturnType<SupabaseClient['from']>);
443
+ it('should throw error when API call fails', async () => {
444
+ mockApiClient.proxy.mockResolvedValue({
445
+ ok: false,
446
+ error: 'Query failed',
447
+ });
448
+ const ctx = createMockContext();
682
449
 
683
450
  await expect(
684
451
  getActivitySchedules({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
685
- ).rejects.toThrow();
452
+ ).rejects.toThrow('Failed to get activity schedules');
686
453
  });
687
454
  });