@crowley/rag-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client.d.ts +4 -0
- package/dist/api-client.js +19 -0
- package/dist/context-enrichment.d.ts +44 -0
- package/dist/context-enrichment.js +190 -0
- package/dist/formatters.d.ts +33 -0
- package/dist/formatters.js +70 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +109 -0
- package/dist/tool-registry.d.ts +20 -0
- package/dist/tool-registry.js +123 -0
- package/dist/tools/advanced.d.ts +9 -0
- package/dist/tools/advanced.js +315 -0
- package/dist/tools/agents.d.ts +8 -0
- package/dist/tools/agents.js +97 -0
- package/dist/tools/analytics.d.ts +9 -0
- package/dist/tools/analytics.js +261 -0
- package/dist/tools/architecture.d.ts +5 -0
- package/dist/tools/architecture.js +720 -0
- package/dist/tools/ask.d.ts +9 -0
- package/dist/tools/ask.js +256 -0
- package/dist/tools/cache.d.ts +5 -0
- package/dist/tools/cache.js +98 -0
- package/dist/tools/clustering.d.ts +9 -0
- package/dist/tools/clustering.js +251 -0
- package/dist/tools/confluence.d.ts +9 -0
- package/dist/tools/confluence.js +147 -0
- package/dist/tools/database.d.ts +5 -0
- package/dist/tools/database.js +429 -0
- package/dist/tools/feedback.d.ts +9 -0
- package/dist/tools/feedback.js +220 -0
- package/dist/tools/guidelines.d.ts +5 -0
- package/dist/tools/guidelines.js +146 -0
- package/dist/tools/indexing.d.ts +9 -0
- package/dist/tools/indexing.js +129 -0
- package/dist/tools/memory.d.ts +9 -0
- package/dist/tools/memory.js +565 -0
- package/dist/tools/pm.d.ts +9 -0
- package/dist/tools/pm.js +680 -0
- package/dist/tools/review.d.ts +8 -0
- package/dist/tools/review.js +213 -0
- package/dist/tools/search.d.ts +9 -0
- package/dist/tools/search.js +377 -0
- package/dist/tools/session.d.ts +10 -0
- package/dist/tools/session.js +386 -0
- package/dist/tools/suggestions.d.ts +9 -0
- package/dist/tools/suggestions.js +301 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +4 -0
- package/package.json +40 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review & testing tools module - code review, test generation, and test analysis.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create the review & testing tools module with project-specific descriptions.
|
|
6
|
+
*/
|
|
7
|
+
export function createReviewTools(projectName) {
|
|
8
|
+
const tools = [
|
|
9
|
+
{
|
|
10
|
+
name: "review_code",
|
|
11
|
+
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"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "generate_tests",
|
|
38
|
+
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"],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "analyze_tests",
|
|
71
|
+
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"],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
];
|
|
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
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search tools module - codebase search, similarity search, grouped/hybrid search,
|
|
3
|
+
* documentation search, and project statistics.
|
|
4
|
+
*/
|
|
5
|
+
import type { ToolModule } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the search tools module with project-specific descriptions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createSearchTools(projectName: string): ToolModule;
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search tools module - codebase search, similarity search, grouped/hybrid search,
|
|
3
|
+
* documentation search, and project statistics.
|
|
4
|
+
*/
|
|
5
|
+
import { formatCodeResults, truncate, pct } from "../formatters.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the search tools module with project-specific descriptions.
|
|
8
|
+
*/
|
|
9
|
+
export function createSearchTools(projectName) {
|
|
10
|
+
const tools = [
|
|
11
|
+
{
|
|
12
|
+
name: "search_codebase",
|
|
13
|
+
description: `Search the ${projectName} codebase for relevant code. Returns matching files with code snippets and relevance scores.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
query: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Search query for finding code",
|
|
20
|
+
},
|
|
21
|
+
limit: {
|
|
22
|
+
type: "number",
|
|
23
|
+
description: "Max results to return (default: 5)",
|
|
24
|
+
default: 5,
|
|
25
|
+
},
|
|
26
|
+
language: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Filter by language (typescript, python, vue, etc.)",
|
|
29
|
+
},
|
|
30
|
+
path: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Filter by path pattern (e.g., 'src/modules/*')",
|
|
33
|
+
},
|
|
34
|
+
layer: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Filter by architectural layer (api, service, util, model, middleware, test, parser, types, config, other)",
|
|
37
|
+
},
|
|
38
|
+
service: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Filter by service/class name (e.g., 'EmbeddingService')",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ["query"],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "search_similar",
|
|
48
|
+
description: "Find code similar to a given snippet.",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
code: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "Code snippet to find similar code for",
|
|
55
|
+
},
|
|
56
|
+
limit: {
|
|
57
|
+
type: "number",
|
|
58
|
+
description: "Max results (default: 5)",
|
|
59
|
+
default: 5,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ["code"],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "grouped_search",
|
|
67
|
+
description: `Search ${projectName} codebase with results grouped by file. Returns one best match per file instead of multiple chunks.`,
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
query: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: "Search query",
|
|
74
|
+
},
|
|
75
|
+
groupBy: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Field to group by (default: 'file')",
|
|
78
|
+
default: "file",
|
|
79
|
+
},
|
|
80
|
+
limit: {
|
|
81
|
+
type: "number",
|
|
82
|
+
description: "Max groups to return (default: 10)",
|
|
83
|
+
default: 10,
|
|
84
|
+
},
|
|
85
|
+
language: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Filter by language",
|
|
88
|
+
},
|
|
89
|
+
layer: {
|
|
90
|
+
type: "string",
|
|
91
|
+
description: "Filter by architectural layer (api, service, util, etc.)",
|
|
92
|
+
},
|
|
93
|
+
service: {
|
|
94
|
+
type: "string",
|
|
95
|
+
description: "Filter by service/class name",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
required: ["query"],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "hybrid_search",
|
|
103
|
+
description: `Hybrid search combining keyword matching and semantic similarity for ${projectName}. Better for finding exact terms + related concepts.`,
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
query: {
|
|
108
|
+
type: "string",
|
|
109
|
+
description: "Search query",
|
|
110
|
+
},
|
|
111
|
+
limit: {
|
|
112
|
+
type: "number",
|
|
113
|
+
description: "Max results (default: 10)",
|
|
114
|
+
default: 10,
|
|
115
|
+
},
|
|
116
|
+
semanticWeight: {
|
|
117
|
+
type: "number",
|
|
118
|
+
description: "Weight for semantic vs keyword (0-1, default: 0.7)",
|
|
119
|
+
default: 0.7,
|
|
120
|
+
},
|
|
121
|
+
language: {
|
|
122
|
+
type: "string",
|
|
123
|
+
description: "Filter by language",
|
|
124
|
+
},
|
|
125
|
+
layer: {
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "Filter by architectural layer (api, service, util, etc.)",
|
|
128
|
+
},
|
|
129
|
+
service: {
|
|
130
|
+
type: "string",
|
|
131
|
+
description: "Filter by service/class name",
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
required: ["query"],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "search_docs",
|
|
139
|
+
description: `Search documentation in the ${projectName} project.`,
|
|
140
|
+
inputSchema: {
|
|
141
|
+
type: "object",
|
|
142
|
+
properties: {
|
|
143
|
+
query: {
|
|
144
|
+
type: "string",
|
|
145
|
+
description: "Search query",
|
|
146
|
+
},
|
|
147
|
+
limit: {
|
|
148
|
+
type: "number",
|
|
149
|
+
description: "Max results (default: 5)",
|
|
150
|
+
default: 5,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
required: ["query"],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "get_project_stats",
|
|
158
|
+
description: `Get statistics about the ${projectName} codebase.`,
|
|
159
|
+
inputSchema: {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: {},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "find_symbol",
|
|
166
|
+
description: `Find a function, class, type, or interface by name in ${projectName}. Fast symbol lookup without full-text search.`,
|
|
167
|
+
inputSchema: {
|
|
168
|
+
type: "object",
|
|
169
|
+
properties: {
|
|
170
|
+
symbol: {
|
|
171
|
+
type: "string",
|
|
172
|
+
description: "Symbol name to find (function, class, type, etc.)",
|
|
173
|
+
},
|
|
174
|
+
kind: {
|
|
175
|
+
type: "string",
|
|
176
|
+
description: "Filter by kind: function, class, interface, type, enum, const",
|
|
177
|
+
},
|
|
178
|
+
limit: {
|
|
179
|
+
type: "number",
|
|
180
|
+
description: "Max results (default: 10)",
|
|
181
|
+
default: 10,
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
required: ["symbol"],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "search_graph",
|
|
189
|
+
description: `Search ${projectName} codebase with graph expansion. Finds semantically similar code plus connected files via import/call relationships.`,
|
|
190
|
+
inputSchema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
query: {
|
|
194
|
+
type: "string",
|
|
195
|
+
description: "Search query",
|
|
196
|
+
},
|
|
197
|
+
limit: {
|
|
198
|
+
type: "number",
|
|
199
|
+
description: "Max direct results (default: 5)",
|
|
200
|
+
default: 5,
|
|
201
|
+
},
|
|
202
|
+
expandHops: {
|
|
203
|
+
type: "number",
|
|
204
|
+
description: "Number of graph hops to expand (default: 1)",
|
|
205
|
+
default: 1,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
required: ["query"],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
];
|
|
212
|
+
const handlers = {
|
|
213
|
+
search_codebase: async (args, ctx) => {
|
|
214
|
+
const { query, limit = 5, language, path, layer, service } = args;
|
|
215
|
+
const response = await ctx.api.post("/api/search", {
|
|
216
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
217
|
+
query,
|
|
218
|
+
limit,
|
|
219
|
+
filters: { language, path, layer, service },
|
|
220
|
+
});
|
|
221
|
+
const results = response.data.results;
|
|
222
|
+
if (!results || results.length === 0) {
|
|
223
|
+
return "No results found for this query.";
|
|
224
|
+
}
|
|
225
|
+
return formatCodeResults(results, 500);
|
|
226
|
+
},
|
|
227
|
+
search_similar: async (args, ctx) => {
|
|
228
|
+
const { code, limit = 5 } = args;
|
|
229
|
+
const response = await ctx.api.post("/api/search-similar", {
|
|
230
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
231
|
+
code,
|
|
232
|
+
limit,
|
|
233
|
+
});
|
|
234
|
+
const results = response.data.results;
|
|
235
|
+
if (!results || results.length === 0) {
|
|
236
|
+
return "No similar code found.";
|
|
237
|
+
}
|
|
238
|
+
return formatCodeResults(results, 400);
|
|
239
|
+
},
|
|
240
|
+
grouped_search: async (args, ctx) => {
|
|
241
|
+
const { query, groupBy = "file", limit = 10, language, layer, service } = args;
|
|
242
|
+
const filters = { language, layer, service };
|
|
243
|
+
const hasFilters = Object.values(filters).some(v => v !== undefined);
|
|
244
|
+
const response = await ctx.api.post("/api/search-grouped", {
|
|
245
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
246
|
+
query,
|
|
247
|
+
groupBy,
|
|
248
|
+
limit,
|
|
249
|
+
filters: hasFilters ? filters : undefined,
|
|
250
|
+
});
|
|
251
|
+
const groups = response.data.groups;
|
|
252
|
+
if (!groups || groups.length === 0) {
|
|
253
|
+
return "No results found.";
|
|
254
|
+
}
|
|
255
|
+
return groups
|
|
256
|
+
.map((g) => {
|
|
257
|
+
const r = g.results[0];
|
|
258
|
+
return (`**${g[groupBy]}** (score: ${pct(r.score)})\n` +
|
|
259
|
+
"```" +
|
|
260
|
+
(r.language || "") +
|
|
261
|
+
"\n" +
|
|
262
|
+
truncate(r.content, 300) +
|
|
263
|
+
"\n```");
|
|
264
|
+
})
|
|
265
|
+
.join("\n\n---\n\n");
|
|
266
|
+
},
|
|
267
|
+
hybrid_search: async (args, ctx) => {
|
|
268
|
+
const { query, limit = 10, semanticWeight = 0.7, language, layer, service } = args;
|
|
269
|
+
const filters = { language, layer, service };
|
|
270
|
+
const hasFilters = Object.values(filters).some(v => v !== undefined);
|
|
271
|
+
const response = await ctx.api.post("/api/search-hybrid", {
|
|
272
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
273
|
+
query,
|
|
274
|
+
limit,
|
|
275
|
+
semanticWeight,
|
|
276
|
+
filters: hasFilters ? filters : undefined,
|
|
277
|
+
});
|
|
278
|
+
const results = response.data.results;
|
|
279
|
+
if (!results || results.length === 0) {
|
|
280
|
+
return "No results found.";
|
|
281
|
+
}
|
|
282
|
+
return results
|
|
283
|
+
.map((r) => `**${r.file}** (combined: ${pct(r.score)}${r.semanticScore != null ? `, semantic: ${pct(r.semanticScore)}` : ''}${r.keywordScore != null ? `, keyword: ${pct(r.keywordScore)}` : ''})\n` +
|
|
284
|
+
"```" +
|
|
285
|
+
(r.language || "") +
|
|
286
|
+
"\n" +
|
|
287
|
+
truncate(r.content, 300) +
|
|
288
|
+
"\n```")
|
|
289
|
+
.join("\n\n---\n\n");
|
|
290
|
+
},
|
|
291
|
+
search_docs: async (args, ctx) => {
|
|
292
|
+
const { query, limit = 5 } = args;
|
|
293
|
+
const response = await ctx.api.post("/api/search", {
|
|
294
|
+
collection: `${ctx.collectionPrefix}docs`,
|
|
295
|
+
query,
|
|
296
|
+
limit,
|
|
297
|
+
});
|
|
298
|
+
const results = response.data.results;
|
|
299
|
+
if (!results || results.length === 0) {
|
|
300
|
+
return "No documentation found for this query.";
|
|
301
|
+
}
|
|
302
|
+
return results
|
|
303
|
+
.map((r) => `**${r.file}**\n` +
|
|
304
|
+
truncate(r.content, 500))
|
|
305
|
+
.join("\n\n---\n\n");
|
|
306
|
+
},
|
|
307
|
+
find_symbol: async (args, ctx) => {
|
|
308
|
+
const { symbol, kind, limit = 10 } = args;
|
|
309
|
+
const response = await ctx.api.post("/api/find-symbol", {
|
|
310
|
+
projectName: ctx.projectName,
|
|
311
|
+
symbol,
|
|
312
|
+
kind,
|
|
313
|
+
limit,
|
|
314
|
+
});
|
|
315
|
+
const results = response.data.results;
|
|
316
|
+
if (!results || results.length === 0) {
|
|
317
|
+
return `No symbol "${symbol}" found.`;
|
|
318
|
+
}
|
|
319
|
+
return results
|
|
320
|
+
.map((r) => `**${r.kind} ${r.name}** in \`${r.file}\` (lines ${r.startLine}-${r.endLine})\n` +
|
|
321
|
+
`\`${truncate(r.signature, 150)}\`` +
|
|
322
|
+
(r.exports ? " _(exported)_" : ""))
|
|
323
|
+
.join("\n\n");
|
|
324
|
+
},
|
|
325
|
+
search_graph: async (args, ctx) => {
|
|
326
|
+
const { query, limit = 5, expandHops = 1 } = args;
|
|
327
|
+
const response = await ctx.api.post("/api/search-graph", {
|
|
328
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
329
|
+
query,
|
|
330
|
+
limit,
|
|
331
|
+
expandHops,
|
|
332
|
+
});
|
|
333
|
+
const { results, graphExpanded, expandedFiles } = response.data;
|
|
334
|
+
let output = "";
|
|
335
|
+
if (results && results.length > 0) {
|
|
336
|
+
output += "**Direct matches:**\n\n";
|
|
337
|
+
output += results
|
|
338
|
+
.map((r) => `**${r.file}** (score: ${pct(r.score)})\n` +
|
|
339
|
+
"```" + (r.language || "") + "\n" +
|
|
340
|
+
truncate(r.content, 300) + "\n```")
|
|
341
|
+
.join("\n\n");
|
|
342
|
+
}
|
|
343
|
+
if (graphExpanded && graphExpanded.length > 0) {
|
|
344
|
+
output += "\n\n---\n\n**Graph-connected files:**\n\n";
|
|
345
|
+
output += graphExpanded
|
|
346
|
+
.map((r) => `**${r.file}** (score: ${pct(r.score)})\n` +
|
|
347
|
+
"```" + (r.language || "") + "\n" +
|
|
348
|
+
truncate(r.content, 300) + "\n```")
|
|
349
|
+
.join("\n\n");
|
|
350
|
+
}
|
|
351
|
+
if (!output) {
|
|
352
|
+
return "No results found.";
|
|
353
|
+
}
|
|
354
|
+
if (expandedFiles && expandedFiles.length > 0) {
|
|
355
|
+
output += `\n\n_Graph expanded to ${expandedFiles.length} additional files._`;
|
|
356
|
+
}
|
|
357
|
+
return output;
|
|
358
|
+
},
|
|
359
|
+
get_project_stats: async (_args, ctx) => {
|
|
360
|
+
const response = await ctx.api.get(`/api/stats/${ctx.collectionPrefix}codebase`);
|
|
361
|
+
const stats = response.data;
|
|
362
|
+
let result = `**${ctx.projectName} Project Statistics**\n\n`;
|
|
363
|
+
result += `- Total Files: ${stats.totalFiles}\n`;
|
|
364
|
+
result += `- Total Lines: ${stats.totalLines?.toLocaleString() || "N/A"}\n`;
|
|
365
|
+
result += `- Vector Count: ${stats.vectorCount}\n`;
|
|
366
|
+
result += `- Last Indexed: ${stats.lastIndexed ? new Date(stats.lastIndexed).toLocaleString() : "Never"}\n`;
|
|
367
|
+
if (stats.languages) {
|
|
368
|
+
result += `\n**Languages:**\n`;
|
|
369
|
+
for (const [lang, count] of Object.entries(stats.languages)) {
|
|
370
|
+
result += `- ${lang}: ${count} files\n`;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return result;
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
return { tools, handlers };
|
|
377
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session tools module - context summarization, session lifecycle management,
|
|
3
|
+
* change tracking, and usage pattern analysis.
|
|
4
|
+
*/
|
|
5
|
+
import type { ToolModule, ToolContext } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the session tools module with project-specific descriptions.
|
|
8
|
+
* Accepts a mutable ctx reference to update activeSessionId on start/end.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSessionTools(projectName: string, sharedCtx?: ToolContext): ToolModule;
|