@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.
Files changed (173) hide show
  1. package/README.md +113 -98
  2. package/dist/api-client.d.ts +1169 -0
  3. package/dist/api-client.js +713 -0
  4. package/dist/cli.d.ts +1 -6
  5. package/dist/cli.js +39 -240
  6. package/dist/config/tool-categories.d.ts +31 -0
  7. package/dist/config/tool-categories.js +253 -0
  8. package/dist/handlers/blockers.js +57 -58
  9. package/dist/handlers/bodies-of-work.d.ts +2 -0
  10. package/dist/handlers/bodies-of-work.js +108 -477
  11. package/dist/handlers/cost.d.ts +1 -0
  12. package/dist/handlers/cost.js +35 -113
  13. package/dist/handlers/decisions.d.ts +2 -0
  14. package/dist/handlers/decisions.js +28 -27
  15. package/dist/handlers/deployment.js +113 -828
  16. package/dist/handlers/discovery.d.ts +3 -0
  17. package/dist/handlers/discovery.js +26 -627
  18. package/dist/handlers/fallback.d.ts +2 -0
  19. package/dist/handlers/fallback.js +56 -142
  20. package/dist/handlers/findings.d.ts +8 -1
  21. package/dist/handlers/findings.js +65 -68
  22. package/dist/handlers/git-issues.d.ts +9 -13
  23. package/dist/handlers/git-issues.js +80 -225
  24. package/dist/handlers/ideas.d.ts +3 -0
  25. package/dist/handlers/ideas.js +53 -134
  26. package/dist/handlers/index.d.ts +2 -0
  27. package/dist/handlers/index.js +6 -0
  28. package/dist/handlers/milestones.d.ts +2 -0
  29. package/dist/handlers/milestones.js +51 -98
  30. package/dist/handlers/organizations.js +79 -275
  31. package/dist/handlers/progress.d.ts +2 -0
  32. package/dist/handlers/progress.js +25 -123
  33. package/dist/handlers/project.js +42 -221
  34. package/dist/handlers/requests.d.ts +2 -0
  35. package/dist/handlers/requests.js +23 -83
  36. package/dist/handlers/session.js +119 -590
  37. package/dist/handlers/sprints.d.ts +32 -0
  38. package/dist/handlers/sprints.js +275 -0
  39. package/dist/handlers/tasks.d.ts +7 -10
  40. package/dist/handlers/tasks.js +245 -894
  41. package/dist/handlers/tool-docs.d.ts +9 -0
  42. package/dist/handlers/tool-docs.js +904 -0
  43. package/dist/handlers/types.d.ts +11 -3
  44. package/dist/handlers/validation.d.ts +1 -1
  45. package/dist/handlers/validation.js +38 -153
  46. package/dist/index.js +493 -162
  47. package/dist/knowledge.js +106 -9
  48. package/dist/tools.js +34 -4
  49. package/dist/validators.d.ts +21 -0
  50. package/dist/validators.js +91 -0
  51. package/package.json +2 -3
  52. package/src/api-client.ts +1822 -0
  53. package/src/cli.test.ts +128 -302
  54. package/src/cli.ts +41 -285
  55. package/src/handlers/__test-setup__.ts +215 -0
  56. package/src/handlers/__test-utils__.ts +4 -134
  57. package/src/handlers/blockers.test.ts +114 -124
  58. package/src/handlers/blockers.ts +68 -70
  59. package/src/handlers/bodies-of-work.test.ts +236 -831
  60. package/src/handlers/bodies-of-work.ts +210 -525
  61. package/src/handlers/cost.test.ts +149 -113
  62. package/src/handlers/cost.ts +44 -132
  63. package/src/handlers/decisions.test.ts +111 -209
  64. package/src/handlers/decisions.ts +35 -27
  65. package/src/handlers/deployment.test.ts +193 -239
  66. package/src/handlers/deployment.ts +143 -896
  67. package/src/handlers/discovery.test.ts +20 -67
  68. package/src/handlers/discovery.ts +29 -714
  69. package/src/handlers/fallback.test.ts +206 -361
  70. package/src/handlers/fallback.ts +81 -156
  71. package/src/handlers/findings.test.ts +229 -320
  72. package/src/handlers/findings.ts +76 -64
  73. package/src/handlers/git-issues.test.ts +623 -0
  74. package/src/handlers/git-issues.ts +174 -0
  75. package/src/handlers/ideas.test.ts +229 -343
  76. package/src/handlers/ideas.ts +69 -143
  77. package/src/handlers/index.ts +6 -0
  78. package/src/handlers/milestones.test.ts +167 -281
  79. package/src/handlers/milestones.ts +54 -93
  80. package/src/handlers/organizations.test.ts +275 -467
  81. package/src/handlers/organizations.ts +84 -294
  82. package/src/handlers/progress.test.ts +112 -218
  83. package/src/handlers/progress.ts +29 -142
  84. package/src/handlers/project.test.ts +203 -226
  85. package/src/handlers/project.ts +48 -238
  86. package/src/handlers/requests.test.ts +74 -342
  87. package/src/handlers/requests.ts +25 -83
  88. package/src/handlers/session.test.ts +276 -206
  89. package/src/handlers/session.ts +136 -662
  90. package/src/handlers/sprints.test.ts +711 -0
  91. package/src/handlers/sprints.ts +510 -0
  92. package/src/handlers/tasks.test.ts +669 -353
  93. package/src/handlers/tasks.ts +263 -1015
  94. package/src/handlers/tool-docs.ts +1024 -0
  95. package/src/handlers/types.ts +12 -4
  96. package/src/handlers/validation.test.ts +237 -568
  97. package/src/handlers/validation.ts +43 -167
  98. package/src/index.ts +493 -186
  99. package/src/tools.ts +2532 -0
  100. package/src/validators.test.ts +223 -223
  101. package/src/validators.ts +127 -0
  102. package/tsconfig.json +1 -1
  103. package/vitest.config.ts +14 -13
  104. package/dist/cli.test.d.ts +0 -1
  105. package/dist/cli.test.js +0 -367
  106. package/dist/handlers/__test-utils__.d.ts +0 -72
  107. package/dist/handlers/__test-utils__.js +0 -176
  108. package/dist/handlers/checkouts.d.ts +0 -37
  109. package/dist/handlers/checkouts.js +0 -377
  110. package/dist/handlers/knowledge-query.d.ts +0 -22
  111. package/dist/handlers/knowledge-query.js +0 -253
  112. package/dist/handlers/knowledge.d.ts +0 -12
  113. package/dist/handlers/knowledge.js +0 -108
  114. package/dist/handlers/roles.d.ts +0 -30
  115. package/dist/handlers/roles.js +0 -281
  116. package/dist/handlers/tasks.test.d.ts +0 -1
  117. package/dist/handlers/tasks.test.js +0 -431
  118. package/dist/utils.test.d.ts +0 -1
  119. package/dist/utils.test.js +0 -532
  120. package/dist/validators.test.d.ts +0 -1
  121. package/dist/validators.test.js +0 -176
  122. package/src/knowledge.ts +0 -132
  123. package/src/tmpclaude-0078-cwd +0 -1
  124. package/src/tmpclaude-0ee1-cwd +0 -1
  125. package/src/tmpclaude-2dd5-cwd +0 -1
  126. package/src/tmpclaude-344c-cwd +0 -1
  127. package/src/tmpclaude-3860-cwd +0 -1
  128. package/src/tmpclaude-4b63-cwd +0 -1
  129. package/src/tmpclaude-5c73-cwd +0 -1
  130. package/src/tmpclaude-5ee3-cwd +0 -1
  131. package/src/tmpclaude-6795-cwd +0 -1
  132. package/src/tmpclaude-709e-cwd +0 -1
  133. package/src/tmpclaude-9839-cwd +0 -1
  134. package/src/tmpclaude-d829-cwd +0 -1
  135. package/src/tmpclaude-e072-cwd +0 -1
  136. package/src/tmpclaude-f6ee-cwd +0 -1
  137. package/tmpclaude-0439-cwd +0 -1
  138. package/tmpclaude-132f-cwd +0 -1
  139. package/tmpclaude-15bb-cwd +0 -1
  140. package/tmpclaude-165a-cwd +0 -1
  141. package/tmpclaude-1ba9-cwd +0 -1
  142. package/tmpclaude-21a3-cwd +0 -1
  143. package/tmpclaude-2a38-cwd +0 -1
  144. package/tmpclaude-2adf-cwd +0 -1
  145. package/tmpclaude-2f56-cwd +0 -1
  146. package/tmpclaude-3626-cwd +0 -1
  147. package/tmpclaude-3727-cwd +0 -1
  148. package/tmpclaude-40bc-cwd +0 -1
  149. package/tmpclaude-436f-cwd +0 -1
  150. package/tmpclaude-4783-cwd +0 -1
  151. package/tmpclaude-4b6d-cwd +0 -1
  152. package/tmpclaude-4ba4-cwd +0 -1
  153. package/tmpclaude-51e6-cwd +0 -1
  154. package/tmpclaude-5ecf-cwd +0 -1
  155. package/tmpclaude-6f97-cwd +0 -1
  156. package/tmpclaude-7fb2-cwd +0 -1
  157. package/tmpclaude-825c-cwd +0 -1
  158. package/tmpclaude-8baf-cwd +0 -1
  159. package/tmpclaude-8d9f-cwd +0 -1
  160. package/tmpclaude-975c-cwd +0 -1
  161. package/tmpclaude-9983-cwd +0 -1
  162. package/tmpclaude-a045-cwd +0 -1
  163. package/tmpclaude-ac4a-cwd +0 -1
  164. package/tmpclaude-b593-cwd +0 -1
  165. package/tmpclaude-b891-cwd +0 -1
  166. package/tmpclaude-c032-cwd +0 -1
  167. package/tmpclaude-cf43-cwd +0 -1
  168. package/tmpclaude-d040-cwd +0 -1
  169. package/tmpclaude-dcdd-cwd +0 -1
  170. package/tmpclaude-dcee-cwd +0 -1
  171. package/tmpclaude-e16b-cwd +0 -1
  172. package/tmpclaude-ecd2-cwd +0 -1
  173. 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
- const supabase = createMockSupabase({
135
- selectResult: { data: mockProjects, error: null },
28
+ mockApiClient.listProjects.mockResolvedValue({
29
+ ok: true,
30
+ data: { projects: mockProjects },
136
31
  });
137
- const ctx = createMockContext(supabase);
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(supabase.from).toHaveBeenCalledWith('projects');
38
+ expect(mockApiClient.listProjects).toHaveBeenCalled();
144
39
  });
145
40
 
146
41
  it('should return found: false when project not found', async () => {
147
- const supabase = createMockSupabase({
148
- selectResult: { data: null, error: { message: 'Not found' } },
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(supabase);
49
+ const ctx = createMockContext();
151
50
 
152
51
  const result = await getProjectContext(
153
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
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
- const supabase = createMockSupabase({
165
- selectResult: {
166
- data: { id: 'proj-1', name: 'Test Project', description: null, goal: null, status: 'active', git_url: 'https://github.com/test', agent_instructions: null, tech_stack: null },
167
- error: null,
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(supabase);
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(supabase.eq).toHaveBeenCalledWith('git_url', 'https://github.com/test');
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
- const supabase = createMockSupabase({
185
- selectResult: {
186
- data: { id: 'proj-1', name: 'Test Project', description: null, goal: null, status: 'active', git_url: null, agent_instructions: null, tech_stack: null },
187
- error: null,
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(supabase);
113
+ const ctx = createMockContext();
191
114
 
192
115
  const result = await getProjectContext(
193
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
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 supabase = createMockSupabase();
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 supabase = createMockSupabase();
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
- const supabase = createMockSupabase({
226
- selectResult: {
227
- data: {
228
- git_workflow: 'github-flow',
229
- git_main_branch: 'main',
230
- git_develop_branch: null,
231
- git_auto_branch: true,
232
- git_auto_tag: false,
233
- git_url: 'https://github.com/test',
234
- },
235
- error: null,
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(supabase);
172
+ const ctx = createMockContext();
239
173
 
240
174
  const result = await getGitWorkflow(
241
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
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
- const supabase = createMockSupabase({
255
- selectResult: {
256
- data: {
257
- git_workflow: 'git-flow',
258
- git_main_branch: 'main',
259
- git_develop_branch: 'develop',
260
- git_auto_branch: false,
261
- git_auto_tag: true,
262
- git_url: 'https://github.com/test',
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(supabase);
200
+ const ctx = createMockContext();
268
201
 
269
202
  const result = await getGitWorkflow(
270
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
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
- const supabase = createMockSupabase({
283
- selectResult: {
284
- data: {
285
- git_workflow: 'none',
286
- git_main_branch: 'main',
287
- git_develop_branch: null,
288
- git_auto_branch: false,
289
- git_auto_tag: false,
290
- git_url: null,
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(supabase);
227
+ const ctx = createMockContext();
296
228
 
297
229
  const result = await getGitWorkflow(
298
- { project_id: '123e4567-e89b-12d3-a456-426614174000' },
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
- const supabase = createMockSupabase({
310
- selectResult: { data: null, error: { message: 'Not found' } },
241
+ mockApiClient.getGitWorkflow.mockResolvedValue({
242
+ ok: false,
243
+ error: 'Project not found',
311
244
  });
312
- const ctx = createMockContext(supabase);
245
+ const ctx = createMockContext();
313
246
 
314
247
  await expect(
315
- getGitWorkflow({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
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
- const supabase = createMockSupabase({
338
- insertResult: { data: mockProject, error: null },
270
+ mockApiClient.createProject.mockResolvedValue({
271
+ ok: true,
272
+ data: {
273
+ success: true,
274
+ project: mockProject,
275
+ },
339
276
  });
340
- const ctx = createMockContext(supabase);
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(supabase.insert).toHaveBeenCalled();
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
- const supabase = createMockSupabase({
362
- insertResult: { data: mockProject, error: null },
304
+ mockApiClient.createProject.mockResolvedValue({
305
+ ok: true,
306
+ data: {
307
+ success: true,
308
+ project: mockProject,
309
+ },
363
310
  });
364
- const ctx = createMockContext(supabase);
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
- const supabase = createMockSupabase({
385
- insertResult: { data: null, error: { message: 'Insert failed' } },
331
+ mockApiClient.createProject.mockResolvedValue({
332
+ ok: false,
333
+ error: 'Failed to create project: Insert failed',
386
334
  });
387
- const ctx = createMockContext(supabase);
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 supabase = createMockSupabase();
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 supabase = createMockSupabase();
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 supabase = createMockSupabase();
420
- const ctx = createMockContext(supabase);
373
+ const ctx = createMockContext();
421
374
 
422
375
  await expect(
423
376
  updateProject({
424
- project_id: '123e4567-e89b-12d3-a456-426614174000',
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
- const supabase = createMockSupabase({
432
- updateResult: { data: null, error: null },
384
+ mockApiClient.updateProject.mockResolvedValue({
385
+ ok: true,
386
+ data: {
387
+ success: true,
388
+ project_id: VALID_UUID,
389
+ },
433
390
  });
434
- const ctx = createMockContext(supabase);
391
+ const ctx = createMockContext();
435
392
 
436
393
  const result = await updateProject(
437
394
  {
438
- project_id: '123e4567-e89b-12d3-a456-426614174000',
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: '123e4567-e89b-12d3-a456-426614174000',
404
+ project_id: VALID_UUID,
448
405
  });
449
- expect(supabase.update).toHaveBeenCalled();
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
- const supabase = createMockSupabase({
454
- updateResult: { data: null, error: null },
416
+ mockApiClient.updateProject.mockResolvedValue({
417
+ ok: true,
418
+ data: {
419
+ success: true,
420
+ project_id: VALID_UUID,
421
+ },
455
422
  });
456
- const ctx = createMockContext(supabase);
423
+ const ctx = createMockContext();
457
424
 
458
425
  const result = await updateProject(
459
426
  {
460
- project_id: '123e4567-e89b-12d3-a456-426614174000',
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
- const supabase = createMockSupabase({
475
- updateResult: { data: null, error: { message: 'Update failed' } },
449
+ mockApiClient.updateProject.mockResolvedValue({
450
+ ok: false,
451
+ error: 'Failed to update project: Update failed',
476
452
  });
477
- const ctx = createMockContext(supabase);
453
+ const ctx = createMockContext();
478
454
 
479
455
  await expect(
480
456
  updateProject({
481
- project_id: '123e4567-e89b-12d3-a456-426614174000',
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 supabase = createMockSupabase();
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 supabase = createMockSupabase();
506
- const ctx = createMockContext(supabase);
480
+ const ctx = createMockContext();
507
481
 
508
482
  await expect(
509
- updateProjectReadme({ project_id: '123e4567-e89b-12d3-a456-426614174000' }, ctx)
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 supabase = createMockSupabase();
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
- const supabase = createMockSupabase({
527
- updateResult: { data: null, error: null },
499
+ mockApiClient.updateProjectReadme.mockResolvedValue({
500
+ ok: true,
501
+ data: {
502
+ success: true,
503
+ project_id: VALID_UUID,
504
+ },
528
505
  });
529
- const ctx = createMockContext(supabase);
506
+ const ctx = createMockContext();
530
507
 
531
508
  const result = await updateProjectReadme(
532
509
  {
533
- project_id: '123e4567-e89b-12d3-a456-426614174000',
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(supabase.update).toHaveBeenCalledWith(
543
- expect.objectContaining({
544
- readme_content: '# My Project\n\nDescription here.',
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
- const supabase = createMockSupabase({
551
- updateResult: { data: null, error: { message: 'Update failed' } },
526
+ mockApiClient.updateProjectReadme.mockResolvedValue({
527
+ ok: false,
528
+ error: 'Failed to update README: Update failed',
552
529
  });
553
- const ctx = createMockContext(supabase);
530
+ const ctx = createMockContext();
554
531
 
555
532
  await expect(
556
533
  updateProjectReadme({
557
- project_id: '123e4567-e89b-12d3-a456-426614174000',
534
+ project_id: VALID_UUID,
558
535
  readme_content: '# README',
559
536
  }, ctx)
560
537
  ).rejects.toThrow('Failed to update README: Update failed');