@crowley/rag-mcp 1.0.5 → 1.1.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.
Files changed (51) hide show
  1. package/dist/annotations.d.ts +16 -0
  2. package/dist/annotations.js +158 -0
  3. package/dist/context-enrichment.js +7 -0
  4. package/dist/formatters.d.ts +2 -0
  5. package/dist/formatters.js +12 -0
  6. package/dist/index.js +99 -47
  7. package/dist/schemas.d.ts +97 -0
  8. package/dist/schemas.js +128 -0
  9. package/dist/tool-middleware.d.ts +40 -0
  10. package/dist/tool-middleware.js +216 -0
  11. package/dist/tool-registry.js +2 -1
  12. package/dist/tools/advanced.d.ts +2 -2
  13. package/dist/tools/advanced.js +200 -275
  14. package/dist/tools/agents.d.ts +2 -2
  15. package/dist/tools/agents.js +59 -78
  16. package/dist/tools/analytics.d.ts +2 -2
  17. package/dist/tools/analytics.js +170 -210
  18. package/dist/tools/architecture.d.ts +2 -2
  19. package/dist/tools/architecture.js +506 -669
  20. package/dist/tools/ask.d.ts +2 -2
  21. package/dist/tools/ask.js +164 -219
  22. package/dist/tools/cache.d.ts +2 -2
  23. package/dist/tools/cache.js +63 -82
  24. package/dist/tools/clustering.d.ts +2 -2
  25. package/dist/tools/clustering.js +154 -215
  26. package/dist/tools/confluence.d.ts +2 -2
  27. package/dist/tools/confluence.js +80 -116
  28. package/dist/tools/database.d.ts +2 -2
  29. package/dist/tools/database.js +303 -380
  30. package/dist/tools/feedback.d.ts +2 -2
  31. package/dist/tools/feedback.js +143 -184
  32. package/dist/tools/guidelines.d.ts +2 -2
  33. package/dist/tools/guidelines.js +123 -135
  34. package/dist/tools/indexing.d.ts +2 -2
  35. package/dist/tools/indexing.js +100 -108
  36. package/dist/tools/memory.d.ts +2 -2
  37. package/dist/tools/memory.js +299 -485
  38. package/dist/tools/pm.d.ts +2 -2
  39. package/dist/tools/pm.js +367 -615
  40. package/dist/tools/quality.d.ts +8 -0
  41. package/dist/tools/quality.js +60 -0
  42. package/dist/tools/review.d.ts +2 -2
  43. package/dist/tools/review.js +142 -189
  44. package/dist/tools/search.d.ts +2 -2
  45. package/dist/tools/search.js +230 -305
  46. package/dist/tools/session.d.ts +2 -2
  47. package/dist/tools/session.js +288 -345
  48. package/dist/tools/suggestions.d.ts +2 -2
  49. package/dist/tools/suggestions.js +517 -512
  50. package/dist/types.d.ts +19 -2
  51. package/package.json +4 -2
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Quality tools module - LLM quality monitoring and reporting.
3
+ */
4
+ import type { ToolSpec } from "../types.js";
5
+ /**
6
+ * Create the quality tools module.
7
+ */
8
+ export declare function createQualityTools(projectName: string): ToolSpec[];
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Quality tools module - LLM quality monitoring and reporting.
3
+ */
4
+ import { z } from "zod";
5
+ import { TOOL_ANNOTATIONS } from "../annotations.js";
6
+ /**
7
+ * Create the quality tools module.
8
+ */
9
+ export function createQualityTools(projectName) {
10
+ return [
11
+ {
12
+ name: "get_quality_report",
13
+ description: `Get LLM quality metrics for ${projectName}. Shows JSON parse rates, latency percentiles, thinking trace rates, and alerts.`,
14
+ schema: z.object({
15
+ endpoint: z.string().optional().describe("Filter by specific endpoint (e.g., '/api/ask')"),
16
+ }),
17
+ annotations: TOOL_ANNOTATIONS["get_quality_report"] || {
18
+ title: "Get Quality Report",
19
+ readOnlyHint: true,
20
+ openWorldHint: false,
21
+ },
22
+ handler: async (args, ctx) => {
23
+ const params = args.endpoint ? `?endpoint=${encodeURIComponent(args.endpoint)}` : '';
24
+ const response = await ctx.api.get(`/api/quality/report${params}`);
25
+ const data = response.data;
26
+ let result = `## Quality Report\n\n`;
27
+ result += `**Total Metrics:** ${data.total}\n\n`;
28
+ if (data.total === 0) {
29
+ result += `No quality metrics recorded yet.\n`;
30
+ return result;
31
+ }
32
+ const m = data.metrics;
33
+ result += `### Aggregate Metrics\n`;
34
+ result += `- **Avg Latency:** ${m.avgLatencyMs}ms\n`;
35
+ result += `- **P95 Latency:** ${m.p95LatencyMs}ms\n`;
36
+ result += `- **JSON Parse Rate:** ${(m.jsonParseRate * 100).toFixed(1)}%\n`;
37
+ result += `- **Thinking Rate:** ${(m.thinkingRate * 100).toFixed(1)}%\n`;
38
+ result += `- **Avg Output Length:** ${m.avgOutputLength} chars\n`;
39
+ result += `- **Avg Thinking Length:** ${m.avgThinkingLength} chars\n`;
40
+ result += `- **Avg Tokens:** ${m.avgTokens}\n\n`;
41
+ if (data.alerts.length > 0) {
42
+ result += `### ⚠ Alerts\n`;
43
+ for (const alert of data.alerts) {
44
+ result += `- ${alert}\n`;
45
+ }
46
+ result += `\n`;
47
+ }
48
+ if (Object.keys(data.byEndpoint).length > 0) {
49
+ result += `### By Endpoint\n`;
50
+ for (const [ep, stats] of Object.entries(data.byEndpoint)) {
51
+ result += `- **${ep}**: ${stats.count} calls, ${stats.avgLatencyMs}ms avg, `;
52
+ result += `JSON: ${(stats.jsonParseRate * 100).toFixed(0)}%, `;
53
+ result += `Thinking: ${(stats.thinkingRate * 100).toFixed(0)}%\n`;
54
+ }
55
+ }
56
+ return result;
57
+ },
58
+ },
59
+ ];
60
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Review & testing tools module - code review, test generation, and test analysis.
3
3
  */
4
- import type { ToolModule } from "../types.js";
4
+ import type { ToolSpec } from "../types.js";
5
5
  /**
6
6
  * Create the review & testing tools module with project-specific descriptions.
7
7
  */
8
- export declare function createReviewTools(projectName: string): ToolModule;
8
+ export declare function createReviewTools(projectName: string): ToolSpec[];
@@ -1,213 +1,166 @@
1
1
  /**
2
2
  * Review & testing tools module - code review, test generation, and test analysis.
3
3
  */
4
+ import { z } from "zod";
5
+ import { TOOL_ANNOTATIONS } from "../annotations.js";
4
6
  /**
5
7
  * Create the review & testing tools module with project-specific descriptions.
6
8
  */
7
9
  export function createReviewTools(projectName) {
8
- const tools = [
10
+ return [
9
11
  {
10
12
  name: "review_code",
11
13
  description: "Review code for issues, pattern violations, and improvements. Uses project patterns and ADRs for context.",
12
- inputSchema: {
13
- type: "object",
14
- properties: {
15
- code: {
16
- type: "string",
17
- description: "Code to review",
18
- },
19
- filePath: {
20
- type: "string",
21
- description: "File path for context",
22
- },
23
- reviewType: {
24
- type: "string",
25
- enum: ["security", "performance", "patterns", "style", "general"],
26
- description: "Type of review focus (default: general)",
27
- },
28
- diff: {
29
- type: "string",
30
- description: "Git diff to review instead of full code",
31
- },
32
- },
33
- required: ["code"],
14
+ schema: z.object({
15
+ code: z.string().describe("Code to review"),
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"),
19
+ }),
20
+ annotations: TOOL_ANNOTATIONS["review_code"],
21
+ handler: async (args, ctx) => {
22
+ const { code, filePath, reviewType = "general", diff } = args;
23
+ const response = await ctx.api.post("/api/review", {
24
+ code: code || diff,
25
+ filePath,
26
+ reviewType,
27
+ diff,
28
+ });
29
+ const { review, context } = response.data;
30
+ let result = `# Code Review\n\n`;
31
+ if (review.score) {
32
+ result += `**Score**: ${review.score}/10\n\n`;
33
+ }
34
+ if (review.summary) {
35
+ result += `## Summary\n${review.summary}\n\n`;
36
+ }
37
+ if (review.issues && review.issues.length > 0) {
38
+ result += `## Issues Found\n`;
39
+ review.issues.forEach((issue, i) => {
40
+ const icon = issue.severity === "critical"
41
+ ? "\u{1F6A8}"
42
+ : issue.severity === "high"
43
+ ? "\u26A0\uFE0F"
44
+ : issue.severity === "medium"
45
+ ? "\u{1F4CB}"
46
+ : "\u2139\uFE0F";
47
+ result += `\n### ${icon} ${i + 1}. ${issue.type} (${issue.severity})\n`;
48
+ result += `${issue.description}\n`;
49
+ if (issue.line)
50
+ result += `- Line: ${issue.line}\n`;
51
+ if (issue.suggestion)
52
+ result += `- Fix: ${issue.suggestion}\n`;
53
+ });
54
+ result += "\n";
55
+ }
56
+ if (review.positives && review.positives.length > 0) {
57
+ result += `## Positives\n`;
58
+ review.positives.forEach((p) => {
59
+ result += `- ${p}\n`;
60
+ });
61
+ result += "\n";
62
+ }
63
+ if (review.suggestions && review.suggestions.length > 0) {
64
+ result += `## Suggestions\n`;
65
+ review.suggestions.forEach((s) => {
66
+ result += `- ${s}\n`;
67
+ });
68
+ }
69
+ result += `\n---\n_Context: ${context.patternsUsed} patterns, ${context.adrsUsed} ADRs, ${context.similarFilesFound} similar files_`;
70
+ return result;
34
71
  },
35
72
  },
36
73
  {
37
74
  name: "generate_tests",
38
75
  description: "Generate unit/integration tests based on code and existing test patterns in the project.",
39
- inputSchema: {
40
- type: "object",
41
- properties: {
42
- code: {
43
- type: "string",
44
- description: "Code to generate tests for",
45
- },
46
- filePath: {
47
- type: "string",
48
- description: "File path for context",
49
- },
50
- framework: {
51
- type: "string",
52
- enum: ["jest", "vitest", "pytest", "mocha"],
53
- description: "Test framework to use (default: jest)",
54
- },
55
- testType: {
56
- type: "string",
57
- enum: ["unit", "integration", "e2e"],
58
- description: "Type of tests to generate (default: unit)",
59
- },
60
- coverage: {
61
- type: "string",
62
- enum: ["minimal", "standard", "comprehensive"],
63
- description: "Coverage level (default: comprehensive)",
64
- },
65
- },
66
- required: ["code"],
76
+ schema: z.object({
77
+ code: z.string().describe("Code to generate tests for"),
78
+ 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)"),
82
+ }),
83
+ annotations: TOOL_ANNOTATIONS["generate_tests"],
84
+ handler: async (args, ctx) => {
85
+ const { code, filePath, framework = "jest", testType = "unit", coverage = "comprehensive", } = args;
86
+ const response = await ctx.api.post("/api/generate-tests", {
87
+ code,
88
+ filePath,
89
+ framework,
90
+ testType,
91
+ coverage,
92
+ });
93
+ const { tests, analysis, existingPatternsFound } = response.data;
94
+ let result = `# Generated Tests\n\n`;
95
+ result += `**Framework**: ${framework}\n`;
96
+ result += `**Type**: ${testType}\n`;
97
+ result += `**Coverage**: ${coverage}\n`;
98
+ result += `**Existing patterns found**: ${existingPatternsFound}\n\n`;
99
+ if (analysis) {
100
+ result += `## Code Analysis\n`;
101
+ result += `- Functions: ${analysis.functions?.join(", ") || "none"}\n`;
102
+ result += `- Classes: ${analysis.classes?.join(", ") || "none"}\n`;
103
+ result += `- Complexity: ${analysis.estimatedComplexity}\n\n`;
104
+ }
105
+ result += `## Generated Test Code\n\n`;
106
+ result +=
107
+ "```" + (framework === "pytest" ? "python" : "typescript") + "\n";
108
+ result += tests;
109
+ result += "\n```\n";
110
+ return result;
67
111
  },
68
112
  },
69
113
  {
70
114
  name: "analyze_tests",
71
115
  description: "Analyze existing tests for coverage and quality.",
72
- inputSchema: {
73
- type: "object",
74
- properties: {
75
- testCode: {
76
- type: "string",
77
- description: "Test code to analyze",
78
- },
79
- sourceCode: {
80
- type: "string",
81
- description: "Optional source code being tested",
82
- },
83
- },
84
- required: ["testCode"],
116
+ schema: z.object({
117
+ testCode: z.string().describe("Test code to analyze"),
118
+ sourceCode: z.string().optional().describe("Optional source code being tested"),
119
+ }),
120
+ annotations: TOOL_ANNOTATIONS["analyze_tests"],
121
+ handler: async (args, ctx) => {
122
+ const { testCode, sourceCode } = args;
123
+ const response = await ctx.api.post("/api/analyze-tests", {
124
+ testCode,
125
+ sourceCode,
126
+ });
127
+ const { analysis } = response.data;
128
+ let result = `# Test Analysis\n\n`;
129
+ if (analysis.quality) {
130
+ result += `**Quality**: ${analysis.quality}`;
131
+ if (analysis.score)
132
+ result += ` (${analysis.score}/10)`;
133
+ result += "\n\n";
134
+ }
135
+ if (analysis.coverage) {
136
+ result += `## Coverage Estimates\n`;
137
+ Object.entries(analysis.coverage).forEach(([key, value]) => {
138
+ result += `- ${key}: ${value}\n`;
139
+ });
140
+ result += "\n";
141
+ }
142
+ if (analysis.strengths && analysis.strengths.length > 0) {
143
+ result += `## Strengths\n`;
144
+ analysis.strengths.forEach((s) => {
145
+ result += `- ${s}\n`;
146
+ });
147
+ result += "\n";
148
+ }
149
+ if (analysis.weaknesses && analysis.weaknesses.length > 0) {
150
+ result += `## Weaknesses\n`;
151
+ analysis.weaknesses.forEach((w) => {
152
+ result += `- ${w}\n`;
153
+ });
154
+ result += "\n";
155
+ }
156
+ if (analysis.missingTests && analysis.missingTests.length > 0) {
157
+ result += `## Missing Tests\n`;
158
+ analysis.missingTests.forEach((t) => {
159
+ result += `- ${t}\n`;
160
+ });
161
+ }
162
+ return result;
85
163
  },
86
164
  },
87
165
  ];
88
- const handlers = {
89
- review_code: async (args, ctx) => {
90
- const { code, filePath, reviewType = "general", diff } = args;
91
- const response = await ctx.api.post("/api/review", {
92
- code: code || diff,
93
- filePath,
94
- reviewType,
95
- diff,
96
- });
97
- const { review, context } = response.data;
98
- let result = `# Code Review\n\n`;
99
- if (review.score) {
100
- result += `**Score**: ${review.score}/10\n\n`;
101
- }
102
- if (review.summary) {
103
- result += `## Summary\n${review.summary}\n\n`;
104
- }
105
- if (review.issues && review.issues.length > 0) {
106
- result += `## Issues Found\n`;
107
- review.issues.forEach((issue, i) => {
108
- const icon = issue.severity === "critical"
109
- ? "\u{1F6A8}"
110
- : issue.severity === "high"
111
- ? "\u26A0\uFE0F"
112
- : issue.severity === "medium"
113
- ? "\u{1F4CB}"
114
- : "\u2139\uFE0F";
115
- result += `\n### ${icon} ${i + 1}. ${issue.type} (${issue.severity})\n`;
116
- result += `${issue.description}\n`;
117
- if (issue.line)
118
- result += `- Line: ${issue.line}\n`;
119
- if (issue.suggestion)
120
- result += `- Fix: ${issue.suggestion}\n`;
121
- });
122
- result += "\n";
123
- }
124
- if (review.positives && review.positives.length > 0) {
125
- result += `## Positives\n`;
126
- review.positives.forEach((p) => {
127
- result += `- ${p}\n`;
128
- });
129
- result += "\n";
130
- }
131
- if (review.suggestions && review.suggestions.length > 0) {
132
- result += `## Suggestions\n`;
133
- review.suggestions.forEach((s) => {
134
- result += `- ${s}\n`;
135
- });
136
- }
137
- result += `\n---\n_Context: ${context.patternsUsed} patterns, ${context.adrsUsed} ADRs, ${context.similarFilesFound} similar files_`;
138
- return result;
139
- },
140
- generate_tests: async (args, ctx) => {
141
- const { code, filePath, framework = "jest", testType = "unit", coverage = "comprehensive", } = args;
142
- const response = await ctx.api.post("/api/generate-tests", {
143
- code,
144
- filePath,
145
- framework,
146
- testType,
147
- coverage,
148
- });
149
- const { tests, analysis, existingPatternsFound } = response.data;
150
- let result = `# Generated Tests\n\n`;
151
- result += `**Framework**: ${framework}\n`;
152
- result += `**Type**: ${testType}\n`;
153
- result += `**Coverage**: ${coverage}\n`;
154
- result += `**Existing patterns found**: ${existingPatternsFound}\n\n`;
155
- if (analysis) {
156
- result += `## Code Analysis\n`;
157
- result += `- Functions: ${analysis.functions?.join(", ") || "none"}\n`;
158
- result += `- Classes: ${analysis.classes?.join(", ") || "none"}\n`;
159
- result += `- Complexity: ${analysis.estimatedComplexity}\n\n`;
160
- }
161
- result += `## Generated Test Code\n\n`;
162
- result +=
163
- "```" + (framework === "pytest" ? "python" : "typescript") + "\n";
164
- result += tests;
165
- result += "\n```\n";
166
- return result;
167
- },
168
- analyze_tests: async (args, ctx) => {
169
- const { testCode, sourceCode } = args;
170
- const response = await ctx.api.post("/api/analyze-tests", {
171
- testCode,
172
- sourceCode,
173
- });
174
- const { analysis } = response.data;
175
- let result = `# Test Analysis\n\n`;
176
- if (analysis.quality) {
177
- result += `**Quality**: ${analysis.quality}`;
178
- if (analysis.score)
179
- result += ` (${analysis.score}/10)`;
180
- result += "\n\n";
181
- }
182
- if (analysis.coverage) {
183
- result += `## Coverage Estimates\n`;
184
- Object.entries(analysis.coverage).forEach(([key, value]) => {
185
- result += `- ${key}: ${value}\n`;
186
- });
187
- result += "\n";
188
- }
189
- if (analysis.strengths && analysis.strengths.length > 0) {
190
- result += `## Strengths\n`;
191
- analysis.strengths.forEach((s) => {
192
- result += `- ${s}\n`;
193
- });
194
- result += "\n";
195
- }
196
- if (analysis.weaknesses && analysis.weaknesses.length > 0) {
197
- result += `## Weaknesses\n`;
198
- analysis.weaknesses.forEach((w) => {
199
- result += `- ${w}\n`;
200
- });
201
- result += "\n";
202
- }
203
- if (analysis.missingTests && analysis.missingTests.length > 0) {
204
- result += `## Missing Tests\n`;
205
- analysis.missingTests.forEach((t) => {
206
- result += `- ${t}\n`;
207
- });
208
- }
209
- return result;
210
- },
211
- };
212
- return { tools, handlers };
213
166
  }
@@ -2,8 +2,8 @@
2
2
  * Search tools module - codebase search, similarity search, grouped/hybrid search,
3
3
  * documentation search, and project statistics.
4
4
  */
5
- import type { ToolModule } from "../types.js";
5
+ import type { ToolSpec } from "../types.js";
6
6
  /**
7
7
  * Create the search tools module with project-specific descriptions.
8
8
  */
9
- export declare function createSearchTools(projectName: string): ToolModule;
9
+ export declare function createSearchTools(projectName: string): ToolSpec[];