@crowley/rag-mcp 1.0.5 → 1.0.6

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