@specforge/mcp 1.5.2 → 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 +1482 -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: {
|
|
@@ -361,6 +746,52 @@ export function getTools() {
|
|
|
361
746
|
items: { type: 'string' },
|
|
362
747
|
description: 'List of files created',
|
|
363
748
|
},
|
|
749
|
+
actualHours: {
|
|
750
|
+
type: 'number',
|
|
751
|
+
description: 'Actual hours spent on the ticket',
|
|
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
|
+
},
|
|
364
795
|
},
|
|
365
796
|
required: ['ticketId', 'summary'],
|
|
366
797
|
},
|
|
@@ -391,7 +822,7 @@ export function getTools() {
|
|
|
391
822
|
},
|
|
392
823
|
{
|
|
393
824
|
name: 'get_work_summary',
|
|
394
|
-
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',
|
|
395
826
|
inputSchema: {
|
|
396
827
|
type: 'object',
|
|
397
828
|
properties: {
|
|
@@ -421,7 +852,7 @@ export function getTools() {
|
|
|
421
852
|
// ========================================================================
|
|
422
853
|
{
|
|
423
854
|
name: 'report_test_results',
|
|
424
|
-
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.',
|
|
425
856
|
inputSchema: {
|
|
426
857
|
type: 'object',
|
|
427
858
|
properties: {
|
|
@@ -476,7 +907,7 @@ export function getTools() {
|
|
|
476
907
|
},
|
|
477
908
|
{
|
|
478
909
|
name: 'get_ticket_test_status',
|
|
479
|
-
description:
|
|
910
|
+
description: "[DEPRECATED] Get test status and history for a ticket. Use get_ticket({ include: ['testStatus'] }) instead. Will be removed in v3.0.",
|
|
480
911
|
inputSchema: {
|
|
481
912
|
type: 'object',
|
|
482
913
|
properties: {
|
|
@@ -490,7 +921,7 @@ export function getTools() {
|
|
|
490
921
|
},
|
|
491
922
|
{
|
|
492
923
|
name: 'validate_ticket_completion',
|
|
493
|
-
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.',
|
|
494
925
|
inputSchema: {
|
|
495
926
|
type: 'object',
|
|
496
927
|
properties: {
|
|
@@ -503,11 +934,11 @@ export function getTools() {
|
|
|
503
934
|
},
|
|
504
935
|
},
|
|
505
936
|
// ========================================================================
|
|
506
|
-
// Discovery Tools (Epic 7)
|
|
937
|
+
// Discovery Tools (Epic 7) - DEPRECATED: Use tag-based ticket operations instead
|
|
507
938
|
// ========================================================================
|
|
508
939
|
{
|
|
509
940
|
name: 'report_discovery',
|
|
510
|
-
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',
|
|
511
942
|
inputSchema: {
|
|
512
943
|
type: 'object',
|
|
513
944
|
properties: {
|
|
@@ -539,7 +970,7 @@ export function getTools() {
|
|
|
539
970
|
},
|
|
540
971
|
{
|
|
541
972
|
name: 'get_pending_discoveries',
|
|
542
|
-
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',
|
|
543
974
|
inputSchema: {
|
|
544
975
|
type: 'object',
|
|
545
976
|
properties: {
|
|
@@ -557,7 +988,7 @@ export function getTools() {
|
|
|
557
988
|
},
|
|
558
989
|
{
|
|
559
990
|
name: 'resolve_discovery',
|
|
560
|
-
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',
|
|
561
992
|
inputSchema: {
|
|
562
993
|
type: 'object',
|
|
563
994
|
properties: {
|
|
@@ -613,9 +1044,56 @@ export function getTools() {
|
|
|
613
1044
|
required: ['epicId'],
|
|
614
1045
|
},
|
|
615
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
|
+
},
|
|
616
1094
|
{
|
|
617
1095
|
name: 'get_implementation_summary',
|
|
618
|
-
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',
|
|
619
1097
|
inputSchema: {
|
|
620
1098
|
type: 'object',
|
|
621
1099
|
properties: {
|
|
@@ -629,7 +1107,7 @@ export function getTools() {
|
|
|
629
1107
|
},
|
|
630
1108
|
{
|
|
631
1109
|
name: 'get_time_report',
|
|
632
|
-
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',
|
|
633
1111
|
inputSchema: {
|
|
634
1112
|
type: 'object',
|
|
635
1113
|
properties: {
|
|
@@ -648,7 +1126,7 @@ export function getTools() {
|
|
|
648
1126
|
},
|
|
649
1127
|
{
|
|
650
1128
|
name: 'get_blockers_report',
|
|
651
|
-
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',
|
|
652
1130
|
inputSchema: {
|
|
653
1131
|
type: 'object',
|
|
654
1132
|
properties: {
|
|
@@ -669,37 +1147,124 @@ export function getTools() {
|
|
|
669
1147
|
// ========================================================================
|
|
670
1148
|
{
|
|
671
1149
|
name: 'search_tickets',
|
|
672
|
-
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.`,
|
|
673
1161
|
inputSchema: {
|
|
674
1162
|
type: 'object',
|
|
675
1163
|
properties: {
|
|
676
1164
|
query: {
|
|
677
1165
|
type: 'string',
|
|
678
|
-
description: '
|
|
1166
|
+
description: 'Full-text search query',
|
|
679
1167
|
},
|
|
680
|
-
|
|
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: {
|
|
681
1183
|
type: 'string',
|
|
682
|
-
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',
|
|
683
1209
|
},
|
|
684
1210
|
projectId: {
|
|
685
1211
|
type: 'string',
|
|
686
|
-
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',
|
|
687
1221
|
},
|
|
688
1222
|
limit: {
|
|
689
1223
|
type: 'number',
|
|
690
|
-
description: 'Maximum results (default: 20)',
|
|
1224
|
+
description: 'Maximum results (default: 20, max: 100)',
|
|
691
1225
|
},
|
|
692
1226
|
offset: {
|
|
693
1227
|
type: 'number',
|
|
694
1228
|
description: 'Pagination offset (default: 0)',
|
|
695
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
|
+
},
|
|
696
1262
|
},
|
|
697
|
-
required: ['query'],
|
|
698
1263
|
},
|
|
699
1264
|
},
|
|
700
1265
|
{
|
|
701
1266
|
name: 'find_tickets_by_file',
|
|
702
|
-
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)',
|
|
703
1268
|
inputSchema: {
|
|
704
1269
|
type: 'object',
|
|
705
1270
|
properties: {
|
|
@@ -721,7 +1286,7 @@ export function getTools() {
|
|
|
721
1286
|
},
|
|
722
1287
|
{
|
|
723
1288
|
name: 'find_tickets_by_tag',
|
|
724
|
-
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',
|
|
725
1290
|
inputSchema: {
|
|
726
1291
|
type: 'object',
|
|
727
1292
|
properties: {
|
|
@@ -748,7 +1313,7 @@ export function getTools() {
|
|
|
748
1313
|
},
|
|
749
1314
|
{
|
|
750
1315
|
name: 'find_related_tickets',
|
|
751
|
-
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',
|
|
752
1317
|
inputSchema: {
|
|
753
1318
|
type: 'object',
|
|
754
1319
|
properties: {
|
|
@@ -833,7 +1398,7 @@ export function getTools() {
|
|
|
833
1398
|
},
|
|
834
1399
|
{
|
|
835
1400
|
name: 'get_ticket_commits',
|
|
836
|
-
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",
|
|
837
1402
|
inputSchema: {
|
|
838
1403
|
type: 'object',
|
|
839
1404
|
properties: {
|
|
@@ -855,7 +1420,7 @@ export function getTools() {
|
|
|
855
1420
|
},
|
|
856
1421
|
{
|
|
857
1422
|
name: 'get_ticket_prs',
|
|
858
|
-
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",
|
|
859
1424
|
inputSchema: {
|
|
860
1425
|
type: 'object',
|
|
861
1426
|
properties: {
|
|
@@ -1023,6 +1588,48 @@ export function getTools() {
|
|
|
1023
1588
|
required: ['title', 'description', 'objective'],
|
|
1024
1589
|
},
|
|
1025
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
|
+
},
|
|
1026
1633
|
},
|
|
1027
1634
|
required: ['projectId', 'title'],
|
|
1028
1635
|
},
|
|
@@ -1129,7 +1736,7 @@ export function getTools() {
|
|
|
1129
1736
|
},
|
|
1130
1737
|
tickets: {
|
|
1131
1738
|
type: 'array',
|
|
1132
|
-
description: 'Nested tickets to create (bulk creation)',
|
|
1739
|
+
description: 'Nested tickets to create (bulk creation) with optional inline dependencies',
|
|
1133
1740
|
items: {
|
|
1134
1741
|
type: 'object',
|
|
1135
1742
|
properties: {
|
|
@@ -1138,17 +1745,57 @@ export function getTools() {
|
|
|
1138
1745
|
acceptanceCriteria: { type: 'array', items: { type: 'string' } },
|
|
1139
1746
|
estimatedHours: { type: 'number' },
|
|
1140
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
|
+
},
|
|
1141
1757
|
},
|
|
1142
1758
|
required: ['title'],
|
|
1143
1759
|
},
|
|
1144
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
|
+
},
|
|
1145
1792
|
},
|
|
1146
1793
|
required: ['specificationId', 'title', 'description', 'objective'],
|
|
1147
1794
|
},
|
|
1148
1795
|
},
|
|
1149
1796
|
{
|
|
1150
1797
|
name: 'create_ticket',
|
|
1151
|
-
description: 'Create a new ticket in an epic',
|
|
1798
|
+
description: 'Create a new ticket in an epic. Returns validation warnings based on complexity level.',
|
|
1152
1799
|
inputSchema: {
|
|
1153
1800
|
type: 'object',
|
|
1154
1801
|
properties: {
|
|
@@ -1209,6 +1856,20 @@ export function getTools() {
|
|
|
1209
1856
|
items: { type: 'string' },
|
|
1210
1857
|
description: 'Array of ticket IDs this ticket depends on',
|
|
1211
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
|
+
},
|
|
1212
1873
|
},
|
|
1213
1874
|
required: ['epicId', 'title'],
|
|
1214
1875
|
},
|
|
@@ -1244,7 +1905,9 @@ export function getTools() {
|
|
|
1244
1905
|
// ========================================================================
|
|
1245
1906
|
{
|
|
1246
1907
|
name: 'update_ticket',
|
|
1247
|
-
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).',
|
|
1248
1911
|
inputSchema: {
|
|
1249
1912
|
type: 'object',
|
|
1250
1913
|
properties: {
|
|
@@ -1262,8 +1925,8 @@ export function getTools() {
|
|
|
1262
1925
|
},
|
|
1263
1926
|
status: {
|
|
1264
1927
|
type: 'string',
|
|
1265
|
-
enum: ['
|
|
1266
|
-
description: '
|
|
1928
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
1929
|
+
description: 'Ticket status. pending/ready may be recalculated based on dependencies.',
|
|
1267
1930
|
},
|
|
1268
1931
|
priority: {
|
|
1269
1932
|
type: 'string',
|
|
@@ -1277,7 +1940,7 @@ export function getTools() {
|
|
|
1277
1940
|
},
|
|
1278
1941
|
blockReason: {
|
|
1279
1942
|
type: 'string',
|
|
1280
|
-
description: '
|
|
1943
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1281
1944
|
},
|
|
1282
1945
|
notes: {
|
|
1283
1946
|
type: 'string',
|
|
@@ -1305,6 +1968,22 @@ export function getTools() {
|
|
|
1305
1968
|
type: 'object',
|
|
1306
1969
|
description: 'Technical details like stack, endpoints (JSON) (optional)',
|
|
1307
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
|
+
},
|
|
1308
1987
|
},
|
|
1309
1988
|
required: ['ticketId'],
|
|
1310
1989
|
},
|
|
@@ -1406,6 +2085,37 @@ export function getTools() {
|
|
|
1406
2085
|
enum: ['low', 'medium', 'high', 'critical'],
|
|
1407
2086
|
description: 'Priority level (optional)',
|
|
1408
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
|
+
},
|
|
1409
2119
|
},
|
|
1410
2120
|
required: ['epicId'],
|
|
1411
2121
|
},
|
|
@@ -1551,6 +2261,48 @@ export function getTools() {
|
|
|
1551
2261
|
type: 'string',
|
|
1552
2262
|
description: 'Output directory for build artifacts (optional)',
|
|
1553
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
|
+
},
|
|
1554
2306
|
},
|
|
1555
2307
|
required: ['specificationId'],
|
|
1556
2308
|
},
|
|
@@ -1644,7 +2396,7 @@ export function getTools() {
|
|
|
1644
2396
|
},
|
|
1645
2397
|
{
|
|
1646
2398
|
name: 'get_session',
|
|
1647
|
-
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",
|
|
1648
2400
|
inputSchema: {
|
|
1649
2401
|
type: 'object',
|
|
1650
2402
|
properties: {
|
|
@@ -1666,7 +2418,7 @@ export function getTools() {
|
|
|
1666
2418
|
},
|
|
1667
2419
|
{
|
|
1668
2420
|
name: 'update_session',
|
|
1669
|
-
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)',
|
|
1670
2422
|
inputSchema: {
|
|
1671
2423
|
type: 'object',
|
|
1672
2424
|
properties: {
|
|
@@ -1697,7 +2449,7 @@ export function getTools() {
|
|
|
1697
2449
|
},
|
|
1698
2450
|
{
|
|
1699
2451
|
name: 'record_session_ticket',
|
|
1700
|
-
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.',
|
|
1701
2453
|
inputSchema: {
|
|
1702
2454
|
type: 'object',
|
|
1703
2455
|
properties: {
|
|
@@ -1755,7 +2507,7 @@ export function getTools() {
|
|
|
1755
2507
|
},
|
|
1756
2508
|
{
|
|
1757
2509
|
name: 'list_sessions',
|
|
1758
|
-
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",
|
|
1759
2511
|
inputSchema: {
|
|
1760
2512
|
type: 'object',
|
|
1761
2513
|
properties: {
|
|
@@ -1790,6 +2542,147 @@ export function getTools() {
|
|
|
1790
2542
|
// ========================================================================
|
|
1791
2543
|
// Bulk Operations
|
|
1792
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
|
+
},
|
|
1793
2686
|
{
|
|
1794
2687
|
name: 'bulk_update_tickets',
|
|
1795
2688
|
description: 'Update multiple tickets in a single atomic operation. All updates succeed or all fail (unless atomic: false).',
|
|
@@ -1807,8 +2700,8 @@ export function getTools() {
|
|
|
1807
2700
|
},
|
|
1808
2701
|
status: {
|
|
1809
2702
|
type: 'string',
|
|
1810
|
-
enum: ['
|
|
1811
|
-
description: '
|
|
2703
|
+
enum: ['pending', 'ready', 'active', 'done'],
|
|
2704
|
+
description: 'Ticket status. Completing (done) triggers cascade to unblock dependents.',
|
|
1812
2705
|
},
|
|
1813
2706
|
priority: {
|
|
1814
2707
|
type: 'string',
|
|
@@ -1823,7 +2716,7 @@ export function getTools() {
|
|
|
1823
2716
|
},
|
|
1824
2717
|
blockReason: {
|
|
1825
2718
|
type: 'string',
|
|
1826
|
-
description: '
|
|
2719
|
+
description: 'External block reason. Forces status to pending until cleared.',
|
|
1827
2720
|
},
|
|
1828
2721
|
},
|
|
1829
2722
|
required: ['ticketId'],
|
|
@@ -1838,13 +2731,21 @@ export function getTools() {
|
|
|
1838
2731
|
type: 'boolean',
|
|
1839
2732
|
description: 'All-or-nothing updates. If false, partial success allowed (default: true)',
|
|
1840
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
|
+
},
|
|
1841
2742
|
},
|
|
1842
2743
|
required: ['updates'],
|
|
1843
2744
|
},
|
|
1844
2745
|
},
|
|
1845
2746
|
{
|
|
1846
2747
|
name: 'reset_tickets',
|
|
1847
|
-
description: 'Reset tickets to
|
|
2748
|
+
description: 'Reset tickets to pending/ready status (calculated from dependencies). Returns statusCalculation showing how many became pending vs ready.',
|
|
1848
2749
|
inputSchema: {
|
|
1849
2750
|
type: 'object',
|
|
1850
2751
|
properties: {
|
|
@@ -1869,11 +2770,6 @@ export function getTools() {
|
|
|
1869
2770
|
type: 'boolean',
|
|
1870
2771
|
description: 'Reset all tickets in the specification',
|
|
1871
2772
|
},
|
|
1872
|
-
targetStatus: {
|
|
1873
|
-
type: 'string',
|
|
1874
|
-
enum: ['todo', 'queue'],
|
|
1875
|
-
description: 'Status to reset tickets to (default: todo)',
|
|
1876
|
-
},
|
|
1877
2773
|
resetDependents: {
|
|
1878
2774
|
type: 'boolean',
|
|
1879
2775
|
description: 'Also reset tickets that depend on the specified tickets (default: false)',
|
|
@@ -1894,7 +2790,47 @@ export function getTools() {
|
|
|
1894
2790
|
required: ['specificationId'],
|
|
1895
2791
|
},
|
|
1896
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
|
+
},
|
|
1897
2831
|
];
|
|
2832
|
+
// Apply format parameter to all read operations
|
|
2833
|
+
return tools.map(tool => READ_TOOL_NAMES.has(tool.name) ? addFormatParameter(tool) : tool);
|
|
1898
2834
|
}
|
|
1899
2835
|
/**
|
|
1900
2836
|
* Retry configuration for transient failures
|
|
@@ -1982,6 +2918,12 @@ export function createToolHandlers(apiClient) {
|
|
|
1982
2918
|
projectId: args.projectId,
|
|
1983
2919
|
});
|
|
1984
2920
|
},
|
|
2921
|
+
lookup_project: async (_client, args) => {
|
|
2922
|
+
validateRequired(args, 'name');
|
|
2923
|
+
return await apiClient.call('lookup_project', {
|
|
2924
|
+
name: args.name,
|
|
2925
|
+
});
|
|
2926
|
+
},
|
|
1985
2927
|
// ========================================================================
|
|
1986
2928
|
// Core Operations - Specifications
|
|
1987
2929
|
// ========================================================================
|
|
@@ -1990,12 +2932,24 @@ export function createToolHandlers(apiClient) {
|
|
|
1990
2932
|
return await apiClient.call('list_specifications', {
|
|
1991
2933
|
projectId: args.projectId,
|
|
1992
2934
|
status: args.status,
|
|
2935
|
+
limit: args.limit,
|
|
2936
|
+
offset: args.offset,
|
|
2937
|
+
fields: args.fields,
|
|
1993
2938
|
});
|
|
1994
2939
|
},
|
|
1995
2940
|
get_specification: async (_client, args) => {
|
|
1996
2941
|
validateRequired(args, 'specificationId');
|
|
1997
2942
|
return await apiClient.call('get_specification', {
|
|
1998
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,
|
|
1999
2953
|
});
|
|
2000
2954
|
},
|
|
2001
2955
|
// ========================================================================
|
|
@@ -2006,12 +2960,29 @@ export function createToolHandlers(apiClient) {
|
|
|
2006
2960
|
return await apiClient.call('list_epics', {
|
|
2007
2961
|
specificationId: args.specificationId,
|
|
2008
2962
|
status: args.status,
|
|
2963
|
+
limit: args.limit,
|
|
2964
|
+
offset: args.offset,
|
|
2965
|
+
fields: args.fields,
|
|
2009
2966
|
});
|
|
2010
2967
|
},
|
|
2011
2968
|
get_epic: async (_client, args) => {
|
|
2012
2969
|
validateRequired(args, 'epicId');
|
|
2013
2970
|
return await apiClient.call('get_epic', {
|
|
2014
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,
|
|
2015
2986
|
});
|
|
2016
2987
|
},
|
|
2017
2988
|
// ========================================================================
|
|
@@ -2022,12 +2993,53 @@ export function createToolHandlers(apiClient) {
|
|
|
2022
2993
|
return await apiClient.call('list_tickets', {
|
|
2023
2994
|
epicId: args.epicId,
|
|
2024
2995
|
status: args.status,
|
|
2996
|
+
limit: args.limit,
|
|
2997
|
+
offset: args.offset,
|
|
2998
|
+
include: args.include,
|
|
2999
|
+
fields: args.fields,
|
|
2025
3000
|
});
|
|
2026
3001
|
},
|
|
2027
3002
|
get_ticket: async (_client, args) => {
|
|
2028
3003
|
validateRequired(args, 'ticketId');
|
|
2029
3004
|
return await apiClient.call('get_ticket', {
|
|
2030
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,
|
|
2031
3043
|
});
|
|
2032
3044
|
},
|
|
2033
3045
|
// ========================================================================
|
|
@@ -2070,9 +3082,52 @@ export function createToolHandlers(apiClient) {
|
|
|
2070
3082
|
// ========================================================================
|
|
2071
3083
|
get_implementation_context: async (_client, args) => {
|
|
2072
3084
|
validateRequired(args, 'ticketId');
|
|
2073
|
-
|
|
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', {
|
|
2074
3088
|
ticketId: args.ticketId,
|
|
3089
|
+
depth,
|
|
2075
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;
|
|
2076
3131
|
},
|
|
2077
3132
|
get_next_actionable_tickets: async (_client, args) => {
|
|
2078
3133
|
// Either specificationId or projectId is required
|
|
@@ -2098,10 +3153,130 @@ export function createToolHandlers(apiClient) {
|
|
|
2098
3153
|
});
|
|
2099
3154
|
},
|
|
2100
3155
|
get_patterns: async (_client, args) => {
|
|
2101
|
-
|
|
2102
|
-
|
|
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', {
|
|
2103
3233
|
specificationId: args.specificationId,
|
|
2104
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
|
+
};
|
|
2105
3280
|
},
|
|
2106
3281
|
// ========================================================================
|
|
2107
3282
|
// Workflow & Tracking
|
|
@@ -2119,6 +3294,10 @@ export function createToolHandlers(apiClient) {
|
|
|
2119
3294
|
summary: args.summary,
|
|
2120
3295
|
filesModified: args.filesModified,
|
|
2121
3296
|
filesCreated: args.filesCreated,
|
|
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
|
|
2122
3301
|
});
|
|
2123
3302
|
},
|
|
2124
3303
|
report_progress: async (_client, args) => {
|
|
@@ -2230,15 +3409,41 @@ export function createToolHandlers(apiClient) {
|
|
|
2230
3409
|
projectId: args.projectId,
|
|
2231
3410
|
});
|
|
2232
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
|
+
},
|
|
2233
3423
|
// ========================================================================
|
|
2234
3424
|
// Search Tools
|
|
2235
3425
|
// ========================================================================
|
|
2236
3426
|
search_tickets: async (_client, args) => {
|
|
2237
|
-
|
|
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
|
+
}
|
|
2238
3435
|
return await apiClient.call('search_tickets', {
|
|
2239
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,
|
|
2240
3444
|
specificationId: args.specificationId,
|
|
2241
3445
|
projectId: args.projectId,
|
|
3446
|
+
epicId: args.epicId,
|
|
2242
3447
|
limit: args.limit ?? 20,
|
|
2243
3448
|
offset: args.offset ?? 0,
|
|
2244
3449
|
});
|
|
@@ -2316,7 +3521,8 @@ export function createToolHandlers(apiClient) {
|
|
|
2316
3521
|
// ========================================================================
|
|
2317
3522
|
create_specification: async (_client, args) => {
|
|
2318
3523
|
validateRequired(args, 'projectId', 'title');
|
|
2319
|
-
|
|
3524
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3525
|
+
const result = await apiClient.call('create_specification', {
|
|
2320
3526
|
projectId: args.projectId,
|
|
2321
3527
|
title: args.title,
|
|
2322
3528
|
description: args.description,
|
|
@@ -2345,10 +3551,54 @@ export function createToolHandlers(apiClient) {
|
|
|
2345
3551
|
apiContracts: args.apiContracts,
|
|
2346
3552
|
targetAudience: args.targetAudience,
|
|
2347
3553
|
});
|
|
3554
|
+
return formatWriteResponse(result, responseMode, 'Specification created');
|
|
2348
3555
|
},
|
|
2349
3556
|
create_epic: async (_client, args) => {
|
|
2350
3557
|
validateRequired(args, 'specificationId', 'title', 'description', 'objective');
|
|
2351
|
-
|
|
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', {
|
|
2352
3602
|
specificationId: args.specificationId,
|
|
2353
3603
|
title: args.title,
|
|
2354
3604
|
description: args.description,
|
|
@@ -2374,10 +3624,18 @@ export function createToolHandlers(apiClient) {
|
|
|
2374
3624
|
dependencies: args.dependencies,
|
|
2375
3625
|
apiContracts: args.apiContracts,
|
|
2376
3626
|
});
|
|
3627
|
+
return formatWriteResponse(result, responseMode, 'Epic created');
|
|
2377
3628
|
},
|
|
2378
3629
|
create_ticket: async (_client, args) => {
|
|
2379
3630
|
validateRequired(args, 'epicId', 'title');
|
|
2380
|
-
|
|
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', {
|
|
2381
3639
|
epicId: args.epicId,
|
|
2382
3640
|
title: args.title,
|
|
2383
3641
|
ticketNumber: args.ticketNumber,
|
|
@@ -2392,6 +3650,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2392
3650
|
order: args.order,
|
|
2393
3651
|
dependsOn: args.dependsOn,
|
|
2394
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');
|
|
2395
3669
|
},
|
|
2396
3670
|
import_specification: async (_client, args) => {
|
|
2397
3671
|
validateRequired(args, 'projectId', 'content');
|
|
@@ -2407,7 +3681,36 @@ export function createToolHandlers(apiClient) {
|
|
|
2407
3681
|
// ========================================================================
|
|
2408
3682
|
update_ticket: async (_client, args) => {
|
|
2409
3683
|
validateRequired(args, 'ticketId');
|
|
2410
|
-
|
|
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', {
|
|
2411
3714
|
ticketId: args.ticketId,
|
|
2412
3715
|
title: args.title,
|
|
2413
3716
|
description: args.description,
|
|
@@ -2423,10 +3726,32 @@ export function createToolHandlers(apiClient) {
|
|
|
2423
3726
|
technicalDetails: args.technicalDetails,
|
|
2424
3727
|
blockReason: args.blockReason,
|
|
2425
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');
|
|
2426
3750
|
},
|
|
2427
3751
|
update_epic: async (_client, args) => {
|
|
2428
3752
|
validateRequired(args, 'epicId');
|
|
2429
|
-
|
|
3753
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3754
|
+
const result = await apiClient.call('update_epic', {
|
|
2430
3755
|
epicId: args.epicId,
|
|
2431
3756
|
title: args.title,
|
|
2432
3757
|
description: args.description,
|
|
@@ -2449,10 +3774,12 @@ export function createToolHandlers(apiClient) {
|
|
|
2449
3774
|
tags: args.tags,
|
|
2450
3775
|
estimatedHours: args.estimatedHours,
|
|
2451
3776
|
});
|
|
3777
|
+
return formatWriteResponse(result, responseMode, 'Epic updated');
|
|
2452
3778
|
},
|
|
2453
3779
|
update_specification: async (_client, args) => {
|
|
2454
3780
|
validateRequired(args, 'specificationId');
|
|
2455
|
-
|
|
3781
|
+
const responseMode = getResponseModeFromArgs(args);
|
|
3782
|
+
const result = await apiClient.call('update_specification', {
|
|
2456
3783
|
specificationId: args.specificationId,
|
|
2457
3784
|
title: args.title,
|
|
2458
3785
|
description: args.description,
|
|
@@ -2483,6 +3810,7 @@ export function createToolHandlers(apiClient) {
|
|
|
2483
3810
|
workingDirectory: args.workingDirectory,
|
|
2484
3811
|
outputDirectory: args.outputDirectory,
|
|
2485
3812
|
});
|
|
3813
|
+
return formatWriteResponse(result, responseMode, 'Specification updated');
|
|
2486
3814
|
},
|
|
2487
3815
|
// ========================================================================
|
|
2488
3816
|
// Working Context Operations
|
|
@@ -2559,6 +3887,74 @@ export function createToolHandlers(apiClient) {
|
|
|
2559
3887
|
// ========================================================================
|
|
2560
3888
|
// Bulk Operations
|
|
2561
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
|
+
},
|
|
2562
3958
|
bulk_update_tickets: async (_client, args) => {
|
|
2563
3959
|
if (!args.updates || !Array.isArray(args.updates) || args.updates.length === 0) {
|
|
2564
3960
|
throw new Error('updates array is required and must not be empty');
|
|
@@ -2584,6 +3980,22 @@ export function createToolHandlers(apiClient) {
|
|
|
2584
3980
|
clearTestResults: args.clearTestResults,
|
|
2585
3981
|
});
|
|
2586
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
|
+
},
|
|
2587
3999
|
};
|
|
2588
4000
|
}
|
|
2589
4001
|
/**
|