@crowley/rag-mcp 1.5.0 → 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.
@@ -5,7 +5,7 @@
5
5
  * batch_remember, validate_memory, review_memories,
6
6
  * promote_memory, run_quality_gates, memory_maintenance
7
7
  */
8
- import { formatMemoryResults, truncate, paginationFooter, PREVIEW } from "../formatters.js";
8
+ import { formatMemoryResults, truncate, paginationFooter, PREVIEW, } from "../formatters.js";
9
9
  import { z } from "zod";
10
10
  import { TOOL_ANNOTATIONS } from "../annotations.js";
11
11
  const typeEmojis = {
@@ -29,8 +29,21 @@ export function createMemoryTools(projectName) {
29
29
  description: "Store important information in agent memory. Use this to save decisions, insights, context, todos, or important conversations for future reference.",
30
30
  schema: z.object({
31
31
  content: z.string().describe("Information to remember"),
32
- type: z.enum(["decision", "insight", "context", "todo", "conversation", "note"]).optional().describe("Type of memory (default: note)"),
33
- tags: z.array(z.string()).optional().describe("Tags for categorization (e.g., ['feature-x', 'important'])"),
32
+ type: z
33
+ .enum([
34
+ "decision",
35
+ "insight",
36
+ "context",
37
+ "todo",
38
+ "conversation",
39
+ "note",
40
+ ])
41
+ .optional()
42
+ .describe("Type of memory (default: note)"),
43
+ tags: z
44
+ .array(z.string())
45
+ .optional()
46
+ .describe("Tags for categorization (e.g., ['feature-x', 'important'])"),
34
47
  relatedTo: z.string().optional().describe("Related feature or topic"),
35
48
  }),
36
49
  annotations: TOOL_ANNOTATIONS["remember"],
@@ -61,9 +74,27 @@ export function createMemoryTools(projectName) {
61
74
  description: "Retrieve relevant memories based on context. Searches agent memory for past decisions, insights, and notes related to the query.",
62
75
  schema: z.object({
63
76
  query: z.string().describe("What to recall (semantic search)"),
64
- type: z.enum(["decision", "insight", "context", "todo", "conversation", "note", "procedure", "all"]).optional().describe("Filter by memory type (default: all)"),
65
- limit: z.coerce.number().optional().describe("Max memories to retrieve (default: 5)"),
66
- graphRecall: z.boolean().optional().describe("Enable graph-aware recall with spreading activation (default: false)"),
77
+ type: z
78
+ .enum([
79
+ "decision",
80
+ "insight",
81
+ "context",
82
+ "todo",
83
+ "conversation",
84
+ "note",
85
+ "procedure",
86
+ "all",
87
+ ])
88
+ .optional()
89
+ .describe("Filter by memory type (default: all)"),
90
+ limit: z.coerce
91
+ .number()
92
+ .optional()
93
+ .describe("Max memories to retrieve (default: 5)"),
94
+ graphRecall: z
95
+ .boolean()
96
+ .optional()
97
+ .describe("Enable graph-aware recall with spreading activation (default: false)"),
67
98
  }),
68
99
  annotations: TOOL_ANNOTATIONS["recall"],
69
100
  handler: async (args, ctx) => {
@@ -90,10 +121,27 @@ export function createMemoryTools(projectName) {
90
121
  name: "list_memories",
91
122
  description: "List recent memories or filter by type/tags. Shows what the agent has remembered.",
92
123
  schema: z.object({
93
- type: z.enum(["decision", "insight", "context", "todo", "conversation", "note", "all"]).optional().describe("Filter by type"),
124
+ type: z
125
+ .enum([
126
+ "decision",
127
+ "insight",
128
+ "context",
129
+ "todo",
130
+ "conversation",
131
+ "note",
132
+ "all",
133
+ ])
134
+ .optional()
135
+ .describe("Filter by type"),
94
136
  tag: z.string().optional().describe("Filter by tag"),
95
- limit: z.coerce.number().optional().describe("Max results (default: 10)"),
96
- offset: z.coerce.number().optional().describe("Pagination offset (default: 0)"),
137
+ limit: z.coerce
138
+ .number()
139
+ .optional()
140
+ .describe("Max results (default: 10)"),
141
+ offset: z.coerce
142
+ .number()
143
+ .optional()
144
+ .describe("Pagination offset (default: 0)"),
97
145
  }),
98
146
  annotations: TOOL_ANNOTATIONS["list_memories"],
99
147
  handler: async (args, ctx) => {
@@ -130,9 +178,25 @@ export function createMemoryTools(projectName) {
130
178
  name: "forget",
131
179
  description: "Delete a specific memory by ID or clear memories by type.",
132
180
  schema: z.object({
133
- memoryId: z.string().optional().describe("Specific memory ID to delete"),
134
- type: z.enum(["decision", "insight", "context", "todo", "conversation", "note"]).optional().describe("Delete all memories of this type"),
135
- olderThanDays: z.coerce.number().optional().describe("Delete memories older than N days"),
181
+ memoryId: z
182
+ .string()
183
+ .optional()
184
+ .describe("Specific memory ID to delete"),
185
+ type: z
186
+ .enum([
187
+ "decision",
188
+ "insight",
189
+ "context",
190
+ "todo",
191
+ "conversation",
192
+ "note",
193
+ ])
194
+ .optional()
195
+ .describe("Delete all memories of this type"),
196
+ olderThanDays: z.coerce
197
+ .number()
198
+ .optional()
199
+ .describe("Delete memories older than N days"),
136
200
  }),
137
201
  annotations: TOOL_ANNOTATIONS["forget"],
138
202
  handler: async (args, ctx) => {
@@ -164,7 +228,9 @@ export function createMemoryTools(projectName) {
164
228
  description: "Update status of a todo/task in memory.",
165
229
  schema: z.object({
166
230
  todoId: z.string().describe("Todo memory ID"),
167
- status: z.enum(["pending", "in_progress", "done", "cancelled"]).describe("New status"),
231
+ status: z
232
+ .enum(["pending", "in_progress", "done", "cancelled"])
233
+ .describe("New status"),
168
234
  note: z.string().optional().describe("Optional note about the update"),
169
235
  }),
170
236
  annotations: TOOL_ANNOTATIONS["update_todo"],
@@ -191,12 +257,53 @@ export function createMemoryTools(projectName) {
191
257
  name: "batch_remember",
192
258
  description: `Efficiently store multiple memories at once in ${projectName}. Faster than individual remember calls.`,
193
259
  schema: z.object({
194
- items: z.array(z.object({
260
+ items: z
261
+ .array(z.object({
195
262
  content: z.string().describe("Content to remember"),
196
- type: z.enum(["decision", "insight", "context", "todo", "conversation", "note"]).optional().describe("Memory type (default: note)"),
197
- tags: z.array(z.string()).optional().describe("Tags for categorization"),
198
- relatedTo: z.string().optional().describe("Related feature or topic"),
199
- })).describe("Array of memories to store"),
263
+ type: z
264
+ .enum([
265
+ "decision",
266
+ "insight",
267
+ "context",
268
+ "todo",
269
+ "conversation",
270
+ "note",
271
+ ])
272
+ .optional()
273
+ .describe("Memory type (default: note)"),
274
+ tags: z
275
+ .array(z.string())
276
+ .optional()
277
+ .describe("Tags for categorization"),
278
+ relatedTo: z
279
+ .string()
280
+ .optional()
281
+ .describe("Related feature or topic"),
282
+ metadata: z
283
+ .record(z.string(), z.unknown())
284
+ .optional()
285
+ .describe("Custom metadata (factEntities, factDateTs, etc.)"),
286
+ factCategory: z
287
+ .enum([
288
+ "personal_info",
289
+ "preference",
290
+ "event",
291
+ "temporal",
292
+ "update",
293
+ "plan",
294
+ ])
295
+ .optional()
296
+ .describe("Structured fact category for temporal retrieval"),
297
+ factEntities: z
298
+ .array(z.string())
299
+ .optional()
300
+ .describe("Named entities: file names, service names, external systems"),
301
+ factDateTs: z
302
+ .number()
303
+ .optional()
304
+ .describe("Unix timestamp (seconds) for temporal filtering"),
305
+ }))
306
+ .describe("Array of memories to store"),
200
307
  }),
201
308
  annotations: TOOL_ANNOTATIONS["batch_remember"],
202
309
  handler: async (args, ctx) => {
@@ -229,7 +336,9 @@ export function createMemoryTools(projectName) {
229
336
  description: `Validate or reject an auto-extracted memory in ${projectName}. Helps improve future extraction accuracy.`,
230
337
  schema: z.object({
231
338
  memoryId: z.string().describe("ID of the memory to validate"),
232
- validated: z.boolean().describe("true to confirm the memory is valuable, false to reject it"),
339
+ validated: z
340
+ .boolean()
341
+ .describe("true to confirm the memory is valuable, false to reject it"),
233
342
  }),
234
343
  annotations: TOOL_ANNOTATIONS["validate_memory"],
235
344
  handler: async (args, ctx) => {
@@ -250,8 +359,14 @@ export function createMemoryTools(projectName) {
250
359
  name: "review_memories",
251
360
  description: `Get auto-extracted memories pending review in ${projectName}. Shows unvalidated learnings that need human confirmation.`,
252
361
  schema: z.object({
253
- limit: z.coerce.number().optional().describe("Max memories to return (default: 20)"),
254
- offset: z.coerce.number().optional().describe("Pagination offset (default: 0)"),
362
+ limit: z.coerce
363
+ .number()
364
+ .optional()
365
+ .describe("Max memories to return (default: 20)"),
366
+ offset: z.coerce
367
+ .number()
368
+ .optional()
369
+ .describe("Pagination offset (default: 0)"),
255
370
  }),
256
371
  annotations: TOOL_ANNOTATIONS["review_memories"],
257
372
  handler: async (args, ctx) => {
@@ -285,10 +400,21 @@ export function createMemoryTools(projectName) {
285
400
  description: `Promote a quarantine memory to durable storage in ${projectName}. Requires a reason for promotion. Optionally runs quality gates before promotion.`,
286
401
  schema: z.object({
287
402
  memoryId: z.string().describe("ID of the memory to promote"),
288
- reason: z.enum(["human_validated", "pr_merged", "tests_passed"]).describe("Reason for promotion"),
289
- evidence: z.string().optional().describe("Optional evidence supporting the promotion"),
290
- runGates: z.boolean().optional().describe("Run quality gates before promotion (default: false)"),
291
- affectedFiles: z.array(z.string()).optional().describe("Files affected by this memory (for quality gate checking)"),
403
+ reason: z
404
+ .enum(["human_validated", "pr_merged", "tests_passed"])
405
+ .describe("Reason for promotion"),
406
+ evidence: z
407
+ .string()
408
+ .optional()
409
+ .describe("Optional evidence supporting the promotion"),
410
+ runGates: z
411
+ .boolean()
412
+ .optional()
413
+ .describe("Run quality gates before promotion (default: false)"),
414
+ affectedFiles: z
415
+ .array(z.string())
416
+ .optional()
417
+ .describe("Files affected by this memory (for quality gate checking)"),
292
418
  }),
293
419
  annotations: TOOL_ANNOTATIONS["promote_memory"],
294
420
  handler: async (args, ctx) => {
@@ -320,8 +446,14 @@ export function createMemoryTools(projectName) {
320
446
  name: "run_quality_gates",
321
447
  description: `Run quality gates (typecheck, tests, blast radius) for ${projectName}.`,
322
448
  schema: z.object({
323
- affectedFiles: z.array(z.string()).optional().describe("Files to check (for related tests and blast radius)"),
324
- skipGates: z.array(z.string()).optional().describe("Gates to skip (typecheck, test, blast_radius)"),
449
+ affectedFiles: z
450
+ .array(z.string())
451
+ .optional()
452
+ .describe("Files to check (for related tests and blast radius)"),
453
+ skipGates: z
454
+ .array(z.string())
455
+ .optional()
456
+ .describe("Gates to skip (typecheck, test, blast_radius)"),
325
457
  }),
326
458
  annotations: TOOL_ANNOTATIONS["run_quality_gates"],
327
459
  handler: async (args, ctx) => {
@@ -359,12 +491,27 @@ export function createMemoryTools(projectName) {
359
491
  name: "memory_maintenance",
360
492
  description: `Run memory maintenance for ${projectName}: quarantine cleanup (expire old auto-memories), feedback-driven promote/prune, and compaction (merge similar durable memories).`,
361
493
  schema: z.object({
362
- operations: z.object({
363
- quarantine_cleanup: z.boolean().optional().describe("Remove expired quarantine memories (default: true)"),
364
- feedback_maintenance: z.boolean().optional().describe("Auto-promote/prune by feedback (default: true)"),
365
- compaction: z.boolean().optional().describe("Merge similar durable memories (default: false)"),
366
- compaction_dry_run: z.boolean().optional().describe("Preview compaction without changes (default: true)"),
367
- }).optional().describe("Which operations to run (default: quarantine_cleanup + feedback_maintenance)"),
494
+ operations: z
495
+ .object({
496
+ quarantine_cleanup: z
497
+ .boolean()
498
+ .optional()
499
+ .describe("Remove expired quarantine memories (default: true)"),
500
+ feedback_maintenance: z
501
+ .boolean()
502
+ .optional()
503
+ .describe("Auto-promote/prune by feedback (default: true)"),
504
+ compaction: z
505
+ .boolean()
506
+ .optional()
507
+ .describe("Merge similar durable memories (default: false)"),
508
+ compaction_dry_run: z
509
+ .boolean()
510
+ .optional()
511
+ .describe("Preview compaction without changes (default: true)"),
512
+ })
513
+ .optional()
514
+ .describe("Which operations to run (default: quarantine_cleanup + feedback_maintenance)"),
368
515
  }),
369
516
  annotations: TOOL_ANNOTATIONS["memory_maintenance"],
370
517
  handler: async (args, ctx) => {
@@ -381,7 +528,9 @@ export function createMemoryTools(projectName) {
381
528
  result += `## Quarantine Cleanup\n`;
382
529
  if (qc.rejected.length > 0) {
383
530
  result += `**Expired** (${qc.rejected.length}): removed from quarantine\n`;
384
- qc.rejected.slice(0, 10).forEach((id) => { result += ` \u{1F5D1}\u{FE0F} ${id}\n`; });
531
+ qc.rejected.slice(0, 10).forEach((id) => {
532
+ result += ` \u{1F5D1}\u{FE0F} ${id}\n`;
533
+ });
385
534
  if (qc.rejected.length > 10)
386
535
  result += ` ... and ${qc.rejected.length - 10} more\n`;
387
536
  }
@@ -389,7 +538,9 @@ export function createMemoryTools(projectName) {
389
538
  result += `No expired quarantine memories.\n`;
390
539
  }
391
540
  if (qc.errors.length > 0) {
392
- qc.errors.forEach((e) => { result += ` \u26A0\u{FE0F} ${e}\n`; });
541
+ qc.errors.forEach((e) => {
542
+ result += ` \u26A0\u{FE0F} ${e}\n`;
543
+ });
393
544
  }
394
545
  result += `\n`;
395
546
  }
@@ -399,24 +550,30 @@ export function createMemoryTools(projectName) {
399
550
  result += `## Feedback Maintenance\n`;
400
551
  if (fm.promoted.length > 0) {
401
552
  result += `**Promoted** (${fm.promoted.length}): moved to durable\n`;
402
- fm.promoted.forEach((id) => { result += ` \u2705 ${id}\n`; });
553
+ fm.promoted.forEach((id) => {
554
+ result += ` \u2705 ${id}\n`;
555
+ });
403
556
  }
404
557
  if (fm.pruned.length > 0) {
405
558
  result += `**Pruned** (${fm.pruned.length}): removed\n`;
406
- fm.pruned.forEach((id) => { result += ` \u{1F5D1}\u{FE0F} ${id}\n`; });
559
+ fm.pruned.forEach((id) => {
560
+ result += ` \u{1F5D1}\u{FE0F} ${id}\n`;
561
+ });
407
562
  }
408
563
  if (fm.promoted.length === 0 && fm.pruned.length === 0) {
409
564
  result += `No feedback-based actions needed.\n`;
410
565
  }
411
566
  if (fm.errors.length > 0) {
412
- fm.errors.forEach((e) => { result += ` \u26A0\u{FE0F} ${e}\n`; });
567
+ fm.errors.forEach((e) => {
568
+ result += ` \u26A0\u{FE0F} ${e}\n`;
569
+ });
413
570
  }
414
571
  result += `\n`;
415
572
  }
416
573
  // Compaction section
417
574
  if (data.compaction) {
418
575
  const cp = data.compaction;
419
- result += `## Compaction${cp.dryRun ? ' (dry run)' : ''}\n`;
576
+ result += `## Compaction${cp.dryRun ? " (dry run)" : ""}\n`;
420
577
  if (cp.clusters.length > 0) {
421
578
  result += `**${cp.totalClusters} cluster(s)** of similar memories found\n\n`;
422
579
  cp.clusters.slice(0, 5).forEach((c, i) => {
package/dist/tools/pm.js CHANGED
@@ -14,8 +14,13 @@ export function createPmTools(projectName) {
14
14
  name: "search_requirements",
15
15
  description: `Search technical requirements and product documentation for ${projectName}. Finds relevant requirements, user stories, and specifications from Confluence.`,
16
16
  schema: z.object({
17
- query: z.string().describe("Search query for requirements (e.g., 'video inspection flow', 'payment integration')"),
18
- limit: z.coerce.number().optional().describe("Max results (default: 5)"),
17
+ query: z
18
+ .string()
19
+ .describe("Search query for requirements (e.g., 'video inspection flow', 'payment integration')"),
20
+ limit: z.coerce
21
+ .number()
22
+ .optional()
23
+ .describe("Max results (default: 5)"),
19
24
  }),
20
25
  annotations: TOOL_ANNOTATIONS["search_requirements"],
21
26
  handler: async (args, ctx) => {
@@ -42,8 +47,13 @@ export function createPmTools(projectName) {
42
47
  name: "analyze_requirements",
43
48
  description: `Analyze technical requirements and compare with existing implementation in ${projectName}. Identifies gaps, missing features, and implementation status.`,
44
49
  schema: z.object({
45
- feature: z.string().describe("Feature or requirement to analyze (e.g., 'video inspection', 'notifications')"),
46
- detailed: z.boolean().optional().describe("Include detailed code references (default: false)"),
50
+ feature: z
51
+ .string()
52
+ .describe("Feature or requirement to analyze (e.g., 'video inspection', 'notifications')"),
53
+ detailed: z
54
+ .boolean()
55
+ .optional()
56
+ .describe("Include detailed code references (default: false)"),
47
57
  }),
48
58
  annotations: TOOL_ANNOTATIONS["analyze_requirements"],
49
59
  handler: async (args, ctx) => {
@@ -107,7 +117,10 @@ export function createPmTools(projectName) {
107
117
  description: `Estimate development effort for a feature based on requirements and codebase analysis. Returns complexity assessment, affected files, and risk factors.`,
108
118
  schema: z.object({
109
119
  feature: z.string().describe("Feature description to estimate"),
110
- includeSubtasks: z.boolean().optional().describe("Break down into subtasks (default: true)"),
120
+ includeSubtasks: z
121
+ .boolean()
122
+ .optional()
123
+ .describe("Break down into subtasks (default: true)"),
111
124
  }),
112
125
  annotations: TOOL_ANNOTATIONS["estimate_feature"],
113
126
  handler: async (args, ctx) => {
@@ -235,13 +248,22 @@ export function createPmTools(projectName) {
235
248
  name: "list_requirements",
236
249
  description: `List all documented requirements/features for ${projectName} from Confluence. Groups by category or status.`,
237
250
  schema: z.object({
238
- category: z.string().optional().describe("Filter by category (optional)"),
239
- limit: z.coerce.number().optional().describe("Max results (default: 20)"),
240
- offset: z.coerce.number().optional().describe("Pagination offset (default: 0)"),
251
+ category: z
252
+ .string()
253
+ .optional()
254
+ .describe("Filter by category (optional)"),
255
+ limit: z.coerce
256
+ .number()
257
+ .optional()
258
+ .describe("Max results (default: 20)"),
259
+ offset: z.coerce
260
+ .number()
261
+ .optional()
262
+ .describe("Pagination offset (default: 0)"),
241
263
  }),
242
264
  annotations: TOOL_ANNOTATIONS["list_requirements"],
243
265
  handler: async (args, ctx) => {
244
- const { category, limit = 20, offset = 0 } = args;
266
+ const { category, limit = 20, offset = 0, } = args;
245
267
  const query = category || "requirements features specifications";
246
268
  const response = await ctx.api.post("/api/search", {
247
269
  collection: `${ctx.collectionPrefix}confluence`,
@@ -274,7 +296,9 @@ export function createPmTools(projectName) {
274
296
  name: "ask_pm",
275
297
  description: `Ask product management questions about ${projectName}. Answers questions about requirements, features, priorities, and project status using both documentation and codebase.`,
276
298
  schema: z.object({
277
- question: z.string().describe("PM question (e.g., 'What features are planned for video inspection?', 'What\\'s the status of notifications?')"),
299
+ question: z
300
+ .string()
301
+ .describe("PM question (e.g., 'What features are planned for video inspection?', 'What\\'s the status of notifications?')"),
278
302
  }),
279
303
  annotations: TOOL_ANNOTATIONS["ask_pm"],
280
304
  handler: async (args, ctx) => {
@@ -335,7 +359,10 @@ export function createPmTools(projectName) {
335
359
  description: `Generate technical specification from requirements. Creates a structured spec document based on Confluence requirements and existing codebase patterns.`,
336
360
  schema: z.object({
337
361
  feature: z.string().describe("Feature to generate spec for"),
338
- format: z.enum(["markdown", "jira", "brief"]).optional().describe("Output format (default: markdown)"),
362
+ format: z
363
+ .enum(["markdown", "jira", "brief"])
364
+ .optional()
365
+ .describe("Output format (default: markdown)"),
339
366
  }),
340
367
  annotations: TOOL_ANNOTATIONS["generate_spec"],
341
368
  handler: async (args, ctx) => {
@@ -12,7 +12,10 @@ export function createQualityTools(projectName) {
12
12
  name: "get_quality_report",
13
13
  description: `Get LLM quality metrics for ${projectName}. Shows JSON parse rates, latency percentiles, thinking trace rates, and alerts.`,
14
14
  schema: z.object({
15
- endpoint: z.string().optional().describe("Filter by specific endpoint (e.g., '/api/ask')"),
15
+ endpoint: z
16
+ .string()
17
+ .optional()
18
+ .describe("Filter by specific endpoint (e.g., '/api/ask')"),
16
19
  }),
17
20
  annotations: TOOL_ANNOTATIONS["get_quality_report"] || {
18
21
  title: "Get Quality Report",
@@ -20,7 +23,9 @@ export function createQualityTools(projectName) {
20
23
  openWorldHint: false,
21
24
  },
22
25
  handler: async (args, ctx) => {
23
- const params = args.endpoint ? `?endpoint=${encodeURIComponent(args.endpoint)}` : '';
26
+ const params = args.endpoint
27
+ ? `?endpoint=${encodeURIComponent(args.endpoint)}`
28
+ : "";
24
29
  const response = await ctx.api.get(`/api/quality/report${params}`);
25
30
  const data = response.data;
26
31
  let result = `## Quality Report\n\n`;
@@ -14,12 +14,18 @@ export function createReviewTools(projectName) {
14
14
  schema: z.object({
15
15
  code: z.string().describe("Code to review"),
16
16
  filePath: z.string().optional().describe("File path for context"),
17
- reviewType: z.enum(["security", "performance", "patterns", "style", "general"]).optional().describe("Type of review focus (default: general)"),
18
- diff: z.string().optional().describe("Git diff to review instead of full code"),
17
+ reviewType: z
18
+ .enum(["security", "performance", "patterns", "style", "general"])
19
+ .optional()
20
+ .describe("Type of review focus (default: general)"),
21
+ diff: z
22
+ .string()
23
+ .optional()
24
+ .describe("Git diff to review instead of full code"),
19
25
  }),
20
26
  annotations: TOOL_ANNOTATIONS["review_code"],
21
27
  handler: async (args, ctx) => {
22
- const { code, filePath, reviewType = "general", diff } = args;
28
+ const { code, filePath, reviewType = "general", diff, } = args;
23
29
  const response = await ctx.api.post("/api/review", {
24
30
  code: code || diff,
25
31
  filePath,
@@ -76,9 +82,18 @@ export function createReviewTools(projectName) {
76
82
  schema: z.object({
77
83
  code: z.string().describe("Code to generate tests for"),
78
84
  filePath: z.string().optional().describe("File path for context"),
79
- framework: z.enum(["jest", "vitest", "pytest", "mocha"]).optional().describe("Test framework to use (default: jest)"),
80
- testType: z.enum(["unit", "integration", "e2e"]).optional().describe("Type of tests to generate (default: unit)"),
81
- coverage: z.enum(["minimal", "standard", "comprehensive"]).optional().describe("Coverage level (default: comprehensive)"),
85
+ framework: z
86
+ .enum(["jest", "vitest", "pytest", "mocha"])
87
+ .optional()
88
+ .describe("Test framework to use (default: jest)"),
89
+ testType: z
90
+ .enum(["unit", "integration", "e2e"])
91
+ .optional()
92
+ .describe("Type of tests to generate (default: unit)"),
93
+ coverage: z
94
+ .enum(["minimal", "standard", "comprehensive"])
95
+ .optional()
96
+ .describe("Coverage level (default: comprehensive)"),
82
97
  }),
83
98
  annotations: TOOL_ANNOTATIONS["generate_tests"],
84
99
  handler: async (args, ctx) => {
@@ -115,7 +130,10 @@ export function createReviewTools(projectName) {
115
130
  description: "Analyze existing tests for coverage and quality.",
116
131
  schema: z.object({
117
132
  testCode: z.string().describe("Test code to analyze"),
118
- sourceCode: z.string().optional().describe("Optional source code being tested"),
133
+ sourceCode: z
134
+ .string()
135
+ .optional()
136
+ .describe("Optional source code being tested"),
119
137
  }),
120
138
  annotations: TOOL_ANNOTATIONS["analyze_tests"],
121
139
  handler: async (args, ctx) => {