@vibescope/mcp-server 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +113 -98
  2. package/dist/api-client.d.ts +1114 -0
  3. package/dist/api-client.js +698 -0
  4. package/dist/cli.d.ts +1 -6
  5. package/dist/cli.js +39 -240
  6. package/dist/config/tool-categories.d.ts +31 -0
  7. package/dist/config/tool-categories.js +253 -0
  8. package/dist/handlers/blockers.js +57 -58
  9. package/dist/handlers/bodies-of-work.d.ts +2 -0
  10. package/dist/handlers/bodies-of-work.js +106 -476
  11. package/dist/handlers/cost.d.ts +1 -0
  12. package/dist/handlers/cost.js +35 -113
  13. package/dist/handlers/decisions.d.ts +2 -0
  14. package/dist/handlers/decisions.js +28 -27
  15. package/dist/handlers/deployment.js +112 -828
  16. package/dist/handlers/discovery.js +31 -0
  17. package/dist/handlers/fallback.d.ts +2 -0
  18. package/dist/handlers/fallback.js +39 -134
  19. package/dist/handlers/findings.js +43 -67
  20. package/dist/handlers/git-issues.d.ts +9 -13
  21. package/dist/handlers/git-issues.js +80 -225
  22. package/dist/handlers/ideas.d.ts +3 -0
  23. package/dist/handlers/ideas.js +53 -134
  24. package/dist/handlers/index.d.ts +2 -0
  25. package/dist/handlers/index.js +6 -0
  26. package/dist/handlers/milestones.d.ts +2 -0
  27. package/dist/handlers/milestones.js +51 -98
  28. package/dist/handlers/organizations.js +79 -275
  29. package/dist/handlers/progress.d.ts +2 -0
  30. package/dist/handlers/progress.js +25 -123
  31. package/dist/handlers/project.js +42 -221
  32. package/dist/handlers/requests.d.ts +2 -0
  33. package/dist/handlers/requests.js +23 -83
  34. package/dist/handlers/session.js +99 -585
  35. package/dist/handlers/sprints.d.ts +32 -0
  36. package/dist/handlers/sprints.js +274 -0
  37. package/dist/handlers/tasks.d.ts +7 -10
  38. package/dist/handlers/tasks.js +230 -900
  39. package/dist/handlers/tool-docs.d.ts +8 -0
  40. package/dist/handlers/tool-docs.js +657 -0
  41. package/dist/handlers/types.d.ts +11 -3
  42. package/dist/handlers/validation.d.ts +1 -1
  43. package/dist/handlers/validation.js +26 -153
  44. package/dist/index.js +473 -160
  45. package/dist/knowledge.js +106 -9
  46. package/dist/tools.js +4 -0
  47. package/dist/validators.d.ts +21 -0
  48. package/dist/validators.js +91 -0
  49. package/package.json +2 -3
  50. package/src/api-client.ts +1752 -0
  51. package/src/cli.test.ts +128 -302
  52. package/src/cli.ts +41 -285
  53. package/src/handlers/__test-setup__.ts +210 -0
  54. package/src/handlers/__test-utils__.ts +4 -134
  55. package/src/handlers/blockers.test.ts +114 -124
  56. package/src/handlers/blockers.ts +68 -70
  57. package/src/handlers/bodies-of-work.test.ts +236 -831
  58. package/src/handlers/bodies-of-work.ts +194 -525
  59. package/src/handlers/cost.test.ts +149 -113
  60. package/src/handlers/cost.ts +44 -132
  61. package/src/handlers/decisions.test.ts +111 -209
  62. package/src/handlers/decisions.ts +35 -27
  63. package/src/handlers/deployment.test.ts +193 -239
  64. package/src/handlers/deployment.ts +140 -895
  65. package/src/handlers/discovery.test.ts +20 -67
  66. package/src/handlers/discovery.ts +32 -0
  67. package/src/handlers/fallback.test.ts +128 -361
  68. package/src/handlers/fallback.ts +62 -148
  69. package/src/handlers/findings.test.ts +127 -345
  70. package/src/handlers/findings.ts +49 -66
  71. package/src/handlers/git-issues.test.ts +623 -0
  72. package/src/handlers/git-issues.ts +174 -0
  73. package/src/handlers/ideas.test.ts +229 -343
  74. package/src/handlers/ideas.ts +69 -143
  75. package/src/handlers/index.ts +6 -0
  76. package/src/handlers/milestones.test.ts +167 -281
  77. package/src/handlers/milestones.ts +54 -93
  78. package/src/handlers/organizations.test.ts +275 -467
  79. package/src/handlers/organizations.ts +84 -294
  80. package/src/handlers/progress.test.ts +112 -218
  81. package/src/handlers/progress.ts +29 -142
  82. package/src/handlers/project.test.ts +203 -226
  83. package/src/handlers/project.ts +48 -238
  84. package/src/handlers/requests.test.ts +74 -342
  85. package/src/handlers/requests.ts +25 -83
  86. package/src/handlers/session.test.ts +241 -206
  87. package/src/handlers/session.ts +110 -657
  88. package/src/handlers/sprints.test.ts +711 -0
  89. package/src/handlers/sprints.ts +497 -0
  90. package/src/handlers/tasks.test.ts +608 -353
  91. package/src/handlers/tasks.ts +248 -1025
  92. package/src/handlers/types.ts +12 -4
  93. package/src/handlers/validation.test.ts +189 -572
  94. package/src/handlers/validation.ts +29 -166
  95. package/src/index.ts +473 -184
  96. package/src/knowledge.ts +107 -9
  97. package/src/tools.ts +2506 -0
  98. package/src/validators.test.ts +223 -223
  99. package/src/validators.ts +127 -0
  100. package/tsconfig.json +1 -1
  101. package/vitest.config.ts +14 -13
  102. package/dist/cli.test.d.ts +0 -1
  103. package/dist/cli.test.js +0 -367
  104. package/dist/handlers/__test-utils__.d.ts +0 -72
  105. package/dist/handlers/__test-utils__.js +0 -176
  106. package/dist/handlers/checkouts.d.ts +0 -37
  107. package/dist/handlers/checkouts.js +0 -377
  108. package/dist/handlers/knowledge-query.d.ts +0 -22
  109. package/dist/handlers/knowledge-query.js +0 -253
  110. package/dist/handlers/knowledge.d.ts +0 -12
  111. package/dist/handlers/knowledge.js +0 -108
  112. package/dist/handlers/roles.d.ts +0 -30
  113. package/dist/handlers/roles.js +0 -281
  114. package/dist/handlers/tasks.test.d.ts +0 -1
  115. package/dist/handlers/tasks.test.js +0 -431
  116. package/dist/utils.test.d.ts +0 -1
  117. package/dist/utils.test.js +0 -532
  118. package/dist/validators.test.d.ts +0 -1
  119. package/dist/validators.test.js +0 -176
  120. package/src/tmpclaude-0078-cwd +0 -1
  121. package/src/tmpclaude-0ee1-cwd +0 -1
  122. package/src/tmpclaude-2dd5-cwd +0 -1
  123. package/src/tmpclaude-344c-cwd +0 -1
  124. package/src/tmpclaude-3860-cwd +0 -1
  125. package/src/tmpclaude-4b63-cwd +0 -1
  126. package/src/tmpclaude-5c73-cwd +0 -1
  127. package/src/tmpclaude-5ee3-cwd +0 -1
  128. package/src/tmpclaude-6795-cwd +0 -1
  129. package/src/tmpclaude-709e-cwd +0 -1
  130. package/src/tmpclaude-9839-cwd +0 -1
  131. package/src/tmpclaude-d829-cwd +0 -1
  132. package/src/tmpclaude-e072-cwd +0 -1
  133. package/src/tmpclaude-f6ee-cwd +0 -1
  134. package/tmpclaude-0439-cwd +0 -1
  135. package/tmpclaude-132f-cwd +0 -1
  136. package/tmpclaude-15bb-cwd +0 -1
  137. package/tmpclaude-165a-cwd +0 -1
  138. package/tmpclaude-1ba9-cwd +0 -1
  139. package/tmpclaude-21a3-cwd +0 -1
  140. package/tmpclaude-2a38-cwd +0 -1
  141. package/tmpclaude-2adf-cwd +0 -1
  142. package/tmpclaude-2f56-cwd +0 -1
  143. package/tmpclaude-3626-cwd +0 -1
  144. package/tmpclaude-3727-cwd +0 -1
  145. package/tmpclaude-40bc-cwd +0 -1
  146. package/tmpclaude-436f-cwd +0 -1
  147. package/tmpclaude-4783-cwd +0 -1
  148. package/tmpclaude-4b6d-cwd +0 -1
  149. package/tmpclaude-4ba4-cwd +0 -1
  150. package/tmpclaude-51e6-cwd +0 -1
  151. package/tmpclaude-5ecf-cwd +0 -1
  152. package/tmpclaude-6f97-cwd +0 -1
  153. package/tmpclaude-7fb2-cwd +0 -1
  154. package/tmpclaude-825c-cwd +0 -1
  155. package/tmpclaude-8baf-cwd +0 -1
  156. package/tmpclaude-8d9f-cwd +0 -1
  157. package/tmpclaude-975c-cwd +0 -1
  158. package/tmpclaude-9983-cwd +0 -1
  159. package/tmpclaude-a045-cwd +0 -1
  160. package/tmpclaude-ac4a-cwd +0 -1
  161. package/tmpclaude-b593-cwd +0 -1
  162. package/tmpclaude-b891-cwd +0 -1
  163. package/tmpclaude-c032-cwd +0 -1
  164. package/tmpclaude-cf43-cwd +0 -1
  165. package/tmpclaude-d040-cwd +0 -1
  166. package/tmpclaude-dcdd-cwd +0 -1
  167. package/tmpclaude-dcee-cwd +0 -1
  168. package/tmpclaude-e16b-cwd +0 -1
  169. package/tmpclaude-ecd2-cwd +0 -1
  170. package/tmpclaude-f48d-cwd +0 -1
@@ -1,6 +1,4 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import type { SupabaseClient } from '@supabase/supabase-js';
3
- import type { HandlerContext, TokenUsage } from './types.js';
4
2
  import {
5
3
  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');