@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
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
addGitIssue,
|
|
4
|
+
resolveGitIssue,
|
|
5
|
+
getGitIssues,
|
|
6
|
+
deleteGitIssue,
|
|
7
|
+
} from './git-issues.js';
|
|
8
|
+
import { ValidationError } from '../validators.js';
|
|
9
|
+
import { createMockContext } from './__test-utils__.js';
|
|
10
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
11
|
+
|
|
12
|
+
const VALID_PROJECT_ID = '123e4567-e89b-12d3-a456-426614174000';
|
|
13
|
+
const VALID_GIT_ISSUE_ID = '987e6543-e21b-12d3-a456-426614174000';
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// addGitIssue Tests
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
describe('addGitIssue', () => {
|
|
20
|
+
beforeEach(() => vi.clearAllMocks());
|
|
21
|
+
|
|
22
|
+
it('should throw error for missing project_id', async () => {
|
|
23
|
+
const ctx = createMockContext();
|
|
24
|
+
|
|
25
|
+
await expect(
|
|
26
|
+
addGitIssue({ issue_type: 'merge_conflict', branch: 'feature/test' }, ctx)
|
|
27
|
+
).rejects.toThrow(ValidationError);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should throw error for invalid project_id UUID', async () => {
|
|
31
|
+
const ctx = createMockContext();
|
|
32
|
+
|
|
33
|
+
await expect(
|
|
34
|
+
addGitIssue({ project_id: 'invalid', issue_type: 'merge_conflict', branch: 'feature/test' }, ctx)
|
|
35
|
+
).rejects.toThrow(ValidationError);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should throw error for missing issue_type', async () => {
|
|
39
|
+
const ctx = createMockContext();
|
|
40
|
+
|
|
41
|
+
await expect(
|
|
42
|
+
addGitIssue({ project_id: VALID_PROJECT_ID, branch: 'feature/test' }, ctx)
|
|
43
|
+
).rejects.toThrow(ValidationError);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should throw error for missing branch', async () => {
|
|
47
|
+
const ctx = createMockContext();
|
|
48
|
+
|
|
49
|
+
await expect(
|
|
50
|
+
addGitIssue({ project_id: VALID_PROJECT_ID, issue_type: 'merge_conflict' }, ctx)
|
|
51
|
+
).rejects.toThrow(ValidationError);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should throw error for invalid issue_type', async () => {
|
|
55
|
+
const ctx = createMockContext();
|
|
56
|
+
|
|
57
|
+
await expect(
|
|
58
|
+
addGitIssue({
|
|
59
|
+
project_id: VALID_PROJECT_ID,
|
|
60
|
+
issue_type: 'invalid_type',
|
|
61
|
+
branch: 'feature/test',
|
|
62
|
+
}, ctx)
|
|
63
|
+
).rejects.toThrow('Invalid issue_type');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should throw error for invalid task_id UUID', async () => {
|
|
67
|
+
const ctx = createMockContext();
|
|
68
|
+
|
|
69
|
+
await expect(
|
|
70
|
+
addGitIssue({
|
|
71
|
+
project_id: VALID_PROJECT_ID,
|
|
72
|
+
issue_type: 'merge_conflict',
|
|
73
|
+
branch: 'feature/test',
|
|
74
|
+
task_id: 'invalid-uuid',
|
|
75
|
+
}, ctx)
|
|
76
|
+
).rejects.toThrow(ValidationError);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should add git issue successfully', async () => {
|
|
80
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
81
|
+
ok: true,
|
|
82
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
83
|
+
});
|
|
84
|
+
const ctx = createMockContext();
|
|
85
|
+
|
|
86
|
+
const result = await addGitIssue(
|
|
87
|
+
{
|
|
88
|
+
project_id: VALID_PROJECT_ID,
|
|
89
|
+
issue_type: 'merge_conflict',
|
|
90
|
+
branch: 'feature/test',
|
|
91
|
+
},
|
|
92
|
+
ctx
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
expect(result.result).toMatchObject({
|
|
96
|
+
success: true,
|
|
97
|
+
git_issue_id: VALID_GIT_ISSUE_ID,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should add git issue with all optional fields', async () => {
|
|
102
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
103
|
+
ok: true,
|
|
104
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
105
|
+
});
|
|
106
|
+
const ctx = createMockContext({ sessionId: 'test-session' });
|
|
107
|
+
|
|
108
|
+
await addGitIssue(
|
|
109
|
+
{
|
|
110
|
+
project_id: VALID_PROJECT_ID,
|
|
111
|
+
issue_type: 'pr_not_mergeable',
|
|
112
|
+
branch: 'feature/test',
|
|
113
|
+
target_branch: 'main',
|
|
114
|
+
pr_url: 'https://github.com/org/repo/pull/123',
|
|
115
|
+
conflicting_files: ['src/file1.ts', 'src/file2.ts'],
|
|
116
|
+
error_message: 'Merge conflict in file1.ts',
|
|
117
|
+
task_id: VALID_GIT_ISSUE_ID,
|
|
118
|
+
},
|
|
119
|
+
ctx
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(mockApiClient.addGitIssue).toHaveBeenCalledWith(
|
|
123
|
+
VALID_PROJECT_ID,
|
|
124
|
+
{
|
|
125
|
+
issue_type: 'pr_not_mergeable',
|
|
126
|
+
branch: 'feature/test',
|
|
127
|
+
target_branch: 'main',
|
|
128
|
+
pr_url: 'https://github.com/org/repo/pull/123',
|
|
129
|
+
conflicting_files: ['src/file1.ts', 'src/file2.ts'],
|
|
130
|
+
error_message: 'Merge conflict in file1.ts',
|
|
131
|
+
task_id: VALID_GIT_ISSUE_ID,
|
|
132
|
+
},
|
|
133
|
+
'test-session'
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should include session_id in API call', async () => {
|
|
138
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
139
|
+
ok: true,
|
|
140
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
141
|
+
});
|
|
142
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
143
|
+
|
|
144
|
+
await addGitIssue(
|
|
145
|
+
{
|
|
146
|
+
project_id: VALID_PROJECT_ID,
|
|
147
|
+
issue_type: 'push_failed',
|
|
148
|
+
branch: 'feature/test',
|
|
149
|
+
},
|
|
150
|
+
ctx
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(mockApiClient.addGitIssue).toHaveBeenCalledWith(
|
|
154
|
+
VALID_PROJECT_ID,
|
|
155
|
+
expect.objectContaining({
|
|
156
|
+
issue_type: 'push_failed',
|
|
157
|
+
branch: 'feature/test',
|
|
158
|
+
}),
|
|
159
|
+
'my-session'
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should accept all valid issue types', async () => {
|
|
164
|
+
const validTypes = ['merge_conflict', 'push_failed', 'rebase_needed', 'branch_diverged', 'pr_not_mergeable'];
|
|
165
|
+
const ctx = createMockContext();
|
|
166
|
+
|
|
167
|
+
for (const issueType of validTypes) {
|
|
168
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
169
|
+
ok: true,
|
|
170
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await expect(
|
|
174
|
+
addGitIssue({
|
|
175
|
+
project_id: VALID_PROJECT_ID,
|
|
176
|
+
issue_type: issueType,
|
|
177
|
+
branch: 'feature/test',
|
|
178
|
+
}, ctx)
|
|
179
|
+
).resolves.not.toThrow();
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should throw error when API call fails', async () => {
|
|
184
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
185
|
+
ok: false,
|
|
186
|
+
error: 'Insert failed',
|
|
187
|
+
});
|
|
188
|
+
const ctx = createMockContext();
|
|
189
|
+
|
|
190
|
+
await expect(
|
|
191
|
+
addGitIssue({
|
|
192
|
+
project_id: VALID_PROJECT_ID,
|
|
193
|
+
issue_type: 'merge_conflict',
|
|
194
|
+
branch: 'feature/test',
|
|
195
|
+
}, ctx)
|
|
196
|
+
).rejects.toThrow('Insert failed');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should throw default error message when API fails without error', async () => {
|
|
200
|
+
mockApiClient.addGitIssue.mockResolvedValue({
|
|
201
|
+
ok: false,
|
|
202
|
+
});
|
|
203
|
+
const ctx = createMockContext();
|
|
204
|
+
|
|
205
|
+
await expect(
|
|
206
|
+
addGitIssue({
|
|
207
|
+
project_id: VALID_PROJECT_ID,
|
|
208
|
+
issue_type: 'merge_conflict',
|
|
209
|
+
branch: 'feature/test',
|
|
210
|
+
}, ctx)
|
|
211
|
+
).rejects.toThrow('Failed to add git issue');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// ============================================================================
|
|
216
|
+
// resolveGitIssue Tests
|
|
217
|
+
// ============================================================================
|
|
218
|
+
|
|
219
|
+
describe('resolveGitIssue', () => {
|
|
220
|
+
beforeEach(() => vi.clearAllMocks());
|
|
221
|
+
|
|
222
|
+
it('should throw error for missing git_issue_id', async () => {
|
|
223
|
+
const ctx = createMockContext();
|
|
224
|
+
|
|
225
|
+
await expect(resolveGitIssue({}, ctx)).rejects.toThrow(ValidationError);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should throw error for invalid git_issue_id UUID', async () => {
|
|
229
|
+
const ctx = createMockContext();
|
|
230
|
+
|
|
231
|
+
await expect(
|
|
232
|
+
resolveGitIssue({ git_issue_id: 'invalid' }, ctx)
|
|
233
|
+
).rejects.toThrow(ValidationError);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should resolve git issue successfully', async () => {
|
|
237
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
238
|
+
ok: true,
|
|
239
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
240
|
+
});
|
|
241
|
+
const ctx = createMockContext();
|
|
242
|
+
|
|
243
|
+
const result = await resolveGitIssue(
|
|
244
|
+
{ git_issue_id: VALID_GIT_ISSUE_ID },
|
|
245
|
+
ctx
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
expect(result.result).toMatchObject({
|
|
249
|
+
success: true,
|
|
250
|
+
git_issue_id: VALID_GIT_ISSUE_ID,
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should resolve git issue with resolution_note', async () => {
|
|
255
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
256
|
+
ok: true,
|
|
257
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
258
|
+
});
|
|
259
|
+
const ctx = createMockContext({ sessionId: 'test-session' });
|
|
260
|
+
|
|
261
|
+
await resolveGitIssue(
|
|
262
|
+
{
|
|
263
|
+
git_issue_id: VALID_GIT_ISSUE_ID,
|
|
264
|
+
resolution_note: 'Resolved by rebasing',
|
|
265
|
+
},
|
|
266
|
+
ctx
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
expect(mockApiClient.resolveGitIssue).toHaveBeenCalledWith(
|
|
270
|
+
VALID_GIT_ISSUE_ID,
|
|
271
|
+
{ resolution_note: 'Resolved by rebasing', auto_resolved: undefined },
|
|
272
|
+
'test-session'
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should resolve git issue with auto_resolved flag', async () => {
|
|
277
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
278
|
+
ok: true,
|
|
279
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
280
|
+
});
|
|
281
|
+
const ctx = createMockContext({ sessionId: 'test-session' });
|
|
282
|
+
|
|
283
|
+
await resolveGitIssue(
|
|
284
|
+
{
|
|
285
|
+
git_issue_id: VALID_GIT_ISSUE_ID,
|
|
286
|
+
auto_resolved: true,
|
|
287
|
+
},
|
|
288
|
+
ctx
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
expect(mockApiClient.resolveGitIssue).toHaveBeenCalledWith(
|
|
292
|
+
VALID_GIT_ISSUE_ID,
|
|
293
|
+
{ resolution_note: undefined, auto_resolved: true },
|
|
294
|
+
'test-session'
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should include session_id in API call', async () => {
|
|
299
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
300
|
+
ok: true,
|
|
301
|
+
data: { success: true, git_issue_id: VALID_GIT_ISSUE_ID },
|
|
302
|
+
});
|
|
303
|
+
const ctx = createMockContext({ sessionId: 'my-session' });
|
|
304
|
+
|
|
305
|
+
await resolveGitIssue(
|
|
306
|
+
{ git_issue_id: VALID_GIT_ISSUE_ID },
|
|
307
|
+
ctx
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
expect(mockApiClient.resolveGitIssue).toHaveBeenCalledWith(
|
|
311
|
+
VALID_GIT_ISSUE_ID,
|
|
312
|
+
expect.any(Object),
|
|
313
|
+
'my-session'
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should throw error when API call fails', async () => {
|
|
318
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
319
|
+
ok: false,
|
|
320
|
+
error: 'Update failed',
|
|
321
|
+
});
|
|
322
|
+
const ctx = createMockContext();
|
|
323
|
+
|
|
324
|
+
await expect(
|
|
325
|
+
resolveGitIssue({ git_issue_id: VALID_GIT_ISSUE_ID }, ctx)
|
|
326
|
+
).rejects.toThrow('Update failed');
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('should throw default error message when API fails without error', async () => {
|
|
330
|
+
mockApiClient.resolveGitIssue.mockResolvedValue({
|
|
331
|
+
ok: false,
|
|
332
|
+
});
|
|
333
|
+
const ctx = createMockContext();
|
|
334
|
+
|
|
335
|
+
await expect(
|
|
336
|
+
resolveGitIssue({ git_issue_id: VALID_GIT_ISSUE_ID }, ctx)
|
|
337
|
+
).rejects.toThrow('Failed to resolve git issue');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// ============================================================================
|
|
342
|
+
// getGitIssues Tests
|
|
343
|
+
// ============================================================================
|
|
344
|
+
|
|
345
|
+
describe('getGitIssues', () => {
|
|
346
|
+
beforeEach(() => vi.clearAllMocks());
|
|
347
|
+
|
|
348
|
+
it('should throw error for missing project_id', async () => {
|
|
349
|
+
const ctx = createMockContext();
|
|
350
|
+
|
|
351
|
+
await expect(getGitIssues({}, ctx)).rejects.toThrow(ValidationError);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should throw error for invalid project_id UUID', async () => {
|
|
355
|
+
const ctx = createMockContext();
|
|
356
|
+
|
|
357
|
+
await expect(
|
|
358
|
+
getGitIssues({ project_id: 'invalid' }, ctx)
|
|
359
|
+
).rejects.toThrow(ValidationError);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it('should throw error for invalid status', async () => {
|
|
363
|
+
const ctx = createMockContext();
|
|
364
|
+
|
|
365
|
+
await expect(
|
|
366
|
+
getGitIssues({ project_id: VALID_PROJECT_ID, status: 'invalid_status' }, ctx)
|
|
367
|
+
).rejects.toThrow('Invalid status');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it('should throw error for invalid issue_type filter', async () => {
|
|
371
|
+
const ctx = createMockContext();
|
|
372
|
+
|
|
373
|
+
await expect(
|
|
374
|
+
getGitIssues({ project_id: VALID_PROJECT_ID, issue_type: 'invalid_type' }, ctx)
|
|
375
|
+
).rejects.toThrow('Invalid issue_type');
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should return empty list when no git issues', async () => {
|
|
379
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
380
|
+
ok: true,
|
|
381
|
+
data: { git_issues: [] },
|
|
382
|
+
});
|
|
383
|
+
const ctx = createMockContext();
|
|
384
|
+
|
|
385
|
+
const result = await getGitIssues(
|
|
386
|
+
{ project_id: VALID_PROJECT_ID },
|
|
387
|
+
ctx
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
expect(result.result).toMatchObject({
|
|
391
|
+
git_issues: [],
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('should return git issues list', async () => {
|
|
396
|
+
const mockGitIssues = [
|
|
397
|
+
{ id: 'gi1', issue_type: 'merge_conflict', branch: 'feature/a', status: 'open', created_at: '2025-01-14T10:00:00Z' },
|
|
398
|
+
{ id: 'gi2', issue_type: 'push_failed', branch: 'feature/b', status: 'open', created_at: '2025-01-14T11:00:00Z' },
|
|
399
|
+
];
|
|
400
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
401
|
+
ok: true,
|
|
402
|
+
data: { git_issues: mockGitIssues },
|
|
403
|
+
});
|
|
404
|
+
const ctx = createMockContext();
|
|
405
|
+
|
|
406
|
+
const result = await getGitIssues(
|
|
407
|
+
{ project_id: VALID_PROJECT_ID },
|
|
408
|
+
ctx
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
expect((result.result as { git_issues: unknown[] }).git_issues).toHaveLength(2);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
it('should pass status parameter to API (default: open)', async () => {
|
|
415
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
416
|
+
ok: true,
|
|
417
|
+
data: { git_issues: [] },
|
|
418
|
+
});
|
|
419
|
+
const ctx = createMockContext();
|
|
420
|
+
|
|
421
|
+
await getGitIssues(
|
|
422
|
+
{ project_id: VALID_PROJECT_ID },
|
|
423
|
+
ctx
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
427
|
+
VALID_PROJECT_ID,
|
|
428
|
+
expect.objectContaining({ status: 'open' })
|
|
429
|
+
);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('should pass custom status to API', async () => {
|
|
433
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
434
|
+
ok: true,
|
|
435
|
+
data: { git_issues: [] },
|
|
436
|
+
});
|
|
437
|
+
const ctx = createMockContext();
|
|
438
|
+
|
|
439
|
+
await getGitIssues(
|
|
440
|
+
{ project_id: VALID_PROJECT_ID, status: 'resolved' },
|
|
441
|
+
ctx
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
445
|
+
VALID_PROJECT_ID,
|
|
446
|
+
expect.objectContaining({ status: 'resolved' })
|
|
447
|
+
);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
it('should pass issue_type filter to API', async () => {
|
|
451
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
452
|
+
ok: true,
|
|
453
|
+
data: { git_issues: [] },
|
|
454
|
+
});
|
|
455
|
+
const ctx = createMockContext();
|
|
456
|
+
|
|
457
|
+
await getGitIssues(
|
|
458
|
+
{ project_id: VALID_PROJECT_ID, issue_type: 'merge_conflict' },
|
|
459
|
+
ctx
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
463
|
+
VALID_PROJECT_ID,
|
|
464
|
+
expect.objectContaining({ issue_type: 'merge_conflict' })
|
|
465
|
+
);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
it('should pass branch filter to API', async () => {
|
|
469
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
470
|
+
ok: true,
|
|
471
|
+
data: { git_issues: [] },
|
|
472
|
+
});
|
|
473
|
+
const ctx = createMockContext();
|
|
474
|
+
|
|
475
|
+
await getGitIssues(
|
|
476
|
+
{ project_id: VALID_PROJECT_ID, branch: 'feature/test' },
|
|
477
|
+
ctx
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
481
|
+
VALID_PROJECT_ID,
|
|
482
|
+
expect.objectContaining({ branch: 'feature/test' })
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it('should pass limit parameter to API (default: 50)', async () => {
|
|
487
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
488
|
+
ok: true,
|
|
489
|
+
data: { git_issues: [] },
|
|
490
|
+
});
|
|
491
|
+
const ctx = createMockContext();
|
|
492
|
+
|
|
493
|
+
await getGitIssues(
|
|
494
|
+
{ project_id: VALID_PROJECT_ID },
|
|
495
|
+
ctx
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
499
|
+
VALID_PROJECT_ID,
|
|
500
|
+
expect.objectContaining({ limit: 50 })
|
|
501
|
+
);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should pass custom limit to API', async () => {
|
|
505
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
506
|
+
ok: true,
|
|
507
|
+
data: { git_issues: [] },
|
|
508
|
+
});
|
|
509
|
+
const ctx = createMockContext();
|
|
510
|
+
|
|
511
|
+
await getGitIssues(
|
|
512
|
+
{ project_id: VALID_PROJECT_ID, limit: 10 },
|
|
513
|
+
ctx
|
|
514
|
+
);
|
|
515
|
+
|
|
516
|
+
expect(mockApiClient.getGitIssues).toHaveBeenCalledWith(
|
|
517
|
+
VALID_PROJECT_ID,
|
|
518
|
+
expect.objectContaining({ limit: 10 })
|
|
519
|
+
);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it('should throw error when API call fails', async () => {
|
|
523
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
524
|
+
ok: false,
|
|
525
|
+
error: 'Query failed',
|
|
526
|
+
});
|
|
527
|
+
const ctx = createMockContext();
|
|
528
|
+
|
|
529
|
+
await expect(
|
|
530
|
+
getGitIssues({ project_id: VALID_PROJECT_ID }, ctx)
|
|
531
|
+
).rejects.toThrow('Query failed');
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it('should throw default error message when API fails without error', async () => {
|
|
535
|
+
mockApiClient.getGitIssues.mockResolvedValue({
|
|
536
|
+
ok: false,
|
|
537
|
+
});
|
|
538
|
+
const ctx = createMockContext();
|
|
539
|
+
|
|
540
|
+
await expect(
|
|
541
|
+
getGitIssues({ project_id: VALID_PROJECT_ID }, ctx)
|
|
542
|
+
).rejects.toThrow('Failed to fetch git issues');
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// ============================================================================
|
|
547
|
+
// deleteGitIssue Tests
|
|
548
|
+
// ============================================================================
|
|
549
|
+
|
|
550
|
+
describe('deleteGitIssue', () => {
|
|
551
|
+
beforeEach(() => vi.clearAllMocks());
|
|
552
|
+
|
|
553
|
+
it('should throw error for missing git_issue_id', async () => {
|
|
554
|
+
const ctx = createMockContext();
|
|
555
|
+
|
|
556
|
+
await expect(deleteGitIssue({}, ctx)).rejects.toThrow(ValidationError);
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('should throw error for invalid git_issue_id UUID', async () => {
|
|
560
|
+
const ctx = createMockContext();
|
|
561
|
+
|
|
562
|
+
await expect(
|
|
563
|
+
deleteGitIssue({ git_issue_id: 'invalid' }, ctx)
|
|
564
|
+
).rejects.toThrow(ValidationError);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it('should delete git issue successfully', async () => {
|
|
568
|
+
mockApiClient.deleteGitIssue.mockResolvedValue({
|
|
569
|
+
ok: true,
|
|
570
|
+
data: { success: true },
|
|
571
|
+
});
|
|
572
|
+
const ctx = createMockContext();
|
|
573
|
+
|
|
574
|
+
const result = await deleteGitIssue(
|
|
575
|
+
{ git_issue_id: VALID_GIT_ISSUE_ID },
|
|
576
|
+
ctx
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
expect(result.result).toMatchObject({
|
|
580
|
+
success: true,
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it('should call API client deleteGitIssue', async () => {
|
|
585
|
+
mockApiClient.deleteGitIssue.mockResolvedValue({
|
|
586
|
+
ok: true,
|
|
587
|
+
data: { success: true },
|
|
588
|
+
});
|
|
589
|
+
const ctx = createMockContext();
|
|
590
|
+
|
|
591
|
+
await deleteGitIssue(
|
|
592
|
+
{ git_issue_id: VALID_GIT_ISSUE_ID },
|
|
593
|
+
ctx
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
expect(mockApiClient.deleteGitIssue).toHaveBeenCalledWith(
|
|
597
|
+
VALID_GIT_ISSUE_ID
|
|
598
|
+
);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
it('should throw error when API call fails', async () => {
|
|
602
|
+
mockApiClient.deleteGitIssue.mockResolvedValue({
|
|
603
|
+
ok: false,
|
|
604
|
+
error: 'Delete failed',
|
|
605
|
+
});
|
|
606
|
+
const ctx = createMockContext();
|
|
607
|
+
|
|
608
|
+
await expect(
|
|
609
|
+
deleteGitIssue({ git_issue_id: VALID_GIT_ISSUE_ID }, ctx)
|
|
610
|
+
).rejects.toThrow('Delete failed');
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it('should throw default error message when API fails without error', async () => {
|
|
614
|
+
mockApiClient.deleteGitIssue.mockResolvedValue({
|
|
615
|
+
ok: false,
|
|
616
|
+
});
|
|
617
|
+
const ctx = createMockContext();
|
|
618
|
+
|
|
619
|
+
await expect(
|
|
620
|
+
deleteGitIssue({ git_issue_id: VALID_GIT_ISSUE_ID }, ctx)
|
|
621
|
+
).rejects.toThrow('Failed to delete git issue');
|
|
622
|
+
});
|
|
623
|
+
});
|