@vibescope/mcp-server 0.1.0 → 0.2.1
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 +1 -1
- package/dist/api-client.d.ts +120 -2
- package/dist/api-client.js +51 -5
- package/dist/handlers/bodies-of-work.js +84 -50
- package/dist/handlers/cost.js +62 -54
- package/dist/handlers/decisions.js +29 -16
- package/dist/handlers/deployment.js +114 -107
- package/dist/handlers/discovery.d.ts +3 -0
- package/dist/handlers/discovery.js +55 -657
- package/dist/handlers/fallback.js +42 -28
- package/dist/handlers/file-checkouts.d.ts +18 -0
- package/dist/handlers/file-checkouts.js +101 -0
- package/dist/handlers/findings.d.ts +14 -1
- package/dist/handlers/findings.js +104 -28
- package/dist/handlers/git-issues.js +36 -32
- package/dist/handlers/ideas.js +44 -26
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +6 -0
- package/dist/handlers/milestones.js +34 -27
- package/dist/handlers/organizations.js +86 -78
- package/dist/handlers/progress.js +22 -11
- package/dist/handlers/project.js +62 -22
- package/dist/handlers/requests.js +15 -11
- package/dist/handlers/roles.d.ts +18 -0
- package/dist/handlers/roles.js +130 -0
- package/dist/handlers/session.js +52 -15
- package/dist/handlers/sprints.js +78 -65
- package/dist/handlers/tasks.js +135 -74
- package/dist/handlers/tool-docs.d.ts +4 -3
- package/dist/handlers/tool-docs.js +252 -5
- package/dist/handlers/validation.js +30 -14
- package/dist/index.js +25 -7
- package/dist/tools.js +417 -4
- package/package.json +1 -1
- package/src/api-client.ts +161 -8
- package/src/handlers/__test-setup__.ts +12 -0
- package/src/handlers/bodies-of-work.ts +127 -111
- package/src/handlers/cost.test.ts +34 -44
- package/src/handlers/cost.ts +77 -92
- package/src/handlers/decisions.test.ts +3 -2
- package/src/handlers/decisions.ts +32 -27
- package/src/handlers/deployment.ts +144 -190
- package/src/handlers/discovery.test.ts +4 -5
- package/src/handlers/discovery.ts +60 -746
- package/src/handlers/fallback.test.ts +78 -0
- package/src/handlers/fallback.ts +51 -38
- package/src/handlers/file-checkouts.test.ts +477 -0
- package/src/handlers/file-checkouts.ts +127 -0
- package/src/handlers/findings.test.ts +274 -2
- package/src/handlers/findings.ts +123 -57
- package/src/handlers/git-issues.ts +40 -80
- package/src/handlers/ideas.ts +56 -54
- package/src/handlers/index.ts +6 -0
- package/src/handlers/milestones.test.ts +1 -1
- package/src/handlers/milestones.ts +47 -45
- package/src/handlers/organizations.ts +104 -129
- package/src/handlers/progress.ts +24 -22
- package/src/handlers/project.ts +89 -57
- package/src/handlers/requests.ts +18 -14
- package/src/handlers/roles.test.ts +303 -0
- package/src/handlers/roles.ts +208 -0
- package/src/handlers/session.test.ts +37 -2
- package/src/handlers/session.ts +64 -21
- package/src/handlers/sprints.ts +114 -134
- package/src/handlers/tasks.test.ts +61 -0
- package/src/handlers/tasks.ts +170 -139
- package/src/handlers/tool-docs.ts +1024 -0
- package/src/handlers/validation.test.ts +53 -1
- package/src/handlers/validation.ts +32 -21
- package/src/index.ts +25 -7
- package/src/tools.ts +417 -4
- package/dist/config/tool-categories.d.ts +0 -31
- package/dist/config/tool-categories.js +0 -253
- package/dist/knowledge.d.ts +0 -6
- package/dist/knowledge.js +0 -218
- package/src/knowledge.ts +0 -230
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Management Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles agent role configuration and assignment:
|
|
5
|
+
* - get_role_settings: Get role configuration for a project
|
|
6
|
+
* - update_role_settings: Update role settings for a project
|
|
7
|
+
* - set_session_role: Set the role for the current session
|
|
8
|
+
* - get_agents_by_role: Get active agents grouped by their assigned roles
|
|
9
|
+
*/
|
|
10
|
+
import { getApiClient } from '../api-client.js';
|
|
11
|
+
export const getRoleSettings = async (args, _ctx) => {
|
|
12
|
+
const { project_id } = args;
|
|
13
|
+
if (!project_id) {
|
|
14
|
+
return {
|
|
15
|
+
result: { error: 'project_id is required' },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const apiClient = getApiClient();
|
|
19
|
+
const response = await apiClient.proxy('get_role_settings', { project_id });
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
return {
|
|
22
|
+
result: { error: response.error || 'Failed to get role settings' },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return { result: response.data };
|
|
26
|
+
};
|
|
27
|
+
export const updateRoleSettings = async (args, _ctx) => {
|
|
28
|
+
const { project_id, role, enabled, display_name, description, priority_filter, fallback_activities, auto_assign_validation, auto_assign_deployment, } = args;
|
|
29
|
+
if (!project_id) {
|
|
30
|
+
return {
|
|
31
|
+
result: { error: 'project_id is required' },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (!role) {
|
|
35
|
+
return {
|
|
36
|
+
result: { error: 'role is required' },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const apiClient = getApiClient();
|
|
40
|
+
const response = await apiClient.proxy('update_role_settings', {
|
|
41
|
+
project_id,
|
|
42
|
+
role,
|
|
43
|
+
enabled,
|
|
44
|
+
display_name,
|
|
45
|
+
description,
|
|
46
|
+
priority_filter,
|
|
47
|
+
fallback_activities,
|
|
48
|
+
auto_assign_validation,
|
|
49
|
+
auto_assign_deployment,
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
return {
|
|
53
|
+
result: { error: response.error || 'Failed to update role settings' },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { result: response.data };
|
|
57
|
+
};
|
|
58
|
+
export const setSessionRole = async (args, ctx) => {
|
|
59
|
+
const { role, role_config } = args;
|
|
60
|
+
const { session, updateSession } = ctx;
|
|
61
|
+
if (!role) {
|
|
62
|
+
return {
|
|
63
|
+
result: { error: 'role is required' },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const validRoles = ['developer', 'validator', 'deployer', 'reviewer', 'maintainer'];
|
|
67
|
+
if (!validRoles.includes(role)) {
|
|
68
|
+
return {
|
|
69
|
+
result: {
|
|
70
|
+
error: `Invalid role: ${role}. Must be one of: ${validRoles.join(', ')}`,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Update local session state
|
|
75
|
+
updateSession({ currentRole: role });
|
|
76
|
+
// If there's an active session, update it on the server too
|
|
77
|
+
if (session.currentSessionId) {
|
|
78
|
+
const apiClient = getApiClient();
|
|
79
|
+
const response = await apiClient.proxy('set_session_role', {
|
|
80
|
+
session_id: session.currentSessionId,
|
|
81
|
+
role,
|
|
82
|
+
role_config,
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
return {
|
|
86
|
+
result: { error: response.error || 'Failed to update session role' },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
result: {
|
|
91
|
+
success: true,
|
|
92
|
+
session_id: session.currentSessionId,
|
|
93
|
+
role,
|
|
94
|
+
message: `Session role updated to ${role}. Task filtering and fallback suggestions will now be optimized for this role.`,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
result: {
|
|
100
|
+
success: true,
|
|
101
|
+
role,
|
|
102
|
+
message: `Local role set to ${role}. Start a session to persist this role.`,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export const getAgentsByRole = async (args, _ctx) => {
|
|
107
|
+
const { project_id } = args;
|
|
108
|
+
if (!project_id) {
|
|
109
|
+
return {
|
|
110
|
+
result: { error: 'project_id is required' },
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const apiClient = getApiClient();
|
|
114
|
+
const response = await apiClient.proxy('get_agents_by_role', { project_id });
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
return {
|
|
117
|
+
result: { error: response.error || 'Failed to get agents by role' },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return { result: response.data };
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Role handlers registry
|
|
124
|
+
*/
|
|
125
|
+
export const roleHandlers = {
|
|
126
|
+
get_role_settings: getRoleSettings,
|
|
127
|
+
update_role_settings: updateRoleSettings,
|
|
128
|
+
set_session_role: setSessionRole,
|
|
129
|
+
get_agents_by_role: getAgentsByRole,
|
|
130
|
+
};
|
package/dist/handlers/session.js
CHANGED
|
@@ -8,14 +8,35 @@
|
|
|
8
8
|
* - get_help
|
|
9
9
|
* - get_token_usage
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { parseArgs, createEnumValidator } from '../validators.js';
|
|
12
12
|
import { getApiClient } from '../api-client.js';
|
|
13
|
+
const VALID_MODES = ['lite', 'full'];
|
|
14
|
+
const VALID_MODELS = ['opus', 'sonnet', 'haiku'];
|
|
15
|
+
const VALID_ROLES = ['developer', 'validator', 'deployer', 'reviewer', 'maintainer'];
|
|
16
|
+
// Argument schemas for type-safe parsing
|
|
17
|
+
const startWorkSessionSchema = {
|
|
18
|
+
project_id: { type: 'string' },
|
|
19
|
+
git_url: { type: 'string' },
|
|
20
|
+
mode: { type: 'string', default: 'lite', validate: createEnumValidator(VALID_MODES) },
|
|
21
|
+
model: { type: 'string', validate: createEnumValidator(VALID_MODELS) },
|
|
22
|
+
role: { type: 'string', default: 'developer', validate: createEnumValidator(VALID_ROLES) },
|
|
23
|
+
};
|
|
24
|
+
const heartbeatSchema = {
|
|
25
|
+
session_id: { type: 'string' },
|
|
26
|
+
current_worktree_path: { type: 'string' },
|
|
27
|
+
};
|
|
28
|
+
const endWorkSessionSchema = {
|
|
29
|
+
session_id: { type: 'string' },
|
|
30
|
+
};
|
|
31
|
+
const getHelpSchema = {
|
|
32
|
+
topic: { type: 'string', required: true },
|
|
33
|
+
};
|
|
13
34
|
export const startWorkSession = async (args, ctx) => {
|
|
14
|
-
const { project_id, git_url, mode
|
|
35
|
+
const { project_id, git_url, mode, model, role } = parseArgs(args, startWorkSessionSchema);
|
|
15
36
|
const { session, updateSession } = ctx;
|
|
16
37
|
// Reset token tracking for new session with model info
|
|
17
38
|
const normalizedModel = model ? model.toLowerCase().replace(/^claude[- ]*/i, '') : null;
|
|
18
|
-
const validModel = normalizedModel &&
|
|
39
|
+
const validModel = normalizedModel && VALID_MODELS.includes(normalizedModel)
|
|
19
40
|
? normalizedModel
|
|
20
41
|
: null;
|
|
21
42
|
updateSession({
|
|
@@ -39,9 +60,9 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
39
60
|
const response = await apiClient.startSession({
|
|
40
61
|
project_id,
|
|
41
62
|
git_url,
|
|
42
|
-
mode,
|
|
43
|
-
model,
|
|
44
|
-
role
|
|
63
|
+
mode: mode,
|
|
64
|
+
model: model,
|
|
65
|
+
role: role
|
|
45
66
|
});
|
|
46
67
|
if (!response.ok) {
|
|
47
68
|
return {
|
|
@@ -114,7 +135,7 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
114
135
|
return { result };
|
|
115
136
|
};
|
|
116
137
|
export const heartbeat = async (args, ctx) => {
|
|
117
|
-
const { session_id } = args;
|
|
138
|
+
const { session_id, current_worktree_path } = parseArgs(args, heartbeatSchema);
|
|
118
139
|
const { session } = ctx;
|
|
119
140
|
const targetSession = session_id || session.currentSessionId;
|
|
120
141
|
if (!targetSession) {
|
|
@@ -125,8 +146,10 @@ export const heartbeat = async (args, ctx) => {
|
|
|
125
146
|
};
|
|
126
147
|
}
|
|
127
148
|
const apiClient = getApiClient();
|
|
128
|
-
// Send heartbeat
|
|
129
|
-
const heartbeatResponse = await apiClient.heartbeat(targetSession
|
|
149
|
+
// Send heartbeat with optional worktree path
|
|
150
|
+
const heartbeatResponse = await apiClient.heartbeat(targetSession, {
|
|
151
|
+
current_worktree_path,
|
|
152
|
+
});
|
|
130
153
|
if (!heartbeatResponse.ok) {
|
|
131
154
|
return {
|
|
132
155
|
result: {
|
|
@@ -149,7 +172,7 @@ export const heartbeat = async (args, ctx) => {
|
|
|
149
172
|
};
|
|
150
173
|
};
|
|
151
174
|
export const endWorkSession = async (args, ctx) => {
|
|
152
|
-
const { session_id } = args;
|
|
175
|
+
const { session_id } = parseArgs(args, endWorkSessionSchema);
|
|
153
176
|
const { session, updateSession } = ctx;
|
|
154
177
|
const targetSession = session_id || session.currentSessionId;
|
|
155
178
|
if (!targetSession) {
|
|
@@ -204,17 +227,31 @@ export const endWorkSession = async (args, ctx) => {
|
|
|
204
227
|
};
|
|
205
228
|
};
|
|
206
229
|
export const getHelp = async (args, _ctx) => {
|
|
207
|
-
const { topic } = args;
|
|
208
|
-
const
|
|
209
|
-
|
|
230
|
+
const { topic } = parseArgs(args, getHelpSchema);
|
|
231
|
+
const apiClient = getApiClient();
|
|
232
|
+
const response = await apiClient.getHelpTopic(topic);
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
// If database fetch fails, return error
|
|
235
|
+
return {
|
|
236
|
+
result: {
|
|
237
|
+
error: response.error || `Failed to fetch help topic: ${topic}`,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (!response.data) {
|
|
242
|
+
// Topic not found - fetch available topics
|
|
243
|
+
const topicsResponse = await apiClient.getHelpTopics();
|
|
244
|
+
const available = topicsResponse.ok && topicsResponse.data
|
|
245
|
+
? topicsResponse.data.map(t => t.slug)
|
|
246
|
+
: ['getting_started', 'tasks', 'validation', 'deployment', 'git', 'blockers', 'milestones', 'fallback', 'session', 'tokens', 'sprints', 'topics'];
|
|
210
247
|
return {
|
|
211
248
|
result: {
|
|
212
249
|
error: `Unknown topic: ${topic}`,
|
|
213
|
-
available
|
|
250
|
+
available,
|
|
214
251
|
},
|
|
215
252
|
};
|
|
216
253
|
}
|
|
217
|
-
return { result: { topic, content } };
|
|
254
|
+
return { result: { topic, content: response.data.content } };
|
|
218
255
|
};
|
|
219
256
|
// Model pricing rates (USD per 1M tokens)
|
|
220
257
|
const MODEL_PRICING = {
|
package/dist/handlers/sprints.js
CHANGED
|
@@ -14,25 +14,76 @@
|
|
|
14
14
|
* - get_sprint_backlog
|
|
15
15
|
* - get_sprint_velocity
|
|
16
16
|
*/
|
|
17
|
-
import {
|
|
17
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
18
18
|
import { getApiClient } from '../api-client.js';
|
|
19
19
|
const SPRINT_STATUSES = ['planning', 'active', 'in_review', 'retrospective', 'completed', 'cancelled'];
|
|
20
20
|
const TASK_PHASES = ['pre', 'core', 'post'];
|
|
21
21
|
const DEPLOY_ENVIRONMENTS = ['development', 'staging', 'production'];
|
|
22
22
|
const VERSION_BUMPS = ['patch', 'minor', 'major'];
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Argument Schemas
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const createSprintSchema = {
|
|
27
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
28
|
+
title: { type: 'string', required: true },
|
|
29
|
+
goal: { type: 'string' },
|
|
30
|
+
start_date: { type: 'string', required: true },
|
|
31
|
+
end_date: { type: 'string', required: true },
|
|
32
|
+
auto_deploy_on_completion: { type: 'boolean' },
|
|
33
|
+
deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
34
|
+
deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
|
|
35
|
+
};
|
|
36
|
+
const updateSprintSchema = {
|
|
37
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
38
|
+
title: { type: 'string' },
|
|
39
|
+
goal: { type: 'string' },
|
|
40
|
+
start_date: { type: 'string' },
|
|
41
|
+
end_date: { type: 'string' },
|
|
42
|
+
auto_deploy_on_completion: { type: 'boolean' },
|
|
43
|
+
deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
44
|
+
deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
|
|
45
|
+
};
|
|
46
|
+
const getSprintSchema = {
|
|
47
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
48
|
+
summary_only: { type: 'boolean', default: false },
|
|
49
|
+
};
|
|
50
|
+
const getSprintsSchema = {
|
|
51
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
52
|
+
status: { type: 'string', validate: createEnumValidator(SPRINT_STATUSES) },
|
|
53
|
+
limit: { type: 'number', default: 20 },
|
|
54
|
+
offset: { type: 'number', default: 0 },
|
|
55
|
+
};
|
|
56
|
+
const deleteSprintSchema = {
|
|
57
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
58
|
+
};
|
|
59
|
+
const startSprintSchema = {
|
|
60
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
61
|
+
};
|
|
62
|
+
const completeSprintSchema = {
|
|
63
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
64
|
+
retrospective_notes: { type: 'string' },
|
|
65
|
+
skip_retrospective: { type: 'boolean' },
|
|
66
|
+
};
|
|
67
|
+
const addTaskToSprintSchema = {
|
|
68
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
69
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
70
|
+
story_points: { type: 'number' },
|
|
71
|
+
phase: { type: 'string', validate: createEnumValidator(TASK_PHASES) },
|
|
72
|
+
};
|
|
73
|
+
const removeTaskFromSprintSchema = {
|
|
74
|
+
sprint_id: { type: 'string', required: true, validate: uuidValidator },
|
|
75
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
76
|
+
};
|
|
77
|
+
const getSprintBacklogSchema = {
|
|
78
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
79
|
+
sprint_id: { type: 'string', validate: uuidValidator },
|
|
80
|
+
};
|
|
81
|
+
const getSprintVelocitySchema = {
|
|
82
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
83
|
+
limit: { type: 'number', default: 10 },
|
|
84
|
+
};
|
|
23
85
|
export const createSprint = async (args, ctx) => {
|
|
24
|
-
const { project_id, title, goal, start_date, end_date, auto_deploy_on_completion, deploy_environment, deploy_version_bump, } = args;
|
|
25
|
-
validateRequired(project_id, 'project_id');
|
|
26
|
-
validateUUID(project_id, 'project_id');
|
|
27
|
-
validateRequired(title, 'title');
|
|
28
|
-
validateRequired(start_date, 'start_date');
|
|
29
|
-
validateRequired(end_date, 'end_date');
|
|
30
|
-
if (deploy_environment) {
|
|
31
|
-
validateEnum(deploy_environment, DEPLOY_ENVIRONMENTS, 'deploy_environment');
|
|
32
|
-
}
|
|
33
|
-
if (deploy_version_bump) {
|
|
34
|
-
validateEnum(deploy_version_bump, VERSION_BUMPS, 'deploy_version_bump');
|
|
35
|
-
}
|
|
86
|
+
const { project_id, title, goal, start_date, end_date, auto_deploy_on_completion, deploy_environment, deploy_version_bump, } = parseArgs(args, createSprintSchema);
|
|
36
87
|
// Validate date format and order
|
|
37
88
|
const startDateObj = new Date(start_date);
|
|
38
89
|
const endDateObj = new Date(end_date);
|
|
@@ -78,15 +129,7 @@ export const createSprint = async (args, ctx) => {
|
|
|
78
129
|
};
|
|
79
130
|
};
|
|
80
131
|
export const updateSprint = async (args, ctx) => {
|
|
81
|
-
const { sprint_id, title, goal, start_date, end_date, auto_deploy_on_completion, deploy_environment, deploy_version_bump, } = args;
|
|
82
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
83
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
84
|
-
if (deploy_environment) {
|
|
85
|
-
validateEnum(deploy_environment, DEPLOY_ENVIRONMENTS, 'deploy_environment');
|
|
86
|
-
}
|
|
87
|
-
if (deploy_version_bump) {
|
|
88
|
-
validateEnum(deploy_version_bump, VERSION_BUMPS, 'deploy_version_bump');
|
|
89
|
-
}
|
|
132
|
+
const { sprint_id, title, goal, start_date, end_date, auto_deploy_on_completion, deploy_environment, deploy_version_bump, } = parseArgs(args, updateSprintSchema);
|
|
90
133
|
// Validate dates if provided
|
|
91
134
|
if (start_date) {
|
|
92
135
|
const startDateObj = new Date(start_date);
|
|
@@ -117,28 +160,22 @@ export const updateSprint = async (args, ctx) => {
|
|
|
117
160
|
return { result: { success: true, sprint_id } };
|
|
118
161
|
};
|
|
119
162
|
export const getSprint = async (args, ctx) => {
|
|
120
|
-
const { sprint_id } = args;
|
|
121
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
122
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
163
|
+
const { sprint_id, summary_only } = parseArgs(args, getSprintSchema);
|
|
123
164
|
const apiClient = getApiClient();
|
|
124
|
-
|
|
165
|
+
// Response type varies based on summary_only
|
|
166
|
+
const response = await apiClient.proxy('get_sprint', { sprint_id, summary_only });
|
|
125
167
|
if (!response.ok) {
|
|
126
168
|
throw new Error(`Failed to get sprint: ${response.error}`);
|
|
127
169
|
}
|
|
128
170
|
return { result: response.data };
|
|
129
171
|
};
|
|
130
172
|
export const getSprints = async (args, ctx) => {
|
|
131
|
-
const { project_id, status, limit
|
|
132
|
-
validateRequired(project_id, 'project_id');
|
|
133
|
-
validateUUID(project_id, 'project_id');
|
|
134
|
-
if (status) {
|
|
135
|
-
validateEnum(status, SPRINT_STATUSES, 'status');
|
|
136
|
-
}
|
|
173
|
+
const { project_id, status, limit, offset } = parseArgs(args, getSprintsSchema);
|
|
137
174
|
const apiClient = getApiClient();
|
|
138
175
|
const response = await apiClient.proxy('get_sprints', {
|
|
139
176
|
project_id,
|
|
140
177
|
status,
|
|
141
|
-
limit: Math.min(limit, 100),
|
|
178
|
+
limit: Math.min(limit ?? 20, 100),
|
|
142
179
|
offset,
|
|
143
180
|
});
|
|
144
181
|
if (!response.ok) {
|
|
@@ -147,9 +184,7 @@ export const getSprints = async (args, ctx) => {
|
|
|
147
184
|
return { result: response.data };
|
|
148
185
|
};
|
|
149
186
|
export const deleteSprint = async (args, ctx) => {
|
|
150
|
-
const { sprint_id } = args;
|
|
151
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
152
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
187
|
+
const { sprint_id } = parseArgs(args, deleteSprintSchema);
|
|
153
188
|
const apiClient = getApiClient();
|
|
154
189
|
const response = await apiClient.proxy('delete_sprint', {
|
|
155
190
|
sprint_id
|
|
@@ -160,9 +195,7 @@ export const deleteSprint = async (args, ctx) => {
|
|
|
160
195
|
return { result: { success: true, message: 'Sprint deleted. Tasks are preserved.' } };
|
|
161
196
|
};
|
|
162
197
|
export const startSprint = async (args, ctx) => {
|
|
163
|
-
const { sprint_id } = args;
|
|
164
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
165
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
198
|
+
const { sprint_id } = parseArgs(args, startSprintSchema);
|
|
166
199
|
const apiClient = getApiClient();
|
|
167
200
|
const response = await apiClient.proxy('start_sprint', { sprint_id });
|
|
168
201
|
if (!response.ok) {
|
|
@@ -171,9 +204,7 @@ export const startSprint = async (args, ctx) => {
|
|
|
171
204
|
return { result: response.data };
|
|
172
205
|
};
|
|
173
206
|
export const completeSprint = async (args, ctx) => {
|
|
174
|
-
const { sprint_id, retrospective_notes, skip_retrospective } = args;
|
|
175
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
176
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
207
|
+
const { sprint_id, retrospective_notes, skip_retrospective } = parseArgs(args, completeSprintSchema);
|
|
177
208
|
const apiClient = getApiClient();
|
|
178
209
|
const response = await apiClient.proxy('complete_sprint', {
|
|
179
210
|
sprint_id,
|
|
@@ -186,14 +217,7 @@ export const completeSprint = async (args, ctx) => {
|
|
|
186
217
|
return { result: response.data };
|
|
187
218
|
};
|
|
188
219
|
export const addTaskToSprint = async (args, ctx) => {
|
|
189
|
-
const { sprint_id, task_id, story_points, phase } = args;
|
|
190
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
191
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
192
|
-
validateRequired(task_id, 'task_id');
|
|
193
|
-
validateUUID(task_id, 'task_id');
|
|
194
|
-
if (phase) {
|
|
195
|
-
validateEnum(phase, TASK_PHASES, 'phase');
|
|
196
|
-
}
|
|
220
|
+
const { sprint_id, task_id, story_points, phase } = parseArgs(args, addTaskToSprintSchema);
|
|
197
221
|
if (story_points !== undefined && (story_points < 0 || !Number.isInteger(story_points))) {
|
|
198
222
|
throw new Error('story_points must be a non-negative integer');
|
|
199
223
|
}
|
|
@@ -210,11 +234,7 @@ export const addTaskToSprint = async (args, ctx) => {
|
|
|
210
234
|
return { result: response.data };
|
|
211
235
|
};
|
|
212
236
|
export const removeTaskFromSprint = async (args, ctx) => {
|
|
213
|
-
const { sprint_id, task_id } = args;
|
|
214
|
-
validateRequired(sprint_id, 'sprint_id');
|
|
215
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
216
|
-
validateRequired(task_id, 'task_id');
|
|
217
|
-
validateUUID(task_id, 'task_id');
|
|
237
|
+
const { sprint_id, task_id } = parseArgs(args, removeTaskFromSprintSchema);
|
|
218
238
|
const apiClient = getApiClient();
|
|
219
239
|
const response = await apiClient.proxy('remove_task_from_sprint', {
|
|
220
240
|
sprint_id,
|
|
@@ -226,12 +246,7 @@ export const removeTaskFromSprint = async (args, ctx) => {
|
|
|
226
246
|
return { result: response.data };
|
|
227
247
|
};
|
|
228
248
|
export const getSprintBacklog = async (args, ctx) => {
|
|
229
|
-
const { project_id, sprint_id } = args;
|
|
230
|
-
validateRequired(project_id, 'project_id');
|
|
231
|
-
validateUUID(project_id, 'project_id');
|
|
232
|
-
if (sprint_id) {
|
|
233
|
-
validateUUID(sprint_id, 'sprint_id');
|
|
234
|
-
}
|
|
249
|
+
const { project_id, sprint_id } = parseArgs(args, getSprintBacklogSchema);
|
|
235
250
|
const apiClient = getApiClient();
|
|
236
251
|
const response = await apiClient.proxy('get_sprint_backlog', {
|
|
237
252
|
project_id,
|
|
@@ -243,13 +258,11 @@ export const getSprintBacklog = async (args, ctx) => {
|
|
|
243
258
|
return { result: response.data };
|
|
244
259
|
};
|
|
245
260
|
export const getSprintVelocity = async (args, ctx) => {
|
|
246
|
-
const { project_id, limit
|
|
247
|
-
validateRequired(project_id, 'project_id');
|
|
248
|
-
validateUUID(project_id, 'project_id');
|
|
261
|
+
const { project_id, limit } = parseArgs(args, getSprintVelocitySchema);
|
|
249
262
|
const apiClient = getApiClient();
|
|
250
263
|
const response = await apiClient.proxy('get_sprint_velocity', {
|
|
251
264
|
project_id,
|
|
252
|
-
limit: Math.min(limit, 50),
|
|
265
|
+
limit: Math.min(limit ?? 10, 50),
|
|
253
266
|
});
|
|
254
267
|
if (!response.ok) {
|
|
255
268
|
throw new Error(`Failed to get sprint velocity: ${response.error}`);
|