@vibescope/mcp-server 0.2.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/dist/api-client.d.ts +64 -1
- package/dist/api-client.js +34 -3
- package/dist/handlers/bodies-of-work.js +82 -49
- package/dist/handlers/cost.js +62 -54
- package/dist/handlers/decisions.js +29 -16
- package/dist/handlers/deployment.js +112 -106
- package/dist/handlers/discovery.js +35 -5
- package/dist/handlers/fallback.js +24 -19
- package/dist/handlers/file-checkouts.d.ts +18 -0
- package/dist/handlers/file-checkouts.js +101 -0
- package/dist/handlers/findings.d.ts +6 -0
- package/dist/handlers/findings.js +85 -30
- 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 +30 -8
- package/dist/handlers/sprints.js +76 -64
- package/dist/handlers/tasks.js +113 -73
- package/dist/handlers/validation.js +18 -14
- package/dist/tools.js +387 -0
- package/package.json +1 -1
- package/src/api-client.ts +89 -6
- package/src/handlers/__test-setup__.ts +7 -0
- package/src/handlers/bodies-of-work.ts +101 -101
- 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 +142 -190
- package/src/handlers/discovery.test.ts +4 -5
- package/src/handlers/discovery.ts +37 -6
- package/src/handlers/fallback.ts +31 -29
- package/src/handlers/file-checkouts.test.ts +477 -0
- package/src/handlers/file-checkouts.ts +127 -0
- package/src/handlers/findings.test.ts +145 -0
- package/src/handlers/findings.ts +101 -64
- 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.ts +39 -17
- package/src/handlers/sprints.ts +96 -129
- package/src/handlers/tasks.ts +144 -138
- package/src/handlers/validation.test.ts +1 -1
- package/src/handlers/validation.ts +20 -22
- package/src/tools.ts +387 -0
- 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
|
@@ -198,7 +198,7 @@ describe('getDecisions', () => {
|
|
|
198
198
|
});
|
|
199
199
|
});
|
|
200
200
|
|
|
201
|
-
it('should call API client getDecisions', async () => {
|
|
201
|
+
it('should call API client getDecisions with options', async () => {
|
|
202
202
|
mockApiClient.getDecisions.mockResolvedValue({
|
|
203
203
|
ok: true,
|
|
204
204
|
data: { decisions: [] },
|
|
@@ -211,7 +211,8 @@ describe('getDecisions', () => {
|
|
|
211
211
|
);
|
|
212
212
|
|
|
213
213
|
expect(mockApiClient.getDecisions).toHaveBeenCalledWith(
|
|
214
|
-
'123e4567-e89b-12d3-a456-426614174000'
|
|
214
|
+
'123e4567-e89b-12d3-a456-426614174000',
|
|
215
|
+
{ limit: 50, offset: 0, search_query: undefined }
|
|
215
216
|
);
|
|
216
217
|
});
|
|
217
218
|
|
|
@@ -10,22 +10,31 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { Handler, HandlerRegistry } from './types.js';
|
|
13
|
-
import {
|
|
13
|
+
import { parseArgs, uuidValidator } from '../validators.js';
|
|
14
14
|
import { getApiClient } from '../api-client.js';
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
// Argument schemas for type-safe parsing
|
|
17
|
+
const logDecisionSchema = {
|
|
18
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
19
|
+
title: { type: 'string' as const, required: true as const },
|
|
20
|
+
description: { type: 'string' as const, required: true as const },
|
|
21
|
+
rationale: { type: 'string' as const },
|
|
22
|
+
alternatives_considered: { type: 'array' as const },
|
|
23
|
+
};
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const getDecisionsSchema = {
|
|
26
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
27
|
+
limit: { type: 'number' as const, default: 50 },
|
|
28
|
+
offset: { type: 'number' as const, default: 0 },
|
|
29
|
+
search_query: { type: 'string' as const },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const deleteDecisionSchema = {
|
|
33
|
+
decision_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const logDecision: Handler = async (args, ctx) => {
|
|
37
|
+
const { project_id, title, description, rationale, alternatives_considered } = parseArgs(args, logDecisionSchema);
|
|
29
38
|
|
|
30
39
|
const { session } = ctx;
|
|
31
40
|
const apiClient = getApiClient();
|
|
@@ -34,7 +43,7 @@ export const logDecision: Handler = async (args, ctx) => {
|
|
|
34
43
|
title,
|
|
35
44
|
description,
|
|
36
45
|
rationale,
|
|
37
|
-
alternatives_considered
|
|
46
|
+
alternatives_considered: alternatives_considered as string[] | undefined
|
|
38
47
|
}, session.currentSessionId || undefined);
|
|
39
48
|
|
|
40
49
|
if (!response.ok) {
|
|
@@ -44,17 +53,16 @@ export const logDecision: Handler = async (args, ctx) => {
|
|
|
44
53
|
return { result: { success: true, title, decision_id: response.data?.decision_id } };
|
|
45
54
|
};
|
|
46
55
|
|
|
47
|
-
export const getDecisions: Handler = async (args,
|
|
48
|
-
const { project_id } = args
|
|
49
|
-
project_id: string;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
validateRequired(project_id, 'project_id');
|
|
53
|
-
validateUUID(project_id, 'project_id');
|
|
56
|
+
export const getDecisions: Handler = async (args, _ctx) => {
|
|
57
|
+
const { project_id, limit, offset, search_query } = parseArgs(args, getDecisionsSchema);
|
|
54
58
|
|
|
55
59
|
const apiClient = getApiClient();
|
|
56
60
|
|
|
57
|
-
const response = await apiClient.getDecisions(project_id
|
|
61
|
+
const response = await apiClient.getDecisions(project_id, {
|
|
62
|
+
limit,
|
|
63
|
+
offset,
|
|
64
|
+
search_query
|
|
65
|
+
});
|
|
58
66
|
|
|
59
67
|
if (!response.ok) {
|
|
60
68
|
throw new Error(`Failed to fetch decisions: ${response.error}`);
|
|
@@ -67,11 +75,8 @@ export const getDecisions: Handler = async (args, ctx) => {
|
|
|
67
75
|
};
|
|
68
76
|
};
|
|
69
77
|
|
|
70
|
-
export const deleteDecision: Handler = async (args,
|
|
71
|
-
const { decision_id } = args
|
|
72
|
-
|
|
73
|
-
validateRequired(decision_id, 'decision_id');
|
|
74
|
-
validateUUID(decision_id, 'decision_id');
|
|
78
|
+
export const deleteDecision: Handler = async (args, _ctx) => {
|
|
79
|
+
const { decision_id } = parseArgs(args, deleteDecisionSchema);
|
|
75
80
|
|
|
76
81
|
const apiClient = getApiClient();
|
|
77
82
|
|
|
@@ -17,34 +17,132 @@
|
|
|
17
17
|
import type { Handler, HandlerRegistry } from './types.js';
|
|
18
18
|
import {
|
|
19
19
|
ValidationError,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
parseArgs,
|
|
21
|
+
uuidValidator,
|
|
22
|
+
createEnumValidator,
|
|
23
23
|
} from '../validators.js';
|
|
24
24
|
import { getApiClient } from '../api-client.js';
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
git_ref?: string;
|
|
33
|
-
};
|
|
26
|
+
const ENVIRONMENTS = ['development', 'staging', 'production'] as const;
|
|
27
|
+
const VERSION_BUMPS = ['patch', 'minor', 'major'] as const;
|
|
28
|
+
const REQUIREMENT_TYPES = ['migration', 'env_var', 'config', 'manual', 'breaking_change', 'agent_task'] as const;
|
|
29
|
+
const REQUIREMENT_STAGES = ['preparation', 'deployment', 'verification'] as const;
|
|
30
|
+
const REQUIREMENT_STATUSES = ['pending', 'completed', 'converted_to_task', 'all'] as const;
|
|
31
|
+
const SCHEDULE_TYPES = ['once', 'daily', 'weekly', 'monthly'] as const;
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
type Environment = typeof ENVIRONMENTS[number];
|
|
34
|
+
type VersionBump = typeof VERSION_BUMPS[number];
|
|
35
|
+
type RequirementType = typeof REQUIREMENT_TYPES[number];
|
|
36
|
+
type RequirementStage = typeof REQUIREMENT_STAGES[number];
|
|
37
|
+
type RequirementStatus = typeof REQUIREMENT_STATUSES[number];
|
|
38
|
+
type ScheduleType = typeof SCHEDULE_TYPES[number];
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Argument Schemas
|
|
42
|
+
// ============================================================================
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const requestDeploymentSchema = {
|
|
45
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
46
|
+
environment: { type: 'string' as const, default: 'production', validate: createEnumValidator(ENVIRONMENTS) },
|
|
47
|
+
version_bump: { type: 'string' as const, default: 'patch', validate: createEnumValidator(VERSION_BUMPS) },
|
|
48
|
+
notes: { type: 'string' as const },
|
|
49
|
+
git_ref: { type: 'string' as const },
|
|
50
|
+
};
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
52
|
+
const claimDeploymentValidationSchema = {
|
|
53
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const reportValidationSchema = {
|
|
57
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
58
|
+
build_passed: { type: 'boolean' as const, required: true as const },
|
|
59
|
+
tests_passed: { type: 'boolean' as const },
|
|
60
|
+
error_message: { type: 'string' as const },
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const checkDeploymentStatusSchema = {
|
|
64
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const startDeploymentSchema = {
|
|
68
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const completeDeploymentSchema = {
|
|
72
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
73
|
+
success: { type: 'boolean' as const, required: true as const },
|
|
74
|
+
summary: { type: 'string' as const },
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const cancelDeploymentSchema = {
|
|
78
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
79
|
+
reason: { type: 'string' as const },
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const addDeploymentRequirementSchema = {
|
|
83
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
84
|
+
type: { type: 'string' as const, required: true as const, validate: createEnumValidator(REQUIREMENT_TYPES) },
|
|
85
|
+
title: { type: 'string' as const, required: true as const },
|
|
86
|
+
description: { type: 'string' as const },
|
|
87
|
+
file_path: { type: 'string' as const },
|
|
88
|
+
stage: { type: 'string' as const, default: 'preparation', validate: createEnumValidator(REQUIREMENT_STAGES) },
|
|
89
|
+
blocking: { type: 'boolean' as const, default: false },
|
|
90
|
+
recurring: { type: 'boolean' as const, default: false },
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const completeDeploymentRequirementSchema = {
|
|
94
|
+
requirement_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const getDeploymentRequirementsSchema = {
|
|
98
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
99
|
+
status: { type: 'string' as const, default: 'pending', validate: createEnumValidator(REQUIREMENT_STATUSES) },
|
|
100
|
+
stage: { type: 'string' as const, validate: createEnumValidator([...REQUIREMENT_STAGES, 'all'] as const) },
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const scheduleDeploymentSchema = {
|
|
104
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
105
|
+
environment: { type: 'string' as const, default: 'production', validate: createEnumValidator(ENVIRONMENTS) },
|
|
106
|
+
version_bump: { type: 'string' as const, default: 'patch', validate: createEnumValidator(VERSION_BUMPS) },
|
|
107
|
+
schedule_type: { type: 'string' as const, default: 'once', validate: createEnumValidator(SCHEDULE_TYPES) },
|
|
108
|
+
scheduled_at: { type: 'string' as const, required: true as const },
|
|
109
|
+
auto_trigger: { type: 'boolean' as const, default: true },
|
|
110
|
+
notes: { type: 'string' as const },
|
|
111
|
+
git_ref: { type: 'string' as const },
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getScheduledDeploymentsSchema = {
|
|
115
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
116
|
+
include_disabled: { type: 'boolean' as const, default: false },
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const updateScheduledDeploymentSchema = {
|
|
120
|
+
schedule_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
121
|
+
environment: { type: 'string' as const, validate: createEnumValidator(ENVIRONMENTS) },
|
|
122
|
+
version_bump: { type: 'string' as const, validate: createEnumValidator(VERSION_BUMPS) },
|
|
123
|
+
schedule_type: { type: 'string' as const, validate: createEnumValidator(SCHEDULE_TYPES) },
|
|
124
|
+
scheduled_at: { type: 'string' as const },
|
|
125
|
+
auto_trigger: { type: 'boolean' as const },
|
|
126
|
+
enabled: { type: 'boolean' as const },
|
|
127
|
+
notes: { type: 'string' as const },
|
|
128
|
+
git_ref: { type: 'string' as const },
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const deleteScheduledDeploymentSchema = {
|
|
132
|
+
schedule_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const triggerScheduledDeploymentSchema = {
|
|
136
|
+
schedule_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const checkDueDeploymentsSchema = {
|
|
140
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const requestDeployment: Handler = async (args, ctx) => {
|
|
144
|
+
const { project_id, environment, version_bump, notes, git_ref } = parseArgs(args, requestDeploymentSchema);
|
|
145
|
+
const { session } = ctx;
|
|
48
146
|
|
|
49
147
|
const apiClient = getApiClient();
|
|
50
148
|
const response = await apiClient.requestDeployment(project_id, {
|
|
@@ -62,12 +160,9 @@ export const requestDeployment: Handler = async (args, ctx) => {
|
|
|
62
160
|
};
|
|
63
161
|
|
|
64
162
|
export const claimDeploymentValidation: Handler = async (args, ctx) => {
|
|
65
|
-
const { project_id } = args
|
|
163
|
+
const { project_id } = parseArgs(args, claimDeploymentValidationSchema);
|
|
66
164
|
const { session } = ctx;
|
|
67
165
|
|
|
68
|
-
validateRequired(project_id, 'project_id');
|
|
69
|
-
validateUUID(project_id, 'project_id');
|
|
70
|
-
|
|
71
166
|
const apiClient = getApiClient();
|
|
72
167
|
const response = await apiClient.claimDeploymentValidation(
|
|
73
168
|
project_id,
|
|
@@ -82,24 +177,9 @@ export const claimDeploymentValidation: Handler = async (args, ctx) => {
|
|
|
82
177
|
};
|
|
83
178
|
|
|
84
179
|
export const reportValidation: Handler = async (args, ctx) => {
|
|
85
|
-
const { project_id, build_passed, tests_passed, error_message } = args
|
|
86
|
-
project_id: string;
|
|
87
|
-
build_passed: boolean;
|
|
88
|
-
tests_passed?: boolean;
|
|
89
|
-
error_message?: string;
|
|
90
|
-
};
|
|
91
|
-
|
|
180
|
+
const { project_id, build_passed, tests_passed, error_message } = parseArgs(args, reportValidationSchema);
|
|
92
181
|
const { session } = ctx;
|
|
93
182
|
|
|
94
|
-
validateRequired(project_id, 'project_id');
|
|
95
|
-
validateUUID(project_id, 'project_id');
|
|
96
|
-
if (build_passed === undefined) {
|
|
97
|
-
throw new ValidationError('build_passed is required', {
|
|
98
|
-
field: 'build_passed',
|
|
99
|
-
hint: 'Set to true if the build succeeded, false otherwise',
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
183
|
const apiClient = getApiClient();
|
|
104
184
|
const response = await apiClient.reportValidation(project_id, {
|
|
105
185
|
build_passed,
|
|
@@ -115,10 +195,7 @@ export const reportValidation: Handler = async (args, ctx) => {
|
|
|
115
195
|
};
|
|
116
196
|
|
|
117
197
|
export const checkDeploymentStatus: Handler = async (args, ctx) => {
|
|
118
|
-
const { project_id } = args
|
|
119
|
-
|
|
120
|
-
validateRequired(project_id, 'project_id');
|
|
121
|
-
validateUUID(project_id, 'project_id');
|
|
198
|
+
const { project_id } = parseArgs(args, checkDeploymentStatusSchema);
|
|
122
199
|
|
|
123
200
|
const apiClient = getApiClient();
|
|
124
201
|
const response = await apiClient.checkDeploymentStatus(project_id);
|
|
@@ -131,12 +208,9 @@ export const checkDeploymentStatus: Handler = async (args, ctx) => {
|
|
|
131
208
|
};
|
|
132
209
|
|
|
133
210
|
export const startDeployment: Handler = async (args, ctx) => {
|
|
134
|
-
const { project_id } = args
|
|
211
|
+
const { project_id } = parseArgs(args, startDeploymentSchema);
|
|
135
212
|
const { session } = ctx;
|
|
136
213
|
|
|
137
|
-
validateRequired(project_id, 'project_id');
|
|
138
|
-
validateUUID(project_id, 'project_id');
|
|
139
|
-
|
|
140
214
|
const apiClient = getApiClient();
|
|
141
215
|
const response = await apiClient.startDeployment(
|
|
142
216
|
project_id,
|
|
@@ -151,23 +225,9 @@ export const startDeployment: Handler = async (args, ctx) => {
|
|
|
151
225
|
};
|
|
152
226
|
|
|
153
227
|
export const completeDeployment: Handler = async (args, ctx) => {
|
|
154
|
-
const { project_id, success, summary } = args
|
|
155
|
-
project_id: string;
|
|
156
|
-
success: boolean;
|
|
157
|
-
summary?: string;
|
|
158
|
-
};
|
|
159
|
-
|
|
228
|
+
const { project_id, success, summary } = parseArgs(args, completeDeploymentSchema);
|
|
160
229
|
const { session } = ctx;
|
|
161
230
|
|
|
162
|
-
validateRequired(project_id, 'project_id');
|
|
163
|
-
validateUUID(project_id, 'project_id');
|
|
164
|
-
if (success === undefined) {
|
|
165
|
-
throw new ValidationError('success is required', {
|
|
166
|
-
field: 'success',
|
|
167
|
-
hint: 'Set to true if deployment succeeded, false otherwise',
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
231
|
const apiClient = getApiClient();
|
|
172
232
|
const response = await apiClient.completeDeployment(project_id, {
|
|
173
233
|
success,
|
|
@@ -182,10 +242,7 @@ export const completeDeployment: Handler = async (args, ctx) => {
|
|
|
182
242
|
};
|
|
183
243
|
|
|
184
244
|
export const cancelDeployment: Handler = async (args, ctx) => {
|
|
185
|
-
const { project_id, reason } = args
|
|
186
|
-
|
|
187
|
-
validateRequired(project_id, 'project_id');
|
|
188
|
-
validateUUID(project_id, 'project_id');
|
|
245
|
+
const { project_id, reason } = parseArgs(args, cancelDeploymentSchema);
|
|
189
246
|
|
|
190
247
|
const apiClient = getApiClient();
|
|
191
248
|
const response = await apiClient.cancelDeployment(project_id, reason);
|
|
@@ -198,31 +255,7 @@ export const cancelDeployment: Handler = async (args, ctx) => {
|
|
|
198
255
|
};
|
|
199
256
|
|
|
200
257
|
export const addDeploymentRequirement: Handler = async (args, ctx) => {
|
|
201
|
-
const { project_id, type, title, description, file_path, stage
|
|
202
|
-
project_id: string;
|
|
203
|
-
type: string;
|
|
204
|
-
title: string;
|
|
205
|
-
description?: string;
|
|
206
|
-
file_path?: string;
|
|
207
|
-
stage?: string;
|
|
208
|
-
blocking?: boolean;
|
|
209
|
-
recurring?: boolean;
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
validateRequired(project_id, 'project_id');
|
|
213
|
-
validateUUID(project_id, 'project_id');
|
|
214
|
-
validateRequired(type, 'type');
|
|
215
|
-
validateRequired(title, 'title');
|
|
216
|
-
|
|
217
|
-
const validTypes = ['migration', 'env_var', 'config', 'manual', 'breaking_change', 'agent_task'];
|
|
218
|
-
if (!validTypes.includes(type)) {
|
|
219
|
-
throw new ValidationError(`type must be one of: ${validTypes.join(', ')}`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const validStages = ['preparation', 'deployment', 'verification'];
|
|
223
|
-
if (!validStages.includes(stage)) {
|
|
224
|
-
throw new ValidationError(`stage must be one of: ${validStages.join(', ')}`);
|
|
225
|
-
}
|
|
258
|
+
const { project_id, type, title, description, file_path, stage, blocking, recurring } = parseArgs(args, addDeploymentRequirementSchema);
|
|
226
259
|
|
|
227
260
|
const apiClient = getApiClient();
|
|
228
261
|
const response = await apiClient.addDeploymentRequirement(project_id, {
|
|
@@ -243,10 +276,7 @@ export const addDeploymentRequirement: Handler = async (args, ctx) => {
|
|
|
243
276
|
};
|
|
244
277
|
|
|
245
278
|
export const completeDeploymentRequirement: Handler = async (args, ctx) => {
|
|
246
|
-
const { requirement_id } = args
|
|
247
|
-
|
|
248
|
-
validateRequired(requirement_id, 'requirement_id');
|
|
249
|
-
validateUUID(requirement_id, 'requirement_id');
|
|
279
|
+
const { requirement_id } = parseArgs(args, completeDeploymentRequirementSchema);
|
|
250
280
|
|
|
251
281
|
const apiClient = getApiClient();
|
|
252
282
|
const response = await apiClient.completeDeploymentRequirement(requirement_id);
|
|
@@ -259,14 +289,7 @@ export const completeDeploymentRequirement: Handler = async (args, ctx) => {
|
|
|
259
289
|
};
|
|
260
290
|
|
|
261
291
|
export const getDeploymentRequirements: Handler = async (args, ctx) => {
|
|
262
|
-
const { project_id, status
|
|
263
|
-
project_id: string;
|
|
264
|
-
status?: string;
|
|
265
|
-
stage?: string;
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
validateRequired(project_id, 'project_id');
|
|
269
|
-
validateUUID(project_id, 'project_id');
|
|
292
|
+
const { project_id, status, stage } = parseArgs(args, getDeploymentRequirementsSchema);
|
|
270
293
|
|
|
271
294
|
const apiClient = getApiClient();
|
|
272
295
|
const response = await apiClient.getDeploymentRequirements(project_id, {
|
|
@@ -288,42 +311,14 @@ export const getDeploymentRequirements: Handler = async (args, ctx) => {
|
|
|
288
311
|
export const scheduleDeployment: Handler = async (args, ctx) => {
|
|
289
312
|
const {
|
|
290
313
|
project_id,
|
|
291
|
-
environment
|
|
292
|
-
version_bump
|
|
293
|
-
schedule_type
|
|
314
|
+
environment,
|
|
315
|
+
version_bump,
|
|
316
|
+
schedule_type,
|
|
294
317
|
scheduled_at,
|
|
295
|
-
auto_trigger
|
|
318
|
+
auto_trigger,
|
|
296
319
|
notes,
|
|
297
320
|
git_ref,
|
|
298
|
-
} = args
|
|
299
|
-
project_id: string;
|
|
300
|
-
environment?: string;
|
|
301
|
-
version_bump?: string;
|
|
302
|
-
schedule_type?: string;
|
|
303
|
-
scheduled_at: string;
|
|
304
|
-
auto_trigger?: boolean;
|
|
305
|
-
notes?: string;
|
|
306
|
-
git_ref?: string;
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
validateRequired(project_id, 'project_id');
|
|
310
|
-
validateUUID(project_id, 'project_id');
|
|
311
|
-
validateRequired(scheduled_at, 'scheduled_at');
|
|
312
|
-
validateEnvironment(environment);
|
|
313
|
-
|
|
314
|
-
if (!['patch', 'minor', 'major'].includes(version_bump)) {
|
|
315
|
-
throw new ValidationError('Invalid version_bump value', {
|
|
316
|
-
field: 'version_bump',
|
|
317
|
-
validValues: ['patch', 'minor', 'major'],
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (!['once', 'daily', 'weekly', 'monthly'].includes(schedule_type)) {
|
|
322
|
-
throw new ValidationError('Invalid schedule_type value', {
|
|
323
|
-
field: 'schedule_type',
|
|
324
|
-
validValues: ['once', 'daily', 'weekly', 'monthly'],
|
|
325
|
-
});
|
|
326
|
-
}
|
|
321
|
+
} = parseArgs(args, scheduleDeploymentSchema);
|
|
327
322
|
|
|
328
323
|
// Parse and validate scheduled_at
|
|
329
324
|
const scheduledDate = new Date(scheduled_at);
|
|
@@ -359,13 +354,7 @@ export const scheduleDeployment: Handler = async (args, ctx) => {
|
|
|
359
354
|
};
|
|
360
355
|
|
|
361
356
|
export const getScheduledDeployments: Handler = async (args, ctx) => {
|
|
362
|
-
const { project_id, include_disabled
|
|
363
|
-
project_id: string;
|
|
364
|
-
include_disabled?: boolean;
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
validateRequired(project_id, 'project_id');
|
|
368
|
-
validateUUID(project_id, 'project_id');
|
|
357
|
+
const { project_id, include_disabled } = parseArgs(args, getScheduledDeploymentsSchema);
|
|
369
358
|
|
|
370
359
|
const apiClient = getApiClient();
|
|
371
360
|
const response = await apiClient.getScheduledDeployments(project_id, include_disabled);
|
|
@@ -388,41 +377,13 @@ export const updateScheduledDeployment: Handler = async (args, ctx) => {
|
|
|
388
377
|
enabled,
|
|
389
378
|
notes,
|
|
390
379
|
git_ref,
|
|
391
|
-
} = args
|
|
392
|
-
schedule_id: string;
|
|
393
|
-
environment?: string;
|
|
394
|
-
version_bump?: string;
|
|
395
|
-
schedule_type?: string;
|
|
396
|
-
scheduled_at?: string;
|
|
397
|
-
auto_trigger?: boolean;
|
|
398
|
-
enabled?: boolean;
|
|
399
|
-
notes?: string;
|
|
400
|
-
git_ref?: string;
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
validateRequired(schedule_id, 'schedule_id');
|
|
404
|
-
validateUUID(schedule_id, 'schedule_id');
|
|
380
|
+
} = parseArgs(args, updateScheduledDeploymentSchema);
|
|
405
381
|
|
|
406
382
|
const updates: Record<string, unknown> = {};
|
|
407
383
|
|
|
408
|
-
if (environment !== undefined)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (version_bump !== undefined) {
|
|
414
|
-
if (!['patch', 'minor', 'major'].includes(version_bump)) {
|
|
415
|
-
throw new ValidationError('Invalid version_bump value');
|
|
416
|
-
}
|
|
417
|
-
updates.version_bump = version_bump;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (schedule_type !== undefined) {
|
|
421
|
-
if (!['once', 'daily', 'weekly', 'monthly'].includes(schedule_type)) {
|
|
422
|
-
throw new ValidationError('Invalid schedule_type value');
|
|
423
|
-
}
|
|
424
|
-
updates.schedule_type = schedule_type;
|
|
425
|
-
}
|
|
384
|
+
if (environment !== undefined) updates.environment = environment;
|
|
385
|
+
if (version_bump !== undefined) updates.version_bump = version_bump;
|
|
386
|
+
if (schedule_type !== undefined) updates.schedule_type = schedule_type;
|
|
426
387
|
|
|
427
388
|
if (scheduled_at !== undefined) {
|
|
428
389
|
const scheduledDate = new Date(scheduled_at);
|
|
@@ -461,10 +422,7 @@ export const updateScheduledDeployment: Handler = async (args, ctx) => {
|
|
|
461
422
|
};
|
|
462
423
|
|
|
463
424
|
export const deleteScheduledDeployment: Handler = async (args, ctx) => {
|
|
464
|
-
const { schedule_id } = args
|
|
465
|
-
|
|
466
|
-
validateRequired(schedule_id, 'schedule_id');
|
|
467
|
-
validateUUID(schedule_id, 'schedule_id');
|
|
425
|
+
const { schedule_id } = parseArgs(args, deleteScheduledDeploymentSchema);
|
|
468
426
|
|
|
469
427
|
const apiClient = getApiClient();
|
|
470
428
|
const response = await apiClient.deleteScheduledDeployment(schedule_id);
|
|
@@ -477,12 +435,9 @@ export const deleteScheduledDeployment: Handler = async (args, ctx) => {
|
|
|
477
435
|
};
|
|
478
436
|
|
|
479
437
|
export const triggerScheduledDeployment: Handler = async (args, ctx) => {
|
|
480
|
-
const { schedule_id } = args
|
|
438
|
+
const { schedule_id } = parseArgs(args, triggerScheduledDeploymentSchema);
|
|
481
439
|
const { session } = ctx;
|
|
482
440
|
|
|
483
|
-
validateRequired(schedule_id, 'schedule_id');
|
|
484
|
-
validateUUID(schedule_id, 'schedule_id');
|
|
485
|
-
|
|
486
441
|
const apiClient = getApiClient();
|
|
487
442
|
const response = await apiClient.triggerScheduledDeployment(
|
|
488
443
|
schedule_id,
|
|
@@ -497,10 +452,7 @@ export const triggerScheduledDeployment: Handler = async (args, ctx) => {
|
|
|
497
452
|
};
|
|
498
453
|
|
|
499
454
|
export const checkDueDeployments: Handler = async (args, ctx) => {
|
|
500
|
-
const { project_id } = args
|
|
501
|
-
|
|
502
|
-
validateRequired(project_id, 'project_id');
|
|
503
|
-
validateUUID(project_id, 'project_id');
|
|
455
|
+
const { project_id } = parseArgs(args, checkDueDeploymentsSchema);
|
|
504
456
|
|
|
505
457
|
const apiClient = getApiClient();
|
|
506
458
|
const response = await apiClient.checkDueDeployments(project_id);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { discoverTools, getToolInfo } from './discovery.js';
|
|
3
3
|
import { createMockContext } from './__test-utils__.js';
|
|
4
|
+
import { ValidationError } from '../validators.js';
|
|
4
5
|
|
|
5
6
|
// ============================================================================
|
|
6
7
|
// discoverTools Tests
|
|
@@ -113,13 +114,11 @@ describe('discoverTools', () => {
|
|
|
113
114
|
// ============================================================================
|
|
114
115
|
|
|
115
116
|
describe('getToolInfo', () => {
|
|
116
|
-
it('should
|
|
117
|
+
it('should throw ValidationError for missing tool_name', async () => {
|
|
117
118
|
const ctx = createMockContext();
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
expect(res.error).toBe('tool_name is required');
|
|
120
|
+
await expect(getToolInfo({}, ctx)).rejects.toThrow(ValidationError);
|
|
121
|
+
await expect(getToolInfo({}, ctx)).rejects.toThrow('Missing required field: tool_name');
|
|
123
122
|
});
|
|
124
123
|
|
|
125
124
|
it('should return error for unknown tool', async () => {
|
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import type { Handler, HandlerRegistry } from './types.js';
|
|
13
|
+
import { parseArgs } from '../validators.js';
|
|
14
|
+
|
|
15
|
+
// Argument schemas for type-safe parsing
|
|
16
|
+
const discoverToolsSchema = {
|
|
17
|
+
category: { type: 'string' as const },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getToolInfoSchema = {
|
|
21
|
+
tool_name: { type: 'string' as const, required: true as const },
|
|
22
|
+
};
|
|
13
23
|
|
|
14
24
|
// Lazy-loaded tool documentation cache
|
|
15
25
|
let toolInfoCache: Record<string, string> | null = null;
|
|
@@ -169,6 +179,22 @@ const TOOL_CATEGORIES: Record<string, { description: string; tools: Array<{ name
|
|
|
169
179
|
{ name: 'activate_body_of_work', brief: 'Activate for work' },
|
|
170
180
|
],
|
|
171
181
|
},
|
|
182
|
+
sprints: {
|
|
183
|
+
description: 'Time-bounded sprints with velocity tracking',
|
|
184
|
+
tools: [
|
|
185
|
+
{ name: 'create_sprint', brief: 'Create new sprint' },
|
|
186
|
+
{ name: 'update_sprint', brief: 'Update sprint details' },
|
|
187
|
+
{ name: 'get_sprint', brief: 'Get sprint with tasks' },
|
|
188
|
+
{ name: 'get_sprints', brief: 'List project sprints' },
|
|
189
|
+
{ name: 'delete_sprint', brief: 'Delete sprint' },
|
|
190
|
+
{ name: 'start_sprint', brief: 'Start sprint' },
|
|
191
|
+
{ name: 'complete_sprint', brief: 'Complete sprint' },
|
|
192
|
+
{ name: 'add_task_to_sprint', brief: 'Add task to sprint' },
|
|
193
|
+
{ name: 'remove_task_from_sprint', brief: 'Remove from sprint' },
|
|
194
|
+
{ name: 'get_sprint_backlog', brief: 'Get available tasks' },
|
|
195
|
+
{ name: 'get_sprint_velocity', brief: 'Velocity metrics' },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
172
198
|
requests: {
|
|
173
199
|
description: 'User request handling',
|
|
174
200
|
tools: [
|
|
@@ -206,6 +232,15 @@ const TOOL_CATEGORIES: Record<string, { description: string; tools: Array<{ name
|
|
|
206
232
|
{ name: 'get_task_costs', brief: 'Cost per task' },
|
|
207
233
|
],
|
|
208
234
|
},
|
|
235
|
+
git_issues: {
|
|
236
|
+
description: 'Git conflict and issue tracking',
|
|
237
|
+
tools: [
|
|
238
|
+
{ name: 'add_git_issue', brief: 'Record git issue' },
|
|
239
|
+
{ name: 'resolve_git_issue', brief: 'Mark resolved' },
|
|
240
|
+
{ name: 'get_git_issues', brief: 'List git issues' },
|
|
241
|
+
{ name: 'delete_git_issue', brief: 'Delete git issue' },
|
|
242
|
+
],
|
|
243
|
+
},
|
|
209
244
|
knowledge: {
|
|
210
245
|
description: 'Queryable knowledge base from project data',
|
|
211
246
|
tools: [
|
|
@@ -215,7 +250,7 @@ const TOOL_CATEGORIES: Record<string, { description: string; tools: Array<{ name
|
|
|
215
250
|
};
|
|
216
251
|
|
|
217
252
|
export const discoverTools: Handler = async (args) => {
|
|
218
|
-
const { category } = args
|
|
253
|
+
const { category } = parseArgs(args, discoverToolsSchema);
|
|
219
254
|
|
|
220
255
|
if (category) {
|
|
221
256
|
// Return tools in specific category
|
|
@@ -254,11 +289,7 @@ export const discoverTools: Handler = async (args) => {
|
|
|
254
289
|
};
|
|
255
290
|
|
|
256
291
|
export const getToolInfo: Handler = async (args) => {
|
|
257
|
-
const { tool_name } = args
|
|
258
|
-
|
|
259
|
-
if (!tool_name) {
|
|
260
|
-
return { result: { error: 'tool_name is required' } };
|
|
261
|
-
}
|
|
292
|
+
const { tool_name } = parseArgs(args, getToolInfoSchema);
|
|
262
293
|
|
|
263
294
|
// Lazy-load tool documentation
|
|
264
295
|
const toolDocs = await getToolDocs();
|