@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,97 +1,8 @@
|
|
|
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 { getPendingRequests, acknowledgeRequest, answerQuestion } from './requests.js';
|
|
5
3
|
import { ValidationError } from '../validators.js';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// Test Utilities
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
function createMockSupabase(overrides: {
|
|
12
|
-
selectResult?: { data: unknown; error: unknown };
|
|
13
|
-
updateResult?: { data: unknown; error: unknown };
|
|
14
|
-
sessionsResult?: { data: unknown; error: unknown };
|
|
15
|
-
} = {}) {
|
|
16
|
-
const defaultResult = { data: null, error: null };
|
|
17
|
-
// Use an object to track state so it persists across all mock function calls
|
|
18
|
-
const state = {
|
|
19
|
-
currentOperation: 'select' as string,
|
|
20
|
-
currentTable: '' as string,
|
|
21
|
-
updateCalled: false,
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const mock = {
|
|
25
|
-
from: vi.fn((table: string) => {
|
|
26
|
-
state.currentTable = table;
|
|
27
|
-
// Reset state for new query chain
|
|
28
|
-
state.currentOperation = 'select';
|
|
29
|
-
state.updateCalled = false;
|
|
30
|
-
return mock;
|
|
31
|
-
}),
|
|
32
|
-
select: vi.fn(() => {
|
|
33
|
-
// Don't reset updateCalled - we need to know if update was in this chain
|
|
34
|
-
if (!state.updateCalled) {
|
|
35
|
-
state.currentOperation = 'select';
|
|
36
|
-
}
|
|
37
|
-
return mock;
|
|
38
|
-
}),
|
|
39
|
-
update: vi.fn(() => {
|
|
40
|
-
state.currentOperation = 'update';
|
|
41
|
-
state.updateCalled = true;
|
|
42
|
-
return mock;
|
|
43
|
-
}),
|
|
44
|
-
eq: vi.fn().mockReturnThis(),
|
|
45
|
-
or: vi.fn().mockReturnThis(),
|
|
46
|
-
order: vi.fn().mockReturnThis(),
|
|
47
|
-
single: vi.fn(() => {
|
|
48
|
-
// If update was called in this chain, return updateResult
|
|
49
|
-
if (state.updateCalled) {
|
|
50
|
-
return Promise.resolve(overrides.updateResult ?? defaultResult);
|
|
51
|
-
}
|
|
52
|
-
return Promise.resolve(overrides.selectResult ?? defaultResult);
|
|
53
|
-
}),
|
|
54
|
-
then: vi.fn((resolve: (value: unknown) => void) => {
|
|
55
|
-
if (state.currentTable === 'agent_sessions') {
|
|
56
|
-
return Promise.resolve(overrides.sessionsResult ?? { data: [], error: null }).then(resolve);
|
|
57
|
-
}
|
|
58
|
-
if (state.updateCalled) {
|
|
59
|
-
return Promise.resolve(overrides.updateResult ?? defaultResult).then(resolve);
|
|
60
|
-
}
|
|
61
|
-
if (state.currentOperation === 'select') {
|
|
62
|
-
return Promise.resolve(overrides.selectResult ?? defaultResult).then(resolve);
|
|
63
|
-
}
|
|
64
|
-
return Promise.resolve(defaultResult).then(resolve);
|
|
65
|
-
}),
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
return mock as unknown as SupabaseClient;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function createMockContext(
|
|
72
|
-
supabase: SupabaseClient,
|
|
73
|
-
options: { sessionId?: string | null } = {}
|
|
74
|
-
): HandlerContext {
|
|
75
|
-
const defaultTokenUsage: TokenUsage = {
|
|
76
|
-
callCount: 5,
|
|
77
|
-
totalTokens: 2500,
|
|
78
|
-
byTool: {},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const sessionId = 'sessionId' in options ? options.sessionId : 'session-123';
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
supabase,
|
|
85
|
-
auth: { userId: 'user-123', apiKeyId: 'api-key-123' },
|
|
86
|
-
session: {
|
|
87
|
-
instanceId: 'instance-abc',
|
|
88
|
-
currentSessionId: sessionId,
|
|
89
|
-
currentPersona: 'Wave',
|
|
90
|
-
tokenUsage: defaultTokenUsage,
|
|
91
|
-
},
|
|
92
|
-
updateSession: vi.fn(),
|
|
93
|
-
};
|
|
94
|
-
}
|
|
4
|
+
import { createMockContext } from './__test-utils__.js';
|
|
5
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
95
6
|
|
|
96
7
|
// ============================================================================
|
|
97
8
|
// getPendingRequests Tests
|
|
@@ -101,15 +12,13 @@ describe('getPendingRequests', () => {
|
|
|
101
12
|
beforeEach(() => vi.clearAllMocks());
|
|
102
13
|
|
|
103
14
|
it('should throw error for missing project_id', async () => {
|
|
104
|
-
const
|
|
105
|
-
const ctx = createMockContext(supabase);
|
|
15
|
+
const ctx = createMockContext();
|
|
106
16
|
|
|
107
17
|
await expect(getPendingRequests({}, ctx)).rejects.toThrow(ValidationError);
|
|
108
18
|
});
|
|
109
19
|
|
|
110
20
|
it('should throw error for invalid project_id UUID', async () => {
|
|
111
|
-
const
|
|
112
|
-
const ctx = createMockContext(supabase);
|
|
21
|
+
const ctx = createMockContext();
|
|
113
22
|
|
|
114
23
|
await expect(
|
|
115
24
|
getPendingRequests({ project_id: 'invalid' }, ctx)
|
|
@@ -117,11 +26,11 @@ describe('getPendingRequests', () => {
|
|
|
117
26
|
});
|
|
118
27
|
|
|
119
28
|
it('should return empty list when no requests', async () => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
29
|
+
mockApiClient.getPendingRequests.mockResolvedValue({
|
|
30
|
+
ok: true,
|
|
31
|
+
data: { requests: [] },
|
|
123
32
|
});
|
|
124
|
-
const ctx = createMockContext(
|
|
33
|
+
const ctx = createMockContext();
|
|
125
34
|
|
|
126
35
|
const result = await getPendingRequests(
|
|
127
36
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -131,7 +40,6 @@ describe('getPendingRequests', () => {
|
|
|
131
40
|
expect(result.result).toMatchObject({
|
|
132
41
|
requests: [],
|
|
133
42
|
count: 0,
|
|
134
|
-
questions_count: 0,
|
|
135
43
|
});
|
|
136
44
|
});
|
|
137
45
|
|
|
@@ -141,181 +49,57 @@ describe('getPendingRequests', () => {
|
|
|
141
49
|
id: 'r1',
|
|
142
50
|
request_type: 'task',
|
|
143
51
|
content: 'Please do this',
|
|
144
|
-
session_id: null, // broadcast
|
|
145
|
-
acknowledged_at: null,
|
|
146
|
-
created_at: '2025-01-14T10:00:00Z',
|
|
147
|
-
},
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
const supabase = createMockSupabase({
|
|
151
|
-
selectResult: { data: mockRequests, error: null },
|
|
152
|
-
sessionsResult: { data: [], error: null },
|
|
153
|
-
});
|
|
154
|
-
const ctx = createMockContext(supabase);
|
|
155
|
-
|
|
156
|
-
const result = await getPendingRequests(
|
|
157
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
158
|
-
ctx
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
expect((result.result as { count: number }).count).toBe(1);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should filter broadcast requests (session_id is null)', async () => {
|
|
165
|
-
const mockRequests = [
|
|
166
|
-
{
|
|
167
|
-
id: 'r1',
|
|
168
|
-
request_type: 'task',
|
|
169
|
-
content: 'Broadcast request',
|
|
170
52
|
session_id: null,
|
|
171
53
|
acknowledged_at: null,
|
|
172
54
|
created_at: '2025-01-14T10:00:00Z',
|
|
173
55
|
},
|
|
174
56
|
];
|
|
175
57
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
58
|
+
mockApiClient.getPendingRequests.mockResolvedValue({
|
|
59
|
+
ok: true,
|
|
60
|
+
data: { requests: mockRequests },
|
|
179
61
|
});
|
|
180
|
-
const ctx = createMockContext(
|
|
62
|
+
const ctx = createMockContext();
|
|
181
63
|
|
|
182
64
|
const result = await getPendingRequests(
|
|
183
65
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
184
66
|
ctx
|
|
185
67
|
);
|
|
186
68
|
|
|
187
|
-
// Broadcast request should be included
|
|
188
69
|
expect((result.result as { count: number }).count).toBe(1);
|
|
189
70
|
});
|
|
190
71
|
|
|
191
|
-
it('should
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
request_type: 'task',
|
|
196
|
-
content: 'Targeted request',
|
|
197
|
-
session_id: 'session-123',
|
|
198
|
-
acknowledged_at: null,
|
|
199
|
-
created_at: '2025-01-14T10:00:00Z',
|
|
200
|
-
},
|
|
201
|
-
];
|
|
202
|
-
|
|
203
|
-
const supabase = createMockSupabase({
|
|
204
|
-
selectResult: { data: mockRequests, error: null },
|
|
205
|
-
sessionsResult: { data: [], error: null },
|
|
206
|
-
});
|
|
207
|
-
const ctx = createMockContext(supabase, { sessionId: 'session-123' });
|
|
208
|
-
|
|
209
|
-
const result = await getPendingRequests(
|
|
210
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
211
|
-
ctx
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
expect((result.result as { count: number }).count).toBe(1);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it('should exclude requests targeted to other sessions', async () => {
|
|
218
|
-
const mockRequests = [
|
|
219
|
-
{
|
|
220
|
-
id: 'r1',
|
|
221
|
-
request_type: 'task',
|
|
222
|
-
content: 'Other session request',
|
|
223
|
-
session_id: 'other-session',
|
|
224
|
-
acknowledged_at: null,
|
|
225
|
-
created_at: '2025-01-14T10:00:00Z',
|
|
226
|
-
},
|
|
227
|
-
];
|
|
228
|
-
|
|
229
|
-
const supabase = createMockSupabase({
|
|
230
|
-
selectResult: { data: mockRequests, error: null },
|
|
231
|
-
sessionsResult: { data: [{ id: 'other-session' }], error: null },
|
|
72
|
+
it('should call API client with project_id and session_id', async () => {
|
|
73
|
+
mockApiClient.getPendingRequests.mockResolvedValue({
|
|
74
|
+
ok: true,
|
|
75
|
+
data: { requests: [] },
|
|
232
76
|
});
|
|
233
|
-
const ctx = createMockContext(
|
|
77
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
234
78
|
|
|
235
|
-
|
|
236
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
237
|
-
ctx
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
// Should be excluded because targeted to an active other session
|
|
241
|
-
expect((result.result as { count: number }).count).toBe(0);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('should count unanswered questions', async () => {
|
|
245
|
-
const mockRequests = [
|
|
246
|
-
{
|
|
247
|
-
id: 'r1',
|
|
248
|
-
request_type: 'question',
|
|
249
|
-
content: 'What is this?',
|
|
250
|
-
session_id: null,
|
|
251
|
-
acknowledged_at: null,
|
|
252
|
-
answered_at: null,
|
|
253
|
-
created_at: '2025-01-14T10:00:00Z',
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
id: 'r2',
|
|
257
|
-
request_type: 'task',
|
|
258
|
-
content: 'Do this',
|
|
259
|
-
session_id: null,
|
|
260
|
-
acknowledged_at: null,
|
|
261
|
-
created_at: '2025-01-14T11:00:00Z',
|
|
262
|
-
},
|
|
263
|
-
];
|
|
264
|
-
|
|
265
|
-
const supabase = createMockSupabase({
|
|
266
|
-
selectResult: { data: mockRequests, error: null },
|
|
267
|
-
sessionsResult: { data: [], error: null },
|
|
268
|
-
});
|
|
269
|
-
const ctx = createMockContext(supabase);
|
|
270
|
-
|
|
271
|
-
const result = await getPendingRequests(
|
|
79
|
+
await getPendingRequests(
|
|
272
80
|
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
273
81
|
ctx
|
|
274
82
|
);
|
|
275
83
|
|
|
276
|
-
expect(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
it('should add wait_minutes to requests', async () => {
|
|
280
|
-
const mockRequests = [
|
|
281
|
-
{
|
|
282
|
-
id: 'r1',
|
|
283
|
-
request_type: 'task',
|
|
284
|
-
content: 'Request',
|
|
285
|
-
session_id: null,
|
|
286
|
-
acknowledged_at: null,
|
|
287
|
-
created_at: new Date(Date.now() - 5 * 60000).toISOString(), // 5 minutes ago
|
|
288
|
-
},
|
|
289
|
-
];
|
|
290
|
-
|
|
291
|
-
const supabase = createMockSupabase({
|
|
292
|
-
selectResult: { data: mockRequests, error: null },
|
|
293
|
-
sessionsResult: { data: [], error: null },
|
|
294
|
-
});
|
|
295
|
-
const ctx = createMockContext(supabase);
|
|
296
|
-
|
|
297
|
-
const result = await getPendingRequests(
|
|
298
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
299
|
-
ctx
|
|
84
|
+
expect(mockApiClient.getPendingRequests).toHaveBeenCalledWith(
|
|
85
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
86
|
+
'my-session'
|
|
300
87
|
);
|
|
301
|
-
|
|
302
|
-
const requests = (result.result as { requests: { wait_minutes: number }[] }).requests;
|
|
303
|
-
expect(requests[0].wait_minutes).toBeGreaterThanOrEqual(4); // Allow some margin
|
|
304
88
|
});
|
|
305
89
|
|
|
306
|
-
it('should
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
90
|
+
it('should throw error when API call fails', async () => {
|
|
91
|
+
mockApiClient.getPendingRequests.mockResolvedValue({
|
|
92
|
+
ok: false,
|
|
93
|
+
error: 'Query failed',
|
|
310
94
|
});
|
|
311
|
-
const ctx = createMockContext(
|
|
312
|
-
|
|
313
|
-
await getPendingRequests(
|
|
314
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
315
|
-
ctx
|
|
316
|
-
);
|
|
95
|
+
const ctx = createMockContext();
|
|
317
96
|
|
|
318
|
-
expect(
|
|
97
|
+
await expect(
|
|
98
|
+
getPendingRequests(
|
|
99
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
100
|
+
ctx
|
|
101
|
+
)
|
|
102
|
+
).rejects.toThrow('Failed to get pending requests: Query failed');
|
|
319
103
|
});
|
|
320
104
|
});
|
|
321
105
|
|
|
@@ -327,15 +111,13 @@ describe('acknowledgeRequest', () => {
|
|
|
327
111
|
beforeEach(() => vi.clearAllMocks());
|
|
328
112
|
|
|
329
113
|
it('should throw error for missing request_id', async () => {
|
|
330
|
-
const
|
|
331
|
-
const ctx = createMockContext(supabase);
|
|
114
|
+
const ctx = createMockContext();
|
|
332
115
|
|
|
333
116
|
await expect(acknowledgeRequest({}, ctx)).rejects.toThrow(ValidationError);
|
|
334
117
|
});
|
|
335
118
|
|
|
336
119
|
it('should throw error for invalid request_id UUID', async () => {
|
|
337
|
-
const
|
|
338
|
-
const ctx = createMockContext(supabase);
|
|
120
|
+
const ctx = createMockContext();
|
|
339
121
|
|
|
340
122
|
await expect(
|
|
341
123
|
acknowledgeRequest({ request_id: 'invalid' }, ctx)
|
|
@@ -343,17 +125,11 @@ describe('acknowledgeRequest', () => {
|
|
|
343
125
|
});
|
|
344
126
|
|
|
345
127
|
it('should acknowledge request successfully', async () => {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
content: 'Do this',
|
|
350
|
-
acknowledged_at: '2025-01-14T12:00:00Z',
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
const supabase = createMockSupabase({
|
|
354
|
-
updateResult: { data: mockRequest, error: null },
|
|
128
|
+
mockApiClient.acknowledgeRequest.mockResolvedValue({
|
|
129
|
+
ok: true,
|
|
130
|
+
data: { success: true },
|
|
355
131
|
});
|
|
356
|
-
const ctx = createMockContext(
|
|
132
|
+
const ctx = createMockContext();
|
|
357
133
|
|
|
358
134
|
const result = await acknowledgeRequest(
|
|
359
135
|
{ request_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
@@ -362,52 +138,37 @@ describe('acknowledgeRequest', () => {
|
|
|
362
138
|
|
|
363
139
|
expect(result.result).toMatchObject({
|
|
364
140
|
success: true,
|
|
365
|
-
request: mockRequest,
|
|
366
141
|
});
|
|
367
142
|
});
|
|
368
143
|
|
|
369
|
-
it('should
|
|
370
|
-
|
|
371
|
-
|
|
144
|
+
it('should call API client with request_id and session_id', async () => {
|
|
145
|
+
mockApiClient.acknowledgeRequest.mockResolvedValue({
|
|
146
|
+
ok: true,
|
|
147
|
+
data: { success: true },
|
|
372
148
|
});
|
|
373
|
-
const ctx = createMockContext(
|
|
149
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
374
150
|
|
|
375
151
|
await acknowledgeRequest(
|
|
376
152
|
{ request_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
377
153
|
ctx
|
|
378
154
|
);
|
|
379
155
|
|
|
380
|
-
expect(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
acknowledged_by_session_id: 'my-session',
|
|
384
|
-
})
|
|
385
|
-
);
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
it('should query agent_requests table', async () => {
|
|
389
|
-
const supabase = createMockSupabase({
|
|
390
|
-
updateResult: { data: { id: 'r1' }, error: null },
|
|
391
|
-
});
|
|
392
|
-
const ctx = createMockContext(supabase);
|
|
393
|
-
|
|
394
|
-
await acknowledgeRequest(
|
|
395
|
-
{ request_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
396
|
-
ctx
|
|
156
|
+
expect(mockApiClient.acknowledgeRequest).toHaveBeenCalledWith(
|
|
157
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
158
|
+
'my-session'
|
|
397
159
|
);
|
|
398
|
-
|
|
399
|
-
expect(supabase.from).toHaveBeenCalledWith('agent_requests');
|
|
400
160
|
});
|
|
401
161
|
|
|
402
|
-
it('should throw error when
|
|
403
|
-
|
|
404
|
-
|
|
162
|
+
it('should throw error when API call fails', async () => {
|
|
163
|
+
mockApiClient.acknowledgeRequest.mockResolvedValue({
|
|
164
|
+
ok: false,
|
|
165
|
+
error: 'Update failed',
|
|
405
166
|
});
|
|
406
|
-
const ctx = createMockContext(
|
|
167
|
+
const ctx = createMockContext();
|
|
407
168
|
|
|
408
169
|
await expect(
|
|
409
170
|
acknowledgeRequest({ request_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
410
|
-
).rejects.toThrow();
|
|
171
|
+
).rejects.toThrow('Failed to acknowledge request: Update failed');
|
|
411
172
|
});
|
|
412
173
|
});
|
|
413
174
|
|
|
@@ -419,8 +180,7 @@ describe('answerQuestion', () => {
|
|
|
419
180
|
beforeEach(() => vi.clearAllMocks());
|
|
420
181
|
|
|
421
182
|
it('should throw error for missing request_id', async () => {
|
|
422
|
-
const
|
|
423
|
-
const ctx = createMockContext(supabase);
|
|
183
|
+
const ctx = createMockContext();
|
|
424
184
|
|
|
425
185
|
await expect(
|
|
426
186
|
answerQuestion({ answer: 'The answer' }, ctx)
|
|
@@ -428,8 +188,7 @@ describe('answerQuestion', () => {
|
|
|
428
188
|
});
|
|
429
189
|
|
|
430
190
|
it('should throw error for missing answer', async () => {
|
|
431
|
-
const
|
|
432
|
-
const ctx = createMockContext(supabase);
|
|
191
|
+
const ctx = createMockContext();
|
|
433
192
|
|
|
434
193
|
await expect(
|
|
435
194
|
answerQuestion({ request_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
|
|
@@ -437,8 +196,7 @@ describe('answerQuestion', () => {
|
|
|
437
196
|
});
|
|
438
197
|
|
|
439
198
|
it('should throw error for invalid request_id UUID', async () => {
|
|
440
|
-
const
|
|
441
|
-
const ctx = createMockContext(supabase);
|
|
199
|
+
const ctx = createMockContext();
|
|
442
200
|
|
|
443
201
|
await expect(
|
|
444
202
|
answerQuestion({ request_id: 'invalid', answer: 'The answer' }, ctx)
|
|
@@ -446,18 +204,11 @@ describe('answerQuestion', () => {
|
|
|
446
204
|
});
|
|
447
205
|
|
|
448
206
|
it('should answer question successfully', async () => {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
content: 'What is this?',
|
|
453
|
-
answer: 'This is the answer',
|
|
454
|
-
answered_at: '2025-01-14T12:00:00Z',
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
const supabase = createMockSupabase({
|
|
458
|
-
updateResult: { data: mockRequest, error: null },
|
|
207
|
+
mockApiClient.answerQuestion.mockResolvedValue({
|
|
208
|
+
ok: true,
|
|
209
|
+
data: { success: true },
|
|
459
210
|
});
|
|
460
|
-
const ctx = createMockContext(
|
|
211
|
+
const ctx = createMockContext();
|
|
461
212
|
|
|
462
213
|
const result = await answerQuestion(
|
|
463
214
|
{
|
|
@@ -470,15 +221,15 @@ describe('answerQuestion', () => {
|
|
|
470
221
|
expect(result.result).toMatchObject({
|
|
471
222
|
success: true,
|
|
472
223
|
message: 'Question answered successfully',
|
|
473
|
-
request: mockRequest,
|
|
474
224
|
});
|
|
475
225
|
});
|
|
476
226
|
|
|
477
|
-
it('should
|
|
478
|
-
|
|
479
|
-
|
|
227
|
+
it('should call API client with request_id, answer, and session_id', async () => {
|
|
228
|
+
mockApiClient.answerQuestion.mockResolvedValue({
|
|
229
|
+
ok: true,
|
|
230
|
+
data: { success: true },
|
|
480
231
|
});
|
|
481
|
-
const ctx = createMockContext(
|
|
232
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
482
233
|
|
|
483
234
|
await answerQuestion(
|
|
484
235
|
{
|
|
@@ -488,44 +239,25 @@ describe('answerQuestion', () => {
|
|
|
488
239
|
ctx
|
|
489
240
|
);
|
|
490
241
|
|
|
491
|
-
expect(
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
acknowledged_at: expect.any(String),
|
|
496
|
-
acknowledged_by_session_id: 'my-session',
|
|
497
|
-
})
|
|
242
|
+
expect(mockApiClient.answerQuestion).toHaveBeenCalledWith(
|
|
243
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
244
|
+
'The answer to the question',
|
|
245
|
+
'my-session'
|
|
498
246
|
);
|
|
499
247
|
});
|
|
500
248
|
|
|
501
|
-
it('should
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const ctx = createMockContext(supabase);
|
|
506
|
-
|
|
507
|
-
await answerQuestion(
|
|
508
|
-
{
|
|
509
|
-
request_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
510
|
-
answer: 'Answer',
|
|
511
|
-
},
|
|
512
|
-
ctx
|
|
513
|
-
);
|
|
514
|
-
|
|
515
|
-
expect(supabase.from).toHaveBeenCalledWith('agent_requests');
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
it('should throw error when update fails', async () => {
|
|
519
|
-
const supabase = createMockSupabase({
|
|
520
|
-
updateResult: { data: null, error: { message: 'Update failed' } },
|
|
249
|
+
it('should throw error when API call fails', async () => {
|
|
250
|
+
mockApiClient.answerQuestion.mockResolvedValue({
|
|
251
|
+
ok: false,
|
|
252
|
+
error: 'Update failed',
|
|
521
253
|
});
|
|
522
|
-
const ctx = createMockContext(
|
|
254
|
+
const ctx = createMockContext();
|
|
523
255
|
|
|
524
256
|
await expect(
|
|
525
257
|
answerQuestion({
|
|
526
258
|
request_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
527
259
|
answer: 'Answer',
|
|
528
260
|
}, ctx)
|
|
529
|
-
).rejects.toThrow();
|
|
261
|
+
).rejects.toThrow('Failed to answer question: Update failed');
|
|
530
262
|
});
|
|
531
263
|
});
|