@vibescope/mcp-server 0.4.5 → 0.4.6
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/CHANGELOG.md +84 -84
- package/README.md +194 -194
- package/dist/api-client/project.d.ts +1 -0
- package/dist/api-client.d.ts +1 -0
- package/dist/cli-init.js +21 -21
- package/dist/cli.js +26 -26
- package/dist/handlers/chat.d.ts +2 -0
- package/dist/handlers/chat.js +25 -0
- package/dist/handlers/discovery.js +12 -0
- package/dist/handlers/project.js +4 -2
- package/dist/handlers/tool-docs.js +1203 -1137
- package/dist/index.js +73 -73
- package/dist/templates/agent-guidelines.d.ts +1 -1
- package/dist/templates/agent-guidelines.js +205 -187
- package/dist/templates/help-content.js +1621 -1621
- package/dist/tools/bodies-of-work.js +6 -6
- package/dist/tools/chat.d.ts +1 -0
- package/dist/tools/chat.js +24 -0
- package/dist/tools/cloud-agents.js +22 -22
- package/dist/tools/features.d.ts +13 -0
- package/dist/tools/features.js +151 -0
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.js +4 -1
- package/dist/tools/milestones.js +2 -2
- package/dist/tools/project.js +4 -0
- package/dist/tools/requests.js +1 -1
- package/dist/tools/session.js +11 -11
- package/dist/tools/sprints.js +9 -9
- package/dist/tools/tasks.js +35 -35
- package/dist/tools/worktrees.js +14 -14
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +3602 -0
- package/dist/utils.js +11 -11
- package/docs/TOOLS.md +2663 -2559
- package/package.json +53 -53
- package/scripts/generate-docs.ts +212 -212
- package/scripts/version-bump.ts +203 -203
- package/src/api-client/blockers.ts +86 -86
- package/src/api-client/bodies-of-work.ts +194 -194
- package/src/api-client/chat.ts +50 -50
- package/src/api-client/connectors.ts +152 -152
- package/src/api-client/cost.ts +185 -185
- package/src/api-client/decisions.ts +87 -87
- package/src/api-client/deployment.ts +313 -313
- package/src/api-client/discovery.ts +81 -81
- package/src/api-client/fallback.ts +52 -52
- package/src/api-client/file-checkouts.ts +115 -115
- package/src/api-client/findings.ts +100 -100
- package/src/api-client/git-issues.ts +88 -88
- package/src/api-client/ideas.ts +112 -112
- package/src/api-client/index.ts +592 -592
- package/src/api-client/milestones.ts +83 -83
- package/src/api-client/organizations.ts +185 -185
- package/src/api-client/progress.ts +94 -94
- package/src/api-client/project.ts +180 -179
- package/src/api-client/requests.ts +54 -54
- package/src/api-client/session.ts +220 -220
- package/src/api-client/sprints.ts +227 -227
- package/src/api-client/subtasks.ts +57 -57
- package/src/api-client/tasks.ts +450 -450
- package/src/api-client/types.ts +32 -32
- package/src/api-client/validation.ts +60 -60
- package/src/api-client/worktrees.ts +53 -53
- package/src/api-client.test.ts +847 -847
- package/src/api-client.ts +2707 -2706
- package/src/cli-init.ts +557 -557
- package/src/cli.test.ts +284 -284
- package/src/cli.ts +204 -204
- package/src/handlers/__test-setup__.ts +240 -240
- package/src/handlers/__test-utils__.ts +89 -89
- package/src/handlers/blockers.test.ts +468 -468
- package/src/handlers/blockers.ts +172 -172
- package/src/handlers/bodies-of-work.test.ts +704 -704
- package/src/handlers/bodies-of-work.ts +526 -526
- package/src/handlers/chat.test.ts +185 -185
- package/src/handlers/chat.ts +101 -69
- package/src/handlers/cloud-agents.test.ts +438 -438
- package/src/handlers/cloud-agents.ts +156 -156
- package/src/handlers/connectors.test.ts +834 -834
- package/src/handlers/connectors.ts +229 -229
- package/src/handlers/cost.test.ts +462 -462
- package/src/handlers/cost.ts +285 -285
- package/src/handlers/decisions.test.ts +382 -382
- package/src/handlers/decisions.ts +153 -153
- package/src/handlers/deployment.test.ts +551 -551
- package/src/handlers/deployment.ts +570 -570
- package/src/handlers/discovery.test.ts +206 -206
- package/src/handlers/discovery.ts +427 -415
- package/src/handlers/fallback.test.ts +537 -537
- package/src/handlers/fallback.ts +194 -194
- package/src/handlers/file-checkouts.test.ts +750 -750
- package/src/handlers/file-checkouts.ts +185 -185
- package/src/handlers/findings.test.ts +633 -633
- package/src/handlers/findings.ts +239 -239
- package/src/handlers/git-issues.test.ts +631 -631
- package/src/handlers/git-issues.ts +136 -136
- package/src/handlers/ideas.test.ts +644 -644
- package/src/handlers/ideas.ts +207 -207
- package/src/handlers/index.ts +93 -93
- package/src/handlers/milestones.test.ts +475 -475
- package/src/handlers/milestones.ts +180 -180
- package/src/handlers/organizations.test.ts +826 -826
- package/src/handlers/organizations.ts +315 -315
- package/src/handlers/progress.test.ts +269 -269
- package/src/handlers/progress.ts +77 -77
- package/src/handlers/project.test.ts +546 -546
- package/src/handlers/project.ts +242 -239
- package/src/handlers/requests.test.ts +303 -303
- package/src/handlers/requests.ts +99 -99
- package/src/handlers/roles.test.ts +305 -305
- package/src/handlers/roles.ts +219 -219
- package/src/handlers/session.test.ts +998 -998
- package/src/handlers/session.ts +1105 -1105
- package/src/handlers/sprints.test.ts +732 -732
- package/src/handlers/sprints.ts +537 -537
- package/src/handlers/tasks.test.ts +931 -931
- package/src/handlers/tasks.ts +1133 -1133
- package/src/handlers/tool-categories.test.ts +66 -66
- package/src/handlers/tool-docs.test.ts +511 -511
- package/src/handlers/tool-docs.ts +1571 -1499
- package/src/handlers/types.test.ts +259 -259
- package/src/handlers/types.ts +176 -176
- package/src/handlers/validation.test.ts +582 -582
- package/src/handlers/validation.ts +164 -164
- package/src/handlers/version.ts +63 -63
- package/src/index.test.ts +674 -674
- package/src/index.ts +807 -807
- package/src/setup.test.ts +233 -233
- package/src/setup.ts +404 -404
- package/src/templates/agent-guidelines.ts +233 -215
- package/src/templates/help-content.ts +1751 -1751
- package/src/token-tracking.test.ts +463 -463
- package/src/token-tracking.ts +167 -167
- package/src/tools/blockers.ts +122 -122
- package/src/tools/bodies-of-work.ts +283 -283
- package/src/tools/chat.ts +72 -46
- package/src/tools/cloud-agents.ts +101 -101
- package/src/tools/connectors.ts +191 -191
- package/src/tools/cost.ts +111 -111
- package/src/tools/decisions.ts +111 -111
- package/src/tools/deployment.ts +455 -455
- package/src/tools/discovery.ts +76 -76
- package/src/tools/fallback.ts +111 -111
- package/src/tools/features.ts +154 -0
- package/src/tools/file-checkouts.ts +145 -145
- package/src/tools/findings.ts +101 -101
- package/src/tools/git-issues.ts +130 -130
- package/src/tools/ideas.ts +162 -162
- package/src/tools/index.ts +141 -137
- package/src/tools/milestones.ts +118 -118
- package/src/tools/organizations.ts +224 -224
- package/src/tools/progress.ts +73 -73
- package/src/tools/project.ts +206 -202
- package/src/tools/requests.ts +68 -68
- package/src/tools/roles.ts +112 -112
- package/src/tools/session.ts +181 -181
- package/src/tools/sprints.ts +298 -298
- package/src/tools/tasks.ts +550 -550
- package/src/tools/tools.test.ts +222 -222
- package/src/tools/types.ts +9 -9
- package/src/tools/validation.ts +75 -75
- package/src/tools/version.ts +34 -34
- package/src/tools/worktrees.ts +66 -66
- package/src/tools.test.ts +416 -416
- package/src/utils.test.ts +1014 -1014
- package/src/utils.ts +586 -586
- package/src/validators.test.ts +223 -223
- package/src/validators.ts +249 -249
- package/src/version.ts +109 -109
- package/tsconfig.json +16 -16
- package/vitest.config.ts +14 -14
|
@@ -1,305 +1,305 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
getRoleSettings,
|
|
4
|
-
updateRoleSettings,
|
|
5
|
-
setSessionRole,
|
|
6
|
-
getAgentsByRole,
|
|
7
|
-
} from './roles.js';
|
|
8
|
-
import { createMockContext } from './__test-utils__.js';
|
|
9
|
-
import { mockApiClient } from './__test-setup__.js';
|
|
10
|
-
|
|
11
|
-
// ============================================================================
|
|
12
|
-
// getRoleSettings Tests
|
|
13
|
-
// ============================================================================
|
|
14
|
-
|
|
15
|
-
describe('getRoleSettings', () => {
|
|
16
|
-
beforeEach(() => vi.clearAllMocks());
|
|
17
|
-
|
|
18
|
-
it('should return error for missing project_id', async () => {
|
|
19
|
-
const ctx = createMockContext();
|
|
20
|
-
|
|
21
|
-
const result = await getRoleSettings({}, ctx);
|
|
22
|
-
|
|
23
|
-
expect(result.result).toMatchObject({
|
|
24
|
-
error: 'project_id is required',
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should get role settings successfully', async () => {
|
|
29
|
-
const mockRoles = [
|
|
30
|
-
{ role: 'developer', enabled: true, display_name: 'Developer' },
|
|
31
|
-
{ role: 'validator', enabled: true, display_name: 'Validator' },
|
|
32
|
-
];
|
|
33
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
34
|
-
ok: true,
|
|
35
|
-
data: { roles: mockRoles },
|
|
36
|
-
});
|
|
37
|
-
const ctx = createMockContext();
|
|
38
|
-
|
|
39
|
-
const result = await getRoleSettings(
|
|
40
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
41
|
-
ctx
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
expect(result.result).toMatchObject({ roles: mockRoles });
|
|
45
|
-
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
46
|
-
'get_role_settings',
|
|
47
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' }
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should return error from API', async () => {
|
|
52
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
53
|
-
ok: false,
|
|
54
|
-
error: 'Project not found',
|
|
55
|
-
});
|
|
56
|
-
const ctx = createMockContext();
|
|
57
|
-
|
|
58
|
-
const result = await getRoleSettings(
|
|
59
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
60
|
-
ctx
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
expect(result.result).toMatchObject({
|
|
64
|
-
error: 'Project not found',
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ============================================================================
|
|
70
|
-
// updateRoleSettings Tests
|
|
71
|
-
// ============================================================================
|
|
72
|
-
|
|
73
|
-
describe('updateRoleSettings', () => {
|
|
74
|
-
beforeEach(() => vi.clearAllMocks());
|
|
75
|
-
|
|
76
|
-
it('should return error for missing project_id', async () => {
|
|
77
|
-
const ctx = createMockContext();
|
|
78
|
-
|
|
79
|
-
const result = await updateRoleSettings({ role: 'developer' }, ctx);
|
|
80
|
-
|
|
81
|
-
expect(result.result).toMatchObject({
|
|
82
|
-
error: 'project_id is required',
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should return error for missing role', async () => {
|
|
87
|
-
const ctx = createMockContext();
|
|
88
|
-
|
|
89
|
-
const result = await updateRoleSettings(
|
|
90
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
91
|
-
ctx
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
expect(result.result).toMatchObject({
|
|
95
|
-
error: 'role is required',
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('should update role settings successfully', async () => {
|
|
100
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
101
|
-
ok: true,
|
|
102
|
-
data: { success: true, role: 'validator' },
|
|
103
|
-
});
|
|
104
|
-
const ctx = createMockContext();
|
|
105
|
-
|
|
106
|
-
const result = await updateRoleSettings(
|
|
107
|
-
{
|
|
108
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
109
|
-
role: 'validator',
|
|
110
|
-
enabled: true,
|
|
111
|
-
auto_assign_validation: true,
|
|
112
|
-
},
|
|
113
|
-
ctx
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
expect(result.result).toMatchObject({
|
|
117
|
-
success: true,
|
|
118
|
-
role: 'validator',
|
|
119
|
-
});
|
|
120
|
-
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
121
|
-
'update_role_settings',
|
|
122
|
-
expect.objectContaining({
|
|
123
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
124
|
-
role: 'validator',
|
|
125
|
-
enabled: true,
|
|
126
|
-
auto_assign_validation: true,
|
|
127
|
-
})
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should return error from API', async () => {
|
|
132
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
133
|
-
ok: false,
|
|
134
|
-
error: 'Access denied',
|
|
135
|
-
});
|
|
136
|
-
const ctx = createMockContext();
|
|
137
|
-
|
|
138
|
-
const result = await updateRoleSettings(
|
|
139
|
-
{
|
|
140
|
-
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
141
|
-
role: 'validator',
|
|
142
|
-
},
|
|
143
|
-
ctx
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
expect(result.result).toMatchObject({
|
|
147
|
-
error: 'Access denied',
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// ============================================================================
|
|
153
|
-
// setSessionRole Tests
|
|
154
|
-
// ============================================================================
|
|
155
|
-
|
|
156
|
-
describe('setSessionRole', () => {
|
|
157
|
-
beforeEach(() => vi.clearAllMocks());
|
|
158
|
-
|
|
159
|
-
it('should return error for missing role', async () => {
|
|
160
|
-
const ctx = createMockContext();
|
|
161
|
-
|
|
162
|
-
const result = await setSessionRole({}, ctx);
|
|
163
|
-
|
|
164
|
-
expect(result.result).toMatchObject({
|
|
165
|
-
error: 'role is required',
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('should accept custom roles (open-ended)', async () => {
|
|
170
|
-
const ctx = createMockContext();
|
|
171
|
-
|
|
172
|
-
const result = await setSessionRole({ role: 'custom_role' }, ctx);
|
|
173
|
-
|
|
174
|
-
// Roles are now open-ended - any role name is accepted
|
|
175
|
-
expect(result.result).toMatchObject({
|
|
176
|
-
success: true,
|
|
177
|
-
role: 'custom_role',
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('should set local role when no active session', async () => {
|
|
182
|
-
const ctx = createMockContext({ sessionId: null });
|
|
183
|
-
|
|
184
|
-
const result = await setSessionRole({ role: 'validator' }, ctx);
|
|
185
|
-
|
|
186
|
-
expect(result.result).toMatchObject({
|
|
187
|
-
success: true,
|
|
188
|
-
role: 'validator',
|
|
189
|
-
message: expect.stringContaining('Local role set to validator'),
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('should update session role on server when session active', async () => {
|
|
194
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
195
|
-
ok: true,
|
|
196
|
-
data: { success: true, session_id: 'session-123', role: 'deployer' },
|
|
197
|
-
});
|
|
198
|
-
const ctx = createMockContext({ sessionId: 'session-123' });
|
|
199
|
-
|
|
200
|
-
const result = await setSessionRole({ role: 'deployer' }, ctx);
|
|
201
|
-
|
|
202
|
-
expect(result.result).toMatchObject({
|
|
203
|
-
success: true,
|
|
204
|
-
session_id: 'session-123',
|
|
205
|
-
role: 'deployer',
|
|
206
|
-
});
|
|
207
|
-
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
208
|
-
'set_session_role',
|
|
209
|
-
expect.objectContaining({
|
|
210
|
-
session_id: 'session-123',
|
|
211
|
-
role: 'deployer',
|
|
212
|
-
})
|
|
213
|
-
);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should update local state when setting role', async () => {
|
|
217
|
-
const updateSession = vi.fn();
|
|
218
|
-
const ctx = createMockContext({ sessionId: null });
|
|
219
|
-
ctx.updateSession = updateSession;
|
|
220
|
-
|
|
221
|
-
await setSessionRole({ role: 'reviewer' }, ctx);
|
|
222
|
-
|
|
223
|
-
expect(updateSession).toHaveBeenCalledWith({ currentRole: 'reviewer' });
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('should return error from API when updating session', async () => {
|
|
227
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
228
|
-
ok: false,
|
|
229
|
-
error: 'Session not found',
|
|
230
|
-
});
|
|
231
|
-
const ctx = createMockContext({ sessionId: 'session-123' });
|
|
232
|
-
|
|
233
|
-
const result = await setSessionRole({ role: 'maintainer' }, ctx);
|
|
234
|
-
|
|
235
|
-
expect(result.result).toMatchObject({
|
|
236
|
-
error: 'Session not found',
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
// ============================================================================
|
|
242
|
-
// getAgentsByRole Tests
|
|
243
|
-
// ============================================================================
|
|
244
|
-
|
|
245
|
-
describe('getAgentsByRole', () => {
|
|
246
|
-
beforeEach(() => vi.clearAllMocks());
|
|
247
|
-
|
|
248
|
-
it('should return error for missing project_id', async () => {
|
|
249
|
-
const ctx = createMockContext();
|
|
250
|
-
|
|
251
|
-
const result = await getAgentsByRole({}, ctx);
|
|
252
|
-
|
|
253
|
-
expect(result.result).toMatchObject({
|
|
254
|
-
error: 'project_id is required',
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('should get agents by role successfully', async () => {
|
|
259
|
-
const mockAgentsByRole = {
|
|
260
|
-
developer: [
|
|
261
|
-
{ session_id: 'session-1', agent_name: 'Edge', status: 'active' },
|
|
262
|
-
],
|
|
263
|
-
validator: [],
|
|
264
|
-
deployer: [],
|
|
265
|
-
reviewer: [],
|
|
266
|
-
maintainer: [],
|
|
267
|
-
};
|
|
268
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
269
|
-
ok: true,
|
|
270
|
-
data: { agents_by_role: mockAgentsByRole, total_active: 1 },
|
|
271
|
-
});
|
|
272
|
-
const ctx = createMockContext();
|
|
273
|
-
|
|
274
|
-
const result = await getAgentsByRole(
|
|
275
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
276
|
-
ctx
|
|
277
|
-
);
|
|
278
|
-
|
|
279
|
-
expect(result.result).toMatchObject({
|
|
280
|
-
agents_by_role: mockAgentsByRole,
|
|
281
|
-
total_active: 1,
|
|
282
|
-
});
|
|
283
|
-
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
284
|
-
'get_agents_by_role',
|
|
285
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000', counts_only: true }
|
|
286
|
-
);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it('should return error from API', async () => {
|
|
290
|
-
mockApiClient.proxy.mockResolvedValue({
|
|
291
|
-
ok: false,
|
|
292
|
-
error: 'Project not found',
|
|
293
|
-
});
|
|
294
|
-
const ctx = createMockContext();
|
|
295
|
-
|
|
296
|
-
const result = await getAgentsByRole(
|
|
297
|
-
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
298
|
-
ctx
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
expect(result.result).toMatchObject({
|
|
302
|
-
error: 'Project not found',
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
getRoleSettings,
|
|
4
|
+
updateRoleSettings,
|
|
5
|
+
setSessionRole,
|
|
6
|
+
getAgentsByRole,
|
|
7
|
+
} from './roles.js';
|
|
8
|
+
import { createMockContext } from './__test-utils__.js';
|
|
9
|
+
import { mockApiClient } from './__test-setup__.js';
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// getRoleSettings Tests
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
describe('getRoleSettings', () => {
|
|
16
|
+
beforeEach(() => vi.clearAllMocks());
|
|
17
|
+
|
|
18
|
+
it('should return error for missing project_id', async () => {
|
|
19
|
+
const ctx = createMockContext();
|
|
20
|
+
|
|
21
|
+
const result = await getRoleSettings({}, ctx);
|
|
22
|
+
|
|
23
|
+
expect(result.result).toMatchObject({
|
|
24
|
+
error: 'project_id is required',
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should get role settings successfully', async () => {
|
|
29
|
+
const mockRoles = [
|
|
30
|
+
{ role: 'developer', enabled: true, display_name: 'Developer' },
|
|
31
|
+
{ role: 'validator', enabled: true, display_name: 'Validator' },
|
|
32
|
+
];
|
|
33
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
34
|
+
ok: true,
|
|
35
|
+
data: { roles: mockRoles },
|
|
36
|
+
});
|
|
37
|
+
const ctx = createMockContext();
|
|
38
|
+
|
|
39
|
+
const result = await getRoleSettings(
|
|
40
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
41
|
+
ctx
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(result.result).toMatchObject({ roles: mockRoles });
|
|
45
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
46
|
+
'get_role_settings',
|
|
47
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' }
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return error from API', async () => {
|
|
52
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
53
|
+
ok: false,
|
|
54
|
+
error: 'Project not found',
|
|
55
|
+
});
|
|
56
|
+
const ctx = createMockContext();
|
|
57
|
+
|
|
58
|
+
const result = await getRoleSettings(
|
|
59
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
60
|
+
ctx
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(result.result).toMatchObject({
|
|
64
|
+
error: 'Project not found',
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// updateRoleSettings Tests
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
describe('updateRoleSettings', () => {
|
|
74
|
+
beforeEach(() => vi.clearAllMocks());
|
|
75
|
+
|
|
76
|
+
it('should return error for missing project_id', async () => {
|
|
77
|
+
const ctx = createMockContext();
|
|
78
|
+
|
|
79
|
+
const result = await updateRoleSettings({ role: 'developer' }, ctx);
|
|
80
|
+
|
|
81
|
+
expect(result.result).toMatchObject({
|
|
82
|
+
error: 'project_id is required',
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should return error for missing role', async () => {
|
|
87
|
+
const ctx = createMockContext();
|
|
88
|
+
|
|
89
|
+
const result = await updateRoleSettings(
|
|
90
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
91
|
+
ctx
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
expect(result.result).toMatchObject({
|
|
95
|
+
error: 'role is required',
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should update role settings successfully', async () => {
|
|
100
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
101
|
+
ok: true,
|
|
102
|
+
data: { success: true, role: 'validator' },
|
|
103
|
+
});
|
|
104
|
+
const ctx = createMockContext();
|
|
105
|
+
|
|
106
|
+
const result = await updateRoleSettings(
|
|
107
|
+
{
|
|
108
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
109
|
+
role: 'validator',
|
|
110
|
+
enabled: true,
|
|
111
|
+
auto_assign_validation: true,
|
|
112
|
+
},
|
|
113
|
+
ctx
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(result.result).toMatchObject({
|
|
117
|
+
success: true,
|
|
118
|
+
role: 'validator',
|
|
119
|
+
});
|
|
120
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
121
|
+
'update_role_settings',
|
|
122
|
+
expect.objectContaining({
|
|
123
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
124
|
+
role: 'validator',
|
|
125
|
+
enabled: true,
|
|
126
|
+
auto_assign_validation: true,
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should return error from API', async () => {
|
|
132
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
133
|
+
ok: false,
|
|
134
|
+
error: 'Access denied',
|
|
135
|
+
});
|
|
136
|
+
const ctx = createMockContext();
|
|
137
|
+
|
|
138
|
+
const result = await updateRoleSettings(
|
|
139
|
+
{
|
|
140
|
+
project_id: '123e4567-e89b-12d3-a456-426614174000',
|
|
141
|
+
role: 'validator',
|
|
142
|
+
},
|
|
143
|
+
ctx
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(result.result).toMatchObject({
|
|
147
|
+
error: 'Access denied',
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// setSessionRole Tests
|
|
154
|
+
// ============================================================================
|
|
155
|
+
|
|
156
|
+
describe('setSessionRole', () => {
|
|
157
|
+
beforeEach(() => vi.clearAllMocks());
|
|
158
|
+
|
|
159
|
+
it('should return error for missing role', async () => {
|
|
160
|
+
const ctx = createMockContext();
|
|
161
|
+
|
|
162
|
+
const result = await setSessionRole({}, ctx);
|
|
163
|
+
|
|
164
|
+
expect(result.result).toMatchObject({
|
|
165
|
+
error: 'role is required',
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should accept custom roles (open-ended)', async () => {
|
|
170
|
+
const ctx = createMockContext();
|
|
171
|
+
|
|
172
|
+
const result = await setSessionRole({ role: 'custom_role' }, ctx);
|
|
173
|
+
|
|
174
|
+
// Roles are now open-ended - any role name is accepted
|
|
175
|
+
expect(result.result).toMatchObject({
|
|
176
|
+
success: true,
|
|
177
|
+
role: 'custom_role',
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should set local role when no active session', async () => {
|
|
182
|
+
const ctx = createMockContext({ sessionId: null });
|
|
183
|
+
|
|
184
|
+
const result = await setSessionRole({ role: 'validator' }, ctx);
|
|
185
|
+
|
|
186
|
+
expect(result.result).toMatchObject({
|
|
187
|
+
success: true,
|
|
188
|
+
role: 'validator',
|
|
189
|
+
message: expect.stringContaining('Local role set to validator'),
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should update session role on server when session active', async () => {
|
|
194
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
195
|
+
ok: true,
|
|
196
|
+
data: { success: true, session_id: 'session-123', role: 'deployer' },
|
|
197
|
+
});
|
|
198
|
+
const ctx = createMockContext({ sessionId: 'session-123' });
|
|
199
|
+
|
|
200
|
+
const result = await setSessionRole({ role: 'deployer' }, ctx);
|
|
201
|
+
|
|
202
|
+
expect(result.result).toMatchObject({
|
|
203
|
+
success: true,
|
|
204
|
+
session_id: 'session-123',
|
|
205
|
+
role: 'deployer',
|
|
206
|
+
});
|
|
207
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
208
|
+
'set_session_role',
|
|
209
|
+
expect.objectContaining({
|
|
210
|
+
session_id: 'session-123',
|
|
211
|
+
role: 'deployer',
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should update local state when setting role', async () => {
|
|
217
|
+
const updateSession = vi.fn();
|
|
218
|
+
const ctx = createMockContext({ sessionId: null });
|
|
219
|
+
ctx.updateSession = updateSession;
|
|
220
|
+
|
|
221
|
+
await setSessionRole({ role: 'reviewer' }, ctx);
|
|
222
|
+
|
|
223
|
+
expect(updateSession).toHaveBeenCalledWith({ currentRole: 'reviewer' });
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should return error from API when updating session', async () => {
|
|
227
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
228
|
+
ok: false,
|
|
229
|
+
error: 'Session not found',
|
|
230
|
+
});
|
|
231
|
+
const ctx = createMockContext({ sessionId: 'session-123' });
|
|
232
|
+
|
|
233
|
+
const result = await setSessionRole({ role: 'maintainer' }, ctx);
|
|
234
|
+
|
|
235
|
+
expect(result.result).toMatchObject({
|
|
236
|
+
error: 'Session not found',
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// getAgentsByRole Tests
|
|
243
|
+
// ============================================================================
|
|
244
|
+
|
|
245
|
+
describe('getAgentsByRole', () => {
|
|
246
|
+
beforeEach(() => vi.clearAllMocks());
|
|
247
|
+
|
|
248
|
+
it('should return error for missing project_id', async () => {
|
|
249
|
+
const ctx = createMockContext();
|
|
250
|
+
|
|
251
|
+
const result = await getAgentsByRole({}, ctx);
|
|
252
|
+
|
|
253
|
+
expect(result.result).toMatchObject({
|
|
254
|
+
error: 'project_id is required',
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should get agents by role successfully', async () => {
|
|
259
|
+
const mockAgentsByRole = {
|
|
260
|
+
developer: [
|
|
261
|
+
{ session_id: 'session-1', agent_name: 'Edge', status: 'active' },
|
|
262
|
+
],
|
|
263
|
+
validator: [],
|
|
264
|
+
deployer: [],
|
|
265
|
+
reviewer: [],
|
|
266
|
+
maintainer: [],
|
|
267
|
+
};
|
|
268
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
269
|
+
ok: true,
|
|
270
|
+
data: { agents_by_role: mockAgentsByRole, total_active: 1 },
|
|
271
|
+
});
|
|
272
|
+
const ctx = createMockContext();
|
|
273
|
+
|
|
274
|
+
const result = await getAgentsByRole(
|
|
275
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
276
|
+
ctx
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
expect(result.result).toMatchObject({
|
|
280
|
+
agents_by_role: mockAgentsByRole,
|
|
281
|
+
total_active: 1,
|
|
282
|
+
});
|
|
283
|
+
expect(mockApiClient.proxy).toHaveBeenCalledWith(
|
|
284
|
+
'get_agents_by_role',
|
|
285
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000', counts_only: true }
|
|
286
|
+
);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should return error from API', async () => {
|
|
290
|
+
mockApiClient.proxy.mockResolvedValue({
|
|
291
|
+
ok: false,
|
|
292
|
+
error: 'Project not found',
|
|
293
|
+
});
|
|
294
|
+
const ctx = createMockContext();
|
|
295
|
+
|
|
296
|
+
const result = await getAgentsByRole(
|
|
297
|
+
{ project_id: '123e4567-e89b-12d3-a456-426614174000' },
|
|
298
|
+
ctx
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
expect(result.result).toMatchObject({
|
|
302
|
+
error: 'Project not found',
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|