@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.
- package/README.md +113 -98
- package/dist/api-client.d.ts +1114 -0
- package/dist/api-client.js +698 -0
- package/dist/cli.d.ts +1 -6
- package/dist/cli.js +39 -240
- package/dist/config/tool-categories.d.ts +31 -0
- package/dist/config/tool-categories.js +253 -0
- package/dist/handlers/blockers.js +57 -58
- package/dist/handlers/bodies-of-work.d.ts +2 -0
- package/dist/handlers/bodies-of-work.js +106 -476
- package/dist/handlers/cost.d.ts +1 -0
- package/dist/handlers/cost.js +35 -113
- package/dist/handlers/decisions.d.ts +2 -0
- package/dist/handlers/decisions.js +28 -27
- package/dist/handlers/deployment.js +112 -828
- package/dist/handlers/discovery.js +31 -0
- package/dist/handlers/fallback.d.ts +2 -0
- package/dist/handlers/fallback.js +39 -134
- package/dist/handlers/findings.js +43 -67
- package/dist/handlers/git-issues.d.ts +9 -13
- package/dist/handlers/git-issues.js +80 -225
- package/dist/handlers/ideas.d.ts +3 -0
- package/dist/handlers/ideas.js +53 -134
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +6 -0
- package/dist/handlers/milestones.d.ts +2 -0
- package/dist/handlers/milestones.js +51 -98
- package/dist/handlers/organizations.js +79 -275
- package/dist/handlers/progress.d.ts +2 -0
- package/dist/handlers/progress.js +25 -123
- package/dist/handlers/project.js +42 -221
- package/dist/handlers/requests.d.ts +2 -0
- package/dist/handlers/requests.js +23 -83
- package/dist/handlers/session.js +99 -585
- package/dist/handlers/sprints.d.ts +32 -0
- package/dist/handlers/sprints.js +274 -0
- package/dist/handlers/tasks.d.ts +7 -10
- package/dist/handlers/tasks.js +230 -900
- package/dist/handlers/tool-docs.d.ts +8 -0
- package/dist/handlers/tool-docs.js +657 -0
- package/dist/handlers/types.d.ts +11 -3
- package/dist/handlers/validation.d.ts +1 -1
- package/dist/handlers/validation.js +26 -153
- package/dist/index.js +473 -160
- package/dist/knowledge.js +106 -9
- package/dist/tools.js +4 -0
- package/dist/validators.d.ts +21 -0
- package/dist/validators.js +91 -0
- package/package.json +2 -3
- package/src/api-client.ts +1752 -0
- package/src/cli.test.ts +128 -302
- package/src/cli.ts +41 -285
- package/src/handlers/__test-setup__.ts +210 -0
- package/src/handlers/__test-utils__.ts +4 -134
- package/src/handlers/blockers.test.ts +114 -124
- package/src/handlers/blockers.ts +68 -70
- package/src/handlers/bodies-of-work.test.ts +236 -831
- package/src/handlers/bodies-of-work.ts +194 -525
- package/src/handlers/cost.test.ts +149 -113
- package/src/handlers/cost.ts +44 -132
- package/src/handlers/decisions.test.ts +111 -209
- package/src/handlers/decisions.ts +35 -27
- package/src/handlers/deployment.test.ts +193 -239
- package/src/handlers/deployment.ts +140 -895
- package/src/handlers/discovery.test.ts +20 -67
- package/src/handlers/discovery.ts +32 -0
- package/src/handlers/fallback.test.ts +128 -361
- package/src/handlers/fallback.ts +62 -148
- package/src/handlers/findings.test.ts +127 -345
- package/src/handlers/findings.ts +49 -66
- package/src/handlers/git-issues.test.ts +623 -0
- package/src/handlers/git-issues.ts +174 -0
- package/src/handlers/ideas.test.ts +229 -343
- package/src/handlers/ideas.ts +69 -143
- package/src/handlers/index.ts +6 -0
- package/src/handlers/milestones.test.ts +167 -281
- package/src/handlers/milestones.ts +54 -93
- package/src/handlers/organizations.test.ts +275 -467
- package/src/handlers/organizations.ts +84 -294
- package/src/handlers/progress.test.ts +112 -218
- package/src/handlers/progress.ts +29 -142
- package/src/handlers/project.test.ts +203 -226
- package/src/handlers/project.ts +48 -238
- package/src/handlers/requests.test.ts +74 -342
- package/src/handlers/requests.ts +25 -83
- package/src/handlers/session.test.ts +241 -206
- package/src/handlers/session.ts +110 -657
- package/src/handlers/sprints.test.ts +711 -0
- package/src/handlers/sprints.ts +497 -0
- package/src/handlers/tasks.test.ts +608 -353
- package/src/handlers/tasks.ts +248 -1025
- package/src/handlers/types.ts +12 -4
- package/src/handlers/validation.test.ts +189 -572
- package/src/handlers/validation.ts +29 -166
- package/src/index.ts +473 -184
- package/src/knowledge.ts +107 -9
- package/src/tools.ts +2506 -0
- package/src/validators.test.ts +223 -223
- package/src/validators.ts +127 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +14 -13
- package/dist/cli.test.d.ts +0 -1
- package/dist/cli.test.js +0 -367
- package/dist/handlers/__test-utils__.d.ts +0 -72
- package/dist/handlers/__test-utils__.js +0 -176
- package/dist/handlers/checkouts.d.ts +0 -37
- package/dist/handlers/checkouts.js +0 -377
- package/dist/handlers/knowledge-query.d.ts +0 -22
- package/dist/handlers/knowledge-query.js +0 -253
- package/dist/handlers/knowledge.d.ts +0 -12
- package/dist/handlers/knowledge.js +0 -108
- package/dist/handlers/roles.d.ts +0 -30
- package/dist/handlers/roles.js +0 -281
- package/dist/handlers/tasks.test.d.ts +0 -1
- package/dist/handlers/tasks.test.js +0 -431
- package/dist/utils.test.d.ts +0 -1
- package/dist/utils.test.js +0 -532
- package/dist/validators.test.d.ts +0 -1
- package/dist/validators.test.js +0 -176
- package/src/tmpclaude-0078-cwd +0 -1
- package/src/tmpclaude-0ee1-cwd +0 -1
- package/src/tmpclaude-2dd5-cwd +0 -1
- package/src/tmpclaude-344c-cwd +0 -1
- package/src/tmpclaude-3860-cwd +0 -1
- package/src/tmpclaude-4b63-cwd +0 -1
- package/src/tmpclaude-5c73-cwd +0 -1
- package/src/tmpclaude-5ee3-cwd +0 -1
- package/src/tmpclaude-6795-cwd +0 -1
- package/src/tmpclaude-709e-cwd +0 -1
- package/src/tmpclaude-9839-cwd +0 -1
- package/src/tmpclaude-d829-cwd +0 -1
- package/src/tmpclaude-e072-cwd +0 -1
- package/src/tmpclaude-f6ee-cwd +0 -1
- package/tmpclaude-0439-cwd +0 -1
- package/tmpclaude-132f-cwd +0 -1
- package/tmpclaude-15bb-cwd +0 -1
- package/tmpclaude-165a-cwd +0 -1
- package/tmpclaude-1ba9-cwd +0 -1
- package/tmpclaude-21a3-cwd +0 -1
- package/tmpclaude-2a38-cwd +0 -1
- package/tmpclaude-2adf-cwd +0 -1
- package/tmpclaude-2f56-cwd +0 -1
- package/tmpclaude-3626-cwd +0 -1
- package/tmpclaude-3727-cwd +0 -1
- package/tmpclaude-40bc-cwd +0 -1
- package/tmpclaude-436f-cwd +0 -1
- package/tmpclaude-4783-cwd +0 -1
- package/tmpclaude-4b6d-cwd +0 -1
- package/tmpclaude-4ba4-cwd +0 -1
- package/tmpclaude-51e6-cwd +0 -1
- package/tmpclaude-5ecf-cwd +0 -1
- package/tmpclaude-6f97-cwd +0 -1
- package/tmpclaude-7fb2-cwd +0 -1
- package/tmpclaude-825c-cwd +0 -1
- package/tmpclaude-8baf-cwd +0 -1
- package/tmpclaude-8d9f-cwd +0 -1
- package/tmpclaude-975c-cwd +0 -1
- package/tmpclaude-9983-cwd +0 -1
- package/tmpclaude-a045-cwd +0 -1
- package/tmpclaude-ac4a-cwd +0 -1
- package/tmpclaude-b593-cwd +0 -1
- package/tmpclaude-b891-cwd +0 -1
- package/tmpclaude-c032-cwd +0 -1
- package/tmpclaude-cf43-cwd +0 -1
- package/tmpclaude-d040-cwd +0 -1
- package/tmpclaude-dcdd-cwd +0 -1
- package/tmpclaude-dcee-cwd +0 -1
- package/tmpclaude-e16b-cwd +0 -1
- package/tmpclaude-ecd2-cwd +0 -1
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
172
|
-
|
|
55
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
56
|
+
ok: true,
|
|
57
|
+
data: { message: 'Started code_review' },
|
|
173
58
|
});
|
|
174
|
-
const ctx = createMockContext(
|
|
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
|
|
192
|
-
|
|
193
|
-
|
|
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(
|
|
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(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
232
|
-
|
|
113
|
+
mockApiClient.startFallbackActivity.mockResolvedValue({
|
|
114
|
+
ok: true,
|
|
115
|
+
data: { message: `Started ${activity}` },
|
|
233
116
|
});
|
|
234
|
-
const ctx = createMockContext(
|
|
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
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
|
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
|
|
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
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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(
|
|
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
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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(
|
|
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(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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(
|
|
363
|
-
|
|
364
|
-
await stopFallbackActivity(
|
|
365
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
366
|
-
ctx
|
|
367
|
-
);
|
|
216
|
+
const ctx = createMockContext();
|
|
368
217
|
|
|
369
|
-
expect(
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
403
|
-
|
|
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(
|
|
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
|
-
|
|
437
|
-
|
|
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(
|
|
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
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
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(
|
|
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(
|
|
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
|
|
516
|
-
|
|
517
|
-
|
|
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(
|
|
335
|
+
const ctx = createMockContext();
|
|
520
336
|
|
|
521
|
-
await
|
|
522
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
523
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
555
|
-
|
|
365
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
366
|
+
ok: true,
|
|
367
|
+
data: {
|
|
368
|
+
schedules: [],
|
|
369
|
+
due_activities: [],
|
|
370
|
+
count: 0,
|
|
371
|
+
},
|
|
556
372
|
});
|
|
557
|
-
const ctx = createMockContext(
|
|
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
|
-
|
|
590
|
-
|
|
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(
|
|
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
|
|
604
|
-
|
|
605
|
-
|
|
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(
|
|
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(
|
|
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
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
});
|