@specforge/mcp 1.5.3 → 1.6.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 +1477 -70
- 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,91 @@ 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
|
+
'get_specification_status',
|
|
52
|
+
// Epic operations
|
|
53
|
+
'list_epics',
|
|
54
|
+
'get_epic',
|
|
55
|
+
'lookup_epic',
|
|
56
|
+
'get_epic_status',
|
|
57
|
+
// Ticket operations
|
|
58
|
+
'list_tickets',
|
|
59
|
+
'get_ticket',
|
|
60
|
+
'lookup_ticket',
|
|
61
|
+
'lookup_tickets_by_status',
|
|
62
|
+
'get_ticket_dependencies',
|
|
63
|
+
'get_ticket_test_status',
|
|
64
|
+
// Dependency operations
|
|
65
|
+
'get_dependency_tree',
|
|
66
|
+
// Context operations
|
|
67
|
+
'get_implementation_context',
|
|
68
|
+
'get_next_actionable_tickets',
|
|
69
|
+
'get_blocked_tickets',
|
|
70
|
+
'get_critical_path',
|
|
71
|
+
'get_patterns',
|
|
72
|
+
// Workflow read operations
|
|
73
|
+
'get_work_summary',
|
|
74
|
+
// Discovery read operations
|
|
75
|
+
'get_pending_discoveries',
|
|
76
|
+
// Status & Analytics
|
|
77
|
+
'get_implementation_summary',
|
|
78
|
+
'get_time_report',
|
|
79
|
+
'get_blockers_report',
|
|
80
|
+
// Search operations
|
|
81
|
+
'search_tickets',
|
|
82
|
+
'find_tickets_by_file',
|
|
83
|
+
'find_tickets_by_tag',
|
|
84
|
+
'find_related_tickets',
|
|
85
|
+
// Git read operations
|
|
86
|
+
'get_ticket_commits',
|
|
87
|
+
'get_ticket_prs',
|
|
88
|
+
// Working context
|
|
89
|
+
'get_working_context',
|
|
90
|
+
// Session read operations
|
|
91
|
+
'get_session',
|
|
92
|
+
'list_sessions',
|
|
93
|
+
// Job status
|
|
94
|
+
'get_job_status',
|
|
95
|
+
]);
|
|
96
|
+
/**
|
|
97
|
+
* Add format parameter to a tool's input schema
|
|
98
|
+
*/
|
|
99
|
+
function addFormatParameter(tool) {
|
|
100
|
+
return {
|
|
101
|
+
...tool,
|
|
102
|
+
inputSchema: {
|
|
103
|
+
...tool.inputSchema,
|
|
104
|
+
properties: {
|
|
105
|
+
...tool.inputSchema.properties,
|
|
106
|
+
format: FORMAT_PARAMETER,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
26
111
|
export function getTools() {
|
|
27
|
-
|
|
112
|
+
const tools = [
|
|
28
113
|
// ========================================================================
|
|
29
114
|
// Core Operations - Projects (Epic 3)
|
|
30
115
|
// ========================================================================
|
|
@@ -51,12 +136,26 @@ export function getTools() {
|
|
|
51
136
|
required: ['projectId'],
|
|
52
137
|
},
|
|
53
138
|
},
|
|
139
|
+
{
|
|
140
|
+
name: 'lookup_project',
|
|
141
|
+
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.',
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
name: {
|
|
146
|
+
type: 'string',
|
|
147
|
+
description: 'Project name to search for (partial match, case-insensitive)',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
required: ['name'],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
54
153
|
// ========================================================================
|
|
55
154
|
// Core Operations - Specifications (Epic 3)
|
|
56
155
|
// ========================================================================
|
|
57
156
|
{
|
|
58
157
|
name: 'list_specifications',
|
|
59
|
-
description: 'List specifications for a project with optional status
|
|
158
|
+
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
159
|
inputSchema: {
|
|
61
160
|
type: 'object',
|
|
62
161
|
properties: {
|
|
@@ -72,13 +171,60 @@ export function getTools() {
|
|
|
72
171
|
},
|
|
73
172
|
description: 'Filter by status (optional)',
|
|
74
173
|
},
|
|
174
|
+
limit: {
|
|
175
|
+
type: 'integer',
|
|
176
|
+
minimum: 1,
|
|
177
|
+
maximum: 100,
|
|
178
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
179
|
+
},
|
|
180
|
+
offset: {
|
|
181
|
+
type: 'integer',
|
|
182
|
+
minimum: 0,
|
|
183
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
184
|
+
},
|
|
185
|
+
fields: {
|
|
186
|
+
type: 'array',
|
|
187
|
+
items: {
|
|
188
|
+
type: 'string',
|
|
189
|
+
enum: [
|
|
190
|
+
'id',
|
|
191
|
+
'projectId',
|
|
192
|
+
'title',
|
|
193
|
+
'description',
|
|
194
|
+
'background',
|
|
195
|
+
'status',
|
|
196
|
+
'priority',
|
|
197
|
+
'estimatedHours',
|
|
198
|
+
'goals',
|
|
199
|
+
'requirements',
|
|
200
|
+
'constraints',
|
|
201
|
+
'guardrails',
|
|
202
|
+
'techStack',
|
|
203
|
+
'architecture',
|
|
204
|
+
'fileStructure',
|
|
205
|
+
'epicCount',
|
|
206
|
+
'ticketCount',
|
|
207
|
+
'completedTicketCount',
|
|
208
|
+
'createdAt',
|
|
209
|
+
'updatedAt',
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "title", "status"] for minimal response.',
|
|
213
|
+
},
|
|
75
214
|
},
|
|
76
215
|
required: ['projectId'],
|
|
77
216
|
},
|
|
78
217
|
},
|
|
79
218
|
{
|
|
80
219
|
name: 'get_specification',
|
|
81
|
-
description:
|
|
220
|
+
description: `Get specification with optional summary mode or full details.
|
|
221
|
+
|
|
222
|
+
Use summary: true for minimal response (~70 tokens) with key fields only (id, title, status, priority, epicCount, ticketCount, completedTicketCount).
|
|
223
|
+
|
|
224
|
+
Optional includes (ignored when summary=true):
|
|
225
|
+
- 'status': Progress, ticket counts, blockers (replaces get_specification_status)
|
|
226
|
+
- 'epics': List of epics with summary data
|
|
227
|
+
- 'patterns': Tech stack, code patterns, naming conventions`,
|
|
82
228
|
inputSchema: {
|
|
83
229
|
type: 'object',
|
|
84
230
|
properties: {
|
|
@@ -86,16 +232,47 @@ export function getTools() {
|
|
|
86
232
|
type: 'string',
|
|
87
233
|
description: 'The ID of the specification to retrieve',
|
|
88
234
|
},
|
|
235
|
+
summary: {
|
|
236
|
+
type: 'boolean',
|
|
237
|
+
description: 'Return minimal summary fields only (~70 tokens vs ~600 full). Ignores include parameter when true. Default: false',
|
|
238
|
+
default: false,
|
|
239
|
+
},
|
|
240
|
+
include: {
|
|
241
|
+
type: 'array',
|
|
242
|
+
items: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
enum: ['status', 'epics', 'patterns'],
|
|
245
|
+
},
|
|
246
|
+
description: 'Optional data to include in response (ignored when summary=true)',
|
|
247
|
+
},
|
|
89
248
|
},
|
|
90
249
|
required: ['specificationId'],
|
|
91
250
|
},
|
|
92
251
|
},
|
|
252
|
+
{
|
|
253
|
+
name: 'lookup_specification',
|
|
254
|
+
description: 'Fast specification lookup by title. Returns minimal data (id, title, status, epicCount, ticketCount) for token efficiency.',
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
projectId: {
|
|
259
|
+
type: 'string',
|
|
260
|
+
description: 'Project ID to search within',
|
|
261
|
+
},
|
|
262
|
+
title: {
|
|
263
|
+
type: 'string',
|
|
264
|
+
description: 'Specification title to search for (partial match, case-insensitive)',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
required: ['projectId', 'title'],
|
|
268
|
+
},
|
|
269
|
+
},
|
|
93
270
|
// ========================================================================
|
|
94
271
|
// Core Operations - Epics (Epic 3)
|
|
95
272
|
// ========================================================================
|
|
96
273
|
{
|
|
97
274
|
name: 'list_epics',
|
|
98
|
-
description: 'List epics for a specification with optional status
|
|
275
|
+
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
276
|
inputSchema: {
|
|
100
277
|
type: 'object',
|
|
101
278
|
properties: {
|
|
@@ -108,13 +285,56 @@ export function getTools() {
|
|
|
108
285
|
enum: ['todo', 'in_progress', 'completed'],
|
|
109
286
|
description: 'Filter by status (optional)',
|
|
110
287
|
},
|
|
288
|
+
limit: {
|
|
289
|
+
type: 'integer',
|
|
290
|
+
minimum: 1,
|
|
291
|
+
maximum: 100,
|
|
292
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
293
|
+
},
|
|
294
|
+
offset: {
|
|
295
|
+
type: 'integer',
|
|
296
|
+
minimum: 0,
|
|
297
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
298
|
+
},
|
|
299
|
+
fields: {
|
|
300
|
+
type: 'array',
|
|
301
|
+
items: {
|
|
302
|
+
type: 'string',
|
|
303
|
+
enum: [
|
|
304
|
+
'id',
|
|
305
|
+
'specificationId',
|
|
306
|
+
'epicNumber',
|
|
307
|
+
'title',
|
|
308
|
+
'description',
|
|
309
|
+
'objective',
|
|
310
|
+
'status',
|
|
311
|
+
'priority',
|
|
312
|
+
'estimatedHours',
|
|
313
|
+
'acceptanceCriteria',
|
|
314
|
+
'scope',
|
|
315
|
+
'constraints',
|
|
316
|
+
'assumptions',
|
|
317
|
+
'ticketCount',
|
|
318
|
+
'completedTicketCount',
|
|
319
|
+
'createdAt',
|
|
320
|
+
'updatedAt',
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "epicNumber", "title", "status"] for minimal response.',
|
|
324
|
+
},
|
|
111
325
|
},
|
|
112
326
|
required: ['specificationId'],
|
|
113
327
|
},
|
|
114
328
|
},
|
|
115
329
|
{
|
|
116
330
|
name: 'get_epic',
|
|
117
|
-
description:
|
|
331
|
+
description: `Get epic with optional summary mode or full details.
|
|
332
|
+
|
|
333
|
+
Use summary: true for minimal response (~80 tokens) with key fields only (id, epicNumber, title, status, objective, ticketCount, completedTicketCount).
|
|
334
|
+
|
|
335
|
+
Optional includes (ignored when summary=true):
|
|
336
|
+
- 'status': Progress percentage, ticket counts, active tickets (replaces get_epic_status)
|
|
337
|
+
- 'tickets': List of tickets with summary data`,
|
|
118
338
|
inputSchema: {
|
|
119
339
|
type: 'object',
|
|
120
340
|
properties: {
|
|
@@ -122,16 +342,51 @@ export function getTools() {
|
|
|
122
342
|
type: 'string',
|
|
123
343
|
description: 'The ID of the epic to retrieve',
|
|
124
344
|
},
|
|
345
|
+
summary: {
|
|
346
|
+
type: 'boolean',
|
|
347
|
+
description: 'Return minimal summary fields only (~80 tokens vs ~400 full). Ignores include parameter when true. Default: false',
|
|
348
|
+
default: false,
|
|
349
|
+
},
|
|
350
|
+
include: {
|
|
351
|
+
type: 'array',
|
|
352
|
+
items: {
|
|
353
|
+
type: 'string',
|
|
354
|
+
enum: ['status', 'tickets'],
|
|
355
|
+
},
|
|
356
|
+
description: 'Optional data to include in response (ignored when summary=true)',
|
|
357
|
+
},
|
|
125
358
|
},
|
|
126
359
|
required: ['epicId'],
|
|
127
360
|
},
|
|
128
361
|
},
|
|
362
|
+
{
|
|
363
|
+
name: 'lookup_epic',
|
|
364
|
+
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.",
|
|
365
|
+
inputSchema: {
|
|
366
|
+
type: 'object',
|
|
367
|
+
properties: {
|
|
368
|
+
specificationId: {
|
|
369
|
+
type: 'string',
|
|
370
|
+
description: 'Specification ID to search within',
|
|
371
|
+
},
|
|
372
|
+
number: {
|
|
373
|
+
type: 'integer',
|
|
374
|
+
description: 'Epic number for exact match lookup',
|
|
375
|
+
},
|
|
376
|
+
title: {
|
|
377
|
+
type: 'string',
|
|
378
|
+
description: 'Epic title for partial match lookup',
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
required: ['specificationId'],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
129
384
|
// ========================================================================
|
|
130
385
|
// Core Operations - Tickets (Epic 3)
|
|
131
386
|
// ========================================================================
|
|
132
387
|
{
|
|
133
388
|
name: 'list_tickets',
|
|
134
|
-
description: 'List tickets for an epic with optional status
|
|
389
|
+
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
390
|
inputSchema: {
|
|
136
391
|
type: 'object',
|
|
137
392
|
properties: {
|
|
@@ -143,9 +398,60 @@ export function getTools() {
|
|
|
143
398
|
type: 'array',
|
|
144
399
|
items: {
|
|
145
400
|
type: 'string',
|
|
146
|
-
enum: ['
|
|
401
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
147
402
|
},
|
|
148
|
-
description: 'Filter by status (optional)',
|
|
403
|
+
description: 'Filter by status (optional). pending/ready are auto-calculated based on dependencies.',
|
|
404
|
+
},
|
|
405
|
+
limit: {
|
|
406
|
+
type: 'integer',
|
|
407
|
+
minimum: 1,
|
|
408
|
+
maximum: 100,
|
|
409
|
+
description: 'Maximum number of items to return (default: 20, max: 100)',
|
|
410
|
+
},
|
|
411
|
+
offset: {
|
|
412
|
+
type: 'integer',
|
|
413
|
+
minimum: 0,
|
|
414
|
+
description: 'Number of items to skip for offset-based pagination (default: 0)',
|
|
415
|
+
},
|
|
416
|
+
include: {
|
|
417
|
+
type: 'array',
|
|
418
|
+
items: {
|
|
419
|
+
type: 'string',
|
|
420
|
+
enum: ['statusReason'],
|
|
421
|
+
},
|
|
422
|
+
description: 'Include statusReason for pending tickets (shows unsatisfied dependencies or block reasons)',
|
|
423
|
+
},
|
|
424
|
+
fields: {
|
|
425
|
+
type: 'array',
|
|
426
|
+
items: {
|
|
427
|
+
type: 'string',
|
|
428
|
+
enum: [
|
|
429
|
+
'id',
|
|
430
|
+
'epicId',
|
|
431
|
+
'ticketNumber',
|
|
432
|
+
'title',
|
|
433
|
+
'description',
|
|
434
|
+
'status',
|
|
435
|
+
'priority',
|
|
436
|
+
'complexity',
|
|
437
|
+
'estimatedHours',
|
|
438
|
+
'actualHours',
|
|
439
|
+
'acceptanceCriteria',
|
|
440
|
+
'implementation',
|
|
441
|
+
'technicalDetails',
|
|
442
|
+
'notes',
|
|
443
|
+
'tags',
|
|
444
|
+
'blockReason',
|
|
445
|
+
'progress',
|
|
446
|
+
'testsPassed',
|
|
447
|
+
'order',
|
|
448
|
+
'startedAt',
|
|
449
|
+
'completedAt',
|
|
450
|
+
'createdAt',
|
|
451
|
+
'updatedAt',
|
|
452
|
+
],
|
|
453
|
+
},
|
|
454
|
+
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
455
|
},
|
|
150
456
|
},
|
|
151
457
|
required: ['epicId'],
|
|
@@ -153,7 +459,18 @@ export function getTools() {
|
|
|
153
459
|
},
|
|
154
460
|
{
|
|
155
461
|
name: 'get_ticket',
|
|
156
|
-
description:
|
|
462
|
+
description: `Get ticket with optional summary mode or full details.
|
|
463
|
+
|
|
464
|
+
Use summary: true for minimal response (~100 tokens) with key fields only (id, ticketNumber, title, status, complexity, estimatedHours, priority).
|
|
465
|
+
|
|
466
|
+
For full details, statusReason is auto-included for pending tickets explaining why the ticket is blocked.
|
|
467
|
+
|
|
468
|
+
Optional includes (ignored when summary=true):
|
|
469
|
+
- 'dependencies': Tickets this blocks and is blocked by (replaces get_ticket_dependencies)
|
|
470
|
+
- 'testStatus': Test results and history (replaces get_ticket_test_status)
|
|
471
|
+
- 'commits': Linked git commits (replaces get_ticket_commits)
|
|
472
|
+
- 'prs': Linked pull requests (replaces get_ticket_prs)
|
|
473
|
+
- 'statusReason': Why ticket is pending (auto-included for pending tickets)`,
|
|
157
474
|
inputSchema: {
|
|
158
475
|
type: 'object',
|
|
159
476
|
properties: {
|
|
@@ -161,10 +478,61 @@ export function getTools() {
|
|
|
161
478
|
type: 'string',
|
|
162
479
|
description: 'The ID of the ticket to retrieve',
|
|
163
480
|
},
|
|
481
|
+
summary: {
|
|
482
|
+
type: 'boolean',
|
|
483
|
+
description: 'Return minimal summary fields only (~100 tokens vs ~500 full). Ignores include parameter when true. Default: false',
|
|
484
|
+
default: false,
|
|
485
|
+
},
|
|
486
|
+
include: {
|
|
487
|
+
type: 'array',
|
|
488
|
+
items: {
|
|
489
|
+
type: 'string',
|
|
490
|
+
enum: ['dependencies', 'testStatus', 'commits', 'prs', 'statusReason'],
|
|
491
|
+
},
|
|
492
|
+
description: 'Additional data to include (ignored when summary=true). statusReason is auto-included for pending tickets.',
|
|
493
|
+
},
|
|
164
494
|
},
|
|
165
495
|
required: ['ticketId'],
|
|
166
496
|
},
|
|
167
497
|
},
|
|
498
|
+
{
|
|
499
|
+
name: 'lookup_ticket',
|
|
500
|
+
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.",
|
|
501
|
+
inputSchema: {
|
|
502
|
+
type: 'object',
|
|
503
|
+
properties: {
|
|
504
|
+
epicId: {
|
|
505
|
+
type: 'string',
|
|
506
|
+
description: 'Epic ID to search within',
|
|
507
|
+
},
|
|
508
|
+
number: {
|
|
509
|
+
type: 'integer',
|
|
510
|
+
description: 'Ticket number for exact match lookup',
|
|
511
|
+
},
|
|
512
|
+
title: {
|
|
513
|
+
type: 'string',
|
|
514
|
+
description: 'Ticket title for partial match lookup',
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
required: ['epicId'],
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
name: 'lookup_tickets_by_status',
|
|
522
|
+
description: 'Batch lookup of ticket statuses. Optimized for checking if dependencies are satisfied. Returns minimal data (id, status, title) for up to 50 tickets.',
|
|
523
|
+
inputSchema: {
|
|
524
|
+
type: 'object',
|
|
525
|
+
properties: {
|
|
526
|
+
ticketIds: {
|
|
527
|
+
type: 'array',
|
|
528
|
+
items: { type: 'string' },
|
|
529
|
+
maxItems: 50,
|
|
530
|
+
description: 'Array of ticket IDs to lookup (max 50)',
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
required: ['ticketIds'],
|
|
534
|
+
},
|
|
535
|
+
},
|
|
168
536
|
// ========================================================================
|
|
169
537
|
// Core Operations - Dependencies (Epic 3)
|
|
170
538
|
// ========================================================================
|
|
@@ -245,7 +613,7 @@ export function getTools() {
|
|
|
245
613
|
// ========================================================================
|
|
246
614
|
{
|
|
247
615
|
name: 'get_implementation_context',
|
|
248
|
-
description: 'Get
|
|
616
|
+
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
617
|
inputSchema: {
|
|
250
618
|
type: 'object',
|
|
251
619
|
properties: {
|
|
@@ -253,13 +621,19 @@ export function getTools() {
|
|
|
253
621
|
type: 'string',
|
|
254
622
|
description: 'The ID of the ticket',
|
|
255
623
|
},
|
|
624
|
+
depth: {
|
|
625
|
+
type: 'string',
|
|
626
|
+
enum: ['minimal', 'standard', 'full'],
|
|
627
|
+
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',
|
|
628
|
+
default: 'standard',
|
|
629
|
+
},
|
|
256
630
|
},
|
|
257
631
|
required: ['ticketId'],
|
|
258
632
|
},
|
|
259
633
|
},
|
|
260
634
|
{
|
|
261
635
|
name: 'get_next_actionable_tickets',
|
|
262
|
-
description: 'Get tickets
|
|
636
|
+
description: 'Get tickets with status "ready" (all dependencies satisfied). Use start_work_session() to begin work on these tickets.',
|
|
263
637
|
inputSchema: {
|
|
264
638
|
type: 'object',
|
|
265
639
|
properties: {
|
|
@@ -280,7 +654,7 @@ export function getTools() {
|
|
|
280
654
|
},
|
|
281
655
|
{
|
|
282
656
|
name: 'get_blocked_tickets',
|
|
283
|
-
description: 'Get tickets
|
|
657
|
+
description: 'Get tickets with status "pending" and their statusReason explaining why they are blocked (unsatisfied dependencies or external block)',
|
|
284
658
|
inputSchema: {
|
|
285
659
|
type: 'object',
|
|
286
660
|
properties: {
|
|
@@ -308,16 +682,19 @@ export function getTools() {
|
|
|
308
682
|
},
|
|
309
683
|
{
|
|
310
684
|
name: 'get_patterns',
|
|
311
|
-
description: '
|
|
685
|
+
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
686
|
inputSchema: {
|
|
313
687
|
type: 'object',
|
|
314
688
|
properties: {
|
|
315
689
|
specificationId: {
|
|
316
690
|
type: 'string',
|
|
317
|
-
description: '
|
|
691
|
+
description: 'Get patterns for entire specification (raw spec patterns only)',
|
|
692
|
+
},
|
|
693
|
+
ticketId: {
|
|
694
|
+
type: 'string',
|
|
695
|
+
description: 'Get resolved patterns for a specific ticket with inheritance chain and override analysis',
|
|
318
696
|
},
|
|
319
697
|
},
|
|
320
|
-
required: ['specificationId'],
|
|
321
698
|
},
|
|
322
699
|
},
|
|
323
700
|
// ========================================================================
|
|
@@ -325,7 +702,7 @@ export function getTools() {
|
|
|
325
702
|
// ========================================================================
|
|
326
703
|
{
|
|
327
704
|
name: 'start_work_session',
|
|
328
|
-
description: 'Start working on a ticket
|
|
705
|
+
description: 'Start working on a ticket. Transitions ready -> active. Returns error with statusReason if ticket is pending (dependencies not met).',
|
|
329
706
|
inputSchema: {
|
|
330
707
|
type: 'object',
|
|
331
708
|
properties: {
|
|
@@ -339,7 +716,15 @@ export function getTools() {
|
|
|
339
716
|
},
|
|
340
717
|
{
|
|
341
718
|
name: 'complete_work_session',
|
|
342
|
-
description: 'Mark a ticket as complete
|
|
719
|
+
description: 'Mark a ticket as complete. Transitions active -> done.\n\n' +
|
|
720
|
+
'Automatically recalculates status for dependent tickets and returns cascade info.\n\n' +
|
|
721
|
+
'By default, checks if summary addresses acceptance criteria and returns warnings (not errors) for gaps.\n\n' +
|
|
722
|
+
'Use validated: true as a simple confirmation that the agent has verified all work meets criteria.\n\n' +
|
|
723
|
+
'Optional validation flags can be provided to report test results inline:\n' +
|
|
724
|
+
'- tests: Unit/integration test results\n' +
|
|
725
|
+
'- lint: Linting results\n' +
|
|
726
|
+
'- typeCheck: TypeScript type checking\n' +
|
|
727
|
+
'- build: Build/compilation results',
|
|
343
728
|
inputSchema: {
|
|
344
729
|
type: 'object',
|
|
345
730
|
properties: {
|
|
@@ -365,6 +750,48 @@ export function getTools() {
|
|
|
365
750
|
type: 'number',
|
|
366
751
|
description: 'Actual hours spent on the ticket',
|
|
367
752
|
},
|
|
753
|
+
validated: {
|
|
754
|
+
type: 'boolean',
|
|
755
|
+
description: 'Simple validation confirmation. When true, indicates:\n' +
|
|
756
|
+
'- Agent has verified work meets acceptance criteria\n' +
|
|
757
|
+
'- All necessary tests/validations were run and passed\n' +
|
|
758
|
+
'- No detailed breakdown needed\n' +
|
|
759
|
+
'Trust-based approach for streamlined completion.',
|
|
760
|
+
},
|
|
761
|
+
validation: {
|
|
762
|
+
type: 'object',
|
|
763
|
+
description: 'Detailed validation flags (optional with validated: true)',
|
|
764
|
+
properties: {
|
|
765
|
+
tests: {
|
|
766
|
+
type: 'string',
|
|
767
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
768
|
+
description: 'Unit/integration test results',
|
|
769
|
+
},
|
|
770
|
+
lint: {
|
|
771
|
+
type: 'string',
|
|
772
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
773
|
+
description: 'Linting results',
|
|
774
|
+
},
|
|
775
|
+
typeCheck: {
|
|
776
|
+
type: 'string',
|
|
777
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
778
|
+
description: 'TypeScript type checking results',
|
|
779
|
+
},
|
|
780
|
+
build: {
|
|
781
|
+
type: 'string',
|
|
782
|
+
enum: ['passed', 'failed', 'skipped', 'na'],
|
|
783
|
+
description: 'Build/compilation results',
|
|
784
|
+
},
|
|
785
|
+
notes: {
|
|
786
|
+
type: 'string',
|
|
787
|
+
description: 'Additional validation notes',
|
|
788
|
+
},
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
skipCriteriaCheck: {
|
|
792
|
+
type: 'boolean',
|
|
793
|
+
description: 'Skip acceptance criteria validation. Use for trivial changes or when criteria check is not needed. Default: false',
|
|
794
|
+
},
|
|
368
795
|
},
|
|
369
796
|
required: ['ticketId', 'summary'],
|
|
370
797
|
},
|
|
@@ -395,7 +822,7 @@ export function getTools() {
|
|
|
395
822
|
},
|
|
396
823
|
{
|
|
397
824
|
name: 'get_work_summary',
|
|
398
|
-
description: 'Get summary of completed work with optional scope filtering',
|
|
825
|
+
description: '[DEPRECATED: Use get_report with type="work"] Get summary of completed work with optional scope filtering',
|
|
399
826
|
inputSchema: {
|
|
400
827
|
type: 'object',
|
|
401
828
|
properties: {
|
|
@@ -425,7 +852,7 @@ export function getTools() {
|
|
|
425
852
|
// ========================================================================
|
|
426
853
|
{
|
|
427
854
|
name: 'report_test_results',
|
|
428
|
-
description: 'Report test results for a ticket',
|
|
855
|
+
description: '[DEPRECATED] Report test results for a ticket. Use complete_work_session({ validation: { tests: "passed", ... } }) instead. Will be removed in v3.0.',
|
|
429
856
|
inputSchema: {
|
|
430
857
|
type: 'object',
|
|
431
858
|
properties: {
|
|
@@ -480,7 +907,7 @@ export function getTools() {
|
|
|
480
907
|
},
|
|
481
908
|
{
|
|
482
909
|
name: 'get_ticket_test_status',
|
|
483
|
-
description:
|
|
910
|
+
description: "[DEPRECATED] Get test status and history for a ticket. Use get_ticket({ include: ['testStatus'] }) instead. Will be removed in v3.0.",
|
|
484
911
|
inputSchema: {
|
|
485
912
|
type: 'object',
|
|
486
913
|
properties: {
|
|
@@ -494,7 +921,7 @@ export function getTools() {
|
|
|
494
921
|
},
|
|
495
922
|
{
|
|
496
923
|
name: 'validate_ticket_completion',
|
|
497
|
-
description: 'Validate that a ticket is ready to be marked complete',
|
|
924
|
+
description: '[DEPRECATED] Validate that a ticket is ready to be marked complete. Validation is now built into complete_work_session(). Will be removed in v3.0.',
|
|
498
925
|
inputSchema: {
|
|
499
926
|
type: 'object',
|
|
500
927
|
properties: {
|
|
@@ -507,11 +934,11 @@ export function getTools() {
|
|
|
507
934
|
},
|
|
508
935
|
},
|
|
509
936
|
// ========================================================================
|
|
510
|
-
// Discovery Tools (Epic 7)
|
|
937
|
+
// Discovery Tools (Epic 7) - DEPRECATED: Use tag-based ticket operations instead
|
|
511
938
|
// ========================================================================
|
|
512
939
|
{
|
|
513
940
|
name: 'report_discovery',
|
|
514
|
-
description: 'Report a discovery (new requirement, bug, or improvement) found during implementation',
|
|
941
|
+
description: '[DEPRECATED: Use create_ticket with tags: ["discovery", "discovery:<type>"] instead] Report a discovery (new requirement, bug, or improvement) found during implementation',
|
|
515
942
|
inputSchema: {
|
|
516
943
|
type: 'object',
|
|
517
944
|
properties: {
|
|
@@ -543,7 +970,7 @@ export function getTools() {
|
|
|
543
970
|
},
|
|
544
971
|
{
|
|
545
972
|
name: 'get_pending_discoveries',
|
|
546
|
-
description: 'Get pending discoveries that need resolution',
|
|
973
|
+
description: '[DEPRECATED: Use search_tickets with tags: ["discovery"] and status filter instead] Get pending discoveries that need resolution',
|
|
547
974
|
inputSchema: {
|
|
548
975
|
type: 'object',
|
|
549
976
|
properties: {
|
|
@@ -561,7 +988,7 @@ export function getTools() {
|
|
|
561
988
|
},
|
|
562
989
|
{
|
|
563
990
|
name: 'resolve_discovery',
|
|
564
|
-
description: 'Resolve a discovery as created (new ticket) or dismissed',
|
|
991
|
+
description: '[DEPRECATED: Use update_ticket to mark done or remove discovery tag instead] Resolve a discovery as created (new ticket) or dismissed',
|
|
565
992
|
inputSchema: {
|
|
566
993
|
type: 'object',
|
|
567
994
|
properties: {
|
|
@@ -617,9 +1044,56 @@ export function getTools() {
|
|
|
617
1044
|
required: ['epicId'],
|
|
618
1045
|
},
|
|
619
1046
|
},
|
|
1047
|
+
{
|
|
1048
|
+
name: 'get_report',
|
|
1049
|
+
description: `Generate unified reports for implementation, time tracking, blockers, or work summary.
|
|
1050
|
+
|
|
1051
|
+
Report types:
|
|
1052
|
+
- 'implementation': Progress, velocity, completions (replaces get_implementation_summary)
|
|
1053
|
+
- 'time': Estimated vs actual hours (replaces get_time_report)
|
|
1054
|
+
- 'blockers': Blocked tickets with reasons (replaces get_blockers_report)
|
|
1055
|
+
- 'work': Completed work summary (replaces get_work_summary)
|
|
1056
|
+
|
|
1057
|
+
Format options:
|
|
1058
|
+
- 'json': Full structured data (default)
|
|
1059
|
+
- 'summary': Condensed text summary`,
|
|
1060
|
+
inputSchema: {
|
|
1061
|
+
type: 'object',
|
|
1062
|
+
properties: {
|
|
1063
|
+
type: {
|
|
1064
|
+
type: 'string',
|
|
1065
|
+
enum: ['implementation', 'time', 'blockers', 'work'],
|
|
1066
|
+
description: 'Type of report to generate',
|
|
1067
|
+
},
|
|
1068
|
+
scope: {
|
|
1069
|
+
type: 'string',
|
|
1070
|
+
enum: ['project', 'specification', 'epic'],
|
|
1071
|
+
description: 'Scope of the report',
|
|
1072
|
+
},
|
|
1073
|
+
scopeId: {
|
|
1074
|
+
type: 'string',
|
|
1075
|
+
description: 'ID of the scoped entity (projectId, specificationId, or epicId)',
|
|
1076
|
+
},
|
|
1077
|
+
format: {
|
|
1078
|
+
type: 'string',
|
|
1079
|
+
enum: ['json', 'toon', 'summary'],
|
|
1080
|
+
description: 'Output format: json (full structured), toon (~44% smaller), summary (key metrics only ~70% smaller). Default: json',
|
|
1081
|
+
},
|
|
1082
|
+
startDate: {
|
|
1083
|
+
type: 'string',
|
|
1084
|
+
description: 'Start date for work report (ISO 8601)',
|
|
1085
|
+
},
|
|
1086
|
+
endDate: {
|
|
1087
|
+
type: 'string',
|
|
1088
|
+
description: 'End date for work report (ISO 8601)',
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
required: ['type', 'scope', 'scopeId'],
|
|
1092
|
+
},
|
|
1093
|
+
},
|
|
620
1094
|
{
|
|
621
1095
|
name: 'get_implementation_summary',
|
|
622
|
-
description: 'Get cross-specification implementation summary with velocity metrics',
|
|
1096
|
+
description: '[DEPRECATED: Use get_report with type="implementation"] Get cross-specification implementation summary with velocity metrics',
|
|
623
1097
|
inputSchema: {
|
|
624
1098
|
type: 'object',
|
|
625
1099
|
properties: {
|
|
@@ -633,7 +1107,7 @@ export function getTools() {
|
|
|
633
1107
|
},
|
|
634
1108
|
{
|
|
635
1109
|
name: 'get_time_report',
|
|
636
|
-
description: 'Get time tracking report with estimated vs actual analysis',
|
|
1110
|
+
description: '[DEPRECATED: Use get_report with type="time"] Get time tracking report with estimated vs actual analysis',
|
|
637
1111
|
inputSchema: {
|
|
638
1112
|
type: 'object',
|
|
639
1113
|
properties: {
|
|
@@ -652,7 +1126,7 @@ export function getTools() {
|
|
|
652
1126
|
},
|
|
653
1127
|
{
|
|
654
1128
|
name: 'get_blockers_report',
|
|
655
|
-
description: 'Get report of all blockers with duration and grouping',
|
|
1129
|
+
description: '[DEPRECATED: Use get_report with type="blockers"] Get report of all blockers with duration and grouping',
|
|
656
1130
|
inputSchema: {
|
|
657
1131
|
type: 'object',
|
|
658
1132
|
properties: {
|
|
@@ -673,37 +1147,124 @@ export function getTools() {
|
|
|
673
1147
|
// ========================================================================
|
|
674
1148
|
{
|
|
675
1149
|
name: 'search_tickets',
|
|
676
|
-
description:
|
|
1150
|
+
description: `Unified ticket search with multiple filter options.
|
|
1151
|
+
|
|
1152
|
+
Combines:
|
|
1153
|
+
- Full-text search (query)
|
|
1154
|
+
- File matching (files) - replaces find_tickets_by_file
|
|
1155
|
+
- Tag filtering (tags) - replaces find_tickets_by_tag
|
|
1156
|
+
- Related tickets (relatedTo) - replaces find_related_tickets
|
|
1157
|
+
- Status, complexity, priority filters
|
|
1158
|
+
|
|
1159
|
+
At least one of: query, files, tags, or relatedTo is required.
|
|
1160
|
+
At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
677
1161
|
inputSchema: {
|
|
678
1162
|
type: 'object',
|
|
679
1163
|
properties: {
|
|
680
1164
|
query: {
|
|
681
1165
|
type: 'string',
|
|
682
|
-
description: '
|
|
1166
|
+
description: 'Full-text search query',
|
|
683
1167
|
},
|
|
684
|
-
|
|
1168
|
+
files: {
|
|
1169
|
+
type: 'array',
|
|
1170
|
+
items: { type: 'string' },
|
|
1171
|
+
description: 'Glob patterns to match ticket files (e.g., "**/channel/*.ts")',
|
|
1172
|
+
},
|
|
1173
|
+
tags: {
|
|
1174
|
+
type: 'array',
|
|
1175
|
+
items: { type: 'string' },
|
|
1176
|
+
description: 'Tags to filter by',
|
|
1177
|
+
},
|
|
1178
|
+
matchAllTags: {
|
|
1179
|
+
type: 'boolean',
|
|
1180
|
+
description: 'If true, match all tags (AND). If false, match any (OR). Default: false',
|
|
1181
|
+
},
|
|
1182
|
+
relatedTo: {
|
|
685
1183
|
type: 'string',
|
|
686
|
-
description: '
|
|
1184
|
+
description: 'Find tickets related to this ticket ID (by tags, files, tech stack)',
|
|
1185
|
+
},
|
|
1186
|
+
status: {
|
|
1187
|
+
type: 'array',
|
|
1188
|
+
items: {
|
|
1189
|
+
type: 'string',
|
|
1190
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
1191
|
+
},
|
|
1192
|
+
description: 'Filter by status',
|
|
1193
|
+
},
|
|
1194
|
+
complexity: {
|
|
1195
|
+
type: 'array',
|
|
1196
|
+
items: {
|
|
1197
|
+
type: 'string',
|
|
1198
|
+
enum: ['small', 'medium', 'large', 'xlarge'],
|
|
1199
|
+
},
|
|
1200
|
+
description: 'Filter by complexity',
|
|
1201
|
+
},
|
|
1202
|
+
priority: {
|
|
1203
|
+
type: 'array',
|
|
1204
|
+
items: {
|
|
1205
|
+
type: 'string',
|
|
1206
|
+
enum: ['low', 'medium', 'high', 'critical'],
|
|
1207
|
+
},
|
|
1208
|
+
description: 'Filter by priority',
|
|
687
1209
|
},
|
|
688
1210
|
projectId: {
|
|
689
1211
|
type: 'string',
|
|
690
|
-
description: 'Limit search to project
|
|
1212
|
+
description: 'Limit search to project',
|
|
1213
|
+
},
|
|
1214
|
+
specificationId: {
|
|
1215
|
+
type: 'string',
|
|
1216
|
+
description: 'Limit search to specification',
|
|
1217
|
+
},
|
|
1218
|
+
epicId: {
|
|
1219
|
+
type: 'string',
|
|
1220
|
+
description: 'Limit search to epic',
|
|
691
1221
|
},
|
|
692
1222
|
limit: {
|
|
693
1223
|
type: 'number',
|
|
694
|
-
description: 'Maximum results (default: 20)',
|
|
1224
|
+
description: 'Maximum results (default: 20, max: 100)',
|
|
695
1225
|
},
|
|
696
1226
|
offset: {
|
|
697
1227
|
type: 'number',
|
|
698
1228
|
description: 'Pagination offset (default: 0)',
|
|
699
1229
|
},
|
|
1230
|
+
fields: {
|
|
1231
|
+
type: 'array',
|
|
1232
|
+
items: {
|
|
1233
|
+
type: 'string',
|
|
1234
|
+
enum: [
|
|
1235
|
+
'id',
|
|
1236
|
+
'epicId',
|
|
1237
|
+
'ticketNumber',
|
|
1238
|
+
'title',
|
|
1239
|
+
'description',
|
|
1240
|
+
'status',
|
|
1241
|
+
'priority',
|
|
1242
|
+
'complexity',
|
|
1243
|
+
'estimatedHours',
|
|
1244
|
+
'actualHours',
|
|
1245
|
+
'acceptanceCriteria',
|
|
1246
|
+
'implementation',
|
|
1247
|
+
'technicalDetails',
|
|
1248
|
+
'notes',
|
|
1249
|
+
'tags',
|
|
1250
|
+
'blockReason',
|
|
1251
|
+
'progress',
|
|
1252
|
+
'testsPassed',
|
|
1253
|
+
'order',
|
|
1254
|
+
'startedAt',
|
|
1255
|
+
'completedAt',
|
|
1256
|
+
'createdAt',
|
|
1257
|
+
'updatedAt',
|
|
1258
|
+
],
|
|
1259
|
+
},
|
|
1260
|
+
description: 'Select specific fields to return. Returns all fields if not specified. id is always included. Example: ["id", "ticketNumber", "title", "status"] for minimal results.',
|
|
1261
|
+
},
|
|
700
1262
|
},
|
|
701
|
-
required: ['query'],
|
|
702
1263
|
},
|
|
703
1264
|
},
|
|
704
1265
|
{
|
|
705
1266
|
name: 'find_tickets_by_file',
|
|
706
|
-
description: 'Find tickets that modify or create specific files (supports glob patterns)',
|
|
1267
|
+
description: '[DEPRECATED: Use search_tickets with files parameter] Find tickets that modify or create specific files (supports glob patterns)',
|
|
707
1268
|
inputSchema: {
|
|
708
1269
|
type: 'object',
|
|
709
1270
|
properties: {
|
|
@@ -725,7 +1286,7 @@ export function getTools() {
|
|
|
725
1286
|
},
|
|
726
1287
|
{
|
|
727
1288
|
name: 'find_tickets_by_tag',
|
|
728
|
-
description: 'Find tickets by tags with AND/OR logic',
|
|
1289
|
+
description: '[DEPRECATED: Use search_tickets with tags parameter] Find tickets by tags with AND/OR logic',
|
|
729
1290
|
inputSchema: {
|
|
730
1291
|
type: 'object',
|
|
731
1292
|
properties: {
|
|
@@ -752,7 +1313,7 @@ export function getTools() {
|
|
|
752
1313
|
},
|
|
753
1314
|
{
|
|
754
1315
|
name: 'find_related_tickets',
|
|
755
|
-
description: 'Find tickets related to a given ticket based on files, tags, and tech stack',
|
|
1316
|
+
description: '[DEPRECATED: Use search_tickets with relatedTo parameter] Find tickets related to a given ticket based on files, tags, and tech stack',
|
|
756
1317
|
inputSchema: {
|
|
757
1318
|
type: 'object',
|
|
758
1319
|
properties: {
|
|
@@ -837,7 +1398,7 @@ export function getTools() {
|
|
|
837
1398
|
},
|
|
838
1399
|
{
|
|
839
1400
|
name: 'get_ticket_commits',
|
|
840
|
-
description: 'Get all commits linked to a ticket
|
|
1401
|
+
description: "[DEPRECATED: Use get_ticket with include: ['commits'] instead] Get all commits linked to a ticket",
|
|
841
1402
|
inputSchema: {
|
|
842
1403
|
type: 'object',
|
|
843
1404
|
properties: {
|
|
@@ -859,7 +1420,7 @@ export function getTools() {
|
|
|
859
1420
|
},
|
|
860
1421
|
{
|
|
861
1422
|
name: 'get_ticket_prs',
|
|
862
|
-
description: 'Get all pull requests linked to a ticket
|
|
1423
|
+
description: "[DEPRECATED: Use get_ticket with include: ['prs'] instead] Get all pull requests linked to a ticket",
|
|
863
1424
|
inputSchema: {
|
|
864
1425
|
type: 'object',
|
|
865
1426
|
properties: {
|
|
@@ -1027,6 +1588,48 @@ export function getTools() {
|
|
|
1027
1588
|
required: ['title', 'description', 'objective'],
|
|
1028
1589
|
},
|
|
1029
1590
|
},
|
|
1591
|
+
// Pattern inheritance fields (specification level)
|
|
1592
|
+
codeStandards: {
|
|
1593
|
+
type: 'object',
|
|
1594
|
+
description: 'Code standards inherited by all epics/tickets',
|
|
1595
|
+
properties: {
|
|
1596
|
+
language: { type: 'string', description: 'Primary language (e.g., "TypeScript")' },
|
|
1597
|
+
asyncPattern: { type: 'string', description: 'Async pattern (e.g., "async/await")' },
|
|
1598
|
+
errorHandling: { type: 'string', description: 'Error handling approach' },
|
|
1599
|
+
documentation: { type: 'string', description: 'Documentation style' },
|
|
1600
|
+
testing: { type: 'string', description: 'Testing approach' },
|
|
1601
|
+
naming: {
|
|
1602
|
+
type: 'object',
|
|
1603
|
+
description: 'Naming conventions',
|
|
1604
|
+
properties: {
|
|
1605
|
+
files: { type: 'string', description: 'File naming convention' },
|
|
1606
|
+
functions: { type: 'string', description: 'Function naming convention' },
|
|
1607
|
+
interfaces: { type: 'string', description: 'Interface naming convention' },
|
|
1608
|
+
actions: { type: 'string', description: 'Action naming convention' },
|
|
1609
|
+
},
|
|
1610
|
+
},
|
|
1611
|
+
},
|
|
1612
|
+
},
|
|
1613
|
+
commonImports: {
|
|
1614
|
+
type: 'array',
|
|
1615
|
+
items: { type: 'string' },
|
|
1616
|
+
description: 'Common imports inherited by all epics/tickets',
|
|
1617
|
+
},
|
|
1618
|
+
returnTypes: {
|
|
1619
|
+
type: 'object',
|
|
1620
|
+
description: 'Standard return types for CRUD operations',
|
|
1621
|
+
properties: {
|
|
1622
|
+
create: { type: 'string', description: 'Return type for create operations' },
|
|
1623
|
+
update: { type: 'string', description: 'Return type for update operations' },
|
|
1624
|
+
delete: { type: 'string', description: 'Return type for delete operations' },
|
|
1625
|
+
list: { type: 'string', description: 'Return type for list operations' },
|
|
1626
|
+
},
|
|
1627
|
+
},
|
|
1628
|
+
responseMode: {
|
|
1629
|
+
type: 'string',
|
|
1630
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1631
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1632
|
+
},
|
|
1030
1633
|
},
|
|
1031
1634
|
required: ['projectId', 'title'],
|
|
1032
1635
|
},
|
|
@@ -1133,7 +1736,7 @@ export function getTools() {
|
|
|
1133
1736
|
},
|
|
1134
1737
|
tickets: {
|
|
1135
1738
|
type: 'array',
|
|
1136
|
-
description: 'Nested tickets to create (bulk creation)',
|
|
1739
|
+
description: 'Nested tickets to create (bulk creation) with optional inline dependencies',
|
|
1137
1740
|
items: {
|
|
1138
1741
|
type: 'object',
|
|
1139
1742
|
properties: {
|
|
@@ -1142,17 +1745,57 @@ export function getTools() {
|
|
|
1142
1745
|
acceptanceCriteria: { type: 'array', items: { type: 'string' } },
|
|
1143
1746
|
estimatedHours: { type: 'number' },
|
|
1144
1747
|
complexity: { type: 'string', enum: ['small', 'medium', 'large', 'xlarge'] },
|
|
1748
|
+
priority: { type: 'string', enum: ['high', 'medium', 'low'] },
|
|
1749
|
+
implementation: { type: 'object', description: 'Implementation details' },
|
|
1750
|
+
technicalDetails: { type: 'object', description: 'Technical details' },
|
|
1751
|
+
tags: { type: 'array', items: { type: 'string' } },
|
|
1752
|
+
dependsOn: {
|
|
1753
|
+
type: 'array',
|
|
1754
|
+
items: { type: 'number' },
|
|
1755
|
+
description: 'Indexes of other tickets in this array that this ticket depends on',
|
|
1756
|
+
},
|
|
1145
1757
|
},
|
|
1146
1758
|
required: ['title'],
|
|
1147
1759
|
},
|
|
1148
1760
|
},
|
|
1761
|
+
// Pattern inheritance fields (epic level)
|
|
1762
|
+
sharedPatterns: {
|
|
1763
|
+
type: 'object',
|
|
1764
|
+
description: 'Patterns shared by all tickets in this epic',
|
|
1765
|
+
properties: {
|
|
1766
|
+
errorHandling: { type: 'string', description: 'Override error handling for this epic' },
|
|
1767
|
+
returnType: { type: 'string', description: 'Epic-specific return type' },
|
|
1768
|
+
actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
|
|
1769
|
+
stateSlice: { type: 'string', description: 'State slice path for this epic' },
|
|
1770
|
+
},
|
|
1771
|
+
},
|
|
1772
|
+
additionalImports: {
|
|
1773
|
+
type: 'array',
|
|
1774
|
+
items: { type: 'string' },
|
|
1775
|
+
description: 'Additional imports for tickets in this epic (added to spec-level imports)',
|
|
1776
|
+
},
|
|
1777
|
+
commonFiles: {
|
|
1778
|
+
type: 'object',
|
|
1779
|
+
description: 'Common file paths for this epic',
|
|
1780
|
+
properties: {
|
|
1781
|
+
reducer: { type: 'string', description: 'Reducer file path' },
|
|
1782
|
+
actions: { type: 'string', description: 'Actions file path' },
|
|
1783
|
+
types: { type: 'string', description: 'Types file path' },
|
|
1784
|
+
index: { type: 'string', description: 'Index/barrel file path' },
|
|
1785
|
+
},
|
|
1786
|
+
},
|
|
1787
|
+
responseMode: {
|
|
1788
|
+
type: 'string',
|
|
1789
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1790
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1791
|
+
},
|
|
1149
1792
|
},
|
|
1150
1793
|
required: ['specificationId', 'title', 'description', 'objective'],
|
|
1151
1794
|
},
|
|
1152
1795
|
},
|
|
1153
1796
|
{
|
|
1154
1797
|
name: 'create_ticket',
|
|
1155
|
-
description: 'Create a new ticket in an epic',
|
|
1798
|
+
description: 'Create a new ticket in an epic. Returns validation warnings based on complexity level.',
|
|
1156
1799
|
inputSchema: {
|
|
1157
1800
|
type: 'object',
|
|
1158
1801
|
properties: {
|
|
@@ -1213,6 +1856,20 @@ export function getTools() {
|
|
|
1213
1856
|
items: { type: 'string' },
|
|
1214
1857
|
description: 'Array of ticket IDs this ticket depends on',
|
|
1215
1858
|
},
|
|
1859
|
+
skipValidation: {
|
|
1860
|
+
type: 'boolean',
|
|
1861
|
+
description: 'Skip validation and completeness scoring. Default: false',
|
|
1862
|
+
},
|
|
1863
|
+
validationStrictness: {
|
|
1864
|
+
type: 'string',
|
|
1865
|
+
enum: ['lenient', 'normal', 'strict'],
|
|
1866
|
+
description: 'Warning strictness level. lenient=warnings only, normal=warnings+recommendations, strict=all. Default: normal',
|
|
1867
|
+
},
|
|
1868
|
+
responseMode: {
|
|
1869
|
+
type: 'string',
|
|
1870
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1871
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1872
|
+
},
|
|
1216
1873
|
},
|
|
1217
1874
|
required: ['epicId', 'title'],
|
|
1218
1875
|
},
|
|
@@ -1248,7 +1905,9 @@ export function getTools() {
|
|
|
1248
1905
|
// ========================================================================
|
|
1249
1906
|
{
|
|
1250
1907
|
name: 'update_ticket',
|
|
1251
|
-
description: "Update a ticket's properties (status, description, estimate, etc.)"
|
|
1908
|
+
description: "Update a ticket's properties (status, description, estimate, etc.).\n\n" +
|
|
1909
|
+
'When status changes, counts are automatically propagated up the hierarchy ' +
|
|
1910
|
+
'(Epic → Specification → Project).',
|
|
1252
1911
|
inputSchema: {
|
|
1253
1912
|
type: 'object',
|
|
1254
1913
|
properties: {
|
|
@@ -1266,8 +1925,8 @@ export function getTools() {
|
|
|
1266
1925
|
},
|
|
1267
1926
|
status: {
|
|
1268
1927
|
type: 'string',
|
|
1269
|
-
enum: ['
|
|
1270
|
-
description: '
|
|
1928
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
1929
|
+
description: 'Ticket status. pending/ready may be recalculated based on dependencies.',
|
|
1271
1930
|
},
|
|
1272
1931
|
priority: {
|
|
1273
1932
|
type: 'string',
|
|
@@ -1281,7 +1940,7 @@ export function getTools() {
|
|
|
1281
1940
|
},
|
|
1282
1941
|
blockReason: {
|
|
1283
1942
|
type: 'string',
|
|
1284
|
-
description: '
|
|
1943
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1285
1944
|
},
|
|
1286
1945
|
notes: {
|
|
1287
1946
|
type: 'string',
|
|
@@ -1309,6 +1968,22 @@ export function getTools() {
|
|
|
1309
1968
|
type: 'object',
|
|
1310
1969
|
description: 'Technical details like stack, endpoints (JSON) (optional)',
|
|
1311
1970
|
},
|
|
1971
|
+
skipValidation: {
|
|
1972
|
+
type: 'boolean',
|
|
1973
|
+
description: 'Skip validation and completeness scoring (default: false)',
|
|
1974
|
+
default: false,
|
|
1975
|
+
},
|
|
1976
|
+
validationStrictness: {
|
|
1977
|
+
type: 'string',
|
|
1978
|
+
enum: ['lenient', 'normal', 'strict'],
|
|
1979
|
+
description: 'Warning strictness level (default: normal)',
|
|
1980
|
+
default: 'normal',
|
|
1981
|
+
},
|
|
1982
|
+
responseMode: {
|
|
1983
|
+
type: 'string',
|
|
1984
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
1985
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
1986
|
+
},
|
|
1312
1987
|
},
|
|
1313
1988
|
required: ['ticketId'],
|
|
1314
1989
|
},
|
|
@@ -1410,6 +2085,37 @@ export function getTools() {
|
|
|
1410
2085
|
enum: ['low', 'medium', 'high', 'critical'],
|
|
1411
2086
|
description: 'Priority level (optional)',
|
|
1412
2087
|
},
|
|
2088
|
+
// Pattern inheritance fields (epic level)
|
|
2089
|
+
sharedPatterns: {
|
|
2090
|
+
type: 'object',
|
|
2091
|
+
description: 'Patterns shared by all tickets in this epic (optional)',
|
|
2092
|
+
properties: {
|
|
2093
|
+
errorHandling: { type: 'string', description: 'Override error handling for this epic' },
|
|
2094
|
+
returnType: { type: 'string', description: 'Epic-specific return type' },
|
|
2095
|
+
actionPrefix: { type: 'string', description: 'Redux/action prefix for this epic' },
|
|
2096
|
+
stateSlice: { type: 'string', description: 'State slice path for this epic' },
|
|
2097
|
+
},
|
|
2098
|
+
},
|
|
2099
|
+
additionalImports: {
|
|
2100
|
+
type: 'array',
|
|
2101
|
+
items: { type: 'string' },
|
|
2102
|
+
description: 'Additional imports for tickets in this epic (optional)',
|
|
2103
|
+
},
|
|
2104
|
+
commonFiles: {
|
|
2105
|
+
type: 'object',
|
|
2106
|
+
description: 'Common file paths for this epic (optional)',
|
|
2107
|
+
properties: {
|
|
2108
|
+
reducer: { type: 'string', description: 'Reducer file path' },
|
|
2109
|
+
actions: { type: 'string', description: 'Actions file path' },
|
|
2110
|
+
types: { type: 'string', description: 'Types file path' },
|
|
2111
|
+
index: { type: 'string', description: 'Index/barrel file path' },
|
|
2112
|
+
},
|
|
2113
|
+
},
|
|
2114
|
+
responseMode: {
|
|
2115
|
+
type: 'string',
|
|
2116
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
2117
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
2118
|
+
},
|
|
1413
2119
|
},
|
|
1414
2120
|
required: ['epicId'],
|
|
1415
2121
|
},
|
|
@@ -1555,6 +2261,48 @@ export function getTools() {
|
|
|
1555
2261
|
type: 'string',
|
|
1556
2262
|
description: 'Output directory for build artifacts (optional)',
|
|
1557
2263
|
},
|
|
2264
|
+
// Pattern inheritance fields (specification level)
|
|
2265
|
+
codeStandards: {
|
|
2266
|
+
type: 'object',
|
|
2267
|
+
description: 'Code standards inherited by all epics/tickets (optional)',
|
|
2268
|
+
properties: {
|
|
2269
|
+
language: { type: 'string', description: 'Primary language (e.g., "TypeScript")' },
|
|
2270
|
+
asyncPattern: { type: 'string', description: 'Async pattern (e.g., "async/await")' },
|
|
2271
|
+
errorHandling: { type: 'string', description: 'Error handling approach' },
|
|
2272
|
+
documentation: { type: 'string', description: 'Documentation style' },
|
|
2273
|
+
testing: { type: 'string', description: 'Testing approach' },
|
|
2274
|
+
naming: {
|
|
2275
|
+
type: 'object',
|
|
2276
|
+
description: 'Naming conventions',
|
|
2277
|
+
properties: {
|
|
2278
|
+
files: { type: 'string', description: 'File naming convention' },
|
|
2279
|
+
functions: { type: 'string', description: 'Function naming convention' },
|
|
2280
|
+
interfaces: { type: 'string', description: 'Interface naming convention' },
|
|
2281
|
+
actions: { type: 'string', description: 'Action naming convention' },
|
|
2282
|
+
},
|
|
2283
|
+
},
|
|
2284
|
+
},
|
|
2285
|
+
},
|
|
2286
|
+
commonImports: {
|
|
2287
|
+
type: 'array',
|
|
2288
|
+
items: { type: 'string' },
|
|
2289
|
+
description: 'Common imports inherited by all epics/tickets (optional)',
|
|
2290
|
+
},
|
|
2291
|
+
returnTypes: {
|
|
2292
|
+
type: 'object',
|
|
2293
|
+
description: 'Standard return types for CRUD operations (optional)',
|
|
2294
|
+
properties: {
|
|
2295
|
+
create: { type: 'string', description: 'Return type for create operations' },
|
|
2296
|
+
update: { type: 'string', description: 'Return type for update operations' },
|
|
2297
|
+
delete: { type: 'string', description: 'Return type for delete operations' },
|
|
2298
|
+
list: { type: 'string', description: 'Return type for list operations' },
|
|
2299
|
+
},
|
|
2300
|
+
},
|
|
2301
|
+
responseMode: {
|
|
2302
|
+
type: 'string',
|
|
2303
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
2304
|
+
description: 'Response verbosity: full (default, ~500 tokens), minimal (~50 tokens), id-only (~20 tokens)',
|
|
2305
|
+
},
|
|
1558
2306
|
},
|
|
1559
2307
|
required: ['specificationId'],
|
|
1560
2308
|
},
|
|
@@ -1648,7 +2396,7 @@ export function getTools() {
|
|
|
1648
2396
|
},
|
|
1649
2397
|
{
|
|
1650
2398
|
name: 'get_session',
|
|
1651
|
-
description: 'Get session by ID or get active session for specification
|
|
2399
|
+
description: "[DEPRECATED: Use get_specification with include: ['session'] instead] Get session by ID or get active session for specification",
|
|
1652
2400
|
inputSchema: {
|
|
1653
2401
|
type: 'object',
|
|
1654
2402
|
properties: {
|
|
@@ -1670,7 +2418,7 @@ export function getTools() {
|
|
|
1670
2418
|
},
|
|
1671
2419
|
{
|
|
1672
2420
|
name: 'update_session',
|
|
1673
|
-
description: 'Update session state (pause/resume, update config, add notes)',
|
|
2421
|
+
description: '[DEPRECATED: Use end_session() then create_session() with new config instead] Update session state (pause/resume, update config, add notes)',
|
|
1674
2422
|
inputSchema: {
|
|
1675
2423
|
type: 'object',
|
|
1676
2424
|
properties: {
|
|
@@ -1701,7 +2449,7 @@ export function getTools() {
|
|
|
1701
2449
|
},
|
|
1702
2450
|
{
|
|
1703
2451
|
name: 'record_session_ticket',
|
|
1704
|
-
description: 'Record a ticket completion/failure within a session. Returns next actionable ticket if available.',
|
|
2452
|
+
description: '[DEPRECATED: Use complete_work_session() which auto-records in active session] Record a ticket completion/failure within a session. Returns next actionable ticket if available.',
|
|
1705
2453
|
inputSchema: {
|
|
1706
2454
|
type: 'object',
|
|
1707
2455
|
properties: {
|
|
@@ -1759,7 +2507,7 @@ export function getTools() {
|
|
|
1759
2507
|
},
|
|
1760
2508
|
{
|
|
1761
2509
|
name: 'list_sessions',
|
|
1762
|
-
description: 'List sessions with filtering by specification, project, or status
|
|
2510
|
+
description: "[DEPRECATED: Use get_report({ type: 'work' }) for work summaries] List sessions with filtering by specification, project, or status",
|
|
1763
2511
|
inputSchema: {
|
|
1764
2512
|
type: 'object',
|
|
1765
2513
|
properties: {
|
|
@@ -1794,6 +2542,147 @@ export function getTools() {
|
|
|
1794
2542
|
// ========================================================================
|
|
1795
2543
|
// Bulk Operations
|
|
1796
2544
|
// ========================================================================
|
|
2545
|
+
{
|
|
2546
|
+
name: 'bulk_create_tickets',
|
|
2547
|
+
description: 'Create multiple tickets in an epic with optional inline dependencies in a single atomic transaction. Reduces 15+ API calls to one.',
|
|
2548
|
+
inputSchema: {
|
|
2549
|
+
type: 'object',
|
|
2550
|
+
properties: {
|
|
2551
|
+
epicId: {
|
|
2552
|
+
type: 'string',
|
|
2553
|
+
description: 'The ID of the epic to create tickets in',
|
|
2554
|
+
},
|
|
2555
|
+
tickets: {
|
|
2556
|
+
type: 'array',
|
|
2557
|
+
description: 'Array of ticket definitions to create',
|
|
2558
|
+
items: {
|
|
2559
|
+
type: 'object',
|
|
2560
|
+
properties: {
|
|
2561
|
+
title: { type: 'string', description: 'Ticket title (required)' },
|
|
2562
|
+
description: { type: 'string', description: 'Ticket description' },
|
|
2563
|
+
estimatedHours: { type: 'number', description: 'Estimated hours' },
|
|
2564
|
+
complexity: {
|
|
2565
|
+
type: 'string',
|
|
2566
|
+
enum: ['small', 'medium', 'large', 'xlarge'],
|
|
2567
|
+
description: 'Complexity level',
|
|
2568
|
+
},
|
|
2569
|
+
priority: {
|
|
2570
|
+
type: 'string',
|
|
2571
|
+
enum: ['high', 'medium', 'low'],
|
|
2572
|
+
description: 'Priority level',
|
|
2573
|
+
},
|
|
2574
|
+
acceptanceCriteria: {
|
|
2575
|
+
type: 'array',
|
|
2576
|
+
items: { type: 'string' },
|
|
2577
|
+
description: 'Acceptance criteria',
|
|
2578
|
+
},
|
|
2579
|
+
implementation: {
|
|
2580
|
+
type: 'object',
|
|
2581
|
+
description: 'Implementation details (filesToCreate, filesToModify, steps, etc.)',
|
|
2582
|
+
},
|
|
2583
|
+
technicalDetails: {
|
|
2584
|
+
type: 'object',
|
|
2585
|
+
description: 'Technical details (files, stack, endpoints, etc.)',
|
|
2586
|
+
},
|
|
2587
|
+
tags: {
|
|
2588
|
+
type: 'array',
|
|
2589
|
+
items: { type: 'string' },
|
|
2590
|
+
description: 'Tags',
|
|
2591
|
+
},
|
|
2592
|
+
},
|
|
2593
|
+
required: ['title'],
|
|
2594
|
+
},
|
|
2595
|
+
},
|
|
2596
|
+
dependencies: {
|
|
2597
|
+
type: 'array',
|
|
2598
|
+
description: 'Optional inline dependencies using array indexes',
|
|
2599
|
+
items: {
|
|
2600
|
+
type: 'object',
|
|
2601
|
+
properties: {
|
|
2602
|
+
ticket: {
|
|
2603
|
+
type: 'number',
|
|
2604
|
+
description: 'Index of the ticket in the tickets array',
|
|
2605
|
+
},
|
|
2606
|
+
dependsOn: {
|
|
2607
|
+
oneOf: [
|
|
2608
|
+
{ type: 'number', description: 'Index of the ticket it depends on' },
|
|
2609
|
+
{
|
|
2610
|
+
type: 'array',
|
|
2611
|
+
items: { type: 'number' },
|
|
2612
|
+
description: 'Indexes of the tickets it depends on',
|
|
2613
|
+
},
|
|
2614
|
+
],
|
|
2615
|
+
description: 'Index(es) of the ticket(s) it depends on',
|
|
2616
|
+
},
|
|
2617
|
+
},
|
|
2618
|
+
required: ['ticket', 'dependsOn'],
|
|
2619
|
+
},
|
|
2620
|
+
},
|
|
2621
|
+
onError: {
|
|
2622
|
+
type: 'string',
|
|
2623
|
+
enum: ['rollback', 'continue'],
|
|
2624
|
+
description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
|
|
2625
|
+
},
|
|
2626
|
+
},
|
|
2627
|
+
required: ['epicId', 'tickets'],
|
|
2628
|
+
},
|
|
2629
|
+
},
|
|
2630
|
+
{
|
|
2631
|
+
name: 'get_job_status',
|
|
2632
|
+
description: 'Get the status of an asynchronous bulk operation job. For batches >= 20 items, bulk operations return a job ID for async processing.',
|
|
2633
|
+
inputSchema: {
|
|
2634
|
+
type: 'object',
|
|
2635
|
+
properties: {
|
|
2636
|
+
jobId: {
|
|
2637
|
+
type: 'string',
|
|
2638
|
+
description: 'The job ID returned from a bulk operation',
|
|
2639
|
+
},
|
|
2640
|
+
},
|
|
2641
|
+
required: ['jobId'],
|
|
2642
|
+
},
|
|
2643
|
+
},
|
|
2644
|
+
{
|
|
2645
|
+
name: 'bulk_add_dependencies',
|
|
2646
|
+
description: 'Add multiple dependencies between tickets in a single atomic transaction.',
|
|
2647
|
+
inputSchema: {
|
|
2648
|
+
type: 'object',
|
|
2649
|
+
properties: {
|
|
2650
|
+
dependencies: {
|
|
2651
|
+
type: 'array',
|
|
2652
|
+
description: 'Array of dependency definitions',
|
|
2653
|
+
items: {
|
|
2654
|
+
type: 'object',
|
|
2655
|
+
properties: {
|
|
2656
|
+
ticketId: {
|
|
2657
|
+
type: 'string',
|
|
2658
|
+
description: 'ID of the ticket that will depend on another',
|
|
2659
|
+
},
|
|
2660
|
+
dependsOnId: {
|
|
2661
|
+
type: 'string',
|
|
2662
|
+
description: 'ID of the ticket it will depend on',
|
|
2663
|
+
},
|
|
2664
|
+
type: {
|
|
2665
|
+
type: 'string',
|
|
2666
|
+
enum: ['blocks', 'requires'],
|
|
2667
|
+
description: "Type of dependency (default: 'requires')",
|
|
2668
|
+
},
|
|
2669
|
+
},
|
|
2670
|
+
required: ['ticketId', 'dependsOnId'],
|
|
2671
|
+
},
|
|
2672
|
+
},
|
|
2673
|
+
skipCircularCheck: {
|
|
2674
|
+
type: 'boolean',
|
|
2675
|
+
description: 'Skip validation of circular dependencies (default: false)',
|
|
2676
|
+
},
|
|
2677
|
+
onError: {
|
|
2678
|
+
type: 'string',
|
|
2679
|
+
enum: ['rollback', 'continue'],
|
|
2680
|
+
description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
|
|
2681
|
+
},
|
|
2682
|
+
},
|
|
2683
|
+
required: ['dependencies'],
|
|
2684
|
+
},
|
|
2685
|
+
},
|
|
1797
2686
|
{
|
|
1798
2687
|
name: 'bulk_update_tickets',
|
|
1799
2688
|
description: 'Update multiple tickets in a single atomic operation. All updates succeed or all fail (unless atomic: false).',
|
|
@@ -1811,8 +2700,8 @@ export function getTools() {
|
|
|
1811
2700
|
},
|
|
1812
2701
|
status: {
|
|
1813
2702
|
type: 'string',
|
|
1814
|
-
enum: ['
|
|
1815
|
-
description: '
|
|
2703
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
2704
|
+
description: 'Ticket status. Completing (done) triggers cascade to unblock dependents.',
|
|
1816
2705
|
},
|
|
1817
2706
|
priority: {
|
|
1818
2707
|
type: 'string',
|
|
@@ -1827,7 +2716,7 @@ export function getTools() {
|
|
|
1827
2716
|
},
|
|
1828
2717
|
blockReason: {
|
|
1829
2718
|
type: 'string',
|
|
1830
|
-
description: '
|
|
2719
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1831
2720
|
},
|
|
1832
2721
|
},
|
|
1833
2722
|
required: ['ticketId'],
|
|
@@ -1842,13 +2731,21 @@ export function getTools() {
|
|
|
1842
2731
|
type: 'boolean',
|
|
1843
2732
|
description: 'All-or-nothing updates. If false, partial success allowed (default: true)',
|
|
1844
2733
|
},
|
|
2734
|
+
responseMode: {
|
|
2735
|
+
type: 'string',
|
|
2736
|
+
enum: ['full', 'minimal', 'id-only'],
|
|
2737
|
+
description: `Response verbosity:
|
|
2738
|
+
- full: Complete updated tickets (default, ~500 tokens per ticket)
|
|
2739
|
+
- minimal: id, title, status per ticket (~50 tokens total)
|
|
2740
|
+
- id-only: Array of updated ticket IDs only (~20 tokens total)`,
|
|
2741
|
+
},
|
|
1845
2742
|
},
|
|
1846
2743
|
required: ['updates'],
|
|
1847
2744
|
},
|
|
1848
2745
|
},
|
|
1849
2746
|
{
|
|
1850
2747
|
name: 'reset_tickets',
|
|
1851
|
-
description: 'Reset tickets to
|
|
2748
|
+
description: 'Reset tickets to pending/ready status (calculated from dependencies). Returns statusCalculation showing how many became pending vs ready.',
|
|
1852
2749
|
inputSchema: {
|
|
1853
2750
|
type: 'object',
|
|
1854
2751
|
properties: {
|
|
@@ -1873,11 +2770,6 @@ export function getTools() {
|
|
|
1873
2770
|
type: 'boolean',
|
|
1874
2771
|
description: 'Reset all tickets in the specification',
|
|
1875
2772
|
},
|
|
1876
|
-
targetStatus: {
|
|
1877
|
-
type: 'string',
|
|
1878
|
-
enum: ['todo', 'queue'],
|
|
1879
|
-
description: 'Status to reset tickets to (default: todo)',
|
|
1880
|
-
},
|
|
1881
2773
|
resetDependents: {
|
|
1882
2774
|
type: 'boolean',
|
|
1883
2775
|
description: 'Also reset tickets that depend on the specified tickets (default: false)',
|
|
@@ -1898,7 +2790,47 @@ export function getTools() {
|
|
|
1898
2790
|
required: ['specificationId'],
|
|
1899
2791
|
},
|
|
1900
2792
|
},
|
|
2793
|
+
// ========================================================================
|
|
2794
|
+
// Validation Operations (MCI-075)
|
|
2795
|
+
// ========================================================================
|
|
2796
|
+
{
|
|
2797
|
+
name: 'validate_counts',
|
|
2798
|
+
description: 'Validate denormalized counts across the hierarchy. ' +
|
|
2799
|
+
'Compares stored counts with actual data and optionally repairs discrepancies.\n\n' +
|
|
2800
|
+
'Use this tool to:\n' +
|
|
2801
|
+
'- Diagnose count inconsistencies\n' +
|
|
2802
|
+
'- Repair counts after data migrations\n' +
|
|
2803
|
+
'- Verify counts before bulk operations',
|
|
2804
|
+
inputSchema: {
|
|
2805
|
+
type: 'object',
|
|
2806
|
+
properties: {
|
|
2807
|
+
projectId: {
|
|
2808
|
+
type: 'string',
|
|
2809
|
+
description: 'Validate all counts within a project',
|
|
2810
|
+
},
|
|
2811
|
+
specificationId: {
|
|
2812
|
+
type: 'string',
|
|
2813
|
+
description: 'Validate all counts within a specification',
|
|
2814
|
+
},
|
|
2815
|
+
epicId: {
|
|
2816
|
+
type: 'string',
|
|
2817
|
+
description: 'Validate counts for a single epic',
|
|
2818
|
+
},
|
|
2819
|
+
repair: {
|
|
2820
|
+
type: 'boolean',
|
|
2821
|
+
description: 'If true, fix any issues found. Default: false (dry run)',
|
|
2822
|
+
},
|
|
2823
|
+
verbose: {
|
|
2824
|
+
type: 'boolean',
|
|
2825
|
+
description: 'Include detailed breakdown in response',
|
|
2826
|
+
},
|
|
2827
|
+
},
|
|
2828
|
+
required: [],
|
|
2829
|
+
},
|
|
2830
|
+
},
|
|
1901
2831
|
];
|
|
2832
|
+
// Apply format parameter to all read operations
|
|
2833
|
+
return tools.map(tool => READ_TOOL_NAMES.has(tool.name) ? addFormatParameter(tool) : tool);
|
|
1902
2834
|
}
|
|
1903
2835
|
/**
|
|
1904
2836
|
* Retry configuration for transient failures
|
|
@@ -1986,6 +2918,12 @@ export function createToolHandlers(apiClient) {
|
|
|
1986
2918
|
projectId: args.projectId,
|
|
1987
2919
|
});
|
|
1988
2920
|
},
|
|
2921
|
+
lookup_project: async (_client, args) => {
|
|
2922
|
+
validateRequired(args, 'name');
|
|
2923
|
+
return await apiClient.call('lookup_project', {
|
|
2924
|
+
name: args.name,
|
|
2925
|
+
});
|
|
2926
|
+
},
|
|
1989
2927
|
// ========================================================================
|
|
1990
2928
|
// Core Operations - Specifications
|
|
1991
2929
|
// ========================================================================
|
|
@@ -1994,12 +2932,24 @@ export function createToolHandlers(apiClient) {
|
|
|
1994
2932
|
return await apiClient.call('list_specifications', {
|
|
1995
2933
|
projectId: args.projectId,
|
|
1996
2934
|
status: args.status,
|
|
2935
|
+
limit: args.limit,
|
|
2936
|
+
offset: args.offset,
|
|
2937
|
+
fields: args.fields,
|
|
1997
2938
|
});
|
|
1998
2939
|
},
|
|
1999
2940
|
get_specification: async (_client, args) => {
|
|
2000
2941
|
validateRequired(args, 'specificationId');
|
|
2001
2942
|
return await apiClient.call('get_specification', {
|
|
2002
2943
|
specificationId: args.specificationId,
|
|
2944
|
+
summary: args.summary,
|
|
2945
|
+
include: args.include,
|
|
2946
|
+
});
|
|
2947
|
+
},
|
|
2948
|
+
lookup_specification: async (_client, args) => {
|
|
2949
|
+
validateRequired(args, 'projectId', 'title');
|
|
2950
|
+
return await apiClient.call('lookup_specification', {
|
|
2951
|
+
projectId: args.projectId,
|
|
2952
|
+
title: args.title,
|
|
2003
2953
|
});
|
|
2004
2954
|
},
|
|
2005
2955
|
// ========================================================================
|
|
@@ -2010,12 +2960,29 @@ export function createToolHandlers(apiClient) {
|
|
|
2010
2960
|
return await apiClient.call('list_epics', {
|
|
2011
2961
|
specificationId: args.specificationId,
|
|
2012
2962
|
status: args.status,
|
|
2963
|
+
limit: args.limit,
|
|
2964
|
+
offset: args.offset,
|
|
2965
|
+
fields: args.fields,
|
|
2013
2966
|
});
|
|
2014
2967
|
},
|
|
2015
2968
|
get_epic: async (_client, args) => {
|
|
2016
2969
|
validateRequired(args, 'epicId');
|
|
2017
2970
|
return await apiClient.call('get_epic', {
|
|
2018
2971
|
epicId: args.epicId,
|
|
2972
|
+
summary: args.summary,
|
|
2973
|
+
include: args.include,
|
|
2974
|
+
});
|
|
2975
|
+
},
|
|
2976
|
+
lookup_epic: async (_client, args) => {
|
|
2977
|
+
validateRequired(args, 'specificationId');
|
|
2978
|
+
// Must provide either title or number
|
|
2979
|
+
if (!args.title && args.number === undefined) {
|
|
2980
|
+
throw new Error("Must provide either 'title' or 'number'");
|
|
2981
|
+
}
|
|
2982
|
+
return await apiClient.call('lookup_epic', {
|
|
2983
|
+
specificationId: args.specificationId,
|
|
2984
|
+
title: args.title,
|
|
2985
|
+
number: args.number,
|
|
2019
2986
|
});
|
|
2020
2987
|
},
|
|
2021
2988
|
// ========================================================================
|
|
@@ -2026,12 +2993,53 @@ export function createToolHandlers(apiClient) {
|
|
|
2026
2993
|
return await apiClient.call('list_tickets', {
|
|
2027
2994
|
epicId: args.epicId,
|
|
2028
2995
|
status: args.status,
|
|
2996
|
+
limit: args.limit,
|
|
2997
|
+
offset: args.offset,
|
|
2998
|
+
include: args.include,
|
|
2999
|
+
fields: args.fields,
|
|
2029
3000
|
});
|
|
2030
3001
|
},
|
|
2031
3002
|
get_ticket: async (_client, args) => {
|
|
2032
3003
|
validateRequired(args, 'ticketId');
|
|
2033
3004
|
return await apiClient.call('get_ticket', {
|
|
2034
3005
|
ticketId: args.ticketId,
|
|
3006
|
+
summary: args.summary,
|
|
3007
|
+
include: args.include,
|
|
3008
|
+
});
|
|
3009
|
+
},
|
|
3010
|
+
lookup_ticket: async (_client, args) => {
|
|
3011
|
+
validateRequired(args, 'epicId');
|
|
3012
|
+
// Must provide either title or number
|
|
3013
|
+
if (!args.title && args.number === undefined) {
|
|
3014
|
+
throw new Error("Must provide either 'title' or 'number'");
|
|
3015
|
+
}
|
|
3016
|
+
return await apiClient.call('lookup_ticket', {
|
|
3017
|
+
epicId: args.epicId,
|
|
3018
|
+
title: args.title,
|
|
3019
|
+
number: args.number,
|
|
3020
|
+
});
|
|
3021
|
+
},
|
|
3022
|
+
lookup_tickets_by_status: async (_client, args) => {
|
|
3023
|
+
validateRequired(args, 'ticketIds');
|
|
3024
|
+
if (!Array.isArray(args.ticketIds)) {
|
|
3025
|
+
throw new Error('ticketIds must be an array');
|
|
3026
|
+
}
|
|
3027
|
+
const MAX_BATCH_SIZE = 50;
|
|
3028
|
+
if (args.ticketIds.length > MAX_BATCH_SIZE) {
|
|
3029
|
+
throw new Error(`Maximum ${MAX_BATCH_SIZE} tickets per call`);
|
|
3030
|
+
}
|
|
3031
|
+
// Empty array returns empty result
|
|
3032
|
+
if (args.ticketIds.length === 0) {
|
|
3033
|
+
return { tickets: [], notFound: [] };
|
|
3034
|
+
}
|
|
3035
|
+
// Validate all IDs are strings
|
|
3036
|
+
for (let i = 0; i < args.ticketIds.length; i++) {
|
|
3037
|
+
if (typeof args.ticketIds[i] !== 'string') {
|
|
3038
|
+
throw new Error(`ticketIds[${i}] must be a string`);
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
return await apiClient.call('lookup_tickets_by_status', {
|
|
3042
|
+
ticketIds: args.ticketIds,
|
|
2035
3043
|
});
|
|
2036
3044
|
},
|
|
2037
3045
|
// ========================================================================
|
|
@@ -2074,9 +3082,52 @@ export function createToolHandlers(apiClient) {
|
|
|
2074
3082
|
// ========================================================================
|
|
2075
3083
|
get_implementation_context: async (_client, args) => {
|
|
2076
3084
|
validateRequired(args, 'ticketId');
|
|
2077
|
-
|
|
3085
|
+
const depth = args.depth || 'standard';
|
|
3086
|
+
// Fetch the implementation context from API with depth parameter
|
|
3087
|
+
const context = await apiClient.call('get_implementation_context', {
|
|
2078
3088
|
ticketId: args.ticketId,
|
|
3089
|
+
depth,
|
|
2079
3090
|
});
|
|
3091
|
+
// Only resolve inherited patterns for 'full' depth (minimal/standard don't include them)
|
|
3092
|
+
if (depth === 'full' && context.specification && context.epic) {
|
|
3093
|
+
const spec = context.specification;
|
|
3094
|
+
const epic = context.epic;
|
|
3095
|
+
const ticket = context.ticket;
|
|
3096
|
+
try {
|
|
3097
|
+
const resolvedPatterns = resolvePatternsWithCache({
|
|
3098
|
+
ticketId: args.ticketId,
|
|
3099
|
+
specification: {
|
|
3100
|
+
id: spec.id,
|
|
3101
|
+
codeStandards: spec.codeStandards,
|
|
3102
|
+
commonImports: spec.commonImports,
|
|
3103
|
+
returnTypes: spec.returnTypes,
|
|
3104
|
+
},
|
|
3105
|
+
epic: {
|
|
3106
|
+
id: epic.id,
|
|
3107
|
+
sharedPatterns: epic.sharedPatterns,
|
|
3108
|
+
additionalImports: epic.additionalImports,
|
|
3109
|
+
commonFiles: epic.commonFiles,
|
|
3110
|
+
},
|
|
3111
|
+
ticket: ticket ? {
|
|
3112
|
+
id: ticket.id,
|
|
3113
|
+
technicalDetails: ticket.technicalDetails,
|
|
3114
|
+
} : undefined,
|
|
3115
|
+
});
|
|
3116
|
+
// Add inherited patterns to the response
|
|
3117
|
+
context.inheritedPatterns = {
|
|
3118
|
+
imports: resolvedPatterns.imports,
|
|
3119
|
+
patterns: resolvedPatterns.patterns,
|
|
3120
|
+
returnTypes: resolvedPatterns.returnTypes,
|
|
3121
|
+
commonFiles: resolvedPatterns.commonFiles,
|
|
3122
|
+
naming: resolvedPatterns.naming,
|
|
3123
|
+
};
|
|
3124
|
+
}
|
|
3125
|
+
catch {
|
|
3126
|
+
// If pattern resolution fails, return context without inherited patterns
|
|
3127
|
+
// This maintains backward compatibility
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
return context;
|
|
2080
3131
|
},
|
|
2081
3132
|
get_next_actionable_tickets: async (_client, args) => {
|
|
2082
3133
|
// Either specificationId or projectId is required
|
|
@@ -2102,10 +3153,130 @@ export function createToolHandlers(apiClient) {
|
|
|
2102
3153
|
});
|
|
2103
3154
|
},
|
|
2104
3155
|
get_patterns: async (_client, args) => {
|
|
2105
|
-
|
|
2106
|
-
|
|
3156
|
+
// Either specificationId or ticketId is required
|
|
3157
|
+
if (!args.specificationId && !args.ticketId) {
|
|
3158
|
+
throw new Error('Either specificationId or ticketId is required');
|
|
3159
|
+
}
|
|
3160
|
+
// If ticketId is provided, return resolved patterns with inheritance
|
|
3161
|
+
if (args.ticketId) {
|
|
3162
|
+
// Fetch ticket data
|
|
3163
|
+
const ticket = await apiClient.call('get_ticket', {
|
|
3164
|
+
ticketId: args.ticketId,
|
|
3165
|
+
});
|
|
3166
|
+
// Get epic data
|
|
3167
|
+
const epic = await apiClient.call('get_epic', {
|
|
3168
|
+
epicId: ticket.epicId,
|
|
3169
|
+
});
|
|
3170
|
+
// Get specification data
|
|
3171
|
+
const spec = await apiClient.call('get_specification', {
|
|
3172
|
+
specificationId: epic.specificationId,
|
|
3173
|
+
});
|
|
3174
|
+
// Build pattern resolution input
|
|
3175
|
+
const input = {
|
|
3176
|
+
ticketId: args.ticketId,
|
|
3177
|
+
specification: {
|
|
3178
|
+
id: spec.id,
|
|
3179
|
+
codeStandards: spec.codeStandards,
|
|
3180
|
+
commonImports: spec.commonImports,
|
|
3181
|
+
returnTypes: spec.returnTypes,
|
|
3182
|
+
},
|
|
3183
|
+
epic: {
|
|
3184
|
+
id: epic.id,
|
|
3185
|
+
sharedPatterns: epic.sharedPatterns,
|
|
3186
|
+
additionalImports: epic.additionalImports,
|
|
3187
|
+
commonFiles: epic.commonFiles,
|
|
3188
|
+
},
|
|
3189
|
+
ticket: {
|
|
3190
|
+
id: ticket.id,
|
|
3191
|
+
technicalDetails: ticket.technicalDetails,
|
|
3192
|
+
},
|
|
3193
|
+
};
|
|
3194
|
+
// Resolve patterns and get override info
|
|
3195
|
+
const resolved = resolvePatternsWithCache(input);
|
|
3196
|
+
const overrideReport = getPatternOverrides(input);
|
|
3197
|
+
return {
|
|
3198
|
+
resolved: {
|
|
3199
|
+
imports: resolved.imports,
|
|
3200
|
+
patterns: resolved.patterns,
|
|
3201
|
+
returnTypes: resolved.returnTypes,
|
|
3202
|
+
commonFiles: resolved.commonFiles,
|
|
3203
|
+
naming: resolved.naming,
|
|
3204
|
+
},
|
|
3205
|
+
raw: {
|
|
3206
|
+
specification: {
|
|
3207
|
+
codeStandards: spec.codeStandards ?? null,
|
|
3208
|
+
commonImports: spec.commonImports ?? [],
|
|
3209
|
+
returnTypes: spec.returnTypes ?? null,
|
|
3210
|
+
},
|
|
3211
|
+
epic: {
|
|
3212
|
+
sharedPatterns: epic.sharedPatterns ?? null,
|
|
3213
|
+
additionalImports: epic.additionalImports ?? [],
|
|
3214
|
+
commonFiles: epic.commonFiles ?? null,
|
|
3215
|
+
},
|
|
3216
|
+
ticket: {
|
|
3217
|
+
patterns: ticket.technicalDetails?.patterns ?? null,
|
|
3218
|
+
},
|
|
3219
|
+
},
|
|
3220
|
+
overrides: overrideReport.overrides,
|
|
3221
|
+
chain: {
|
|
3222
|
+
specificationId: spec.id,
|
|
3223
|
+
specificationTitle: spec.title,
|
|
3224
|
+
epicId: epic.id,
|
|
3225
|
+
epicTitle: epic.title,
|
|
3226
|
+
ticketId: ticket.id,
|
|
3227
|
+
ticketTitle: ticket.title,
|
|
3228
|
+
},
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
// Specification-level query (backward compatible)
|
|
3232
|
+
const specPatterns = await apiClient.call('get_patterns', {
|
|
2107
3233
|
specificationId: args.specificationId,
|
|
2108
3234
|
});
|
|
3235
|
+
// Get spec details for raw patterns if available
|
|
3236
|
+
let specData = null;
|
|
3237
|
+
try {
|
|
3238
|
+
specData = await apiClient.call('get_specification', {
|
|
3239
|
+
specificationId: args.specificationId,
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
catch {
|
|
3243
|
+
// If spec fetch fails, just return the raw response
|
|
3244
|
+
return specPatterns;
|
|
3245
|
+
}
|
|
3246
|
+
// Return enhanced response with raw patterns
|
|
3247
|
+
return {
|
|
3248
|
+
resolved: {
|
|
3249
|
+
imports: specData.commonImports ?? [],
|
|
3250
|
+
patterns: flattenCodeStandards(specData.codeStandards),
|
|
3251
|
+
returnTypes: specData.returnTypes ?? {},
|
|
3252
|
+
commonFiles: {},
|
|
3253
|
+
naming: specData.codeStandards?.naming ?? {},
|
|
3254
|
+
},
|
|
3255
|
+
raw: {
|
|
3256
|
+
specification: {
|
|
3257
|
+
codeStandards: specData.codeStandards ?? null,
|
|
3258
|
+
commonImports: specData.commonImports ?? [],
|
|
3259
|
+
returnTypes: specData.returnTypes ?? null,
|
|
3260
|
+
},
|
|
3261
|
+
epic: {
|
|
3262
|
+
sharedPatterns: null,
|
|
3263
|
+
additionalImports: [],
|
|
3264
|
+
commonFiles: null,
|
|
3265
|
+
},
|
|
3266
|
+
ticket: {
|
|
3267
|
+
patterns: null,
|
|
3268
|
+
},
|
|
3269
|
+
},
|
|
3270
|
+
overrides: [],
|
|
3271
|
+
chain: {
|
|
3272
|
+
specificationId: specData.id,
|
|
3273
|
+
specificationTitle: specData.title,
|
|
3274
|
+
epicId: '',
|
|
3275
|
+
epicTitle: '',
|
|
3276
|
+
ticketId: '',
|
|
3277
|
+
ticketTitle: '',
|
|
3278
|
+
},
|
|
3279
|
+
};
|
|
2109
3280
|
},
|
|
2110
3281
|
// ========================================================================
|
|
2111
3282
|
// Workflow & Tracking
|
|
@@ -2124,6 +3295,9 @@ export function createToolHandlers(apiClient) {
|
|
|
2124
3295
|
filesModified: args.filesModified,
|
|
2125
3296
|
filesCreated: args.filesCreated,
|
|
2126
3297
|
actualHours: args.actualHours,
|
|
3298
|
+
validated: args.validated, // MCI-066: simple validation flag
|
|
3299
|
+
validation: args.validation, // MCI-064: validation flags
|
|
3300
|
+
skipCriteriaCheck: args.skipCriteriaCheck, // MCI-065: skip criteria check
|
|
2127
3301
|
});
|
|
2128
3302
|
},
|
|
2129
3303
|
report_progress: async (_client, args) => {
|
|
@@ -2235,15 +3409,41 @@ export function createToolHandlers(apiClient) {
|
|
|
2235
3409
|
projectId: args.projectId,
|
|
2236
3410
|
});
|
|
2237
3411
|
},
|
|
3412
|
+
get_report: async (_client, args) => {
|
|
3413
|
+
validateRequired(args, 'type', 'scope', 'scopeId');
|
|
3414
|
+
return await apiClient.call('get_report', {
|
|
3415
|
+
type: args.type,
|
|
3416
|
+
scope: args.scope,
|
|
3417
|
+
scopeId: args.scopeId,
|
|
3418
|
+
format: args.format ?? 'json',
|
|
3419
|
+
startDate: args.startDate,
|
|
3420
|
+
endDate: args.endDate,
|
|
3421
|
+
});
|
|
3422
|
+
},
|
|
2238
3423
|
// ========================================================================
|
|
2239
3424
|
// Search Tools
|
|
2240
3425
|
// ========================================================================
|
|
2241
3426
|
search_tickets: async (_client, args) => {
|
|
2242
|
-
|
|
3427
|
+
// Validate at least one search criterion
|
|
3428
|
+
if (!args.query && !args.files && !args.tags && !args.relatedTo) {
|
|
3429
|
+
throw new Error('At least one filter is required: query, files, tags, or relatedTo');
|
|
3430
|
+
}
|
|
3431
|
+
// Validate at least one scope
|
|
3432
|
+
if (!args.projectId && !args.specificationId && !args.epicId) {
|
|
3433
|
+
throw new Error('One of projectId, specificationId, or epicId is required');
|
|
3434
|
+
}
|
|
2243
3435
|
return await apiClient.call('search_tickets', {
|
|
2244
3436
|
query: args.query,
|
|
3437
|
+
files: args.files,
|
|
3438
|
+
tags: args.tags,
|
|
3439
|
+
matchAllTags: args.matchAllTags ?? false,
|
|
3440
|
+
relatedTo: args.relatedTo,
|
|
3441
|
+
status: args.status,
|
|
3442
|
+
complexity: args.complexity,
|
|
3443
|
+
priority: args.priority,
|
|
2245
3444
|
specificationId: args.specificationId,
|
|
2246
3445
|
projectId: args.projectId,
|
|
3446
|
+
epicId: args.epicId,
|
|
2247
3447
|
limit: args.limit ?? 20,
|
|
2248
3448
|
offset: args.offset ?? 0,
|
|
2249
3449
|
});
|
|
@@ -2321,7 +3521,8 @@ export function createToolHandlers(apiClient) {
|
|
|
2321
3521
|
// ========================================================================
|
|
2322
3522
|
create_specification: async (_client, args) => {
|
|
2323
3523
|
validateRequired(args, 'projectId', 'title');
|
|
2324
|
-
|
|
3524
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3525
|
+
const result = await apiClient.call('create_specification', {
|
|
2325
3526
|
projectId: args.projectId,
|
|
2326
3527
|
title: args.title,
|
|
2327
3528
|
description: args.description,
|
|
@@ -2350,10 +3551,54 @@ export function createToolHandlers(apiClient) {
|
|
|
2350
3551
|
apiContracts: args.apiContracts,
|
|
2351
3552
|
targetAudience: args.targetAudience,
|
|
2352
3553
|
});
|
|
3554
|
+
return formatWriteResponse(result, responseMode, 'Specification created');
|
|
2353
3555
|
},
|
|
2354
3556
|
create_epic: async (_client, args) => {
|
|
2355
3557
|
validateRequired(args, 'specificationId', 'title', 'description', 'objective');
|
|
2356
|
-
|
|
3558
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3559
|
+
// Validate inline dependencies if tickets are provided with dependsOn
|
|
3560
|
+
if (args.tickets && Array.isArray(args.tickets)) {
|
|
3561
|
+
const tickets = args.tickets;
|
|
3562
|
+
const ticketCount = tickets.length;
|
|
3563
|
+
for (let i = 0; i < ticketCount; i++) {
|
|
3564
|
+
const ticket = tickets[i];
|
|
3565
|
+
if (ticket.dependsOn && Array.isArray(ticket.dependsOn)) {
|
|
3566
|
+
for (const depIndex of ticket.dependsOn) {
|
|
3567
|
+
// Check bounds
|
|
3568
|
+
if (typeof depIndex !== 'number' || depIndex < 0 || depIndex >= ticketCount) {
|
|
3569
|
+
throw new Error(`tickets[${i}].dependsOn: index ${depIndex} is out of bounds (must be 0-${ticketCount - 1})`);
|
|
3570
|
+
}
|
|
3571
|
+
// Check self-reference
|
|
3572
|
+
if (depIndex === i) {
|
|
3573
|
+
throw new Error(`tickets[${i}].dependsOn: ticket cannot depend on itself`);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
// Check for circular dependencies using DFS
|
|
3579
|
+
const hasCycle = (startIdx, visited, path) => {
|
|
3580
|
+
if (path.has(startIdx))
|
|
3581
|
+
return true;
|
|
3582
|
+
if (visited.has(startIdx))
|
|
3583
|
+
return false;
|
|
3584
|
+
visited.add(startIdx);
|
|
3585
|
+
path.add(startIdx);
|
|
3586
|
+
const deps = tickets[startIdx].dependsOn || [];
|
|
3587
|
+
for (const depIdx of deps) {
|
|
3588
|
+
if (hasCycle(depIdx, visited, path))
|
|
3589
|
+
return true;
|
|
3590
|
+
}
|
|
3591
|
+
path.delete(startIdx);
|
|
3592
|
+
return false;
|
|
3593
|
+
};
|
|
3594
|
+
const visited = new Set();
|
|
3595
|
+
for (let i = 0; i < ticketCount; i++) {
|
|
3596
|
+
if (hasCycle(i, visited, new Set())) {
|
|
3597
|
+
throw new Error(`Circular dependency detected in tickets array`);
|
|
3598
|
+
}
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
const result = await apiClient.call('create_epic', {
|
|
2357
3602
|
specificationId: args.specificationId,
|
|
2358
3603
|
title: args.title,
|
|
2359
3604
|
description: args.description,
|
|
@@ -2379,10 +3624,18 @@ export function createToolHandlers(apiClient) {
|
|
|
2379
3624
|
dependencies: args.dependencies,
|
|
2380
3625
|
apiContracts: args.apiContracts,
|
|
2381
3626
|
});
|
|
3627
|
+
return formatWriteResponse(result, responseMode, 'Epic created');
|
|
2382
3628
|
},
|
|
2383
3629
|
create_ticket: async (_client, args) => {
|
|
2384
3630
|
validateRequired(args, 'epicId', 'title');
|
|
2385
|
-
|
|
3631
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3632
|
+
// Extract validation options
|
|
3633
|
+
const skipValidation = args.skipValidation === true;
|
|
3634
|
+
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
3635
|
+
? args.validationStrictness
|
|
3636
|
+
: 'normal';
|
|
3637
|
+
// Create the ticket
|
|
3638
|
+
const result = await apiClient.call('create_ticket', {
|
|
2386
3639
|
epicId: args.epicId,
|
|
2387
3640
|
title: args.title,
|
|
2388
3641
|
ticketNumber: args.ticketNumber,
|
|
@@ -2397,6 +3650,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2397
3650
|
order: args.order,
|
|
2398
3651
|
dependsOn: args.dependsOn,
|
|
2399
3652
|
});
|
|
3653
|
+
// Run validation unless skipped
|
|
3654
|
+
if (!skipValidation) {
|
|
3655
|
+
const validation = validateTicket({
|
|
3656
|
+
complexity: args.complexity,
|
|
3657
|
+
implementation: args.implementation,
|
|
3658
|
+
technicalDetails: args.technicalDetails,
|
|
3659
|
+
notes: args.notes,
|
|
3660
|
+
acceptanceCriteria: args.acceptanceCriteria,
|
|
3661
|
+
});
|
|
3662
|
+
// Filter warnings by strictness level
|
|
3663
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
3664
|
+
// Add validation results to response
|
|
3665
|
+
result.warnings = warnings;
|
|
3666
|
+
result.completenessScore = validation.completenessScore;
|
|
3667
|
+
}
|
|
3668
|
+
return formatWriteResponse(result, responseMode, 'Ticket created');
|
|
2400
3669
|
},
|
|
2401
3670
|
import_specification: async (_client, args) => {
|
|
2402
3671
|
validateRequired(args, 'projectId', 'content');
|
|
@@ -2412,7 +3681,36 @@ export function createToolHandlers(apiClient) {
|
|
|
2412
3681
|
// ========================================================================
|
|
2413
3682
|
update_ticket: async (_client, args) => {
|
|
2414
3683
|
validateRequired(args, 'ticketId');
|
|
2415
|
-
|
|
3684
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3685
|
+
// Extract validation options
|
|
3686
|
+
const skipValidation = args.skipValidation === true;
|
|
3687
|
+
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
3688
|
+
? args.validationStrictness
|
|
3689
|
+
: 'normal';
|
|
3690
|
+
// Get current ticket to calculate previous completeness score
|
|
3691
|
+
let previousCompletenessScore;
|
|
3692
|
+
if (!skipValidation) {
|
|
3693
|
+
try {
|
|
3694
|
+
const currentTicket = await apiClient.call('get_ticket', {
|
|
3695
|
+
ticketId: args.ticketId,
|
|
3696
|
+
});
|
|
3697
|
+
// Calculate previous completeness score
|
|
3698
|
+
const prevValidation = validateTicket({
|
|
3699
|
+
complexity: currentTicket.complexity,
|
|
3700
|
+
implementation: currentTicket.implementation,
|
|
3701
|
+
technicalDetails: currentTicket.technicalDetails,
|
|
3702
|
+
notes: currentTicket.notes,
|
|
3703
|
+
acceptanceCriteria: currentTicket.acceptanceCriteria,
|
|
3704
|
+
});
|
|
3705
|
+
previousCompletenessScore = prevValidation.completenessScore;
|
|
3706
|
+
}
|
|
3707
|
+
catch {
|
|
3708
|
+
// If we can't get the current ticket, skip previous score tracking
|
|
3709
|
+
previousCompletenessScore = undefined;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
// Update the ticket
|
|
3713
|
+
const result = await apiClient.call('update_ticket', {
|
|
2416
3714
|
ticketId: args.ticketId,
|
|
2417
3715
|
title: args.title,
|
|
2418
3716
|
description: args.description,
|
|
@@ -2428,10 +3726,32 @@ export function createToolHandlers(apiClient) {
|
|
|
2428
3726
|
technicalDetails: args.technicalDetails,
|
|
2429
3727
|
blockReason: args.blockReason,
|
|
2430
3728
|
});
|
|
3729
|
+
// Run validation on updated ticket unless skipped
|
|
3730
|
+
if (!skipValidation) {
|
|
3731
|
+
// Use the updated values (from args) merged with existing values (from result)
|
|
3732
|
+
// The result should contain the final state after update
|
|
3733
|
+
const validation = validateTicket({
|
|
3734
|
+
complexity: (args.complexity || result.complexity),
|
|
3735
|
+
implementation: (args.implementation || result.implementation),
|
|
3736
|
+
technicalDetails: (args.technicalDetails || result.technicalDetails),
|
|
3737
|
+
notes: (args.notes || result.notes),
|
|
3738
|
+
acceptanceCriteria: (args.acceptanceCriteria || result.acceptanceCriteria),
|
|
3739
|
+
});
|
|
3740
|
+
// Filter warnings by strictness level
|
|
3741
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
3742
|
+
// Add validation results to response
|
|
3743
|
+
result.warnings = warnings;
|
|
3744
|
+
result.completenessScore = validation.completenessScore;
|
|
3745
|
+
if (previousCompletenessScore !== undefined) {
|
|
3746
|
+
result.previousCompletenessScore = previousCompletenessScore;
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
return formatWriteResponse(result, responseMode, 'Ticket updated');
|
|
2431
3750
|
},
|
|
2432
3751
|
update_epic: async (_client, args) => {
|
|
2433
3752
|
validateRequired(args, 'epicId');
|
|
2434
|
-
|
|
3753
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3754
|
+
const result = await apiClient.call('update_epic', {
|
|
2435
3755
|
epicId: args.epicId,
|
|
2436
3756
|
title: args.title,
|
|
2437
3757
|
description: args.description,
|
|
@@ -2454,10 +3774,12 @@ export function createToolHandlers(apiClient) {
|
|
|
2454
3774
|
tags: args.tags,
|
|
2455
3775
|
estimatedHours: args.estimatedHours,
|
|
2456
3776
|
});
|
|
3777
|
+
return formatWriteResponse(result, responseMode, 'Epic updated');
|
|
2457
3778
|
},
|
|
2458
3779
|
update_specification: async (_client, args) => {
|
|
2459
3780
|
validateRequired(args, 'specificationId');
|
|
2460
|
-
|
|
3781
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3782
|
+
const result = await apiClient.call('update_specification', {
|
|
2461
3783
|
specificationId: args.specificationId,
|
|
2462
3784
|
title: args.title,
|
|
2463
3785
|
description: args.description,
|
|
@@ -2488,6 +3810,7 @@ export function createToolHandlers(apiClient) {
|
|
|
2488
3810
|
workingDirectory: args.workingDirectory,
|
|
2489
3811
|
outputDirectory: args.outputDirectory,
|
|
2490
3812
|
});
|
|
3813
|
+
return formatWriteResponse(result, responseMode, 'Specification updated');
|
|
2491
3814
|
},
|
|
2492
3815
|
// ========================================================================
|
|
2493
3816
|
// Working Context Operations
|
|
@@ -2564,6 +3887,74 @@ export function createToolHandlers(apiClient) {
|
|
|
2564
3887
|
// ========================================================================
|
|
2565
3888
|
// Bulk Operations
|
|
2566
3889
|
// ========================================================================
|
|
3890
|
+
bulk_create_tickets: async (_client, args) => {
|
|
3891
|
+
validateRequired(args, 'epicId', 'tickets');
|
|
3892
|
+
if (!Array.isArray(args.tickets) || args.tickets.length === 0) {
|
|
3893
|
+
throw new Error('tickets array is required and must not be empty');
|
|
3894
|
+
}
|
|
3895
|
+
// Validate each ticket has a title
|
|
3896
|
+
const tickets = args.tickets;
|
|
3897
|
+
for (let i = 0; i < tickets.length; i++) {
|
|
3898
|
+
if (!tickets[i].title || typeof tickets[i].title !== 'string') {
|
|
3899
|
+
throw new Error(`tickets[${i}].title is required and must be a string`);
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
// Validate dependencies if provided
|
|
3903
|
+
if (args.dependencies && Array.isArray(args.dependencies)) {
|
|
3904
|
+
const deps = args.dependencies;
|
|
3905
|
+
for (let i = 0; i < deps.length; i++) {
|
|
3906
|
+
const dep = deps[i];
|
|
3907
|
+
if (typeof dep.ticket !== 'number' || dep.ticket < 0 || dep.ticket >= tickets.length) {
|
|
3908
|
+
throw new Error(`dependencies[${i}].ticket must be a valid index in tickets array (0-${tickets.length - 1})`);
|
|
3909
|
+
}
|
|
3910
|
+
const dependsOn = Array.isArray(dep.dependsOn) ? dep.dependsOn : [dep.dependsOn];
|
|
3911
|
+
for (const idx of dependsOn) {
|
|
3912
|
+
if (typeof idx !== 'number' || idx < 0 || idx >= tickets.length) {
|
|
3913
|
+
throw new Error(`dependencies[${i}].dependsOn contains invalid index ${idx} (must be 0-${tickets.length - 1})`);
|
|
3914
|
+
}
|
|
3915
|
+
if (idx === dep.ticket) {
|
|
3916
|
+
throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
return await apiClient.call('bulk_create_tickets', {
|
|
3922
|
+
epicId: args.epicId,
|
|
3923
|
+
tickets: args.tickets,
|
|
3924
|
+
dependencies: args.dependencies,
|
|
3925
|
+
onError: args.onError,
|
|
3926
|
+
});
|
|
3927
|
+
},
|
|
3928
|
+
get_job_status: async (_client, args) => {
|
|
3929
|
+
validateRequired(args, 'jobId');
|
|
3930
|
+
return await apiClient.call('get_job_status', {
|
|
3931
|
+
jobId: args.jobId,
|
|
3932
|
+
});
|
|
3933
|
+
},
|
|
3934
|
+
bulk_add_dependencies: async (_client, args) => {
|
|
3935
|
+
validateRequired(args, 'dependencies');
|
|
3936
|
+
if (!Array.isArray(args.dependencies) || args.dependencies.length === 0) {
|
|
3937
|
+
throw new Error('dependencies array is required and must not be empty');
|
|
3938
|
+
}
|
|
3939
|
+
// Validate each dependency has required fields
|
|
3940
|
+
const deps = args.dependencies;
|
|
3941
|
+
for (let i = 0; i < deps.length; i++) {
|
|
3942
|
+
if (!deps[i].ticketId || typeof deps[i].ticketId !== 'string') {
|
|
3943
|
+
throw new Error(`dependencies[${i}].ticketId is required`);
|
|
3944
|
+
}
|
|
3945
|
+
if (!deps[i].dependsOnId || typeof deps[i].dependsOnId !== 'string') {
|
|
3946
|
+
throw new Error(`dependencies[${i}].dependsOnId is required`);
|
|
3947
|
+
}
|
|
3948
|
+
if (deps[i].ticketId === deps[i].dependsOnId) {
|
|
3949
|
+
throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
return await apiClient.call('bulk_add_dependencies', {
|
|
3953
|
+
dependencies: args.dependencies,
|
|
3954
|
+
skipCircularCheck: args.skipCircularCheck,
|
|
3955
|
+
onError: args.onError,
|
|
3956
|
+
});
|
|
3957
|
+
},
|
|
2567
3958
|
bulk_update_tickets: async (_client, args) => {
|
|
2568
3959
|
if (!args.updates || !Array.isArray(args.updates) || args.updates.length === 0) {
|
|
2569
3960
|
throw new Error('updates array is required and must not be empty');
|
|
@@ -2589,6 +3980,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2589
3980
|
clearTestResults: args.clearTestResults,
|
|
2590
3981
|
});
|
|
2591
3982
|
},
|
|
3983
|
+
// ========================================================================
|
|
3984
|
+
// Validation Operations (MCI-075)
|
|
3985
|
+
// ========================================================================
|
|
3986
|
+
validate_counts: async (_client, args) => {
|
|
3987
|
+
// Must specify at least one scope
|
|
3988
|
+
if (!args.projectId && !args.specificationId && !args.epicId) {
|
|
3989
|
+
throw new Error('Must specify projectId, specificationId, or epicId');
|
|
3990
|
+
}
|
|
3991
|
+
return await apiClient.call('validate_counts', {
|
|
3992
|
+
projectId: args.projectId,
|
|
3993
|
+
specificationId: args.specificationId,
|
|
3994
|
+
epicId: args.epicId,
|
|
3995
|
+
repair: args.repair,
|
|
3996
|
+
verbose: args.verbose,
|
|
3997
|
+
});
|
|
3998
|
+
},
|
|
2592
3999
|
};
|
|
2593
4000
|
}
|
|
2594
4001
|
/**
|