@vibescope/mcp-server 0.0.1 → 0.2.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 +1169 -0
- package/dist/api-client.js +713 -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 +108 -477
- 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 +113 -828
- package/dist/handlers/discovery.d.ts +3 -0
- package/dist/handlers/discovery.js +26 -627
- package/dist/handlers/fallback.d.ts +2 -0
- package/dist/handlers/fallback.js +56 -142
- package/dist/handlers/findings.d.ts +8 -1
- package/dist/handlers/findings.js +65 -68
- 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 +119 -590
- package/dist/handlers/sprints.d.ts +32 -0
- package/dist/handlers/sprints.js +275 -0
- package/dist/handlers/tasks.d.ts +7 -10
- package/dist/handlers/tasks.js +245 -894
- package/dist/handlers/tool-docs.d.ts +9 -0
- package/dist/handlers/tool-docs.js +904 -0
- package/dist/handlers/types.d.ts +11 -3
- package/dist/handlers/validation.d.ts +1 -1
- package/dist/handlers/validation.js +38 -153
- package/dist/index.js +493 -162
- package/dist/knowledge.js +106 -9
- package/dist/tools.js +34 -4
- package/dist/validators.d.ts +21 -0
- package/dist/validators.js +91 -0
- package/package.json +2 -3
- package/src/api-client.ts +1822 -0
- package/src/cli.test.ts +128 -302
- package/src/cli.ts +41 -285
- package/src/handlers/__test-setup__.ts +215 -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 +210 -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 +143 -896
- package/src/handlers/discovery.test.ts +20 -67
- package/src/handlers/discovery.ts +29 -714
- package/src/handlers/fallback.test.ts +206 -361
- package/src/handlers/fallback.ts +81 -156
- package/src/handlers/findings.test.ts +229 -320
- package/src/handlers/findings.ts +76 -64
- 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 +276 -206
- package/src/handlers/session.ts +136 -662
- package/src/handlers/sprints.test.ts +711 -0
- package/src/handlers/sprints.ts +510 -0
- package/src/handlers/tasks.test.ts +669 -353
- package/src/handlers/tasks.ts +263 -1015
- package/src/handlers/tool-docs.ts +1024 -0
- package/src/handlers/types.ts +12 -4
- package/src/handlers/validation.test.ts +237 -568
- package/src/handlers/validation.ts +43 -167
- package/src/index.ts +493 -186
- package/src/tools.ts +2532 -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/knowledge.ts +0 -132
- 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
|
getProjectContext,
|
|
6
4
|
getGitWorkflow,
|
|
@@ -9,114 +7,10 @@ import {
|
|
|
9
7
|
updateProjectReadme,
|
|
10
8
|
} from './project.js';
|
|
11
9
|
import { ValidationError } from '../validators.js';
|
|
10
|
+
import { createMockContext } from './__test-utils__.js';
|
|
11
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
// Test Utilities
|
|
15
|
-
// ============================================================================
|
|
16
|
-
|
|
17
|
-
function createMockSupabase(overrides: {
|
|
18
|
-
selectResult?: { data: unknown; error: unknown };
|
|
19
|
-
insertResult?: { data: unknown; error: unknown };
|
|
20
|
-
updateResult?: { 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
|
-
return Promise.resolve(defaultResult).then(resolve);
|
|
90
|
-
}),
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
return mock as unknown as SupabaseClient;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function createMockContext(
|
|
97
|
-
supabase: SupabaseClient,
|
|
98
|
-
options: { sessionId?: string | null } = {}
|
|
99
|
-
): HandlerContext {
|
|
100
|
-
const defaultTokenUsage: TokenUsage = {
|
|
101
|
-
callCount: 5,
|
|
102
|
-
totalTokens: 2500,
|
|
103
|
-
byTool: {},
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const sessionId = 'sessionId' in options ? options.sessionId : 'session-123';
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
supabase,
|
|
110
|
-
auth: { userId: 'user-123', apiKeyId: 'api-key-123' },
|
|
111
|
-
session: {
|
|
112
|
-
instanceId: 'instance-abc',
|
|
113
|
-
currentSessionId: sessionId,
|
|
114
|
-
currentPersona: 'Wave',
|
|
115
|
-
tokenUsage: defaultTokenUsage,
|
|
116
|
-
},
|
|
117
|
-
updateSession: vi.fn(),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
13
|
+
const VALID_UUID = '123e4567-e89b-12d3-a456-426614174000';
|
|
120
14
|
|
|
121
15
|
// ============================================================================
|
|
122
16
|
// getProjectContext Tests
|
|
@@ -131,26 +25,31 @@ describe('getProjectContext', () => {
|
|
|
131
25
|
{ id: 'proj-2', name: 'Project 2', description: 'Desc 2', status: 'active', git_url: 'https://github.com/test' },
|
|
132
26
|
];
|
|
133
27
|
|
|
134
|
-
|
|
135
|
-
|
|
28
|
+
mockApiClient.listProjects.mockResolvedValue({
|
|
29
|
+
ok: true,
|
|
30
|
+
data: { projects: mockProjects },
|
|
136
31
|
});
|
|
137
|
-
const ctx = createMockContext(
|
|
32
|
+
const ctx = createMockContext();
|
|
138
33
|
|
|
139
34
|
const result = await getProjectContext({}, ctx);
|
|
140
35
|
|
|
141
36
|
expect(result.result).toHaveProperty('projects');
|
|
142
37
|
expect((result.result as { projects: unknown[] }).projects).toEqual(mockProjects);
|
|
143
|
-
expect(
|
|
38
|
+
expect(mockApiClient.listProjects).toHaveBeenCalled();
|
|
144
39
|
});
|
|
145
40
|
|
|
146
41
|
it('should return found: false when project not found', async () => {
|
|
147
|
-
|
|
148
|
-
|
|
42
|
+
mockApiClient.getProject.mockResolvedValue({
|
|
43
|
+
ok: true,
|
|
44
|
+
data: {
|
|
45
|
+
found: false,
|
|
46
|
+
message: 'Project not found. Use create_project to create one.',
|
|
47
|
+
},
|
|
149
48
|
});
|
|
150
|
-
const ctx = createMockContext(
|
|
49
|
+
const ctx = createMockContext();
|
|
151
50
|
|
|
152
51
|
const result = await getProjectContext(
|
|
153
|
-
{ project_id:
|
|
52
|
+
{ project_id: VALID_UUID },
|
|
154
53
|
ctx
|
|
155
54
|
);
|
|
156
55
|
|
|
@@ -161,13 +60,23 @@ describe('getProjectContext', () => {
|
|
|
161
60
|
});
|
|
162
61
|
|
|
163
62
|
it('should find project by git_url', async () => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
63
|
+
mockApiClient.getProject.mockResolvedValue({
|
|
64
|
+
ok: true,
|
|
65
|
+
data: {
|
|
66
|
+
found: true,
|
|
67
|
+
project: {
|
|
68
|
+
id: 'proj-1',
|
|
69
|
+
name: 'Test Project',
|
|
70
|
+
description: null,
|
|
71
|
+
goal: null,
|
|
72
|
+
status: 'active',
|
|
73
|
+
git_url: 'https://github.com/test',
|
|
74
|
+
agent_instructions: null,
|
|
75
|
+
tech_stack: null,
|
|
76
|
+
},
|
|
168
77
|
},
|
|
169
78
|
});
|
|
170
|
-
const ctx = createMockContext(
|
|
79
|
+
const ctx = createMockContext();
|
|
171
80
|
|
|
172
81
|
const result = await getProjectContext(
|
|
173
82
|
{ git_url: 'https://github.com/test' },
|
|
@@ -177,25 +86,49 @@ describe('getProjectContext', () => {
|
|
|
177
86
|
expect(result.result).toMatchObject({
|
|
178
87
|
found: true,
|
|
179
88
|
});
|
|
180
|
-
expect(
|
|
89
|
+
expect(mockApiClient.getProject).toHaveBeenCalledWith(
|
|
90
|
+
'by-git-url',
|
|
91
|
+
'https://github.com/test'
|
|
92
|
+
);
|
|
181
93
|
});
|
|
182
94
|
|
|
183
95
|
it('should include active_tasks in result', async () => {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
96
|
+
mockApiClient.getProject.mockResolvedValue({
|
|
97
|
+
ok: true,
|
|
98
|
+
data: {
|
|
99
|
+
found: true,
|
|
100
|
+
project: {
|
|
101
|
+
id: 'proj-1',
|
|
102
|
+
name: 'Test Project',
|
|
103
|
+
description: null,
|
|
104
|
+
goal: null,
|
|
105
|
+
status: 'active',
|
|
106
|
+
git_url: null,
|
|
107
|
+
agent_instructions: null,
|
|
108
|
+
tech_stack: null,
|
|
109
|
+
},
|
|
110
|
+
active_tasks: [],
|
|
188
111
|
},
|
|
189
112
|
});
|
|
190
|
-
const ctx = createMockContext(
|
|
113
|
+
const ctx = createMockContext();
|
|
191
114
|
|
|
192
115
|
const result = await getProjectContext(
|
|
193
|
-
{ project_id:
|
|
116
|
+
{ project_id: VALID_UUID },
|
|
194
117
|
ctx
|
|
195
118
|
);
|
|
196
119
|
|
|
197
120
|
expect(result.result).toHaveProperty('active_tasks');
|
|
198
121
|
});
|
|
122
|
+
|
|
123
|
+
it('should throw error when API call fails', async () => {
|
|
124
|
+
mockApiClient.listProjects.mockResolvedValue({
|
|
125
|
+
ok: false,
|
|
126
|
+
error: 'Database error',
|
|
127
|
+
});
|
|
128
|
+
const ctx = createMockContext();
|
|
129
|
+
|
|
130
|
+
await expect(getProjectContext({}, ctx)).rejects.toThrow('Database error');
|
|
131
|
+
});
|
|
199
132
|
});
|
|
200
133
|
|
|
201
134
|
// ============================================================================
|
|
@@ -206,15 +139,13 @@ describe('getGitWorkflow', () => {
|
|
|
206
139
|
beforeEach(() => vi.clearAllMocks());
|
|
207
140
|
|
|
208
141
|
it('should throw error for missing project_id', async () => {
|
|
209
|
-
const
|
|
210
|
-
const ctx = createMockContext(supabase);
|
|
142
|
+
const ctx = createMockContext();
|
|
211
143
|
|
|
212
144
|
await expect(getGitWorkflow({}, ctx)).rejects.toThrow(ValidationError);
|
|
213
145
|
});
|
|
214
146
|
|
|
215
147
|
it('should throw error for invalid project_id UUID', async () => {
|
|
216
|
-
const
|
|
217
|
-
const ctx = createMockContext(supabase);
|
|
148
|
+
const ctx = createMockContext();
|
|
218
149
|
|
|
219
150
|
await expect(
|
|
220
151
|
getGitWorkflow({ project_id: 'invalid' }, ctx)
|
|
@@ -222,23 +153,26 @@ describe('getGitWorkflow', () => {
|
|
|
222
153
|
});
|
|
223
154
|
|
|
224
155
|
it('should return workflow instructions for github-flow', async () => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
156
|
+
mockApiClient.getGitWorkflow.mockResolvedValue({
|
|
157
|
+
ok: true,
|
|
158
|
+
data: {
|
|
159
|
+
workflow: 'github-flow',
|
|
160
|
+
main_branch: 'main',
|
|
161
|
+
develop_branch: null,
|
|
162
|
+
auto_branch: true,
|
|
163
|
+
auto_tag: false,
|
|
164
|
+
git_url: 'https://github.com/test',
|
|
165
|
+
instructions: [
|
|
166
|
+
'Create feature branch from main',
|
|
167
|
+
'Make changes and commit',
|
|
168
|
+
'Create PR to main',
|
|
169
|
+
],
|
|
236
170
|
},
|
|
237
171
|
});
|
|
238
|
-
const ctx = createMockContext(
|
|
172
|
+
const ctx = createMockContext();
|
|
239
173
|
|
|
240
174
|
const result = await getGitWorkflow(
|
|
241
|
-
{ project_id:
|
|
175
|
+
{ project_id: VALID_UUID },
|
|
242
176
|
ctx
|
|
243
177
|
);
|
|
244
178
|
|
|
@@ -251,23 +185,22 @@ describe('getGitWorkflow', () => {
|
|
|
251
185
|
});
|
|
252
186
|
|
|
253
187
|
it('should return workflow instructions for git-flow', async () => {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
error: null,
|
|
188
|
+
mockApiClient.getGitWorkflow.mockResolvedValue({
|
|
189
|
+
ok: true,
|
|
190
|
+
data: {
|
|
191
|
+
workflow: 'git-flow',
|
|
192
|
+
main_branch: 'main',
|
|
193
|
+
develop_branch: 'develop',
|
|
194
|
+
auto_branch: false,
|
|
195
|
+
auto_tag: true,
|
|
196
|
+
git_url: 'https://github.com/test',
|
|
197
|
+
instructions: ['Create feature branch from develop'],
|
|
265
198
|
},
|
|
266
199
|
});
|
|
267
|
-
const ctx = createMockContext(
|
|
200
|
+
const ctx = createMockContext();
|
|
268
201
|
|
|
269
202
|
const result = await getGitWorkflow(
|
|
270
|
-
{ project_id:
|
|
203
|
+
{ project_id: VALID_UUID },
|
|
271
204
|
ctx
|
|
272
205
|
);
|
|
273
206
|
|
|
@@ -279,23 +212,22 @@ describe('getGitWorkflow', () => {
|
|
|
279
212
|
});
|
|
280
213
|
|
|
281
214
|
it('should return no workflow instructions when workflow is none', async () => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
error: null,
|
|
215
|
+
mockApiClient.getGitWorkflow.mockResolvedValue({
|
|
216
|
+
ok: true,
|
|
217
|
+
data: {
|
|
218
|
+
workflow: 'none',
|
|
219
|
+
main_branch: 'main',
|
|
220
|
+
develop_branch: null,
|
|
221
|
+
auto_branch: false,
|
|
222
|
+
auto_tag: false,
|
|
223
|
+
git_url: null,
|
|
224
|
+
instructions: ['No git workflow configured for this project.'],
|
|
293
225
|
},
|
|
294
226
|
});
|
|
295
|
-
const ctx = createMockContext(
|
|
227
|
+
const ctx = createMockContext();
|
|
296
228
|
|
|
297
229
|
const result = await getGitWorkflow(
|
|
298
|
-
{ project_id:
|
|
230
|
+
{ project_id: VALID_UUID },
|
|
299
231
|
ctx
|
|
300
232
|
);
|
|
301
233
|
|
|
@@ -306,13 +238,14 @@ describe('getGitWorkflow', () => {
|
|
|
306
238
|
});
|
|
307
239
|
|
|
308
240
|
it('should throw error when project not found', async () => {
|
|
309
|
-
|
|
310
|
-
|
|
241
|
+
mockApiClient.getGitWorkflow.mockResolvedValue({
|
|
242
|
+
ok: false,
|
|
243
|
+
error: 'Project not found',
|
|
311
244
|
});
|
|
312
|
-
const ctx = createMockContext(
|
|
245
|
+
const ctx = createMockContext();
|
|
313
246
|
|
|
314
247
|
await expect(
|
|
315
|
-
getGitWorkflow({ project_id:
|
|
248
|
+
getGitWorkflow({ project_id: VALID_UUID }, ctx)
|
|
316
249
|
).rejects.toThrow('Project not found');
|
|
317
250
|
});
|
|
318
251
|
});
|
|
@@ -334,10 +267,14 @@ describe('createProject', () => {
|
|
|
334
267
|
tech_stack: null,
|
|
335
268
|
};
|
|
336
269
|
|
|
337
|
-
|
|
338
|
-
|
|
270
|
+
mockApiClient.createProject.mockResolvedValue({
|
|
271
|
+
ok: true,
|
|
272
|
+
data: {
|
|
273
|
+
success: true,
|
|
274
|
+
project: mockProject,
|
|
275
|
+
},
|
|
339
276
|
});
|
|
340
|
-
const ctx = createMockContext(
|
|
277
|
+
const ctx = createMockContext();
|
|
341
278
|
|
|
342
279
|
const result = await createProject({ name: 'New Project' }, ctx);
|
|
343
280
|
|
|
@@ -345,7 +282,13 @@ describe('createProject', () => {
|
|
|
345
282
|
success: true,
|
|
346
283
|
project: mockProject,
|
|
347
284
|
});
|
|
348
|
-
expect(
|
|
285
|
+
expect(mockApiClient.createProject).toHaveBeenCalledWith({
|
|
286
|
+
name: 'New Project',
|
|
287
|
+
description: undefined,
|
|
288
|
+
goal: undefined,
|
|
289
|
+
git_url: undefined,
|
|
290
|
+
tech_stack: undefined,
|
|
291
|
+
});
|
|
349
292
|
});
|
|
350
293
|
|
|
351
294
|
it('should create project with all optional fields', async () => {
|
|
@@ -358,10 +301,14 @@ describe('createProject', () => {
|
|
|
358
301
|
tech_stack: ['TypeScript', 'Svelte'],
|
|
359
302
|
};
|
|
360
303
|
|
|
361
|
-
|
|
362
|
-
|
|
304
|
+
mockApiClient.createProject.mockResolvedValue({
|
|
305
|
+
ok: true,
|
|
306
|
+
data: {
|
|
307
|
+
success: true,
|
|
308
|
+
project: mockProject,
|
|
309
|
+
},
|
|
363
310
|
});
|
|
364
|
-
const ctx = createMockContext(
|
|
311
|
+
const ctx = createMockContext();
|
|
365
312
|
|
|
366
313
|
const result = await createProject(
|
|
367
314
|
{
|
|
@@ -381,15 +328,24 @@ describe('createProject', () => {
|
|
|
381
328
|
});
|
|
382
329
|
|
|
383
330
|
it('should throw error when insert fails', async () => {
|
|
384
|
-
|
|
385
|
-
|
|
331
|
+
mockApiClient.createProject.mockResolvedValue({
|
|
332
|
+
ok: false,
|
|
333
|
+
error: 'Failed to create project: Insert failed',
|
|
386
334
|
});
|
|
387
|
-
const ctx = createMockContext(
|
|
335
|
+
const ctx = createMockContext();
|
|
388
336
|
|
|
389
337
|
await expect(
|
|
390
338
|
createProject({ name: 'Test Project' }, ctx)
|
|
391
339
|
).rejects.toThrow('Failed to create project: Insert failed');
|
|
392
340
|
});
|
|
341
|
+
|
|
342
|
+
it('should throw error when name is missing', async () => {
|
|
343
|
+
const ctx = createMockContext();
|
|
344
|
+
|
|
345
|
+
await expect(
|
|
346
|
+
createProject({}, ctx)
|
|
347
|
+
).rejects.toThrow(ValidationError);
|
|
348
|
+
});
|
|
393
349
|
});
|
|
394
350
|
|
|
395
351
|
// ============================================================================
|
|
@@ -400,15 +356,13 @@ describe('updateProject', () => {
|
|
|
400
356
|
beforeEach(() => vi.clearAllMocks());
|
|
401
357
|
|
|
402
358
|
it('should throw error for missing project_id', async () => {
|
|
403
|
-
const
|
|
404
|
-
const ctx = createMockContext(supabase);
|
|
359
|
+
const ctx = createMockContext();
|
|
405
360
|
|
|
406
361
|
await expect(updateProject({}, ctx)).rejects.toThrow(ValidationError);
|
|
407
362
|
});
|
|
408
363
|
|
|
409
364
|
it('should throw error for invalid project_id UUID', async () => {
|
|
410
|
-
const
|
|
411
|
-
const ctx = createMockContext(supabase);
|
|
365
|
+
const ctx = createMockContext();
|
|
412
366
|
|
|
413
367
|
await expect(
|
|
414
368
|
updateProject({ project_id: 'invalid' }, ctx)
|
|
@@ -416,26 +370,29 @@ describe('updateProject', () => {
|
|
|
416
370
|
});
|
|
417
371
|
|
|
418
372
|
it('should throw error for invalid status', async () => {
|
|
419
|
-
const
|
|
420
|
-
const ctx = createMockContext(supabase);
|
|
373
|
+
const ctx = createMockContext();
|
|
421
374
|
|
|
422
375
|
await expect(
|
|
423
376
|
updateProject({
|
|
424
|
-
project_id:
|
|
377
|
+
project_id: VALID_UUID,
|
|
425
378
|
status: 'invalid_status',
|
|
426
379
|
}, ctx)
|
|
427
380
|
).rejects.toThrow(ValidationError);
|
|
428
381
|
});
|
|
429
382
|
|
|
430
383
|
it('should update project successfully', async () => {
|
|
431
|
-
|
|
432
|
-
|
|
384
|
+
mockApiClient.updateProject.mockResolvedValue({
|
|
385
|
+
ok: true,
|
|
386
|
+
data: {
|
|
387
|
+
success: true,
|
|
388
|
+
project_id: VALID_UUID,
|
|
389
|
+
},
|
|
433
390
|
});
|
|
434
|
-
const ctx = createMockContext(
|
|
391
|
+
const ctx = createMockContext();
|
|
435
392
|
|
|
436
393
|
const result = await updateProject(
|
|
437
394
|
{
|
|
438
|
-
project_id:
|
|
395
|
+
project_id: VALID_UUID,
|
|
439
396
|
name: 'Updated Name',
|
|
440
397
|
status: 'active',
|
|
441
398
|
},
|
|
@@ -444,20 +401,30 @@ describe('updateProject', () => {
|
|
|
444
401
|
|
|
445
402
|
expect(result.result).toMatchObject({
|
|
446
403
|
success: true,
|
|
447
|
-
project_id:
|
|
404
|
+
project_id: VALID_UUID,
|
|
448
405
|
});
|
|
449
|
-
expect(
|
|
406
|
+
expect(mockApiClient.updateProject).toHaveBeenCalledWith(
|
|
407
|
+
VALID_UUID,
|
|
408
|
+
{
|
|
409
|
+
name: 'Updated Name',
|
|
410
|
+
status: 'active',
|
|
411
|
+
}
|
|
412
|
+
);
|
|
450
413
|
});
|
|
451
414
|
|
|
452
415
|
it('should update git workflow settings', async () => {
|
|
453
|
-
|
|
454
|
-
|
|
416
|
+
mockApiClient.updateProject.mockResolvedValue({
|
|
417
|
+
ok: true,
|
|
418
|
+
data: {
|
|
419
|
+
success: true,
|
|
420
|
+
project_id: VALID_UUID,
|
|
421
|
+
},
|
|
455
422
|
});
|
|
456
|
-
const ctx = createMockContext(
|
|
423
|
+
const ctx = createMockContext();
|
|
457
424
|
|
|
458
425
|
const result = await updateProject(
|
|
459
426
|
{
|
|
460
|
-
project_id:
|
|
427
|
+
project_id: VALID_UUID,
|
|
461
428
|
git_workflow: 'github-flow',
|
|
462
429
|
git_main_branch: 'main',
|
|
463
430
|
git_auto_branch: true,
|
|
@@ -468,17 +435,26 @@ describe('updateProject', () => {
|
|
|
468
435
|
expect(result.result).toMatchObject({
|
|
469
436
|
success: true,
|
|
470
437
|
});
|
|
438
|
+
expect(mockApiClient.updateProject).toHaveBeenCalledWith(
|
|
439
|
+
VALID_UUID,
|
|
440
|
+
{
|
|
441
|
+
git_workflow: 'github-flow',
|
|
442
|
+
git_main_branch: 'main',
|
|
443
|
+
git_auto_branch: true,
|
|
444
|
+
}
|
|
445
|
+
);
|
|
471
446
|
});
|
|
472
447
|
|
|
473
448
|
it('should throw error when update fails', async () => {
|
|
474
|
-
|
|
475
|
-
|
|
449
|
+
mockApiClient.updateProject.mockResolvedValue({
|
|
450
|
+
ok: false,
|
|
451
|
+
error: 'Failed to update project: Update failed',
|
|
476
452
|
});
|
|
477
|
-
const ctx = createMockContext(
|
|
453
|
+
const ctx = createMockContext();
|
|
478
454
|
|
|
479
455
|
await expect(
|
|
480
456
|
updateProject({
|
|
481
|
-
project_id:
|
|
457
|
+
project_id: VALID_UUID,
|
|
482
458
|
name: 'Test',
|
|
483
459
|
}, ctx)
|
|
484
460
|
).rejects.toThrow('Failed to update project: Update failed');
|
|
@@ -493,8 +469,7 @@ describe('updateProjectReadme', () => {
|
|
|
493
469
|
beforeEach(() => vi.clearAllMocks());
|
|
494
470
|
|
|
495
471
|
it('should throw error for missing project_id', async () => {
|
|
496
|
-
const
|
|
497
|
-
const ctx = createMockContext(supabase);
|
|
472
|
+
const ctx = createMockContext();
|
|
498
473
|
|
|
499
474
|
await expect(
|
|
500
475
|
updateProjectReadme({ readme_content: '# README' }, ctx)
|
|
@@ -502,17 +477,15 @@ describe('updateProjectReadme', () => {
|
|
|
502
477
|
});
|
|
503
478
|
|
|
504
479
|
it('should throw error for missing readme_content', async () => {
|
|
505
|
-
const
|
|
506
|
-
const ctx = createMockContext(supabase);
|
|
480
|
+
const ctx = createMockContext();
|
|
507
481
|
|
|
508
482
|
await expect(
|
|
509
|
-
updateProjectReadme({ project_id:
|
|
483
|
+
updateProjectReadme({ project_id: VALID_UUID }, ctx)
|
|
510
484
|
).rejects.toThrow(ValidationError);
|
|
511
485
|
});
|
|
512
486
|
|
|
513
487
|
it('should throw error for invalid project_id UUID', async () => {
|
|
514
|
-
const
|
|
515
|
-
const ctx = createMockContext(supabase);
|
|
488
|
+
const ctx = createMockContext();
|
|
516
489
|
|
|
517
490
|
await expect(
|
|
518
491
|
updateProjectReadme({
|
|
@@ -523,14 +496,18 @@ describe('updateProjectReadme', () => {
|
|
|
523
496
|
});
|
|
524
497
|
|
|
525
498
|
it('should update readme successfully', async () => {
|
|
526
|
-
|
|
527
|
-
|
|
499
|
+
mockApiClient.updateProjectReadme.mockResolvedValue({
|
|
500
|
+
ok: true,
|
|
501
|
+
data: {
|
|
502
|
+
success: true,
|
|
503
|
+
project_id: VALID_UUID,
|
|
504
|
+
},
|
|
528
505
|
});
|
|
529
|
-
const ctx = createMockContext(
|
|
506
|
+
const ctx = createMockContext();
|
|
530
507
|
|
|
531
508
|
const result = await updateProjectReadme(
|
|
532
509
|
{
|
|
533
|
-
project_id:
|
|
510
|
+
project_id: VALID_UUID,
|
|
534
511
|
readme_content: '# My Project\n\nDescription here.',
|
|
535
512
|
},
|
|
536
513
|
ctx
|
|
@@ -539,22 +516,22 @@ describe('updateProjectReadme', () => {
|
|
|
539
516
|
expect(result.result).toMatchObject({
|
|
540
517
|
success: true,
|
|
541
518
|
});
|
|
542
|
-
expect(
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
})
|
|
519
|
+
expect(mockApiClient.updateProjectReadme).toHaveBeenCalledWith(
|
|
520
|
+
VALID_UUID,
|
|
521
|
+
'# My Project\n\nDescription here.'
|
|
546
522
|
);
|
|
547
523
|
});
|
|
548
524
|
|
|
549
525
|
it('should throw error when update fails', async () => {
|
|
550
|
-
|
|
551
|
-
|
|
526
|
+
mockApiClient.updateProjectReadme.mockResolvedValue({
|
|
527
|
+
ok: false,
|
|
528
|
+
error: 'Failed to update README: Update failed',
|
|
552
529
|
});
|
|
553
|
-
const ctx = createMockContext(
|
|
530
|
+
const ctx = createMockContext();
|
|
554
531
|
|
|
555
532
|
await expect(
|
|
556
533
|
updateProjectReadme({
|
|
557
|
-
project_id:
|
|
534
|
+
project_id: VALID_UUID,
|
|
558
535
|
readme_content: '# README',
|
|
559
536
|
}, ctx)
|
|
560
537
|
).rejects.toThrow('Failed to update README: Update failed');
|