@specforge/mcp 1.5.3 → 2.0.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/dist/lib/format.d.ts +145 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +227 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/index.d.ts +7 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/response.d.ts +119 -0
- package/dist/lib/response.d.ts.map +1 -0
- package/dist/lib/response.js +123 -0
- package/dist/lib/response.js.map +1 -0
- package/dist/patterns/index.d.ts +9 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +15 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/inheritance.d.ts +193 -0
- package/dist/patterns/inheritance.d.ts.map +1 -0
- package/dist/patterns/inheritance.js +265 -0
- package/dist/patterns/inheritance.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +21 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1384 -695
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +567 -19
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +244 -1
- package/dist/types/index.js.map +1 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +163 -0
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/ticket-validation.d.ts +162 -0
- package/dist/validation/ticket-validation.d.ts.map +1 -0
- package/dist/validation/ticket-validation.js +311 -0
- package/dist/validation/ticket-validation.js.map +1 -0
- package/package.json +6 -5
package/dist/tools/index.js
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* - Search: Search, find by file/tag, find related
|
|
15
15
|
* - Git: Link commits and PRs, get linked items
|
|
16
16
|
*/
|
|
17
|
-
import { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, } from '../validation/index.js';
|
|
17
|
+
import { ValidationError, ApiError, validateToolArgs, formatMCPError, transformError, validateTicket, filterWarningsByStrictness, } from '../validation/index.js';
|
|
18
|
+
import { resolvePatternsWithCache, getPatternOverrides, flattenCodeStandards, } from '../patterns/index.js';
|
|
19
|
+
import { getResponseModeFromArgs, formatWriteResponse, } from '../lib/response.js';
|
|
18
20
|
/**
|
|
19
21
|
* Get list of all available tools
|
|
20
22
|
*
|
|
@@ -23,8 +25,72 @@ import { ValidationError, ApiError, validateToolArgs, formatMCPError, transformE
|
|
|
23
25
|
*
|
|
24
26
|
* @returns Array of tool definitions
|
|
25
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* Format parameter definition for read operations
|
|
30
|
+
* Allows AI agents to request TOON-formatted responses for token efficiency
|
|
31
|
+
*/
|
|
32
|
+
const FORMAT_PARAMETER = {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['json', 'toon'],
|
|
35
|
+
description: 'Output format. Use "toon" for ~44% token reduction. Default: "json"',
|
|
36
|
+
default: 'json',
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* List of read operation tool names that support the format parameter
|
|
40
|
+
* Write operations (create_*, update_*, report_*, etc.) are excluded
|
|
41
|
+
*/
|
|
42
|
+
const READ_TOOL_NAMES = new Set([
|
|
43
|
+
// Project operations
|
|
44
|
+
'list_projects',
|
|
45
|
+
'get_project',
|
|
46
|
+
'lookup_project',
|
|
47
|
+
// Specification operations
|
|
48
|
+
'list_specifications',
|
|
49
|
+
'get_specification',
|
|
50
|
+
'lookup_specification',
|
|
51
|
+
// Epic operations
|
|
52
|
+
'list_epics',
|
|
53
|
+
'get_epic',
|
|
54
|
+
'lookup_epic',
|
|
55
|
+
// Ticket operations
|
|
56
|
+
'list_tickets',
|
|
57
|
+
'get_ticket',
|
|
58
|
+
'lookup_ticket',
|
|
59
|
+
'lookup_tickets_by_status',
|
|
60
|
+
// Dependency operations
|
|
61
|
+
'get_dependency_tree',
|
|
62
|
+
// Context operations
|
|
63
|
+
'get_implementation_context',
|
|
64
|
+
'get_next_actionable_tickets',
|
|
65
|
+
'get_blocked_tickets',
|
|
66
|
+
'get_critical_path',
|
|
67
|
+
'get_patterns',
|
|
68
|
+
// Status & Analytics
|
|
69
|
+
'get_report',
|
|
70
|
+
// Search operations
|
|
71
|
+
'search_tickets',
|
|
72
|
+
// Working context
|
|
73
|
+
'get_working_context',
|
|
74
|
+
// Job status
|
|
75
|
+
'get_job_status',
|
|
76
|
+
]);
|
|
77
|
+
/**
|
|
78
|
+
* Add format parameter to a tool's input schema
|
|
79
|
+
*/
|
|
80
|
+
function addFormatParameter(tool) {
|
|
81
|
+
return {
|
|
82
|
+
...tool,
|
|
83
|
+
inputSchema: {
|
|
84
|
+
...tool.inputSchema,
|
|
85
|
+
properties: {
|
|
86
|
+
...tool.inputSchema.properties,
|
|
87
|
+
format: FORMAT_PARAMETER,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
26
92
|
export function getTools() {
|
|
27
|
-
|
|
93
|
+
const tools = [
|
|
28
94
|
// ========================================================================
|
|
29
95
|
// Core Operations - Projects (Epic 3)
|
|
30
96
|
// ========================================================================
|
|
@@ -51,12 +117,26 @@ export function getTools() {
|
|
|
51
117
|
required: ['projectId'],
|
|
52
118
|
},
|
|
53
119
|
},
|
|
120
|
+
{
|
|
121
|
+
name: 'lookup_project',
|
|
122
|
+
description: 'Fast project lookup by name. Returns minimal data (id, name, specCount) for token efficiency. Use this instead of list_projects when you just need to find a project ID.',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
name: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: 'Project name to search for (partial match, case-insensitive)',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
required: ['name'],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
54
134
|
// ========================================================================
|
|
55
135
|
// Core Operations - Specifications (Epic 3)
|
|
56
136
|
// ========================================================================
|
|
57
137
|
{
|
|
58
138
|
name: 'list_specifications',
|
|
59
|
-
description: 'List specifications for a project with optional status
|
|
139
|
+
description: 'List specifications for a project with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage.',
|
|
60
140
|
inputSchema: {
|
|
61
141
|
type: 'object',
|
|
62
142
|
properties: {
|
|
@@ -72,13 +152,60 @@ export function getTools() {
|
|
|
72
152
|
},
|
|
73
153
|
description: 'Filter by status (optional)',
|
|
74
154
|
},
|
|
155
|
+
limit: {
|
|
156
|
+
type: 'integer',
|
|
157
|
+
minimum: 1,
|
|
158
|
+
maximum: 100,
|
|
159
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
160
|
+
},
|
|
161
|
+
offset: {
|
|
162
|
+
type: 'integer',
|
|
163
|
+
minimum: 0,
|
|
164
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
165
|
+
},
|
|
166
|
+
fields: {
|
|
167
|
+
type: 'array',
|
|
168
|
+
items: {
|
|
169
|
+
type: 'string',
|
|
170
|
+
enum: [
|
|
171
|
+
'id',
|
|
172
|
+
'projectId',
|
|
173
|
+
'title',
|
|
174
|
+
'description',
|
|
175
|
+
'background',
|
|
176
|
+
'status',
|
|
177
|
+
'priority',
|
|
178
|
+
'estimatedHours',
|
|
179
|
+
'goals',
|
|
180
|
+
'requirements',
|
|
181
|
+
'constraints',
|
|
182
|
+
'guardrails',
|
|
183
|
+
'techStack',
|
|
184
|
+
'architecture',
|
|
185
|
+
'fileStructure',
|
|
186
|
+
'epicCount',
|
|
187
|
+
'ticketCount',
|
|
188
|
+
'completedTicketCount',
|
|
189
|
+
'createdAt',
|
|
190
|
+
'updatedAt',
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "title", "status"] for minimal response.',
|
|
194
|
+
},
|
|
75
195
|
},
|
|
76
196
|
required: ['projectId'],
|
|
77
197
|
},
|
|
78
198
|
},
|
|
79
199
|
{
|
|
80
200
|
name: 'get_specification',
|
|
81
|
-
description:
|
|
201
|
+
description: `Get specification with optional summary mode or full details.
|
|
202
|
+
|
|
203
|
+
Use summary: true for minimal response (~70 tokens) with key fields only (id, title, status, priority, epicCount, ticketCount, completedTicketCount).
|
|
204
|
+
|
|
205
|
+
Optional includes (ignored when summary=true):
|
|
206
|
+
- 'status': Progress, ticket counts, blockers (replaces get_specification_status)
|
|
207
|
+
- 'epics': List of epics with summary data
|
|
208
|
+
- 'patterns': Tech stack, code patterns, naming conventions`,
|
|
82
209
|
inputSchema: {
|
|
83
210
|
type: 'object',
|
|
84
211
|
properties: {
|
|
@@ -86,16 +213,47 @@ export function getTools() {
|
|
|
86
213
|
type: 'string',
|
|
87
214
|
description: 'The ID of the specification to retrieve',
|
|
88
215
|
},
|
|
216
|
+
summary: {
|
|
217
|
+
type: 'boolean',
|
|
218
|
+
description: 'Return minimal summary fields only (~70 tokens vs ~600 full). Ignores include parameter when true. Default: false',
|
|
219
|
+
default: false,
|
|
220
|
+
},
|
|
221
|
+
include: {
|
|
222
|
+
type: 'array',
|
|
223
|
+
items: {
|
|
224
|
+
type: 'string',
|
|
225
|
+
enum: ['status', 'epics', 'patterns'],
|
|
226
|
+
},
|
|
227
|
+
description: 'Optional data to include in response (ignored when summary=true)',
|
|
228
|
+
},
|
|
89
229
|
},
|
|
90
230
|
required: ['specificationId'],
|
|
91
231
|
},
|
|
92
232
|
},
|
|
233
|
+
{
|
|
234
|
+
name: 'lookup_specification',
|
|
235
|
+
description: 'Fast specification lookup by title. Returns minimal data (id, title, status, epicCount, ticketCount) for token efficiency.',
|
|
236
|
+
inputSchema: {
|
|
237
|
+
type: 'object',
|
|
238
|
+
properties: {
|
|
239
|
+
projectId: {
|
|
240
|
+
type: 'string',
|
|
241
|
+
description: 'Project ID to search within',
|
|
242
|
+
},
|
|
243
|
+
title: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'Specification title to search for (partial match, case-insensitive)',
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
required: ['projectId', 'title'],
|
|
249
|
+
},
|
|
250
|
+
},
|
|
93
251
|
// ========================================================================
|
|
94
252
|
// Core Operations - Epics (Epic 3)
|
|
95
253
|
// ========================================================================
|
|
96
254
|
{
|
|
97
255
|
name: 'list_epics',
|
|
98
|
-
description: 'List epics for a specification with optional status
|
|
256
|
+
description: 'List epics for a specification with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage.',
|
|
99
257
|
inputSchema: {
|
|
100
258
|
type: 'object',
|
|
101
259
|
properties: {
|
|
@@ -108,13 +266,56 @@ export function getTools() {
|
|
|
108
266
|
enum: ['todo', 'in_progress', 'completed'],
|
|
109
267
|
description: 'Filter by status (optional)',
|
|
110
268
|
},
|
|
269
|
+
limit: {
|
|
270
|
+
type: 'integer',
|
|
271
|
+
minimum: 1,
|
|
272
|
+
maximum: 100,
|
|
273
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
274
|
+
},
|
|
275
|
+
offset: {
|
|
276
|
+
type: 'integer',
|
|
277
|
+
minimum: 0,
|
|
278
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
279
|
+
},
|
|
280
|
+
fields: {
|
|
281
|
+
type: 'array',
|
|
282
|
+
items: {
|
|
283
|
+
type: 'string',
|
|
284
|
+
enum: [
|
|
285
|
+
'id',
|
|
286
|
+
'specificationId',
|
|
287
|
+
'epicNumber',
|
|
288
|
+
'title',
|
|
289
|
+
'description',
|
|
290
|
+
'objective',
|
|
291
|
+
'status',
|
|
292
|
+
'priority',
|
|
293
|
+
'estimatedHours',
|
|
294
|
+
'acceptanceCriteria',
|
|
295
|
+
'scope',
|
|
296
|
+
'constraints',
|
|
297
|
+
'assumptions',
|
|
298
|
+
'ticketCount',
|
|
299
|
+
'completedTicketCount',
|
|
300
|
+
'createdAt',
|
|
301
|
+
'updatedAt',
|
|
302
|
+
],
|
|
303
|
+
},
|
|
304
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "epicNumber", "title", "status"] for minimal response.',
|
|
305
|
+
},
|
|
111
306
|
},
|
|
112
307
|
required: ['specificationId'],
|
|
113
308
|
},
|
|
114
309
|
},
|
|
115
310
|
{
|
|
116
311
|
name: 'get_epic',
|
|
117
|
-
description:
|
|
312
|
+
description: `Get epic with optional summary mode or full details.
|
|
313
|
+
|
|
314
|
+
Use summary: true for minimal response (~80 tokens) with key fields only (id, epicNumber, title, status, objective, ticketCount, completedTicketCount).
|
|
315
|
+
|
|
316
|
+
Optional includes (ignored when summary=true):
|
|
317
|
+
- 'status': Progress percentage, ticket counts, active tickets (replaces get_epic_status)
|
|
318
|
+
- 'tickets': List of tickets with summary data`,
|
|
118
319
|
inputSchema: {
|
|
119
320
|
type: 'object',
|
|
120
321
|
properties: {
|
|
@@ -122,16 +323,51 @@ export function getTools() {
|
|
|
122
323
|
type: 'string',
|
|
123
324
|
description: 'The ID of the epic to retrieve',
|
|
124
325
|
},
|
|
326
|
+
summary: {
|
|
327
|
+
type: 'boolean',
|
|
328
|
+
description: 'Return minimal summary fields only (~80 tokens vs ~400 full). Ignores include parameter when true. Default: false',
|
|
329
|
+
default: false,
|
|
330
|
+
},
|
|
331
|
+
include: {
|
|
332
|
+
type: 'array',
|
|
333
|
+
items: {
|
|
334
|
+
type: 'string',
|
|
335
|
+
enum: ['status', 'tickets'],
|
|
336
|
+
},
|
|
337
|
+
description: 'Optional data to include in response (ignored when summary=true)',
|
|
338
|
+
},
|
|
125
339
|
},
|
|
126
340
|
required: ['epicId'],
|
|
127
341
|
},
|
|
128
342
|
},
|
|
343
|
+
{
|
|
344
|
+
name: 'lookup_epic',
|
|
345
|
+
description: "Fast epic lookup by number or title. Returns minimal data (id, number, title, status, ticketCount). Use 'number' for exact match, 'title' for partial match.",
|
|
346
|
+
inputSchema: {
|
|
347
|
+
type: 'object',
|
|
348
|
+
properties: {
|
|
349
|
+
specificationId: {
|
|
350
|
+
type: 'string',
|
|
351
|
+
description: 'Specification ID to search within',
|
|
352
|
+
},
|
|
353
|
+
number: {
|
|
354
|
+
type: 'integer',
|
|
355
|
+
description: 'Epic number for exact match lookup',
|
|
356
|
+
},
|
|
357
|
+
title: {
|
|
358
|
+
type: 'string',
|
|
359
|
+
description: 'Epic title for partial match lookup',
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
required: ['specificationId'],
|
|
363
|
+
},
|
|
364
|
+
},
|
|
129
365
|
// ========================================================================
|
|
130
366
|
// Core Operations - Tickets (Epic 3)
|
|
131
367
|
// ========================================================================
|
|
132
368
|
{
|
|
133
369
|
name: 'list_tickets',
|
|
134
|
-
description: 'List tickets for an epic with optional status
|
|
370
|
+
description: 'List tickets for an epic with optional status and field filters. Supports pagination with limit/offset. Use fields to select specific fields and reduce token usage. Use include: ["statusReason"] to get reasons why pending tickets are blocked.',
|
|
135
371
|
inputSchema: {
|
|
136
372
|
type: 'object',
|
|
137
373
|
properties: {
|
|
@@ -143,9 +379,60 @@ export function getTools() {
|
|
|
143
379
|
type: 'array',
|
|
144
380
|
items: {
|
|
145
381
|
type: 'string',
|
|
146
|
-
enum: ['
|
|
382
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
147
383
|
},
|
|
148
|
-
description: 'Filter by status (optional)',
|
|
384
|
+
description: 'Filter by status (optional). pending/ready are auto-calculated based on dependencies.',
|
|
385
|
+
},
|
|
386
|
+
limit: {
|
|
387
|
+
type: 'integer',
|
|
388
|
+
minimum: 1,
|
|
389
|
+
maximum: 100,
|
|
390
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
391
|
+
},
|
|
392
|
+
offset: {
|
|
393
|
+
type: 'integer',
|
|
394
|
+
minimum: 0,
|
|
395
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
396
|
+
},
|
|
397
|
+
include: {
|
|
398
|
+
type: 'array',
|
|
399
|
+
items: {
|
|
400
|
+
type: 'string',
|
|
401
|
+
enum: ['statusReason'],
|
|
402
|
+
},
|
|
403
|
+
description: 'Include statusReason for pending tickets (shows unsatisfied dependencies or block reasons)',
|
|
404
|
+
},
|
|
405
|
+
fields: {
|
|
406
|
+
type: 'array',
|
|
407
|
+
items: {
|
|
408
|
+
type: 'string',
|
|
409
|
+
enum: [
|
|
410
|
+
'id',
|
|
411
|
+
'epicId',
|
|
412
|
+
'ticketNumber',
|
|
413
|
+
'title',
|
|
414
|
+
'description',
|
|
415
|
+
'status',
|
|
416
|
+
'priority',
|
|
417
|
+
'complexity',
|
|
418
|
+
'estimatedHours',
|
|
419
|
+
'actualHours',
|
|
420
|
+
'acceptanceCriteria',
|
|
421
|
+
'implementation',
|
|
422
|
+
'technicalDetails',
|
|
423
|
+
'notes',
|
|
424
|
+
'tags',
|
|
425
|
+
'blockReason',
|
|
426
|
+
'progress',
|
|
427
|
+
'testsPassed',
|
|
428
|
+
'order',
|
|
429
|
+
'startedAt',
|
|
430
|
+
'completedAt',
|
|
431
|
+
'createdAt',
|
|
432
|
+
'updatedAt',
|
|
433
|
+
],
|
|
434
|
+
},
|
|
435
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "ticketNumber", "title", "status"] for minimal response (~60 tokens per ticket vs ~500 full).',
|
|
149
436
|
},
|
|
150
437
|
},
|
|
151
438
|
required: ['epicId'],
|
|
@@ -153,7 +440,18 @@ export function getTools() {
|
|
|
153
440
|
},
|
|
154
441
|
{
|
|
155
442
|
name: 'get_ticket',
|
|
156
|
-
description:
|
|
443
|
+
description: `Get ticket with optional summary mode or full details.
|
|
444
|
+
|
|
445
|
+
Use summary: true for minimal response (~100 tokens) with key fields only (id, ticketNumber, title, status, complexity, estimatedHours, priority).
|
|
446
|
+
|
|
447
|
+
For full details, statusReason is auto-included for pending tickets explaining why the ticket is blocked.
|
|
448
|
+
|
|
449
|
+
Optional includes (ignored when summary=true):
|
|
450
|
+
- 'dependencies': Tickets this blocks and is blocked by (replaces get_ticket_dependencies)
|
|
451
|
+
- 'testStatus': Test results and history (replaces get_ticket_test_status)
|
|
452
|
+
- 'commits': Linked git commits (replaces get_ticket_commits)
|
|
453
|
+
- 'prs': Linked pull requests (replaces get_ticket_prs)
|
|
454
|
+
- 'statusReason': Why ticket is pending (auto-included for pending tickets)`,
|
|
157
455
|
inputSchema: {
|
|
158
456
|
type: 'object',
|
|
159
457
|
properties: {
|
|
@@ -161,27 +459,64 @@ export function getTools() {
|
|
|
161
459
|
type: 'string',
|
|
162
460
|
description: 'The ID of the ticket to retrieve',
|
|
163
461
|
},
|
|
462
|
+
summary: {
|
|
463
|
+
type: 'boolean',
|
|
464
|
+
description: 'Return minimal summary fields only (~100 tokens vs ~500 full). Ignores include parameter when true. Default: false',
|
|
465
|
+
default: false,
|
|
466
|
+
},
|
|
467
|
+
include: {
|
|
468
|
+
type: 'array',
|
|
469
|
+
items: {
|
|
470
|
+
type: 'string',
|
|
471
|
+
enum: ['dependencies', 'testStatus', 'commits', 'prs', 'statusReason'],
|
|
472
|
+
},
|
|
473
|
+
description: 'Additional data to include (ignored when summary=true). statusReason is auto-included for pending tickets.',
|
|
474
|
+
},
|
|
164
475
|
},
|
|
165
476
|
required: ['ticketId'],
|
|
166
477
|
},
|
|
167
478
|
},
|
|
168
|
-
// ========================================================================
|
|
169
|
-
// Core Operations - Dependencies (Epic 3)
|
|
170
|
-
// ========================================================================
|
|
171
479
|
{
|
|
172
|
-
name: '
|
|
173
|
-
description:
|
|
480
|
+
name: 'lookup_ticket',
|
|
481
|
+
description: "Fast ticket lookup by number or title. Returns minimal data (id, number, title, status, complexity). Use 'number' for exact match, 'title' for partial match.",
|
|
174
482
|
inputSchema: {
|
|
175
483
|
type: 'object',
|
|
176
484
|
properties: {
|
|
177
|
-
|
|
485
|
+
epicId: {
|
|
178
486
|
type: 'string',
|
|
179
|
-
description: '
|
|
487
|
+
description: 'Epic ID to search within',
|
|
488
|
+
},
|
|
489
|
+
number: {
|
|
490
|
+
type: 'integer',
|
|
491
|
+
description: 'Ticket number for exact match lookup',
|
|
492
|
+
},
|
|
493
|
+
title: {
|
|
494
|
+
type: 'string',
|
|
495
|
+
description: 'Ticket title for partial match lookup',
|
|
180
496
|
},
|
|
181
497
|
},
|
|
182
|
-
required: ['
|
|
498
|
+
required: ['epicId'],
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: 'lookup_tickets_by_status',
|
|
503
|
+
description: 'Batch lookup of ticket statuses. Optimized for checking if dependencies are satisfied. Returns minimal data (id, status, title) for up to 50 tickets.',
|
|
504
|
+
inputSchema: {
|
|
505
|
+
type: 'object',
|
|
506
|
+
properties: {
|
|
507
|
+
ticketIds: {
|
|
508
|
+
type: 'array',
|
|
509
|
+
items: { type: 'string' },
|
|
510
|
+
maxItems: 50,
|
|
511
|
+
description: 'Array of ticket IDs to lookup (max 50)',
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
required: ['ticketIds'],
|
|
183
515
|
},
|
|
184
516
|
},
|
|
517
|
+
// ========================================================================
|
|
518
|
+
// Core Operations - Dependencies (Epic 3)
|
|
519
|
+
// ========================================================================
|
|
185
520
|
{
|
|
186
521
|
name: 'add_dependency',
|
|
187
522
|
description: 'Add a dependency between two tickets. The first ticket will depend on the second.',
|
|
@@ -245,7 +580,7 @@ export function getTools() {
|
|
|
245
580
|
// ========================================================================
|
|
246
581
|
{
|
|
247
582
|
name: 'get_implementation_context',
|
|
248
|
-
description: 'Get
|
|
583
|
+
description: 'Get implementation context for a ticket. Use depth parameter to control response size: minimal (~300 tokens) for quick status checks, standard (~800 tokens) for typical implementation, full (~2000 tokens) for complex debugging.',
|
|
249
584
|
inputSchema: {
|
|
250
585
|
type: 'object',
|
|
251
586
|
properties: {
|
|
@@ -253,13 +588,19 @@ export function getTools() {
|
|
|
253
588
|
type: 'string',
|
|
254
589
|
description: 'The ID of the ticket',
|
|
255
590
|
},
|
|
591
|
+
depth: {
|
|
592
|
+
type: 'string',
|
|
593
|
+
enum: ['minimal', 'standard', 'full'],
|
|
594
|
+
description: 'Context depth level. minimal: ticket essentials + dependency status (~300 tokens). standard: ticket + epic summary + blockers (~800 tokens). full: complete context with patterns and history (~2000 tokens). Default: standard',
|
|
595
|
+
default: 'standard',
|
|
596
|
+
},
|
|
256
597
|
},
|
|
257
598
|
required: ['ticketId'],
|
|
258
599
|
},
|
|
259
600
|
},
|
|
260
601
|
{
|
|
261
602
|
name: 'get_next_actionable_tickets',
|
|
262
|
-
description: 'Get tickets
|
|
603
|
+
description: 'Get tickets with status "ready" (all dependencies satisfied). Use start_work_session() to begin work on these tickets.',
|
|
263
604
|
inputSchema: {
|
|
264
605
|
type: 'object',
|
|
265
606
|
properties: {
|
|
@@ -280,7 +621,7 @@ export function getTools() {
|
|
|
280
621
|
},
|
|
281
622
|
{
|
|
282
623
|
name: 'get_blocked_tickets',
|
|
283
|
-
description: 'Get tickets
|
|
624
|
+
description: 'Get tickets with status "pending" and their statusReason explaining why they are blocked (unsatisfied dependencies or external block)',
|
|
284
625
|
inputSchema: {
|
|
285
626
|
type: 'object',
|
|
286
627
|
properties: {
|
|
@@ -308,16 +649,19 @@ export function getTools() {
|
|
|
308
649
|
},
|
|
309
650
|
{
|
|
310
651
|
name: 'get_patterns',
|
|
311
|
-
description: '
|
|
652
|
+
description: 'Get patterns for a specification or ticket with full inheritance chain. When ticketId is provided, returns resolved patterns with spec → epic → ticket inheritance.',
|
|
312
653
|
inputSchema: {
|
|
313
654
|
type: 'object',
|
|
314
655
|
properties: {
|
|
315
656
|
specificationId: {
|
|
316
657
|
type: 'string',
|
|
317
|
-
description: '
|
|
658
|
+
description: 'Get patterns for entire specification (raw spec patterns only)',
|
|
659
|
+
},
|
|
660
|
+
ticketId: {
|
|
661
|
+
type: 'string',
|
|
662
|
+
description: 'Get resolved patterns for a specific ticket with inheritance chain and override analysis',
|
|
318
663
|
},
|
|
319
664
|
},
|
|
320
|
-
required: ['specificationId'],
|
|
321
665
|
},
|
|
322
666
|
},
|
|
323
667
|
// ========================================================================
|
|
@@ -325,7 +669,7 @@ export function getTools() {
|
|
|
325
669
|
// ========================================================================
|
|
326
670
|
{
|
|
327
671
|
name: 'start_work_session',
|
|
328
|
-
description: 'Start working on a ticket
|
|
672
|
+
description: 'Start working on a ticket. Transitions ready -> active. Returns error with statusReason if ticket is pending (dependencies not met).',
|
|
329
673
|
inputSchema: {
|
|
330
674
|
type: 'object',
|
|
331
675
|
properties: {
|
|
@@ -339,7 +683,15 @@ export function getTools() {
|
|
|
339
683
|
},
|
|
340
684
|
{
|
|
341
685
|
name: 'complete_work_session',
|
|
342
|
-
description: 'Mark a ticket as complete
|
|
686
|
+
description: 'Mark a ticket as complete. Transitions active -> done.\n\n' +
|
|
687
|
+
'Automatically recalculates status for dependent tickets and returns cascade info.\n\n' +
|
|
688
|
+
'By default, checks if summary addresses acceptance criteria and returns warnings (not errors) for gaps.\n\n' +
|
|
689
|
+
'Use validated: true as a simple confirmation that the agent has verified all work meets criteria.\n\n' +
|
|
690
|
+
'Optional validation flags can be provided to report test results inline:\n' +
|
|
691
|
+
'- tests: Unit/integration test results\n' +
|
|
692
|
+
'- lint: Linting results\n' +
|
|
693
|
+
'- typeCheck: TypeScript type checking\n' +
|
|
694
|
+
'- build: Build/compilation results',
|
|
343
695
|
inputSchema: {
|
|
344
696
|
type: 'object',
|
|
345
697
|
properties: {
|
|
@@ -365,6 +717,48 @@ export function getTools() {
|
|
|
365
717
|
type: 'number',
|
|
366
718
|
description: 'Actual hours spent on the ticket',
|
|
367
719
|
},
|
|
720
|
+
validated: {
|
|
721
|
+
type: 'boolean',
|
|
722
|
+
description: 'Simple validation confirmation. When true, indicates:\n' +
|
|
723
|
+
'- Agent has verified work meets acceptance criteria\n' +
|
|
724
|
+
'- All necessary tests/validations were run and passed\n' +
|
|
725
|
+
'- No detailed breakdown needed\n' +
|
|
726
|
+
'Trust-based approach for streamlined completion.',
|
|
727
|
+
},
|
|
728
|
+
validation: {
|
|
729
|
+
type: 'object',
|
|
730
|
+
description: 'Detailed validation flags (optional with validated: true)',
|
|
731
|
+
properties: {
|
|
732
|
+
tests: {
|
|
733
|
+
type: 'string',
|
|
734
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
735
|
+
description: 'Unit/integration test results',
|
|
736
|
+
},
|
|
737
|
+
lint: {
|
|
738
|
+
type: 'string',
|
|
739
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
740
|
+
description: 'Linting results',
|
|
741
|
+
},
|
|
742
|
+
typeCheck: {
|
|
743
|
+
type: 'string',
|
|
744
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
745
|
+
description: 'TypeScript type checking results',
|
|
746
|
+
},
|
|
747
|
+
build: {
|
|
748
|
+
type: 'string',
|
|
749
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
750
|
+
description: 'Build/compilation results',
|
|
751
|
+
},
|
|
752
|
+
notes: {
|
|
753
|
+
type: 'string',
|
|
754
|
+
description: 'Additional validation notes',
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
skipCriteriaCheck: {
|
|
759
|
+
type: 'boolean',
|
|
760
|
+
description: 'Skip acceptance criteria validation. Use for trivial changes or when criteria check is not needed. Default: false',
|
|
761
|
+
},
|
|
368
762
|
},
|
|
369
763
|
required: ['ticketId', 'summary'],
|
|
370
764
|
},
|
|
@@ -393,379 +787,174 @@ export function getTools() {
|
|
|
393
787
|
required: ['ticketId', 'progress'],
|
|
394
788
|
},
|
|
395
789
|
},
|
|
396
|
-
{
|
|
397
|
-
name: 'get_work_summary',
|
|
398
|
-
description: 'Get summary of completed work with optional scope filtering',
|
|
399
|
-
inputSchema: {
|
|
400
|
-
type: 'object',
|
|
401
|
-
properties: {
|
|
402
|
-
scope: {
|
|
403
|
-
type: 'string',
|
|
404
|
-
enum: ['epic', 'specification', 'project', 'user'],
|
|
405
|
-
description: 'Scope of the summary',
|
|
406
|
-
},
|
|
407
|
-
scopeId: {
|
|
408
|
-
type: 'string',
|
|
409
|
-
description: 'ID of the scoped entity (epicId, specificationId, or projectId)',
|
|
410
|
-
},
|
|
411
|
-
startDate: {
|
|
412
|
-
type: 'string',
|
|
413
|
-
description: 'Start date filter (ISO 8601)',
|
|
414
|
-
},
|
|
415
|
-
endDate: {
|
|
416
|
-
type: 'string',
|
|
417
|
-
description: 'End date filter (ISO 8601)',
|
|
418
|
-
},
|
|
419
|
-
},
|
|
420
|
-
required: ['scope'],
|
|
421
|
-
},
|
|
422
|
-
},
|
|
423
|
-
// ========================================================================
|
|
424
|
-
// Testing Tools (Epic 6)
|
|
425
|
-
// ========================================================================
|
|
426
|
-
{
|
|
427
|
-
name: 'report_test_results',
|
|
428
|
-
description: 'Report test results for a ticket',
|
|
429
|
-
inputSchema: {
|
|
430
|
-
type: 'object',
|
|
431
|
-
properties: {
|
|
432
|
-
ticketId: {
|
|
433
|
-
type: 'string',
|
|
434
|
-
description: 'The ID of the ticket',
|
|
435
|
-
},
|
|
436
|
-
passed: {
|
|
437
|
-
type: 'boolean',
|
|
438
|
-
description: 'Whether the tests passed',
|
|
439
|
-
},
|
|
440
|
-
testType: {
|
|
441
|
-
type: 'string',
|
|
442
|
-
enum: [
|
|
443
|
-
'unit', 'integration', 'e2e', 'manual',
|
|
444
|
-
'typescript', 'lint', 'build', 'typecheck',
|
|
445
|
-
'format', 'security', 'custom',
|
|
446
|
-
],
|
|
447
|
-
description: 'Type of test',
|
|
448
|
-
},
|
|
449
|
-
summary: {
|
|
450
|
-
type: 'string',
|
|
451
|
-
description: 'Summary of test results',
|
|
452
|
-
},
|
|
453
|
-
output: {
|
|
454
|
-
type: 'string',
|
|
455
|
-
description: 'Test output (will be truncated if too long)',
|
|
456
|
-
},
|
|
457
|
-
command: {
|
|
458
|
-
type: 'string',
|
|
459
|
-
description: 'The command that was run',
|
|
460
|
-
},
|
|
461
|
-
exitCode: {
|
|
462
|
-
type: 'number',
|
|
463
|
-
description: 'Process exit code',
|
|
464
|
-
},
|
|
465
|
-
durationMs: {
|
|
466
|
-
type: 'number',
|
|
467
|
-
description: 'How long it took in milliseconds',
|
|
468
|
-
},
|
|
469
|
-
errorCount: {
|
|
470
|
-
type: 'number',
|
|
471
|
-
description: 'Number of errors (for lint, typecheck)',
|
|
472
|
-
},
|
|
473
|
-
warningCount: {
|
|
474
|
-
type: 'number',
|
|
475
|
-
description: 'Number of warnings',
|
|
476
|
-
},
|
|
477
|
-
},
|
|
478
|
-
required: ['ticketId', 'passed', 'testType'],
|
|
479
|
-
},
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
name: 'get_ticket_test_status',
|
|
483
|
-
description: 'Get test status and history for a ticket',
|
|
484
|
-
inputSchema: {
|
|
485
|
-
type: 'object',
|
|
486
|
-
properties: {
|
|
487
|
-
ticketId: {
|
|
488
|
-
type: 'string',
|
|
489
|
-
description: 'The ID of the ticket',
|
|
490
|
-
},
|
|
491
|
-
},
|
|
492
|
-
required: ['ticketId'],
|
|
493
|
-
},
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
name: 'validate_ticket_completion',
|
|
497
|
-
description: 'Validate that a ticket is ready to be marked complete',
|
|
498
|
-
inputSchema: {
|
|
499
|
-
type: 'object',
|
|
500
|
-
properties: {
|
|
501
|
-
ticketId: {
|
|
502
|
-
type: 'string',
|
|
503
|
-
description: 'The ID of the ticket',
|
|
504
|
-
},
|
|
505
|
-
},
|
|
506
|
-
required: ['ticketId'],
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
// ========================================================================
|
|
510
|
-
// Discovery Tools (Epic 7)
|
|
511
|
-
// ========================================================================
|
|
512
|
-
{
|
|
513
|
-
name: 'report_discovery',
|
|
514
|
-
description: 'Report a discovery (new requirement, bug, or improvement) found during implementation',
|
|
515
|
-
inputSchema: {
|
|
516
|
-
type: 'object',
|
|
517
|
-
properties: {
|
|
518
|
-
ticketId: {
|
|
519
|
-
type: 'string',
|
|
520
|
-
description: 'The ID of the ticket where discovery was made',
|
|
521
|
-
},
|
|
522
|
-
type: {
|
|
523
|
-
type: 'string',
|
|
524
|
-
enum: ['bug', 'requirement', 'improvement', 'question'],
|
|
525
|
-
description: 'Type of discovery',
|
|
526
|
-
},
|
|
527
|
-
title: {
|
|
528
|
-
type: 'string',
|
|
529
|
-
description: 'Short title for the discovery',
|
|
530
|
-
},
|
|
531
|
-
description: {
|
|
532
|
-
type: 'string',
|
|
533
|
-
description: 'Detailed description',
|
|
534
|
-
},
|
|
535
|
-
priority: {
|
|
536
|
-
type: 'string',
|
|
537
|
-
enum: ['low', 'medium', 'high', 'critical'],
|
|
538
|
-
description: 'Priority level',
|
|
539
|
-
},
|
|
540
|
-
},
|
|
541
|
-
required: ['ticketId', 'type', 'title'],
|
|
542
|
-
},
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
name: 'get_pending_discoveries',
|
|
546
|
-
description: 'Get pending discoveries that need resolution',
|
|
547
|
-
inputSchema: {
|
|
548
|
-
type: 'object',
|
|
549
|
-
properties: {
|
|
550
|
-
specificationId: {
|
|
551
|
-
type: 'string',
|
|
552
|
-
description: 'Filter by specification (optional)',
|
|
553
|
-
},
|
|
554
|
-
projectId: {
|
|
555
|
-
type: 'string',
|
|
556
|
-
description: 'Filter by project (optional)',
|
|
557
|
-
},
|
|
558
|
-
},
|
|
559
|
-
required: [],
|
|
560
|
-
},
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
name: 'resolve_discovery',
|
|
564
|
-
description: 'Resolve a discovery as created (new ticket) or dismissed',
|
|
565
|
-
inputSchema: {
|
|
566
|
-
type: 'object',
|
|
567
|
-
properties: {
|
|
568
|
-
discoveryId: {
|
|
569
|
-
type: 'string',
|
|
570
|
-
description: 'The ID of the discovery',
|
|
571
|
-
},
|
|
572
|
-
resolution: {
|
|
573
|
-
type: 'string',
|
|
574
|
-
enum: ['created', 'dismissed'],
|
|
575
|
-
description: 'Resolution type',
|
|
576
|
-
},
|
|
577
|
-
createdTicketId: {
|
|
578
|
-
type: 'string',
|
|
579
|
-
description: 'ID of created ticket (if resolution is "created")',
|
|
580
|
-
},
|
|
581
|
-
notes: {
|
|
582
|
-
type: 'string',
|
|
583
|
-
description: 'Resolution notes',
|
|
584
|
-
},
|
|
585
|
-
},
|
|
586
|
-
required: ['discoveryId', 'resolution'],
|
|
587
|
-
},
|
|
588
|
-
},
|
|
589
790
|
// ========================================================================
|
|
590
791
|
// Status & Analytics Tools (Epic 8)
|
|
591
792
|
// ========================================================================
|
|
592
793
|
{
|
|
593
|
-
name: '
|
|
594
|
-
description:
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
},
|
|
606
|
-
{
|
|
607
|
-
name: 'get_epic_status',
|
|
608
|
-
description: 'Get detailed status for an epic including progress and actionable tickets',
|
|
609
|
-
inputSchema: {
|
|
610
|
-
type: 'object',
|
|
611
|
-
properties: {
|
|
612
|
-
epicId: {
|
|
613
|
-
type: 'string',
|
|
614
|
-
description: 'The ID of the epic',
|
|
615
|
-
},
|
|
616
|
-
},
|
|
617
|
-
required: ['epicId'],
|
|
618
|
-
},
|
|
619
|
-
},
|
|
620
|
-
{
|
|
621
|
-
name: 'get_implementation_summary',
|
|
622
|
-
description: 'Get cross-specification implementation summary with velocity metrics',
|
|
794
|
+
name: 'get_report',
|
|
795
|
+
description: `Generate unified reports for implementation, time tracking, blockers, or work summary.
|
|
796
|
+
|
|
797
|
+
Report types:
|
|
798
|
+
- 'implementation': Progress, velocity, completions (replaces get_implementation_summary)
|
|
799
|
+
- 'time': Estimated vs actual hours (replaces get_time_report)
|
|
800
|
+
- 'blockers': Blocked tickets with reasons (replaces get_blockers_report)
|
|
801
|
+
- 'work': Completed work summary (replaces get_work_summary)
|
|
802
|
+
|
|
803
|
+
Format options:
|
|
804
|
+
- 'json': Full structured data (default)
|
|
805
|
+
- 'summary': Condensed text summary`,
|
|
623
806
|
inputSchema: {
|
|
624
807
|
type: 'object',
|
|
625
808
|
properties: {
|
|
626
|
-
|
|
809
|
+
type: {
|
|
627
810
|
type: 'string',
|
|
628
|
-
|
|
811
|
+
enum: ['implementation', 'time', 'blockers', 'work'],
|
|
812
|
+
description: 'Type of report to generate',
|
|
629
813
|
},
|
|
630
|
-
},
|
|
631
|
-
required: [],
|
|
632
|
-
},
|
|
633
|
-
},
|
|
634
|
-
{
|
|
635
|
-
name: 'get_time_report',
|
|
636
|
-
description: 'Get time tracking report with estimated vs actual analysis',
|
|
637
|
-
inputSchema: {
|
|
638
|
-
type: 'object',
|
|
639
|
-
properties: {
|
|
640
814
|
scope: {
|
|
641
815
|
type: 'string',
|
|
642
|
-
enum: ['
|
|
816
|
+
enum: ['project', 'specification', 'epic'],
|
|
643
817
|
description: 'Scope of the report',
|
|
644
818
|
},
|
|
645
819
|
scopeId: {
|
|
646
820
|
type: 'string',
|
|
647
|
-
description: 'ID of the scoped entity',
|
|
648
|
-
},
|
|
649
|
-
},
|
|
650
|
-
required: ['scope', 'scopeId'],
|
|
651
|
-
},
|
|
652
|
-
},
|
|
653
|
-
{
|
|
654
|
-
name: 'get_blockers_report',
|
|
655
|
-
description: 'Get report of all blockers with duration and grouping',
|
|
656
|
-
inputSchema: {
|
|
657
|
-
type: 'object',
|
|
658
|
-
properties: {
|
|
659
|
-
specificationId: {
|
|
660
|
-
type: 'string',
|
|
661
|
-
description: 'Filter by specification (optional)',
|
|
662
|
-
},
|
|
663
|
-
projectId: {
|
|
664
|
-
type: 'string',
|
|
665
|
-
description: 'Filter by project (optional)',
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
required: [],
|
|
669
|
-
},
|
|
670
|
-
},
|
|
671
|
-
// ========================================================================
|
|
672
|
-
// Search Tools (Epic 9)
|
|
673
|
-
// ========================================================================
|
|
674
|
-
{
|
|
675
|
-
name: 'search_tickets',
|
|
676
|
-
description: 'Full-text search across tickets with relevance ranking',
|
|
677
|
-
inputSchema: {
|
|
678
|
-
type: 'object',
|
|
679
|
-
properties: {
|
|
680
|
-
query: {
|
|
681
|
-
type: 'string',
|
|
682
|
-
description: 'Search query',
|
|
683
|
-
},
|
|
684
|
-
specificationId: {
|
|
685
|
-
type: 'string',
|
|
686
|
-
description: 'Limit search to specification (optional)',
|
|
687
|
-
},
|
|
688
|
-
projectId: {
|
|
689
|
-
type: 'string',
|
|
690
|
-
description: 'Limit search to project (optional)',
|
|
691
|
-
},
|
|
692
|
-
limit: {
|
|
693
|
-
type: 'number',
|
|
694
|
-
description: 'Maximum results (default: 20)',
|
|
695
|
-
},
|
|
696
|
-
offset: {
|
|
697
|
-
type: 'number',
|
|
698
|
-
description: 'Pagination offset (default: 0)',
|
|
821
|
+
description: 'ID of the scoped entity (projectId, specificationId, or epicId)',
|
|
699
822
|
},
|
|
700
|
-
|
|
701
|
-
required: ['query'],
|
|
702
|
-
},
|
|
703
|
-
},
|
|
704
|
-
{
|
|
705
|
-
name: 'find_tickets_by_file',
|
|
706
|
-
description: 'Find tickets that modify or create specific files (supports glob patterns)',
|
|
707
|
-
inputSchema: {
|
|
708
|
-
type: 'object',
|
|
709
|
-
properties: {
|
|
710
|
-
filePath: {
|
|
823
|
+
format: {
|
|
711
824
|
type: 'string',
|
|
712
|
-
|
|
825
|
+
enum: ['json', 'toon', 'summary'],
|
|
826
|
+
description: 'Output format: json (full structured), toon (~44% smaller), summary (key metrics only ~70% smaller). Default: json',
|
|
713
827
|
},
|
|
714
|
-
|
|
828
|
+
startDate: {
|
|
715
829
|
type: 'string',
|
|
716
|
-
description: '
|
|
830
|
+
description: 'Start date for work report (ISO 8601)',
|
|
717
831
|
},
|
|
718
|
-
|
|
832
|
+
endDate: {
|
|
719
833
|
type: 'string',
|
|
720
|
-
description: '
|
|
834
|
+
description: 'End date for work report (ISO 8601)',
|
|
721
835
|
},
|
|
722
836
|
},
|
|
723
|
-
required: ['
|
|
837
|
+
required: ['type', 'scope', 'scopeId'],
|
|
724
838
|
},
|
|
725
839
|
},
|
|
840
|
+
// ========================================================================
|
|
841
|
+
// Search Tools (Epic 9)
|
|
842
|
+
// ========================================================================
|
|
726
843
|
{
|
|
727
|
-
name: '
|
|
728
|
-
description:
|
|
844
|
+
name: 'search_tickets',
|
|
845
|
+
description: `Unified ticket search with multiple filter options.
|
|
846
|
+
|
|
847
|
+
Combines:
|
|
848
|
+
- Full-text search (query)
|
|
849
|
+
- File matching (files) - replaces find_tickets_by_file
|
|
850
|
+
- Tag filtering (tags) - replaces find_tickets_by_tag
|
|
851
|
+
- Related tickets (relatedTo) - replaces find_related_tickets
|
|
852
|
+
- Status, complexity, priority filters
|
|
853
|
+
|
|
854
|
+
At least one of: query, files, tags, or relatedTo is required.
|
|
855
|
+
At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
729
856
|
inputSchema: {
|
|
730
857
|
type: 'object',
|
|
731
858
|
properties: {
|
|
859
|
+
query: {
|
|
860
|
+
type: 'string',
|
|
861
|
+
description: 'Full-text search query',
|
|
862
|
+
},
|
|
863
|
+
files: {
|
|
864
|
+
type: 'array',
|
|
865
|
+
items: { type: 'string' },
|
|
866
|
+
description: 'Glob patterns to match ticket files (e.g., "**/channel/*.ts")',
|
|
867
|
+
},
|
|
732
868
|
tags: {
|
|
733
869
|
type: 'array',
|
|
734
870
|
items: { type: 'string' },
|
|
735
|
-
description: 'Tags to
|
|
871
|
+
description: 'Tags to filter by',
|
|
736
872
|
},
|
|
737
|
-
|
|
873
|
+
matchAllTags: {
|
|
738
874
|
type: 'boolean',
|
|
739
875
|
description: 'If true, match all tags (AND). If false, match any (OR). Default: false',
|
|
740
876
|
},
|
|
741
|
-
|
|
877
|
+
relatedTo: {
|
|
742
878
|
type: 'string',
|
|
743
|
-
description: '
|
|
879
|
+
description: 'Find tickets related to this ticket ID (by tags, files, tech stack)',
|
|
880
|
+
},
|
|
881
|
+
status: {
|
|
882
|
+
type: 'array',
|
|
883
|
+
items: {
|
|
884
|
+
type: 'string',
|
|
885
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
886
|
+
},
|
|
887
|
+
description: 'Filter by status',
|
|
888
|
+
},
|
|
889
|
+
complexity: {
|
|
890
|
+
type: 'array',
|
|
891
|
+
items: {
|
|
892
|
+
type: 'string',
|
|
893
|
+
enum: ['small', 'medium', 'large', 'xlarge'],
|
|
894
|
+
},
|
|
895
|
+
description: 'Filter by complexity',
|
|
896
|
+
},
|
|
897
|
+
priority: {
|
|
898
|
+
type: 'array',
|
|
899
|
+
items: {
|
|
900
|
+
type: 'string',
|
|
901
|
+
enum: ['low', 'medium', 'high', 'critical'],
|
|
902
|
+
},
|
|
903
|
+
description: 'Filter by priority',
|
|
744
904
|
},
|
|
745
905
|
projectId: {
|
|
746
906
|
type: 'string',
|
|
747
|
-
description: 'Limit search to project
|
|
907
|
+
description: 'Limit search to project',
|
|
748
908
|
},
|
|
749
|
-
|
|
750
|
-
required: ['tags'],
|
|
751
|
-
},
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
name: 'find_related_tickets',
|
|
755
|
-
description: 'Find tickets related to a given ticket based on files, tags, and tech stack',
|
|
756
|
-
inputSchema: {
|
|
757
|
-
type: 'object',
|
|
758
|
-
properties: {
|
|
759
|
-
ticketId: {
|
|
909
|
+
specificationId: {
|
|
760
910
|
type: 'string',
|
|
761
|
-
description: '
|
|
911
|
+
description: 'Limit search to specification',
|
|
912
|
+
},
|
|
913
|
+
epicId: {
|
|
914
|
+
type: 'string',
|
|
915
|
+
description: 'Limit search to epic',
|
|
762
916
|
},
|
|
763
917
|
limit: {
|
|
764
918
|
type: 'number',
|
|
765
|
-
description: 'Maximum results (default:
|
|
919
|
+
description: 'Maximum results (default: 20, max: 100)',
|
|
920
|
+
},
|
|
921
|
+
offset: {
|
|
922
|
+
type: 'number',
|
|
923
|
+
description: 'Pagination offset (default: 0)',
|
|
924
|
+
},
|
|
925
|
+
fields: {
|
|
926
|
+
type: 'array',
|
|
927
|
+
items: {
|
|
928
|
+
type: 'string',
|
|
929
|
+
enum: [
|
|
930
|
+
'id',
|
|
931
|
+
'epicId',
|
|
932
|
+
'ticketNumber',
|
|
933
|
+
'title',
|
|
934
|
+
'description',
|
|
935
|
+
'status',
|
|
936
|
+
'priority',
|
|
937
|
+
'complexity',
|
|
938
|
+
'estimatedHours',
|
|
939
|
+
'actualHours',
|
|
940
|
+
'acceptanceCriteria',
|
|
941
|
+
'implementation',
|
|
942
|
+
'technicalDetails',
|
|
943
|
+
'notes',
|
|
944
|
+
'tags',
|
|
945
|
+
'blockReason',
|
|
946
|
+
'progress',
|
|
947
|
+
'testsPassed',
|
|
948
|
+
'order',
|
|
949
|
+
'startedAt',
|
|
950
|
+
'completedAt',
|
|
951
|
+
'createdAt',
|
|
952
|
+
'updatedAt',
|
|
953
|
+
],
|
|
954
|
+
},
|
|
955
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "ticketNumber", "title", "status"] for minimal results.',
|
|
766
956
|
},
|
|
767
957
|
},
|
|
768
|
-
required: ['ticketId'],
|
|
769
958
|
},
|
|
770
959
|
},
|
|
771
960
|
// ========================================================================
|
|
@@ -835,50 +1024,6 @@ export function getTools() {
|
|
|
835
1024
|
required: ['ticketId'],
|
|
836
1025
|
},
|
|
837
1026
|
},
|
|
838
|
-
{
|
|
839
|
-
name: 'get_ticket_commits',
|
|
840
|
-
description: 'Get all commits linked to a ticket',
|
|
841
|
-
inputSchema: {
|
|
842
|
-
type: 'object',
|
|
843
|
-
properties: {
|
|
844
|
-
ticketId: {
|
|
845
|
-
type: 'string',
|
|
846
|
-
description: 'The ID of the ticket',
|
|
847
|
-
},
|
|
848
|
-
limit: {
|
|
849
|
-
type: 'number',
|
|
850
|
-
description: 'Maximum results (default: 20)',
|
|
851
|
-
},
|
|
852
|
-
offset: {
|
|
853
|
-
type: 'number',
|
|
854
|
-
description: 'Pagination offset (default: 0)',
|
|
855
|
-
},
|
|
856
|
-
},
|
|
857
|
-
required: ['ticketId'],
|
|
858
|
-
},
|
|
859
|
-
},
|
|
860
|
-
{
|
|
861
|
-
name: 'get_ticket_prs',
|
|
862
|
-
description: 'Get all pull requests linked to a ticket',
|
|
863
|
-
inputSchema: {
|
|
864
|
-
type: 'object',
|
|
865
|
-
properties: {
|
|
866
|
-
ticketId: {
|
|
867
|
-
type: 'string',
|
|
868
|
-
description: 'The ID of the ticket',
|
|
869
|
-
},
|
|
870
|
-
limit: {
|
|
871
|
-
type: 'number',
|
|
872
|
-
description: 'Maximum results (default: 20)',
|
|
873
|
-
},
|
|
874
|
-
offset: {
|
|
875
|
-
type: 'number',
|
|
876
|
-
description: 'Pagination offset (default: 0)',
|
|
877
|
-
},
|
|
878
|
-
},
|
|
879
|
-
required: ['ticketId'],
|
|
880
|
-
},
|
|
881
|
-
},
|
|
882
1027
|
// ========================================================================
|
|
883
1028
|
// Creation Operations
|
|
884
1029
|
// ========================================================================
|
|
@@ -1027,6 +1172,48 @@ export function getTools() {
|
|
|
1027
1172
|
required: ['title', 'description', 'objective'],
|
|
1028
1173
|
},
|
|
1029
1174
|
},
|
|
1175
|
+
// Pattern inheritance fields (specification level)
|
|
1176
|
+
codeStandards: {
|
|
1177
|
+
type: 'object',
|
|
1178
|
+
description: 'Code standards inherited by all epics/tickets',
|
|
1179
|
+
properties: {
|
|
1180
|
+
language: { type: 'string', description: 'Primary language (e.g., "TypeScript")' },
|
|
1181
|
+
asyncPattern: { type: 'string', description: 'Async pattern (e.g., "async/await")' },
|
|
1182
|
+
errorHandling: { type: 'string', description: 'Error handling approach' },
|
|
1183
|
+
documentation: { type: 'string', description: 'Documentation style' },
|
|
1184
|
+
testing: { type: 'string', description: 'Testing approach' },
|
|
1185
|
+
naming: {
|
|
1186
|
+
type: 'object',
|
|
1187
|
+
description: 'Naming conventions',
|
|
1188
|
+
properties: {
|
|
1189
|
+
files: { type: 'string', description: 'File naming convention' },
|
|
1190
|
+
functions: { type: 'string', description: 'Function naming convention' },
|
|
1191
|
+
interfaces: { type: 'string', description: 'Interface naming convention' },
|
|
1192
|
+
actions: { type: 'string', description: 'Action naming convention' },
|
|
1193
|
+
},
|
|
1194
|
+
},
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1197
|
+
commonImports: {
|
|
1198
|
+
type: 'array',
|
|
1199
|
+
items: { type: 'string' },
|
|
1200
|
+
description: 'Common imports inherited by all epics/tickets',
|
|
1201
|
+
},
|
|
1202
|
+
returnTypes: {
|
|
1203
|
+
type: 'object',
|
|
1204
|
+
description: 'Standard return types for CRUD operations',
|
|
1205
|
+
properties: {
|
|
1206
|
+
create: { type: 'string', description: 'Return type for create operations' },
|
|
1207
|
+
update: { type: 'string', description: 'Return type for update operations' },
|
|
1208
|
+
delete: { type: 'string', description: 'Return type for delete operations' },
|
|
1209
|
+
list: { type: 'string', description: 'Return type for list operations' },
|
|
1210
|
+
},
|
|
1211
|
+
},
|
|
1212
|
+
responseMode: {
|
|
1213
|
+
type: 'string',
|
|
1214
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1215
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1216
|
+
},
|
|
1030
1217
|
},
|
|
1031
1218
|
required: ['projectId', 'title'],
|
|
1032
1219
|
},
|
|
@@ -1133,7 +1320,7 @@ export function getTools() {
|
|
|
1133
1320
|
},
|
|
1134
1321
|
tickets: {
|
|
1135
1322
|
type: 'array',
|
|
1136
|
-
description: 'Nested tickets to create (bulk creation)',
|
|
1323
|
+
description: 'Nested tickets to create (bulk creation) with optional inline dependencies',
|
|
1137
1324
|
items: {
|
|
1138
1325
|
type: 'object',
|
|
1139
1326
|
properties: {
|
|
@@ -1142,17 +1329,57 @@ export function getTools() {
|
|
|
1142
1329
|
acceptanceCriteria: { type: 'array', items: { type: 'string' } },
|
|
1143
1330
|
estimatedHours: { type: 'number' },
|
|
1144
1331
|
complexity: { type: 'string', enum: ['small', 'medium', 'large', 'xlarge'] },
|
|
1332
|
+
priority: { type: 'string', enum: ['high', 'medium', 'low'] },
|
|
1333
|
+
implementation: { type: 'object', description: 'Implementation details' },
|
|
1334
|
+
technicalDetails: { type: 'object', description: 'Technical details' },
|
|
1335
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
1336
|
+
dependsOn: {
|
|
1337
|
+
type: 'array',
|
|
1338
|
+
items: { type: 'number' },
|
|
1339
|
+
description: 'Indexes of other tickets in this array that this ticket depends on',
|
|
1340
|
+
},
|
|
1145
1341
|
},
|
|
1146
1342
|
required: ['title'],
|
|
1147
1343
|
},
|
|
1148
1344
|
},
|
|
1345
|
+
// Pattern inheritance fields (epic level)
|
|
1346
|
+
sharedPatterns: {
|
|
1347
|
+
type: 'object',
|
|
1348
|
+
description: 'Patterns shared by all tickets in this epic',
|
|
1349
|
+
properties: {
|
|
1350
|
+
errorHandling: { type: 'string', description: 'Override error handling for this epic' },
|
|
1351
|
+
returnType: { type: 'string', description: 'Epic-specific return type' },
|
|
1352
|
+
actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
|
|
1353
|
+
stateSlice: { type: 'string', description: 'State slice path for this epic' },
|
|
1354
|
+
},
|
|
1355
|
+
},
|
|
1356
|
+
additionalImports: {
|
|
1357
|
+
type: 'array',
|
|
1358
|
+
items: { type: 'string' },
|
|
1359
|
+
description: 'Additional imports for tickets in this epic (added to spec-level imports)',
|
|
1360
|
+
},
|
|
1361
|
+
commonFiles: {
|
|
1362
|
+
type: 'object',
|
|
1363
|
+
description: 'Common file paths for this epic',
|
|
1364
|
+
properties: {
|
|
1365
|
+
reducer: { type: 'string', description: 'Reducer file path' },
|
|
1366
|
+
actions: { type: 'string', description: 'Actions file path' },
|
|
1367
|
+
types: { type: 'string', description: 'Types file path' },
|
|
1368
|
+
index: { type: 'string', description: 'Index/barrel file path' },
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
responseMode: {
|
|
1372
|
+
type: 'string',
|
|
1373
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1374
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1375
|
+
},
|
|
1149
1376
|
},
|
|
1150
1377
|
required: ['specificationId', 'title', 'description', 'objective'],
|
|
1151
1378
|
},
|
|
1152
1379
|
},
|
|
1153
1380
|
{
|
|
1154
1381
|
name: 'create_ticket',
|
|
1155
|
-
description: 'Create a new ticket in an epic',
|
|
1382
|
+
description: 'Create a new ticket in an epic. Returns validation warnings based on complexity level.',
|
|
1156
1383
|
inputSchema: {
|
|
1157
1384
|
type: 'object',
|
|
1158
1385
|
properties: {
|
|
@@ -1213,6 +1440,20 @@ export function getTools() {
|
|
|
1213
1440
|
items: { type: 'string' },
|
|
1214
1441
|
description: 'Array of ticket IDs this ticket depends on',
|
|
1215
1442
|
},
|
|
1443
|
+
skipValidation: {
|
|
1444
|
+
type: 'boolean',
|
|
1445
|
+
description: 'Skip validation and completeness scoring. Default: false',
|
|
1446
|
+
},
|
|
1447
|
+
validationStrictness: {
|
|
1448
|
+
type: 'string',
|
|
1449
|
+
enum: ['lenient', 'normal', 'strict'],
|
|
1450
|
+
description: 'Warning strictness level. lenient=warnings only, normal=warnings+recommendations, strict=all. Default: normal',
|
|
1451
|
+
},
|
|
1452
|
+
responseMode: {
|
|
1453
|
+
type: 'string',
|
|
1454
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1455
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1456
|
+
},
|
|
1216
1457
|
},
|
|
1217
1458
|
required: ['epicId', 'title'],
|
|
1218
1459
|
},
|
|
@@ -1248,7 +1489,9 @@ export function getTools() {
|
|
|
1248
1489
|
// ========================================================================
|
|
1249
1490
|
{
|
|
1250
1491
|
name: 'update_ticket',
|
|
1251
|
-
description: "Update a ticket's properties (status, description, estimate, etc.)"
|
|
1492
|
+
description: "Update a ticket's properties (status, description, estimate, etc.).\n\n" +
|
|
1493
|
+
'When status changes, counts are automatically propagated up the hierarchy ' +
|
|
1494
|
+
'(Epic → Specification → Project).',
|
|
1252
1495
|
inputSchema: {
|
|
1253
1496
|
type: 'object',
|
|
1254
1497
|
properties: {
|
|
@@ -1266,8 +1509,8 @@ export function getTools() {
|
|
|
1266
1509
|
},
|
|
1267
1510
|
status: {
|
|
1268
1511
|
type: 'string',
|
|
1269
|
-
enum: ['
|
|
1270
|
-
description: '
|
|
1512
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
1513
|
+
description: 'Ticket status. pending/ready may be recalculated based on dependencies.',
|
|
1271
1514
|
},
|
|
1272
1515
|
priority: {
|
|
1273
1516
|
type: 'string',
|
|
@@ -1281,7 +1524,7 @@ export function getTools() {
|
|
|
1281
1524
|
},
|
|
1282
1525
|
blockReason: {
|
|
1283
1526
|
type: 'string',
|
|
1284
|
-
description: '
|
|
1527
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1285
1528
|
},
|
|
1286
1529
|
notes: {
|
|
1287
1530
|
type: 'string',
|
|
@@ -1309,6 +1552,22 @@ export function getTools() {
|
|
|
1309
1552
|
type: 'object',
|
|
1310
1553
|
description: 'Technical details like stack, endpoints (JSON) (optional)',
|
|
1311
1554
|
},
|
|
1555
|
+
skipValidation: {
|
|
1556
|
+
type: 'boolean',
|
|
1557
|
+
description: 'Skip validation and completeness scoring (default: false)',
|
|
1558
|
+
default: false,
|
|
1559
|
+
},
|
|
1560
|
+
validationStrictness: {
|
|
1561
|
+
type: 'string',
|
|
1562
|
+
enum: ['lenient', 'normal', 'strict'],
|
|
1563
|
+
description: 'Warning strictness level (default: normal)',
|
|
1564
|
+
default: 'normal',
|
|
1565
|
+
},
|
|
1566
|
+
responseMode: {
|
|
1567
|
+
type: 'string',
|
|
1568
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1569
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1570
|
+
},
|
|
1312
1571
|
},
|
|
1313
1572
|
required: ['ticketId'],
|
|
1314
1573
|
},
|
|
@@ -1410,6 +1669,37 @@ export function getTools() {
|
|
|
1410
1669
|
enum: ['low', 'medium', 'high', 'critical'],
|
|
1411
1670
|
description: 'Priority level (optional)',
|
|
1412
1671
|
},
|
|
1672
|
+
// Pattern inheritance fields (epic level)
|
|
1673
|
+
sharedPatterns: {
|
|
1674
|
+
type: 'object',
|
|
1675
|
+
description: 'Patterns shared by all tickets in this epic (optional)',
|
|
1676
|
+
properties: {
|
|
1677
|
+
errorHandling: { type: 'string', description: 'Override error handling for this epic' },
|
|
1678
|
+
returnType: { type: 'string', description: 'Epic-specific return type' },
|
|
1679
|
+
actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
|
|
1680
|
+
stateSlice: { type: 'string', description: 'State slice path for this epic' },
|
|
1681
|
+
},
|
|
1682
|
+
},
|
|
1683
|
+
additionalImports: {
|
|
1684
|
+
type: 'array',
|
|
1685
|
+
items: { type: 'string' },
|
|
1686
|
+
description: 'Additional imports for tickets in this epic (optional)',
|
|
1687
|
+
},
|
|
1688
|
+
commonFiles: {
|
|
1689
|
+
type: 'object',
|
|
1690
|
+
description: 'Common file paths for this epic (optional)',
|
|
1691
|
+
properties: {
|
|
1692
|
+
reducer: { type: 'string', description: 'Reducer file path' },
|
|
1693
|
+
actions: { type: 'string', description: 'Actions file path' },
|
|
1694
|
+
types: { type: 'string', description: 'Types file path' },
|
|
1695
|
+
index: { type: 'string', description: 'Index/barrel file path' },
|
|
1696
|
+
},
|
|
1697
|
+
},
|
|
1698
|
+
responseMode: {
|
|
1699
|
+
type: 'string',
|
|
1700
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1701
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1702
|
+
},
|
|
1413
1703
|
},
|
|
1414
1704
|
required: ['epicId'],
|
|
1415
1705
|
},
|
|
@@ -1555,6 +1845,48 @@ export function getTools() {
|
|
|
1555
1845
|
type: 'string',
|
|
1556
1846
|
description: 'Output directory for build artifacts (optional)',
|
|
1557
1847
|
},
|
|
1848
|
+
// Pattern inheritance fields (specification level)
|
|
1849
|
+
codeStandards: {
|
|
1850
|
+
type: 'object',
|
|
1851
|
+
description: 'Code standards inherited by all epics/tickets (optional)',
|
|
1852
|
+
properties: {
|
|
1853
|
+
language: { type: 'string', description: 'Primary language (e.g., "TypeScript")' },
|
|
1854
|
+
asyncPattern: { type: 'string', description: 'Async pattern (e.g., "async/await")' },
|
|
1855
|
+
errorHandling: { type: 'string', description: 'Error handling approach' },
|
|
1856
|
+
documentation: { type: 'string', description: 'Documentation style' },
|
|
1857
|
+
testing: { type: 'string', description: 'Testing approach' },
|
|
1858
|
+
naming: {
|
|
1859
|
+
type: 'object',
|
|
1860
|
+
description: 'Naming conventions',
|
|
1861
|
+
properties: {
|
|
1862
|
+
files: { type: 'string', description: 'File naming convention' },
|
|
1863
|
+
functions: { type: 'string', description: 'Function naming convention' },
|
|
1864
|
+
interfaces: { type: 'string', description: 'Interface naming convention' },
|
|
1865
|
+
actions: { type: 'string', description: 'Action naming convention' },
|
|
1866
|
+
},
|
|
1867
|
+
},
|
|
1868
|
+
},
|
|
1869
|
+
},
|
|
1870
|
+
commonImports: {
|
|
1871
|
+
type: 'array',
|
|
1872
|
+
items: { type: 'string' },
|
|
1873
|
+
description: 'Common imports inherited by all epics/tickets (optional)',
|
|
1874
|
+
},
|
|
1875
|
+
returnTypes: {
|
|
1876
|
+
type: 'object',
|
|
1877
|
+
description: 'Standard return types for CRUD operations (optional)',
|
|
1878
|
+
properties: {
|
|
1879
|
+
create: { type: 'string', description: 'Return type for create operations' },
|
|
1880
|
+
update: { type: 'string', description: 'Return type for update operations' },
|
|
1881
|
+
delete: { type: 'string', description: 'Return type for delete operations' },
|
|
1882
|
+
list: { type: 'string', description: 'Return type for list operations' },
|
|
1883
|
+
},
|
|
1884
|
+
},
|
|
1885
|
+
responseMode: {
|
|
1886
|
+
type: 'string',
|
|
1887
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1888
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1889
|
+
},
|
|
1558
1890
|
},
|
|
1559
1891
|
required: ['specificationId'],
|
|
1560
1892
|
},
|
|
@@ -1647,153 +1979,172 @@ export function getTools() {
|
|
|
1647
1979
|
},
|
|
1648
1980
|
},
|
|
1649
1981
|
{
|
|
1650
|
-
name: '
|
|
1651
|
-
description: '
|
|
1652
|
-
inputSchema: {
|
|
1653
|
-
type: 'object',
|
|
1654
|
-
properties: {
|
|
1655
|
-
sessionId: {
|
|
1656
|
-
type: 'string',
|
|
1657
|
-
description: 'Get specific session by ID',
|
|
1658
|
-
},
|
|
1659
|
-
specificationId: {
|
|
1660
|
-
type: 'string',
|
|
1661
|
-
description: 'Get active session for specification',
|
|
1662
|
-
},
|
|
1663
|
-
includeHistory: {
|
|
1664
|
-
type: 'boolean',
|
|
1665
|
-
description: 'Include completed sessions when querying by specification',
|
|
1666
|
-
},
|
|
1667
|
-
},
|
|
1668
|
-
required: [],
|
|
1669
|
-
},
|
|
1670
|
-
},
|
|
1671
|
-
{
|
|
1672
|
-
name: 'update_session',
|
|
1673
|
-
description: 'Update session state (pause/resume, update config, add notes)',
|
|
1982
|
+
name: 'end_session',
|
|
1983
|
+
description: 'End an implementation session. Returns final stats.',
|
|
1674
1984
|
inputSchema: {
|
|
1675
1985
|
type: 'object',
|
|
1676
1986
|
properties: {
|
|
1677
1987
|
sessionId: {
|
|
1678
1988
|
type: 'string',
|
|
1679
|
-
description: 'The ID of the session to
|
|
1989
|
+
description: 'The ID of the session to end',
|
|
1680
1990
|
},
|
|
1681
1991
|
status: {
|
|
1682
1992
|
type: 'string',
|
|
1683
|
-
enum: ['
|
|
1684
|
-
description: '
|
|
1685
|
-
},
|
|
1686
|
-
config: {
|
|
1687
|
-
type: 'object',
|
|
1688
|
-
description: 'Config updates to merge with existing',
|
|
1689
|
-
},
|
|
1690
|
-
notes: {
|
|
1691
|
-
type: 'string',
|
|
1692
|
-
description: 'Session notes',
|
|
1993
|
+
enum: ['completed', 'aborted'],
|
|
1994
|
+
description: 'How the session ended',
|
|
1693
1995
|
},
|
|
1694
|
-
|
|
1996
|
+
summary: {
|
|
1695
1997
|
type: 'string',
|
|
1696
|
-
description: '
|
|
1998
|
+
description: 'End-of-session summary',
|
|
1697
1999
|
},
|
|
1698
2000
|
},
|
|
1699
|
-
required: ['sessionId'],
|
|
2001
|
+
required: ['sessionId', 'status'],
|
|
1700
2002
|
},
|
|
1701
2003
|
},
|
|
2004
|
+
// ========================================================================
|
|
2005
|
+
// Bulk Operations
|
|
2006
|
+
// ========================================================================
|
|
1702
2007
|
{
|
|
1703
|
-
name: '
|
|
1704
|
-
description: '
|
|
2008
|
+
name: 'bulk_create_tickets',
|
|
2009
|
+
description: 'Create multiple tickets in an epic with optional inline dependencies in a single atomic transaction. Reduces 15+ API calls to one.',
|
|
1705
2010
|
inputSchema: {
|
|
1706
2011
|
type: 'object',
|
|
1707
2012
|
properties: {
|
|
1708
|
-
|
|
1709
|
-
type: 'string',
|
|
1710
|
-
description: 'The ID of the session',
|
|
1711
|
-
},
|
|
1712
|
-
ticketId: {
|
|
1713
|
-
type: 'string',
|
|
1714
|
-
description: 'The ID of the ticket',
|
|
1715
|
-
},
|
|
1716
|
-
result: {
|
|
2013
|
+
epicId: {
|
|
1717
2014
|
type: 'string',
|
|
1718
|
-
|
|
1719
|
-
description: 'Result of the ticket work',
|
|
2015
|
+
description: 'The ID of the epic to create tickets in',
|
|
1720
2016
|
},
|
|
1721
|
-
|
|
1722
|
-
type: '
|
|
1723
|
-
description: '
|
|
2017
|
+
tickets: {
|
|
2018
|
+
type: 'array',
|
|
2019
|
+
description: 'Array of ticket definitions to create',
|
|
2020
|
+
items: {
|
|
2021
|
+
type: 'object',
|
|
2022
|
+
properties: {
|
|
2023
|
+
title: { type: 'string', description: 'Ticket title (required)' },
|
|
2024
|
+
description: { type: 'string', description: 'Ticket description' },
|
|
2025
|
+
estimatedHours: { type: 'number', description: 'Estimated hours' },
|
|
2026
|
+
complexity: {
|
|
2027
|
+
type: 'string',
|
|
2028
|
+
enum: ['small', 'medium', 'large', 'xlarge'],
|
|
2029
|
+
description: 'Complexity level',
|
|
2030
|
+
},
|
|
2031
|
+
priority: {
|
|
2032
|
+
type: 'string',
|
|
2033
|
+
enum: ['high', 'medium', 'low'],
|
|
2034
|
+
description: 'Priority level',
|
|
2035
|
+
},
|
|
2036
|
+
acceptanceCriteria: {
|
|
2037
|
+
type: 'array',
|
|
2038
|
+
items: { type: 'string' },
|
|
2039
|
+
description: 'Acceptance criteria',
|
|
2040
|
+
},
|
|
2041
|
+
implementation: {
|
|
2042
|
+
type: 'object',
|
|
2043
|
+
description: 'Implementation details (filesToCreate, filesToModify, steps, etc.)',
|
|
2044
|
+
},
|
|
2045
|
+
technicalDetails: {
|
|
2046
|
+
type: 'object',
|
|
2047
|
+
description: 'Technical details (files, stack, endpoints, etc.)',
|
|
2048
|
+
},
|
|
2049
|
+
tags: {
|
|
2050
|
+
type: 'array',
|
|
2051
|
+
items: { type: 'string' },
|
|
2052
|
+
description: 'Tags',
|
|
2053
|
+
},
|
|
2054
|
+
},
|
|
2055
|
+
required: ['title'],
|
|
2056
|
+
},
|
|
1724
2057
|
},
|
|
1725
|
-
|
|
1726
|
-
type: '
|
|
1727
|
-
description: '
|
|
2058
|
+
dependencies: {
|
|
2059
|
+
type: 'array',
|
|
2060
|
+
description: 'Optional inline dependencies using array indexes',
|
|
2061
|
+
items: {
|
|
2062
|
+
type: 'object',
|
|
2063
|
+
properties: {
|
|
2064
|
+
ticket: {
|
|
2065
|
+
type: 'number',
|
|
2066
|
+
description: 'Index of the ticket in the tickets array',
|
|
2067
|
+
},
|
|
2068
|
+
dependsOn: {
|
|
2069
|
+
oneOf: [
|
|
2070
|
+
{ type: 'number', description: 'Index of the ticket it depends on' },
|
|
2071
|
+
{
|
|
2072
|
+
type: 'array',
|
|
2073
|
+
items: { type: 'number' },
|
|
2074
|
+
description: 'Indexes of the tickets it depends on',
|
|
2075
|
+
},
|
|
2076
|
+
],
|
|
2077
|
+
description: 'Index(es) of the ticket(s) it depends on',
|
|
2078
|
+
},
|
|
2079
|
+
},
|
|
2080
|
+
required: ['ticket', 'dependsOn'],
|
|
2081
|
+
},
|
|
1728
2082
|
},
|
|
1729
|
-
|
|
2083
|
+
onError: {
|
|
1730
2084
|
type: 'string',
|
|
1731
|
-
|
|
2085
|
+
enum: ['rollback', 'continue'],
|
|
2086
|
+
description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
|
|
1732
2087
|
},
|
|
1733
2088
|
},
|
|
1734
|
-
required: ['
|
|
2089
|
+
required: ['epicId', 'tickets'],
|
|
1735
2090
|
},
|
|
1736
2091
|
},
|
|
1737
2092
|
{
|
|
1738
|
-
name: '
|
|
1739
|
-
description: '
|
|
2093
|
+
name: 'get_job_status',
|
|
2094
|
+
description: 'Get the status of an asynchronous bulk operation job. For batches >= 20 items, bulk operations return a job ID for async processing.',
|
|
1740
2095
|
inputSchema: {
|
|
1741
2096
|
type: 'object',
|
|
1742
2097
|
properties: {
|
|
1743
|
-
|
|
1744
|
-
type: 'string',
|
|
1745
|
-
description: 'The ID of the session to end',
|
|
1746
|
-
},
|
|
1747
|
-
status: {
|
|
1748
|
-
type: 'string',
|
|
1749
|
-
enum: ['completed', 'aborted'],
|
|
1750
|
-
description: 'How the session ended',
|
|
1751
|
-
},
|
|
1752
|
-
summary: {
|
|
2098
|
+
jobId: {
|
|
1753
2099
|
type: 'string',
|
|
1754
|
-
description: '
|
|
2100
|
+
description: 'The job ID returned from a bulk operation',
|
|
1755
2101
|
},
|
|
1756
2102
|
},
|
|
1757
|
-
required: ['
|
|
2103
|
+
required: ['jobId'],
|
|
1758
2104
|
},
|
|
1759
2105
|
},
|
|
1760
2106
|
{
|
|
1761
|
-
name: '
|
|
1762
|
-
description: '
|
|
2107
|
+
name: 'bulk_add_dependencies',
|
|
2108
|
+
description: 'Add multiple dependencies between tickets in a single atomic transaction.',
|
|
1763
2109
|
inputSchema: {
|
|
1764
2110
|
type: 'object',
|
|
1765
2111
|
properties: {
|
|
1766
|
-
|
|
1767
|
-
type: 'string',
|
|
1768
|
-
description: 'Filter by specification',
|
|
1769
|
-
},
|
|
1770
|
-
projectId: {
|
|
1771
|
-
type: 'string',
|
|
1772
|
-
description: 'Filter by project',
|
|
1773
|
-
},
|
|
1774
|
-
status: {
|
|
2112
|
+
dependencies: {
|
|
1775
2113
|
type: 'array',
|
|
2114
|
+
description: 'Array of dependency definitions',
|
|
1776
2115
|
items: {
|
|
1777
|
-
type: '
|
|
1778
|
-
|
|
2116
|
+
type: 'object',
|
|
2117
|
+
properties: {
|
|
2118
|
+
ticketId: {
|
|
2119
|
+
type: 'string',
|
|
2120
|
+
description: 'ID of the ticket that will depend on another',
|
|
2121
|
+
},
|
|
2122
|
+
dependsOnId: {
|
|
2123
|
+
type: 'string',
|
|
2124
|
+
description: 'ID of the ticket it will depend on',
|
|
2125
|
+
},
|
|
2126
|
+
type: {
|
|
2127
|
+
type: 'string',
|
|
2128
|
+
enum: ['blocks', 'requires'],
|
|
2129
|
+
description: "Type of dependency (default: 'requires')",
|
|
2130
|
+
},
|
|
2131
|
+
},
|
|
2132
|
+
required: ['ticketId', 'dependsOnId'],
|
|
1779
2133
|
},
|
|
1780
|
-
description: 'Filter by status',
|
|
1781
2134
|
},
|
|
1782
|
-
|
|
1783
|
-
type: '
|
|
1784
|
-
description: '
|
|
2135
|
+
skipCircularCheck: {
|
|
2136
|
+
type: 'boolean',
|
|
2137
|
+
description: 'Skip validation of circular dependencies (default: false)',
|
|
1785
2138
|
},
|
|
1786
|
-
|
|
1787
|
-
type: '
|
|
1788
|
-
|
|
2139
|
+
onError: {
|
|
2140
|
+
type: 'string',
|
|
2141
|
+
enum: ['rollback', 'continue'],
|
|
2142
|
+
description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
|
|
1789
2143
|
},
|
|
1790
2144
|
},
|
|
1791
|
-
required: [],
|
|
2145
|
+
required: ['dependencies'],
|
|
1792
2146
|
},
|
|
1793
2147
|
},
|
|
1794
|
-
// ========================================================================
|
|
1795
|
-
// Bulk Operations
|
|
1796
|
-
// ========================================================================
|
|
1797
2148
|
{
|
|
1798
2149
|
name: 'bulk_update_tickets',
|
|
1799
2150
|
description: 'Update multiple tickets in a single atomic operation. All updates succeed or all fail (unless atomic: false).',
|
|
@@ -1811,8 +2162,8 @@ export function getTools() {
|
|
|
1811
2162
|
},
|
|
1812
2163
|
status: {
|
|
1813
2164
|
type: 'string',
|
|
1814
|
-
enum: ['
|
|
1815
|
-
description: '
|
|
2165
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
2166
|
+
description: 'Ticket status. Completing (done) triggers cascade to unblock dependents.',
|
|
1816
2167
|
},
|
|
1817
2168
|
priority: {
|
|
1818
2169
|
type: 'string',
|
|
@@ -1827,7 +2178,7 @@ export function getTools() {
|
|
|
1827
2178
|
},
|
|
1828
2179
|
blockReason: {
|
|
1829
2180
|
type: 'string',
|
|
1830
|
-
description: '
|
|
2181
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1831
2182
|
},
|
|
1832
2183
|
},
|
|
1833
2184
|
required: ['ticketId'],
|
|
@@ -1842,13 +2193,21 @@ export function getTools() {
|
|
|
1842
2193
|
type: 'boolean',
|
|
1843
2194
|
description: 'All-or-nothing updates. If false, partial success allowed (default: true)',
|
|
1844
2195
|
},
|
|
2196
|
+
responseMode: {
|
|
2197
|
+
type: 'string',
|
|
2198
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
2199
|
+
description: `Response verbosity:
|
|
2200
|
+
- full: Complete updated tickets (default, ~500 tokens per ticket)
|
|
2201
|
+
- minimal: id, title, status per ticket (~50 tokens total)
|
|
2202
|
+
- id-only: Array of updated ticket IDs only (~20 tokens total)`,
|
|
2203
|
+
},
|
|
1845
2204
|
},
|
|
1846
2205
|
required: ['updates'],
|
|
1847
2206
|
},
|
|
1848
2207
|
},
|
|
1849
2208
|
{
|
|
1850
2209
|
name: 'reset_tickets',
|
|
1851
|
-
description: 'Reset tickets to
|
|
2210
|
+
description: 'Reset tickets to pending/ready status (calculated from dependencies). Returns statusCalculation showing how many became pending vs ready.',
|
|
1852
2211
|
inputSchema: {
|
|
1853
2212
|
type: 'object',
|
|
1854
2213
|
properties: {
|
|
@@ -1873,11 +2232,6 @@ export function getTools() {
|
|
|
1873
2232
|
type: 'boolean',
|
|
1874
2233
|
description: 'Reset all tickets in the specification',
|
|
1875
2234
|
},
|
|
1876
|
-
targetStatus: {
|
|
1877
|
-
type: 'string',
|
|
1878
|
-
enum: ['todo', 'queue'],
|
|
1879
|
-
description: 'Status to reset tickets to (default: todo)',
|
|
1880
|
-
},
|
|
1881
2235
|
resetDependents: {
|
|
1882
2236
|
type: 'boolean',
|
|
1883
2237
|
description: 'Also reset tickets that depend on the specified tickets (default: false)',
|
|
@@ -1898,7 +2252,47 @@ export function getTools() {
|
|
|
1898
2252
|
required: ['specificationId'],
|
|
1899
2253
|
},
|
|
1900
2254
|
},
|
|
2255
|
+
// ========================================================================
|
|
2256
|
+
// Validation Operations (MCI-075)
|
|
2257
|
+
// ========================================================================
|
|
2258
|
+
{
|
|
2259
|
+
name: 'validate_counts',
|
|
2260
|
+
description: 'Validate denormalized counts across the hierarchy. ' +
|
|
2261
|
+
'Compares stored counts with actual data and optionally repairs discrepancies.\n\n' +
|
|
2262
|
+
'Use this tool to:\n' +
|
|
2263
|
+
'- Diagnose count inconsistencies\n' +
|
|
2264
|
+
'- Repair counts after data migrations\n' +
|
|
2265
|
+
'- Verify counts before bulk operations',
|
|
2266
|
+
inputSchema: {
|
|
2267
|
+
type: 'object',
|
|
2268
|
+
properties: {
|
|
2269
|
+
projectId: {
|
|
2270
|
+
type: 'string',
|
|
2271
|
+
description: 'Validate all counts within a project',
|
|
2272
|
+
},
|
|
2273
|
+
specificationId: {
|
|
2274
|
+
type: 'string',
|
|
2275
|
+
description: 'Validate all counts within a specification',
|
|
2276
|
+
},
|
|
2277
|
+
epicId: {
|
|
2278
|
+
type: 'string',
|
|
2279
|
+
description: 'Validate counts for a single epic',
|
|
2280
|
+
},
|
|
2281
|
+
repair: {
|
|
2282
|
+
type: 'boolean',
|
|
2283
|
+
description: 'If true, fix any issues found. Default: false (dry run)',
|
|
2284
|
+
},
|
|
2285
|
+
verbose: {
|
|
2286
|
+
type: 'boolean',
|
|
2287
|
+
description: 'Include detailed breakdown in response',
|
|
2288
|
+
},
|
|
2289
|
+
},
|
|
2290
|
+
required: [],
|
|
2291
|
+
},
|
|
2292
|
+
},
|
|
1901
2293
|
];
|
|
2294
|
+
// Apply format parameter to all read operations
|
|
2295
|
+
return tools.map(tool => READ_TOOL_NAMES.has(tool.name) ? addFormatParameter(tool) : tool);
|
|
1902
2296
|
}
|
|
1903
2297
|
/**
|
|
1904
2298
|
* Retry configuration for transient failures
|
|
@@ -1986,6 +2380,12 @@ export function createToolHandlers(apiClient) {
|
|
|
1986
2380
|
projectId: args.projectId,
|
|
1987
2381
|
});
|
|
1988
2382
|
},
|
|
2383
|
+
lookup_project: async (_client, args) => {
|
|
2384
|
+
validateRequired(args, 'name');
|
|
2385
|
+
return await apiClient.call('lookup_project', {
|
|
2386
|
+
name: args.name,
|
|
2387
|
+
});
|
|
2388
|
+
},
|
|
1989
2389
|
// ========================================================================
|
|
1990
2390
|
// Core Operations - Specifications
|
|
1991
2391
|
// ========================================================================
|
|
@@ -1994,12 +2394,24 @@ export function createToolHandlers(apiClient) {
|
|
|
1994
2394
|
return await apiClient.call('list_specifications', {
|
|
1995
2395
|
projectId: args.projectId,
|
|
1996
2396
|
status: args.status,
|
|
2397
|
+
limit: args.limit,
|
|
2398
|
+
offset: args.offset,
|
|
2399
|
+
fields: args.fields,
|
|
1997
2400
|
});
|
|
1998
2401
|
},
|
|
1999
2402
|
get_specification: async (_client, args) => {
|
|
2000
2403
|
validateRequired(args, 'specificationId');
|
|
2001
2404
|
return await apiClient.call('get_specification', {
|
|
2002
2405
|
specificationId: args.specificationId,
|
|
2406
|
+
summary: args.summary,
|
|
2407
|
+
include: args.include,
|
|
2408
|
+
});
|
|
2409
|
+
},
|
|
2410
|
+
lookup_specification: async (_client, args) => {
|
|
2411
|
+
validateRequired(args, 'projectId', 'title');
|
|
2412
|
+
return await apiClient.call('lookup_specification', {
|
|
2413
|
+
projectId: args.projectId,
|
|
2414
|
+
title: args.title,
|
|
2003
2415
|
});
|
|
2004
2416
|
},
|
|
2005
2417
|
// ========================================================================
|
|
@@ -2010,12 +2422,29 @@ export function createToolHandlers(apiClient) {
|
|
|
2010
2422
|
return await apiClient.call('list_epics', {
|
|
2011
2423
|
specificationId: args.specificationId,
|
|
2012
2424
|
status: args.status,
|
|
2425
|
+
limit: args.limit,
|
|
2426
|
+
offset: args.offset,
|
|
2427
|
+
fields: args.fields,
|
|
2013
2428
|
});
|
|
2014
2429
|
},
|
|
2015
2430
|
get_epic: async (_client, args) => {
|
|
2016
2431
|
validateRequired(args, 'epicId');
|
|
2017
2432
|
return await apiClient.call('get_epic', {
|
|
2018
2433
|
epicId: args.epicId,
|
|
2434
|
+
summary: args.summary,
|
|
2435
|
+
include: args.include,
|
|
2436
|
+
});
|
|
2437
|
+
},
|
|
2438
|
+
lookup_epic: async (_client, args) => {
|
|
2439
|
+
validateRequired(args, 'specificationId');
|
|
2440
|
+
// Must provide either title or number
|
|
2441
|
+
if (!args.title && args.number === undefined) {
|
|
2442
|
+
throw new Error("Must provide either 'title' or 'number'");
|
|
2443
|
+
}
|
|
2444
|
+
return await apiClient.call('lookup_epic', {
|
|
2445
|
+
specificationId: args.specificationId,
|
|
2446
|
+
title: args.title,
|
|
2447
|
+
number: args.number,
|
|
2019
2448
|
});
|
|
2020
2449
|
},
|
|
2021
2450
|
// ========================================================================
|
|
@@ -2026,23 +2455,58 @@ export function createToolHandlers(apiClient) {
|
|
|
2026
2455
|
return await apiClient.call('list_tickets', {
|
|
2027
2456
|
epicId: args.epicId,
|
|
2028
2457
|
status: args.status,
|
|
2458
|
+
limit: args.limit,
|
|
2459
|
+
offset: args.offset,
|
|
2460
|
+
include: args.include,
|
|
2461
|
+
fields: args.fields,
|
|
2029
2462
|
});
|
|
2030
2463
|
},
|
|
2031
2464
|
get_ticket: async (_client, args) => {
|
|
2032
2465
|
validateRequired(args, 'ticketId');
|
|
2033
2466
|
return await apiClient.call('get_ticket', {
|
|
2034
2467
|
ticketId: args.ticketId,
|
|
2468
|
+
summary: args.summary,
|
|
2469
|
+
include: args.include,
|
|
2470
|
+
});
|
|
2471
|
+
},
|
|
2472
|
+
lookup_ticket: async (_client, args) => {
|
|
2473
|
+
validateRequired(args, 'epicId');
|
|
2474
|
+
// Must provide either title or number
|
|
2475
|
+
if (!args.title && args.number === undefined) {
|
|
2476
|
+
throw new Error("Must provide either 'title' or 'number'");
|
|
2477
|
+
}
|
|
2478
|
+
return await apiClient.call('lookup_ticket', {
|
|
2479
|
+
epicId: args.epicId,
|
|
2480
|
+
title: args.title,
|
|
2481
|
+
number: args.number,
|
|
2482
|
+
});
|
|
2483
|
+
},
|
|
2484
|
+
lookup_tickets_by_status: async (_client, args) => {
|
|
2485
|
+
validateRequired(args, 'ticketIds');
|
|
2486
|
+
if (!Array.isArray(args.ticketIds)) {
|
|
2487
|
+
throw new Error('ticketIds must be an array');
|
|
2488
|
+
}
|
|
2489
|
+
const MAX_BATCH_SIZE = 50;
|
|
2490
|
+
if (args.ticketIds.length > MAX_BATCH_SIZE) {
|
|
2491
|
+
throw new Error(`Maximum ${MAX_BATCH_SIZE} tickets per call`);
|
|
2492
|
+
}
|
|
2493
|
+
// Empty array returns empty result
|
|
2494
|
+
if (args.ticketIds.length === 0) {
|
|
2495
|
+
return { tickets: [], notFound: [] };
|
|
2496
|
+
}
|
|
2497
|
+
// Validate all IDs are strings
|
|
2498
|
+
for (let i = 0; i < args.ticketIds.length; i++) {
|
|
2499
|
+
if (typeof args.ticketIds[i] !== 'string') {
|
|
2500
|
+
throw new Error(`ticketIds[${i}] must be a string`);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
return await apiClient.call('lookup_tickets_by_status', {
|
|
2504
|
+
ticketIds: args.ticketIds,
|
|
2035
2505
|
});
|
|
2036
2506
|
},
|
|
2037
2507
|
// ========================================================================
|
|
2038
2508
|
// Core Operations - Dependencies
|
|
2039
2509
|
// ========================================================================
|
|
2040
|
-
get_ticket_dependencies: async (_client, args) => {
|
|
2041
|
-
validateRequired(args, 'ticketId');
|
|
2042
|
-
return await apiClient.call('get_ticket_dependencies', {
|
|
2043
|
-
ticketId: args.ticketId,
|
|
2044
|
-
});
|
|
2045
|
-
},
|
|
2046
2510
|
add_dependency: async (_client, args) => {
|
|
2047
2511
|
validateRequired(args, 'ticketId');
|
|
2048
2512
|
validateRequired(args, 'dependsOnId');
|
|
@@ -2074,9 +2538,52 @@ export function createToolHandlers(apiClient) {
|
|
|
2074
2538
|
// ========================================================================
|
|
2075
2539
|
get_implementation_context: async (_client, args) => {
|
|
2076
2540
|
validateRequired(args, 'ticketId');
|
|
2077
|
-
|
|
2541
|
+
const depth = args.depth || 'standard';
|
|
2542
|
+
// Fetch the implementation context from API with depth parameter
|
|
2543
|
+
const context = await apiClient.call('get_implementation_context', {
|
|
2078
2544
|
ticketId: args.ticketId,
|
|
2545
|
+
depth,
|
|
2079
2546
|
});
|
|
2547
|
+
// Only resolve inherited patterns for 'full' depth (minimal/standard don't include them)
|
|
2548
|
+
if (depth === 'full' && context.specification && context.epic) {
|
|
2549
|
+
const spec = context.specification;
|
|
2550
|
+
const epic = context.epic;
|
|
2551
|
+
const ticket = context.ticket;
|
|
2552
|
+
try {
|
|
2553
|
+
const resolvedPatterns = resolvePatternsWithCache({
|
|
2554
|
+
ticketId: args.ticketId,
|
|
2555
|
+
specification: {
|
|
2556
|
+
id: spec.id,
|
|
2557
|
+
codeStandards: spec.codeStandards,
|
|
2558
|
+
commonImports: spec.commonImports,
|
|
2559
|
+
returnTypes: spec.returnTypes,
|
|
2560
|
+
},
|
|
2561
|
+
epic: {
|
|
2562
|
+
id: epic.id,
|
|
2563
|
+
sharedPatterns: epic.sharedPatterns,
|
|
2564
|
+
additionalImports: epic.additionalImports,
|
|
2565
|
+
commonFiles: epic.commonFiles,
|
|
2566
|
+
},
|
|
2567
|
+
ticket: ticket ? {
|
|
2568
|
+
id: ticket.id,
|
|
2569
|
+
technicalDetails: ticket.technicalDetails,
|
|
2570
|
+
} : undefined,
|
|
2571
|
+
});
|
|
2572
|
+
// Add inherited patterns to the response
|
|
2573
|
+
context.inheritedPatterns = {
|
|
2574
|
+
imports: resolvedPatterns.imports,
|
|
2575
|
+
patterns: resolvedPatterns.patterns,
|
|
2576
|
+
returnTypes: resolvedPatterns.returnTypes,
|
|
2577
|
+
commonFiles: resolvedPatterns.commonFiles,
|
|
2578
|
+
naming: resolvedPatterns.naming,
|
|
2579
|
+
};
|
|
2580
|
+
}
|
|
2581
|
+
catch {
|
|
2582
|
+
// If pattern resolution fails, return context without inherited patterns
|
|
2583
|
+
// This maintains backward compatibility
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return context;
|
|
2080
2587
|
},
|
|
2081
2588
|
get_next_actionable_tickets: async (_client, args) => {
|
|
2082
2589
|
// Either specificationId or projectId is required
|
|
@@ -2102,10 +2609,130 @@ export function createToolHandlers(apiClient) {
|
|
|
2102
2609
|
});
|
|
2103
2610
|
},
|
|
2104
2611
|
get_patterns: async (_client, args) => {
|
|
2105
|
-
|
|
2106
|
-
|
|
2612
|
+
// Either specificationId or ticketId is required
|
|
2613
|
+
if (!args.specificationId && !args.ticketId) {
|
|
2614
|
+
throw new Error('Either specificationId or ticketId is required');
|
|
2615
|
+
}
|
|
2616
|
+
// If ticketId is provided, return resolved patterns with inheritance
|
|
2617
|
+
if (args.ticketId) {
|
|
2618
|
+
// Fetch ticket data
|
|
2619
|
+
const ticket = await apiClient.call('get_ticket', {
|
|
2620
|
+
ticketId: args.ticketId,
|
|
2621
|
+
});
|
|
2622
|
+
// Get epic data
|
|
2623
|
+
const epic = await apiClient.call('get_epic', {
|
|
2624
|
+
epicId: ticket.epicId,
|
|
2625
|
+
});
|
|
2626
|
+
// Get specification data
|
|
2627
|
+
const spec = await apiClient.call('get_specification', {
|
|
2628
|
+
specificationId: epic.specificationId,
|
|
2629
|
+
});
|
|
2630
|
+
// Build pattern resolution input
|
|
2631
|
+
const input = {
|
|
2632
|
+
ticketId: args.ticketId,
|
|
2633
|
+
specification: {
|
|
2634
|
+
id: spec.id,
|
|
2635
|
+
codeStandards: spec.codeStandards,
|
|
2636
|
+
commonImports: spec.commonImports,
|
|
2637
|
+
returnTypes: spec.returnTypes,
|
|
2638
|
+
},
|
|
2639
|
+
epic: {
|
|
2640
|
+
id: epic.id,
|
|
2641
|
+
sharedPatterns: epic.sharedPatterns,
|
|
2642
|
+
additionalImports: epic.additionalImports,
|
|
2643
|
+
commonFiles: epic.commonFiles,
|
|
2644
|
+
},
|
|
2645
|
+
ticket: {
|
|
2646
|
+
id: ticket.id,
|
|
2647
|
+
technicalDetails: ticket.technicalDetails,
|
|
2648
|
+
},
|
|
2649
|
+
};
|
|
2650
|
+
// Resolve patterns and get override info
|
|
2651
|
+
const resolved = resolvePatternsWithCache(input);
|
|
2652
|
+
const overrideReport = getPatternOverrides(input);
|
|
2653
|
+
return {
|
|
2654
|
+
resolved: {
|
|
2655
|
+
imports: resolved.imports,
|
|
2656
|
+
patterns: resolved.patterns,
|
|
2657
|
+
returnTypes: resolved.returnTypes,
|
|
2658
|
+
commonFiles: resolved.commonFiles,
|
|
2659
|
+
naming: resolved.naming,
|
|
2660
|
+
},
|
|
2661
|
+
raw: {
|
|
2662
|
+
specification: {
|
|
2663
|
+
codeStandards: spec.codeStandards ?? null,
|
|
2664
|
+
commonImports: spec.commonImports ?? [],
|
|
2665
|
+
returnTypes: spec.returnTypes ?? null,
|
|
2666
|
+
},
|
|
2667
|
+
epic: {
|
|
2668
|
+
sharedPatterns: epic.sharedPatterns ?? null,
|
|
2669
|
+
additionalImports: epic.additionalImports ?? [],
|
|
2670
|
+
commonFiles: epic.commonFiles ?? null,
|
|
2671
|
+
},
|
|
2672
|
+
ticket: {
|
|
2673
|
+
patterns: ticket.technicalDetails?.patterns ?? null,
|
|
2674
|
+
},
|
|
2675
|
+
},
|
|
2676
|
+
overrides: overrideReport.overrides,
|
|
2677
|
+
chain: {
|
|
2678
|
+
specificationId: spec.id,
|
|
2679
|
+
specificationTitle: spec.title,
|
|
2680
|
+
epicId: epic.id,
|
|
2681
|
+
epicTitle: epic.title,
|
|
2682
|
+
ticketId: ticket.id,
|
|
2683
|
+
ticketTitle: ticket.title,
|
|
2684
|
+
},
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
// Specification-level query (backward compatible)
|
|
2688
|
+
const specPatterns = await apiClient.call('get_patterns', {
|
|
2107
2689
|
specificationId: args.specificationId,
|
|
2108
2690
|
});
|
|
2691
|
+
// Get spec details for raw patterns if available
|
|
2692
|
+
let specData = null;
|
|
2693
|
+
try {
|
|
2694
|
+
specData = await apiClient.call('get_specification', {
|
|
2695
|
+
specificationId: args.specificationId,
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
catch {
|
|
2699
|
+
// If spec fetch fails, just return the raw response
|
|
2700
|
+
return specPatterns;
|
|
2701
|
+
}
|
|
2702
|
+
// Return enhanced response with raw patterns
|
|
2703
|
+
return {
|
|
2704
|
+
resolved: {
|
|
2705
|
+
imports: specData.commonImports ?? [],
|
|
2706
|
+
patterns: flattenCodeStandards(specData.codeStandards),
|
|
2707
|
+
returnTypes: specData.returnTypes ?? {},
|
|
2708
|
+
commonFiles: {},
|
|
2709
|
+
naming: specData.codeStandards?.naming ?? {},
|
|
2710
|
+
},
|
|
2711
|
+
raw: {
|
|
2712
|
+
specification: {
|
|
2713
|
+
codeStandards: specData.codeStandards ?? null,
|
|
2714
|
+
commonImports: specData.commonImports ?? [],
|
|
2715
|
+
returnTypes: specData.returnTypes ?? null,
|
|
2716
|
+
},
|
|
2717
|
+
epic: {
|
|
2718
|
+
sharedPatterns: null,
|
|
2719
|
+
additionalImports: [],
|
|
2720
|
+
commonFiles: null,
|
|
2721
|
+
},
|
|
2722
|
+
ticket: {
|
|
2723
|
+
patterns: null,
|
|
2724
|
+
},
|
|
2725
|
+
},
|
|
2726
|
+
overrides: [],
|
|
2727
|
+
chain: {
|
|
2728
|
+
specificationId: specData.id,
|
|
2729
|
+
specificationTitle: specData.title,
|
|
2730
|
+
epicId: '',
|
|
2731
|
+
epicTitle: '',
|
|
2732
|
+
ticketId: '',
|
|
2733
|
+
ticketTitle: '',
|
|
2734
|
+
},
|
|
2735
|
+
};
|
|
2109
2736
|
},
|
|
2110
2737
|
// ========================================================================
|
|
2111
2738
|
// Workflow & Tracking
|
|
@@ -2124,6 +2751,9 @@ export function createToolHandlers(apiClient) {
|
|
|
2124
2751
|
filesModified: args.filesModified,
|
|
2125
2752
|
filesCreated: args.filesCreated,
|
|
2126
2753
|
actualHours: args.actualHours,
|
|
2754
|
+
validated: args.validated, // MCI-066: simple validation flag
|
|
2755
|
+
validation: args.validation, // MCI-064: validation flags
|
|
2756
|
+
skipCriteriaCheck: args.skipCriteriaCheck, // MCI-065: skip criteria check
|
|
2127
2757
|
});
|
|
2128
2758
|
},
|
|
2129
2759
|
report_progress: async (_client, args) => {
|
|
@@ -2135,143 +2765,48 @@ export function createToolHandlers(apiClient) {
|
|
|
2135
2765
|
message: args.message,
|
|
2136
2766
|
});
|
|
2137
2767
|
},
|
|
2138
|
-
get_work_summary: async (_client, args) => {
|
|
2139
|
-
validateRequired(args, 'scope');
|
|
2140
|
-
return await apiClient.call('get_work_summary', {
|
|
2141
|
-
scope: args.scope,
|
|
2142
|
-
scopeId: args.scopeId,
|
|
2143
|
-
startDate: args.startDate,
|
|
2144
|
-
endDate: args.endDate,
|
|
2145
|
-
});
|
|
2146
|
-
},
|
|
2147
|
-
// ========================================================================
|
|
2148
|
-
// Testing Tools
|
|
2149
|
-
// ========================================================================
|
|
2150
|
-
report_test_results: async (_client, args) => {
|
|
2151
|
-
validateRequired(args, 'ticketId', 'passed', 'testType');
|
|
2152
|
-
return await apiClient.call('report_test_results', {
|
|
2153
|
-
ticketId: args.ticketId,
|
|
2154
|
-
passed: args.passed,
|
|
2155
|
-
testType: args.testType,
|
|
2156
|
-
summary: args.summary,
|
|
2157
|
-
output: args.output,
|
|
2158
|
-
command: args.command,
|
|
2159
|
-
exitCode: args.exitCode,
|
|
2160
|
-
durationMs: args.durationMs,
|
|
2161
|
-
errorCount: args.errorCount,
|
|
2162
|
-
warningCount: args.warningCount,
|
|
2163
|
-
});
|
|
2164
|
-
},
|
|
2165
|
-
get_ticket_test_status: async (_client, args) => {
|
|
2166
|
-
validateRequired(args, 'ticketId');
|
|
2167
|
-
return await apiClient.call('get_ticket_test_status', {
|
|
2168
|
-
ticketId: args.ticketId,
|
|
2169
|
-
});
|
|
2170
|
-
},
|
|
2171
|
-
validate_ticket_completion: async (_client, args) => {
|
|
2172
|
-
validateRequired(args, 'ticketId');
|
|
2173
|
-
return await apiClient.call('validate_ticket_completion', {
|
|
2174
|
-
ticketId: args.ticketId,
|
|
2175
|
-
});
|
|
2176
|
-
},
|
|
2177
|
-
// ========================================================================
|
|
2178
|
-
// Discovery Tools
|
|
2179
|
-
// ========================================================================
|
|
2180
|
-
report_discovery: async (_client, args) => {
|
|
2181
|
-
validateRequired(args, 'ticketId', 'type', 'title');
|
|
2182
|
-
return await apiClient.call('report_discovery', {
|
|
2183
|
-
ticketId: args.ticketId,
|
|
2184
|
-
type: args.type,
|
|
2185
|
-
title: args.title,
|
|
2186
|
-
description: args.description,
|
|
2187
|
-
priority: args.priority,
|
|
2188
|
-
});
|
|
2189
|
-
},
|
|
2190
|
-
get_pending_discoveries: async (_client, args) => {
|
|
2191
|
-
return await apiClient.call('get_pending_discoveries', {
|
|
2192
|
-
specificationId: args.specificationId,
|
|
2193
|
-
projectId: args.projectId,
|
|
2194
|
-
});
|
|
2195
|
-
},
|
|
2196
|
-
resolve_discovery: async (_client, args) => {
|
|
2197
|
-
validateRequired(args, 'discoveryId', 'resolution');
|
|
2198
|
-
return await apiClient.call('resolve_discovery', {
|
|
2199
|
-
discoveryId: args.discoveryId,
|
|
2200
|
-
resolution: args.resolution,
|
|
2201
|
-
createdTicketId: args.createdTicketId,
|
|
2202
|
-
notes: args.notes,
|
|
2203
|
-
});
|
|
2204
|
-
},
|
|
2205
2768
|
// ========================================================================
|
|
2206
2769
|
// Status & Analytics Tools
|
|
2207
2770
|
// ========================================================================
|
|
2208
|
-
|
|
2209
|
-
validateRequired(args, '
|
|
2210
|
-
return await apiClient.call('
|
|
2211
|
-
|
|
2212
|
-
});
|
|
2213
|
-
},
|
|
2214
|
-
get_epic_status: async (_client, args) => {
|
|
2215
|
-
validateRequired(args, 'epicId');
|
|
2216
|
-
return await apiClient.call('get_epic_status', {
|
|
2217
|
-
epicId: args.epicId,
|
|
2218
|
-
});
|
|
2219
|
-
},
|
|
2220
|
-
get_implementation_summary: async (_client, args) => {
|
|
2221
|
-
return await apiClient.call('get_implementation_summary', {
|
|
2222
|
-
projectId: args.projectId,
|
|
2223
|
-
});
|
|
2224
|
-
},
|
|
2225
|
-
get_time_report: async (_client, args) => {
|
|
2226
|
-
validateRequired(args, 'scope', 'scopeId');
|
|
2227
|
-
return await apiClient.call('get_time_report', {
|
|
2771
|
+
get_report: async (_client, args) => {
|
|
2772
|
+
validateRequired(args, 'type', 'scope', 'scopeId');
|
|
2773
|
+
return await apiClient.call('get_report', {
|
|
2774
|
+
type: args.type,
|
|
2228
2775
|
scope: args.scope,
|
|
2229
2776
|
scopeId: args.scopeId,
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
return await apiClient.call('get_blockers_report', {
|
|
2234
|
-
specificationId: args.specificationId,
|
|
2235
|
-
projectId: args.projectId,
|
|
2777
|
+
format: args.format ?? 'json',
|
|
2778
|
+
startDate: args.startDate,
|
|
2779
|
+
endDate: args.endDate,
|
|
2236
2780
|
});
|
|
2237
2781
|
},
|
|
2238
2782
|
// ========================================================================
|
|
2239
2783
|
// Search Tools
|
|
2240
2784
|
// ========================================================================
|
|
2241
2785
|
search_tickets: async (_client, args) => {
|
|
2242
|
-
|
|
2786
|
+
// Validate at least one search criterion
|
|
2787
|
+
if (!args.query && !args.files && !args.tags && !args.relatedTo) {
|
|
2788
|
+
throw new Error('At least one filter is required: query, files, tags, or relatedTo');
|
|
2789
|
+
}
|
|
2790
|
+
// Validate at least one scope
|
|
2791
|
+
if (!args.projectId && !args.specificationId && !args.epicId) {
|
|
2792
|
+
throw new Error('One of projectId, specificationId, or epicId is required');
|
|
2793
|
+
}
|
|
2243
2794
|
return await apiClient.call('search_tickets', {
|
|
2244
2795
|
query: args.query,
|
|
2796
|
+
files: args.files,
|
|
2797
|
+
tags: args.tags,
|
|
2798
|
+
matchAllTags: args.matchAllTags ?? false,
|
|
2799
|
+
relatedTo: args.relatedTo,
|
|
2800
|
+
status: args.status,
|
|
2801
|
+
complexity: args.complexity,
|
|
2802
|
+
priority: args.priority,
|
|
2245
2803
|
specificationId: args.specificationId,
|
|
2246
2804
|
projectId: args.projectId,
|
|
2805
|
+
epicId: args.epicId,
|
|
2247
2806
|
limit: args.limit ?? 20,
|
|
2248
2807
|
offset: args.offset ?? 0,
|
|
2249
2808
|
});
|
|
2250
2809
|
},
|
|
2251
|
-
find_tickets_by_file: async (_client, args) => {
|
|
2252
|
-
validateRequired(args, 'filePath');
|
|
2253
|
-
return await apiClient.call('find_tickets_by_file', {
|
|
2254
|
-
filePath: args.filePath,
|
|
2255
|
-
specificationId: args.specificationId,
|
|
2256
|
-
projectId: args.projectId,
|
|
2257
|
-
});
|
|
2258
|
-
},
|
|
2259
|
-
find_tickets_by_tag: async (_client, args) => {
|
|
2260
|
-
validateRequired(args, 'tags');
|
|
2261
|
-
return await apiClient.call('find_tickets_by_tag', {
|
|
2262
|
-
tags: args.tags,
|
|
2263
|
-
matchAll: args.matchAll ?? false,
|
|
2264
|
-
specificationId: args.specificationId,
|
|
2265
|
-
projectId: args.projectId,
|
|
2266
|
-
});
|
|
2267
|
-
},
|
|
2268
|
-
find_related_tickets: async (_client, args) => {
|
|
2269
|
-
validateRequired(args, 'ticketId');
|
|
2270
|
-
return await apiClient.call('find_related_tickets', {
|
|
2271
|
-
ticketId: args.ticketId,
|
|
2272
|
-
limit: args.limit ?? 10,
|
|
2273
|
-
});
|
|
2274
|
-
},
|
|
2275
2810
|
// ========================================================================
|
|
2276
2811
|
// Git Integration Tools
|
|
2277
2812
|
// ========================================================================
|
|
@@ -2300,28 +2835,13 @@ export function createToolHandlers(apiClient) {
|
|
|
2300
2835
|
repoUrl: args.repoUrl,
|
|
2301
2836
|
});
|
|
2302
2837
|
},
|
|
2303
|
-
get_ticket_commits: async (_client, args) => {
|
|
2304
|
-
validateRequired(args, 'ticketId');
|
|
2305
|
-
return await apiClient.call('get_ticket_commits', {
|
|
2306
|
-
ticketId: args.ticketId,
|
|
2307
|
-
limit: args.limit ?? 20,
|
|
2308
|
-
offset: args.offset ?? 0,
|
|
2309
|
-
});
|
|
2310
|
-
},
|
|
2311
|
-
get_ticket_prs: async (_client, args) => {
|
|
2312
|
-
validateRequired(args, 'ticketId');
|
|
2313
|
-
return await apiClient.call('get_ticket_prs', {
|
|
2314
|
-
ticketId: args.ticketId,
|
|
2315
|
-
limit: args.limit ?? 20,
|
|
2316
|
-
offset: args.offset ?? 0,
|
|
2317
|
-
});
|
|
2318
|
-
},
|
|
2319
2838
|
// ========================================================================
|
|
2320
2839
|
// Creation Operations
|
|
2321
2840
|
// ========================================================================
|
|
2322
2841
|
create_specification: async (_client, args) => {
|
|
2323
2842
|
validateRequired(args, 'projectId', 'title');
|
|
2324
|
-
|
|
2843
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
2844
|
+
const result = await apiClient.call('create_specification', {
|
|
2325
2845
|
projectId: args.projectId,
|
|
2326
2846
|
title: args.title,
|
|
2327
2847
|
description: args.description,
|
|
@@ -2350,10 +2870,54 @@ export function createToolHandlers(apiClient) {
|
|
|
2350
2870
|
apiContracts: args.apiContracts,
|
|
2351
2871
|
targetAudience: args.targetAudience,
|
|
2352
2872
|
});
|
|
2873
|
+
return formatWriteResponse(result, responseMode, 'Specification created');
|
|
2353
2874
|
},
|
|
2354
2875
|
create_epic: async (_client, args) => {
|
|
2355
2876
|
validateRequired(args, 'specificationId', 'title', 'description', 'objective');
|
|
2356
|
-
|
|
2877
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
2878
|
+
// Validate inline dependencies if tickets are provided with dependsOn
|
|
2879
|
+
if (args.tickets && Array.isArray(args.tickets)) {
|
|
2880
|
+
const tickets = args.tickets;
|
|
2881
|
+
const ticketCount = tickets.length;
|
|
2882
|
+
for (let i = 0; i < ticketCount; i++) {
|
|
2883
|
+
const ticket = tickets[i];
|
|
2884
|
+
if (ticket.dependsOn && Array.isArray(ticket.dependsOn)) {
|
|
2885
|
+
for (const depIndex of ticket.dependsOn) {
|
|
2886
|
+
// Check bounds
|
|
2887
|
+
if (typeof depIndex !== 'number' || depIndex < 0 || depIndex >= ticketCount) {
|
|
2888
|
+
throw new Error(`tickets[${i}].dependsOn: index ${depIndex} is out of bounds (must be 0-${ticketCount - 1})`);
|
|
2889
|
+
}
|
|
2890
|
+
// Check self-reference
|
|
2891
|
+
if (depIndex === i) {
|
|
2892
|
+
throw new Error(`tickets[${i}].dependsOn: ticket cannot depend on itself`);
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
// Check for circular dependencies using DFS
|
|
2898
|
+
const hasCycle = (startIdx, visited, path) => {
|
|
2899
|
+
if (path.has(startIdx))
|
|
2900
|
+
return true;
|
|
2901
|
+
if (visited.has(startIdx))
|
|
2902
|
+
return false;
|
|
2903
|
+
visited.add(startIdx);
|
|
2904
|
+
path.add(startIdx);
|
|
2905
|
+
const deps = tickets[startIdx].dependsOn || [];
|
|
2906
|
+
for (const depIdx of deps) {
|
|
2907
|
+
if (hasCycle(depIdx, visited, path))
|
|
2908
|
+
return true;
|
|
2909
|
+
}
|
|
2910
|
+
path.delete(startIdx);
|
|
2911
|
+
return false;
|
|
2912
|
+
};
|
|
2913
|
+
const visited = new Set();
|
|
2914
|
+
for (let i = 0; i < ticketCount; i++) {
|
|
2915
|
+
if (hasCycle(i, visited, new Set())) {
|
|
2916
|
+
throw new Error(`Circular dependency detected in tickets array`);
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
const result = await apiClient.call('create_epic', {
|
|
2357
2921
|
specificationId: args.specificationId,
|
|
2358
2922
|
title: args.title,
|
|
2359
2923
|
description: args.description,
|
|
@@ -2379,10 +2943,18 @@ export function createToolHandlers(apiClient) {
|
|
|
2379
2943
|
dependencies: args.dependencies,
|
|
2380
2944
|
apiContracts: args.apiContracts,
|
|
2381
2945
|
});
|
|
2946
|
+
return formatWriteResponse(result, responseMode, 'Epic created');
|
|
2382
2947
|
},
|
|
2383
2948
|
create_ticket: async (_client, args) => {
|
|
2384
2949
|
validateRequired(args, 'epicId', 'title');
|
|
2385
|
-
|
|
2950
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
2951
|
+
// Extract validation options
|
|
2952
|
+
const skipValidation = args.skipValidation === true;
|
|
2953
|
+
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
2954
|
+
? args.validationStrictness
|
|
2955
|
+
: 'normal';
|
|
2956
|
+
// Create the ticket
|
|
2957
|
+
const result = await apiClient.call('create_ticket', {
|
|
2386
2958
|
epicId: args.epicId,
|
|
2387
2959
|
title: args.title,
|
|
2388
2960
|
ticketNumber: args.ticketNumber,
|
|
@@ -2397,6 +2969,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2397
2969
|
order: args.order,
|
|
2398
2970
|
dependsOn: args.dependsOn,
|
|
2399
2971
|
});
|
|
2972
|
+
// Run validation unless skipped
|
|
2973
|
+
if (!skipValidation) {
|
|
2974
|
+
const validation = validateTicket({
|
|
2975
|
+
complexity: args.complexity,
|
|
2976
|
+
implementation: args.implementation,
|
|
2977
|
+
technicalDetails: args.technicalDetails,
|
|
2978
|
+
notes: args.notes,
|
|
2979
|
+
acceptanceCriteria: args.acceptanceCriteria,
|
|
2980
|
+
});
|
|
2981
|
+
// Filter warnings by strictness level
|
|
2982
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
2983
|
+
// Add validation results to response
|
|
2984
|
+
result.warnings = warnings;
|
|
2985
|
+
result.completenessScore = validation.completenessScore;
|
|
2986
|
+
}
|
|
2987
|
+
return formatWriteResponse(result, responseMode, 'Ticket created');
|
|
2400
2988
|
},
|
|
2401
2989
|
import_specification: async (_client, args) => {
|
|
2402
2990
|
validateRequired(args, 'projectId', 'content');
|
|
@@ -2412,7 +3000,36 @@ export function createToolHandlers(apiClient) {
|
|
|
2412
3000
|
// ========================================================================
|
|
2413
3001
|
update_ticket: async (_client, args) => {
|
|
2414
3002
|
validateRequired(args, 'ticketId');
|
|
2415
|
-
|
|
3003
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3004
|
+
// Extract validation options
|
|
3005
|
+
const skipValidation = args.skipValidation === true;
|
|
3006
|
+
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
3007
|
+
? args.validationStrictness
|
|
3008
|
+
: 'normal';
|
|
3009
|
+
// Get current ticket to calculate previous completeness score
|
|
3010
|
+
let previousCompletenessScore;
|
|
3011
|
+
if (!skipValidation) {
|
|
3012
|
+
try {
|
|
3013
|
+
const currentTicket = await apiClient.call('get_ticket', {
|
|
3014
|
+
ticketId: args.ticketId,
|
|
3015
|
+
});
|
|
3016
|
+
// Calculate previous completeness score
|
|
3017
|
+
const prevValidation = validateTicket({
|
|
3018
|
+
complexity: currentTicket.complexity,
|
|
3019
|
+
implementation: currentTicket.implementation,
|
|
3020
|
+
technicalDetails: currentTicket.technicalDetails,
|
|
3021
|
+
notes: currentTicket.notes,
|
|
3022
|
+
acceptanceCriteria: currentTicket.acceptanceCriteria,
|
|
3023
|
+
});
|
|
3024
|
+
previousCompletenessScore = prevValidation.completenessScore;
|
|
3025
|
+
}
|
|
3026
|
+
catch {
|
|
3027
|
+
// If we can't get the current ticket, skip previous score tracking
|
|
3028
|
+
previousCompletenessScore = undefined;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
// Update the ticket
|
|
3032
|
+
const result = await apiClient.call('update_ticket', {
|
|
2416
3033
|
ticketId: args.ticketId,
|
|
2417
3034
|
title: args.title,
|
|
2418
3035
|
description: args.description,
|
|
@@ -2428,10 +3045,32 @@ export function createToolHandlers(apiClient) {
|
|
|
2428
3045
|
technicalDetails: args.technicalDetails,
|
|
2429
3046
|
blockReason: args.blockReason,
|
|
2430
3047
|
});
|
|
3048
|
+
// Run validation on updated ticket unless skipped
|
|
3049
|
+
if (!skipValidation) {
|
|
3050
|
+
// Use the updated values (from args) merged with existing values (from result)
|
|
3051
|
+
// The result should contain the final state after update
|
|
3052
|
+
const validation = validateTicket({
|
|
3053
|
+
complexity: (args.complexity || result.complexity),
|
|
3054
|
+
implementation: (args.implementation || result.implementation),
|
|
3055
|
+
technicalDetails: (args.technicalDetails || result.technicalDetails),
|
|
3056
|
+
notes: (args.notes || result.notes),
|
|
3057
|
+
acceptanceCriteria: (args.acceptanceCriteria || result.acceptanceCriteria),
|
|
3058
|
+
});
|
|
3059
|
+
// Filter warnings by strictness level
|
|
3060
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
3061
|
+
// Add validation results to response
|
|
3062
|
+
result.warnings = warnings;
|
|
3063
|
+
result.completenessScore = validation.completenessScore;
|
|
3064
|
+
if (previousCompletenessScore !== undefined) {
|
|
3065
|
+
result.previousCompletenessScore = previousCompletenessScore;
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
return formatWriteResponse(result, responseMode, 'Ticket updated');
|
|
2431
3069
|
},
|
|
2432
3070
|
update_epic: async (_client, args) => {
|
|
2433
3071
|
validateRequired(args, 'epicId');
|
|
2434
|
-
|
|
3072
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3073
|
+
const result = await apiClient.call('update_epic', {
|
|
2435
3074
|
epicId: args.epicId,
|
|
2436
3075
|
title: args.title,
|
|
2437
3076
|
description: args.description,
|
|
@@ -2454,10 +3093,12 @@ export function createToolHandlers(apiClient) {
|
|
|
2454
3093
|
tags: args.tags,
|
|
2455
3094
|
estimatedHours: args.estimatedHours,
|
|
2456
3095
|
});
|
|
3096
|
+
return formatWriteResponse(result, responseMode, 'Epic updated');
|
|
2457
3097
|
},
|
|
2458
3098
|
update_specification: async (_client, args) => {
|
|
2459
3099
|
validateRequired(args, 'specificationId');
|
|
2460
|
-
|
|
3100
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3101
|
+
const result = await apiClient.call('update_specification', {
|
|
2461
3102
|
specificationId: args.specificationId,
|
|
2462
3103
|
title: args.title,
|
|
2463
3104
|
description: args.description,
|
|
@@ -2488,6 +3129,7 @@ export function createToolHandlers(apiClient) {
|
|
|
2488
3129
|
workingDirectory: args.workingDirectory,
|
|
2489
3130
|
outputDirectory: args.outputDirectory,
|
|
2490
3131
|
});
|
|
3132
|
+
return formatWriteResponse(result, responseMode, 'Specification updated');
|
|
2491
3133
|
},
|
|
2492
3134
|
// ========================================================================
|
|
2493
3135
|
// Working Context Operations
|
|
@@ -2516,34 +3158,6 @@ export function createToolHandlers(apiClient) {
|
|
|
2516
3158
|
config: args.config,
|
|
2517
3159
|
});
|
|
2518
3160
|
},
|
|
2519
|
-
get_session: async (_client, args) => {
|
|
2520
|
-
return await apiClient.call('get_session', {
|
|
2521
|
-
sessionId: args.sessionId,
|
|
2522
|
-
specificationId: args.specificationId,
|
|
2523
|
-
includeHistory: args.includeHistory,
|
|
2524
|
-
});
|
|
2525
|
-
},
|
|
2526
|
-
update_session: async (_client, args) => {
|
|
2527
|
-
validateRequired(args, 'sessionId');
|
|
2528
|
-
return await apiClient.call('update_session', {
|
|
2529
|
-
sessionId: args.sessionId,
|
|
2530
|
-
status: args.status,
|
|
2531
|
-
config: args.config,
|
|
2532
|
-
notes: args.notes,
|
|
2533
|
-
currentTicketId: args.currentTicketId,
|
|
2534
|
-
});
|
|
2535
|
-
},
|
|
2536
|
-
record_session_ticket: async (_client, args) => {
|
|
2537
|
-
validateRequired(args, 'sessionId', 'ticketId', 'result');
|
|
2538
|
-
return await apiClient.call('record_session_ticket', {
|
|
2539
|
-
sessionId: args.sessionId,
|
|
2540
|
-
ticketId: args.ticketId,
|
|
2541
|
-
result: args.result,
|
|
2542
|
-
durationMinutes: args.durationMinutes,
|
|
2543
|
-
errorMessage: args.errorMessage,
|
|
2544
|
-
skipReason: args.skipReason,
|
|
2545
|
-
});
|
|
2546
|
-
},
|
|
2547
3161
|
end_session: async (_client, args) => {
|
|
2548
3162
|
validateRequired(args, 'sessionId', 'status');
|
|
2549
3163
|
return await apiClient.call('end_session', {
|
|
@@ -2552,18 +3166,77 @@ export function createToolHandlers(apiClient) {
|
|
|
2552
3166
|
summary: args.summary,
|
|
2553
3167
|
});
|
|
2554
3168
|
},
|
|
2555
|
-
list_sessions: async (_client, args) => {
|
|
2556
|
-
return await apiClient.call('list_sessions', {
|
|
2557
|
-
specificationId: args.specificationId,
|
|
2558
|
-
projectId: args.projectId,
|
|
2559
|
-
status: args.status,
|
|
2560
|
-
limit: args.limit,
|
|
2561
|
-
offset: args.offset,
|
|
2562
|
-
});
|
|
2563
|
-
},
|
|
2564
3169
|
// ========================================================================
|
|
2565
3170
|
// Bulk Operations
|
|
2566
3171
|
// ========================================================================
|
|
3172
|
+
bulk_create_tickets: async (_client, args) => {
|
|
3173
|
+
validateRequired(args, 'epicId', 'tickets');
|
|
3174
|
+
if (!Array.isArray(args.tickets) || args.tickets.length === 0) {
|
|
3175
|
+
throw new Error('tickets array is required and must not be empty');
|
|
3176
|
+
}
|
|
3177
|
+
// Validate each ticket has a title
|
|
3178
|
+
const tickets = args.tickets;
|
|
3179
|
+
for (let i = 0; i < tickets.length; i++) {
|
|
3180
|
+
if (!tickets[i].title || typeof tickets[i].title !== 'string') {
|
|
3181
|
+
throw new Error(`tickets[${i}].title is required and must be a string`);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
// Validate dependencies if provided
|
|
3185
|
+
if (args.dependencies && Array.isArray(args.dependencies)) {
|
|
3186
|
+
const deps = args.dependencies;
|
|
3187
|
+
for (let i = 0; i < deps.length; i++) {
|
|
3188
|
+
const dep = deps[i];
|
|
3189
|
+
if (typeof dep.ticket !== 'number' || dep.ticket < 0 || dep.ticket >= tickets.length) {
|
|
3190
|
+
throw new Error(`dependencies[${i}].ticket must be a valid index in tickets array (0-${tickets.length - 1})`);
|
|
3191
|
+
}
|
|
3192
|
+
const dependsOn = Array.isArray(dep.dependsOn) ? dep.dependsOn : [dep.dependsOn];
|
|
3193
|
+
for (const idx of dependsOn) {
|
|
3194
|
+
if (typeof idx !== 'number' || idx < 0 || idx >= tickets.length) {
|
|
3195
|
+
throw new Error(`dependencies[${i}].dependsOn contains invalid index ${idx} (must be 0-${tickets.length - 1})`);
|
|
3196
|
+
}
|
|
3197
|
+
if (idx === dep.ticket) {
|
|
3198
|
+
throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
return await apiClient.call('bulk_create_tickets', {
|
|
3204
|
+
epicId: args.epicId,
|
|
3205
|
+
tickets: args.tickets,
|
|
3206
|
+
dependencies: args.dependencies,
|
|
3207
|
+
onError: args.onError,
|
|
3208
|
+
});
|
|
3209
|
+
},
|
|
3210
|
+
get_job_status: async (_client, args) => {
|
|
3211
|
+
validateRequired(args, 'jobId');
|
|
3212
|
+
return await apiClient.call('get_job_status', {
|
|
3213
|
+
jobId: args.jobId,
|
|
3214
|
+
});
|
|
3215
|
+
},
|
|
3216
|
+
bulk_add_dependencies: async (_client, args) => {
|
|
3217
|
+
validateRequired(args, 'dependencies');
|
|
3218
|
+
if (!Array.isArray(args.dependencies) || args.dependencies.length === 0) {
|
|
3219
|
+
throw new Error('dependencies array is required and must not be empty');
|
|
3220
|
+
}
|
|
3221
|
+
// Validate each dependency has required fields
|
|
3222
|
+
const deps = args.dependencies;
|
|
3223
|
+
for (let i = 0; i < deps.length; i++) {
|
|
3224
|
+
if (!deps[i].ticketId || typeof deps[i].ticketId !== 'string') {
|
|
3225
|
+
throw new Error(`dependencies[${i}].ticketId is required`);
|
|
3226
|
+
}
|
|
3227
|
+
if (!deps[i].dependsOnId || typeof deps[i].dependsOnId !== 'string') {
|
|
3228
|
+
throw new Error(`dependencies[${i}].dependsOnId is required`);
|
|
3229
|
+
}
|
|
3230
|
+
if (deps[i].ticketId === deps[i].dependsOnId) {
|
|
3231
|
+
throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
return await apiClient.call('bulk_add_dependencies', {
|
|
3235
|
+
dependencies: args.dependencies,
|
|
3236
|
+
skipCircularCheck: args.skipCircularCheck,
|
|
3237
|
+
onError: args.onError,
|
|
3238
|
+
});
|
|
3239
|
+
},
|
|
2567
3240
|
bulk_update_tickets: async (_client, args) => {
|
|
2568
3241
|
if (!args.updates || !Array.isArray(args.updates) || args.updates.length === 0) {
|
|
2569
3242
|
throw new Error('updates array is required and must not be empty');
|
|
@@ -2589,6 +3262,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2589
3262
|
clearTestResults: args.clearTestResults,
|
|
2590
3263
|
});
|
|
2591
3264
|
},
|
|
3265
|
+
// ========================================================================
|
|
3266
|
+
// Validation Operations (MCI-075)
|
|
3267
|
+
// ========================================================================
|
|
3268
|
+
validate_counts: async (_client, args) => {
|
|
3269
|
+
// Must specify at least one scope
|
|
3270
|
+
if (!args.projectId && !args.specificationId && !args.epicId) {
|
|
3271
|
+
throw new Error('Must specify projectId, specificationId, or epicId');
|
|
3272
|
+
}
|
|
3273
|
+
return await apiClient.call('validate_counts', {
|
|
3274
|
+
projectId: args.projectId,
|
|
3275
|
+
specificationId: args.specificationId,
|
|
3276
|
+
epicId: args.epicId,
|
|
3277
|
+
repair: args.repair,
|
|
3278
|
+
verbose: args.verbose,
|
|
3279
|
+
});
|
|
3280
|
+
},
|
|
2592
3281
|
};
|
|
2593
3282
|
}
|
|
2594
3283
|
/**
|