@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
@@ -1,97 +1,78 @@
1
1
  /**
2
2
  * Agent tools module - run specialized agents and list agent types.
3
3
  */
4
+ import { z } from "zod";
5
+ import { TOOL_ANNOTATIONS } from "../annotations.js";
4
6
  /**
5
7
  * Create the agent tools module with project-specific descriptions.
6
8
  */
7
9
  export function createAgentTools(projectName) {
8
- const tools = [
10
+ return [
9
11
  {
10
12
  name: "run_agent",
11
13
  description: `Run a specialized agent for ${projectName}. Agents autonomously research, review, or analyze using multiple tool calls. Returns result + reasoning trace.`,
12
- inputSchema: {
13
- type: "object",
14
- properties: {
15
- type: {
16
- type: "string",
17
- description: "Agent type: research, review, documentation, refactor, or test",
18
- enum: ["research", "review", "documentation", "refactor", "test"],
19
- },
20
- task: {
21
- type: "string",
22
- description: "The task for the agent to perform",
23
- },
24
- context: {
25
- type: "string",
26
- description: "Optional additional context (code, requirements, etc.)",
27
- },
28
- maxIterations: {
29
- type: "number",
30
- description: "Maximum ReAct iterations (default: varies by agent type)",
31
- },
32
- },
33
- required: ["type", "task"],
14
+ schema: z.object({
15
+ type: z.enum(["research", "review", "documentation", "refactor", "test"]).describe("Agent type: research, review, documentation, refactor, or test"),
16
+ task: z.string().describe("The task for the agent to perform"),
17
+ context: z.string().optional().describe("Optional additional context (code, requirements, etc.)"),
18
+ maxIterations: z.number().optional().describe("Maximum ReAct iterations (default: varies by agent type)"),
19
+ }),
20
+ annotations: TOOL_ANNOTATIONS["run_agent"],
21
+ handler: async (args, ctx) => {
22
+ const { type, task, context, maxIterations } = args;
23
+ const response = await ctx.api.post("/api/agent/run", {
24
+ projectName: ctx.projectName,
25
+ agentType: type,
26
+ task,
27
+ context,
28
+ maxIterations,
29
+ });
30
+ const data = response.data;
31
+ // Format result with reasoning trace
32
+ let result = `## Agent Result (${data.type})\n`;
33
+ result += `**Task:** ${data.task}\n`;
34
+ result += `**Status:** ${data.status}`;
35
+ result += ` | **Iterations:** ${data.usage?.iterations || 0}`;
36
+ result += ` | **Tool Calls:** ${data.usage?.toolCalls || 0}`;
37
+ result += ` | **Duration:** ${data.usage?.durationMs ? Math.round(data.usage.durationMs / 1000) + "s" : "N/A"}`;
38
+ result += "\n\n";
39
+ if (data.error) {
40
+ result += `**Error:** ${data.error}\n\n`;
41
+ }
42
+ if (data.result) {
43
+ result += `### Result\n${data.result}\n\n`;
44
+ }
45
+ // Reasoning trace
46
+ if (data.steps && data.steps.length > 0) {
47
+ result += `### Reasoning Trace\n`;
48
+ for (const step of data.steps) {
49
+ result += `**Step ${step.iteration}:** ${step.thought?.slice(0, 200) || "..."}\n`;
50
+ if (step.action) {
51
+ result += ` Action: ${step.action.tool}(${JSON.stringify(step.action.input).slice(0, 100)})\n`;
52
+ }
53
+ if (step.observation) {
54
+ const obsPreview = step.observation.result?.slice(0, 150) || "...";
55
+ result += ` Result: ${obsPreview}${step.observation.truncated ? " [truncated]" : ""}\n`;
56
+ }
57
+ }
58
+ }
59
+ return result;
34
60
  },
35
61
  },
36
62
  {
37
63
  name: "get_agent_types",
38
64
  description: `List available agent types for ${projectName} with descriptions.`,
39
- inputSchema: {
40
- type: "object",
41
- properties: {},
65
+ schema: z.object({}),
66
+ annotations: TOOL_ANNOTATIONS["get_agent_types"],
67
+ handler: async (_args, ctx) => {
68
+ const response = await ctx.api.get("/api/agent/types");
69
+ const data = response.data;
70
+ let result = `## Available Agent Types\n\n`;
71
+ for (const agent of data.agents || []) {
72
+ result += `- **${agent.name}**: ${agent.description}\n`;
73
+ }
74
+ return result;
42
75
  },
43
76
  },
44
77
  ];
45
- const handlers = {
46
- run_agent: async (args, ctx) => {
47
- const { type, task, context, maxIterations } = args;
48
- const response = await ctx.api.post("/api/agent/run", {
49
- projectName: ctx.projectName,
50
- agentType: type,
51
- task,
52
- context,
53
- maxIterations,
54
- });
55
- const data = response.data;
56
- // Format result with reasoning trace
57
- let result = `## Agent Result (${data.type})\n`;
58
- result += `**Task:** ${data.task}\n`;
59
- result += `**Status:** ${data.status}`;
60
- result += ` | **Iterations:** ${data.usage?.iterations || 0}`;
61
- result += ` | **Tool Calls:** ${data.usage?.toolCalls || 0}`;
62
- result += ` | **Duration:** ${data.usage?.durationMs ? Math.round(data.usage.durationMs / 1000) + "s" : "N/A"}`;
63
- result += "\n\n";
64
- if (data.error) {
65
- result += `**Error:** ${data.error}\n\n`;
66
- }
67
- if (data.result) {
68
- result += `### Result\n${data.result}\n\n`;
69
- }
70
- // Reasoning trace
71
- if (data.steps && data.steps.length > 0) {
72
- result += `### Reasoning Trace\n`;
73
- for (const step of data.steps) {
74
- result += `**Step ${step.iteration}:** ${step.thought?.slice(0, 200) || "..."}\n`;
75
- if (step.action) {
76
- result += ` Action: ${step.action.tool}(${JSON.stringify(step.action.input).slice(0, 100)})\n`;
77
- }
78
- if (step.observation) {
79
- const obsPreview = step.observation.result?.slice(0, 150) || "...";
80
- result += ` Result: ${obsPreview}${step.observation.truncated ? " [truncated]" : ""}\n`;
81
- }
82
- }
83
- }
84
- return result;
85
- },
86
- get_agent_types: async (_args, ctx) => {
87
- const response = await ctx.api.get("/api/agent/types");
88
- const data = response.data;
89
- let result = `## Available Agent Types\n\n`;
90
- for (const agent of data.agents || []) {
91
- result += `- **${agent.name}**: ${agent.description}\n`;
92
- }
93
- return result;
94
- },
95
- };
96
- return { tools, handlers };
97
78
  }
@@ -2,8 +2,8 @@
2
2
  * Analytics tools module - tool analytics, knowledge gaps, collection analytics,
3
3
  * backups, and quantization.
4
4
  */
5
- import type { ToolModule } from "../types.js";
5
+ import type { ToolSpec } from "../types.js";
6
6
  /**
7
7
  * Create the analytics tools module with project-specific descriptions.
8
8
  */
9
- export declare function createAnalyticsTools(projectName: string): ToolModule;
9
+ export declare function createAnalyticsTools(projectName: string): ToolSpec[];
@@ -3,259 +3,219 @@
3
3
  * backups, and quantization.
4
4
  */
5
5
  import { pct } from "../formatters.js";
6
+ import { z } from "zod";
7
+ import { TOOL_ANNOTATIONS } from "../annotations.js";
6
8
  /**
7
9
  * Create the analytics tools module with project-specific descriptions.
8
10
  */
9
11
  export function createAnalyticsTools(projectName) {
10
- const tools = [
12
+ return [
11
13
  {
12
14
  name: "get_tool_analytics",
13
15
  description: `Get tool usage analytics for ${projectName}. Shows call counts, success rates, and performance.`,
14
- inputSchema: {
15
- type: "object",
16
- properties: {},
16
+ schema: z.object({}),
17
+ annotations: TOOL_ANNOTATIONS["get_tool_analytics"],
18
+ handler: async (_args, ctx) => {
19
+ const response = await ctx.api.get("/api/tool-analytics");
20
+ const data = response.data;
21
+ let result = `## Tool Analytics\n\n`;
22
+ result += `- **Total Calls:** ${data.totalCalls ?? "N/A"}\n`;
23
+ result += `- **Success Rate:** ${data.successRate !== undefined ? pct(data.successRate) : "N/A"}\n`;
24
+ result += `- **Avg Duration:** ${data.avgDurationMs ? data.avgDurationMs + "ms" : "N/A"}\n\n`;
25
+ if (data.topTools && data.topTools.length > 0) {
26
+ result += `### Top Tools\n`;
27
+ for (const t of data.topTools) {
28
+ result += `- **${t.tool || t.name}**: ${t.count ?? t.calls} calls`;
29
+ if (t.avgDurationMs || t.avgDuration)
30
+ result += ` (avg ${t.avgDurationMs || t.avgDuration}ms)`;
31
+ result += "\n";
32
+ }
33
+ result += "\n";
34
+ }
35
+ if (data.errorsByTool && Object.keys(data.errorsByTool).length > 0) {
36
+ result += `### Errors by Tool\n`;
37
+ for (const [tool, count] of Object.entries(data.errorsByTool)) {
38
+ result += `- **${tool}**: ${count} errors\n`;
39
+ }
40
+ }
41
+ return result;
17
42
  },
18
43
  },
19
44
  {
20
45
  name: "get_knowledge_gaps",
21
46
  description: `Get knowledge gaps for ${projectName}. Shows queries that returned few or no results.`,
22
- inputSchema: {
23
- type: "object",
24
- properties: {},
47
+ schema: z.object({}),
48
+ annotations: TOOL_ANNOTATIONS["get_knowledge_gaps"],
49
+ handler: async (_args, ctx) => {
50
+ const response = await ctx.api.get("/api/knowledge-gaps");
51
+ const data = response.data;
52
+ const queries = data.queries || data.gaps || data;
53
+ if (!queries || (Array.isArray(queries) && queries.length === 0)) {
54
+ return "No knowledge gaps identified.";
55
+ }
56
+ let result = `## Knowledge Gaps\n\n`;
57
+ result += `Queries with low or no results:\n\n`;
58
+ for (const q of Array.isArray(queries) ? queries : []) {
59
+ result += `- **"${q.query}"**`;
60
+ if (q.count)
61
+ result += ` (${q.count} times)`;
62
+ if (q.avgResultCount !== undefined)
63
+ result += ` - avg results: ${q.avgResultCount}`;
64
+ if (q.toolName)
65
+ result += ` [${q.toolName}]`;
66
+ result += "\n";
67
+ }
68
+ return result;
25
69
  },
26
70
  },
27
71
  {
28
72
  name: "get_analytics",
29
73
  description: `Get detailed analytics for a ${projectName} collection. Shows vectors, storage, language breakdown, and more.`,
30
- inputSchema: {
31
- type: "object",
32
- properties: {
33
- collectionName: {
34
- type: "string",
35
- description: "Collection name to get analytics for (e.g., 'codebase', 'docs', 'memory')",
36
- },
37
- },
38
- required: ["collectionName"],
74
+ schema: z.object({
75
+ collectionName: z.string().describe("Collection name to get analytics for (e.g., 'codebase', 'docs', 'memory')"),
76
+ }),
77
+ annotations: TOOL_ANNOTATIONS["get_analytics"],
78
+ handler: async (args, ctx) => {
79
+ const { collectionName } = args;
80
+ const fullName = collectionName.startsWith(ctx.collectionPrefix)
81
+ ? collectionName
82
+ : `${ctx.collectionPrefix}${collectionName}`;
83
+ const response = await ctx.api.get(`/api/analytics/${fullName}`);
84
+ const data = response.data;
85
+ let result = `## Collection Analytics: ${collectionName}\n\n`;
86
+ result += `- **Vectors:** ${data.vectorCount ?? data.vectors ?? "N/A"}\n`;
87
+ result += `- **Files:** ${data.totalFiles ?? data.files ?? "N/A"}\n`;
88
+ result += `- **Segments:** ${data.segments ?? "N/A"}\n`;
89
+ result += `- **Optimizer:** ${data.optimizerStatus || data.optimizer || "N/A"}\n`;
90
+ result += `- **Quantization:** ${data.quantization || "none"}\n`;
91
+ result += `- **RAM Usage:** ${data.ramUsage || "N/A"}\n`;
92
+ result += `- **Disk Usage:** ${data.diskUsage || "N/A"}\n`;
93
+ if (data.languages && Object.keys(data.languages).length > 0) {
94
+ result += `\n### Language Breakdown\n`;
95
+ for (const [lang, count] of Object.entries(data.languages)) {
96
+ result += `- ${lang}: ${count} files\n`;
97
+ }
98
+ }
99
+ result += `\n- **Last Indexed:** ${data.lastIndexed ? new Date(data.lastIndexed).toLocaleString() : "Never"}\n`;
100
+ return result;
39
101
  },
40
102
  },
41
103
  {
42
104
  name: "backup_collection",
43
105
  description: `Create a backup snapshot of a ${projectName} collection.`,
44
- inputSchema: {
45
- type: "object",
46
- properties: {
47
- collectionName: {
48
- type: "string",
49
- description: "Collection name to backup",
50
- },
51
- },
52
- required: ["collectionName"],
106
+ schema: z.object({
107
+ collectionName: z.string().describe("Collection name to backup"),
108
+ }),
109
+ annotations: TOOL_ANNOTATIONS["backup_collection"],
110
+ handler: async (args, ctx) => {
111
+ const { collectionName } = args;
112
+ const fullName = collectionName.startsWith(ctx.collectionPrefix)
113
+ ? collectionName
114
+ : `${ctx.collectionPrefix}${collectionName}`;
115
+ const response = await ctx.api.post(`/api/collections/${fullName}/snapshots`);
116
+ const data = response.data;
117
+ let result = `## Backup Created\n\n`;
118
+ result += `- **Collection:** ${fullName}\n`;
119
+ result += `- **Snapshot:** ${data.name || data.snapshotName || "N/A"}\n`;
120
+ result += `- **Created:** ${data.createdAt ? new Date(data.createdAt).toLocaleString() : new Date().toLocaleString()}\n`;
121
+ return result;
53
122
  },
54
123
  },
55
124
  {
56
125
  name: "list_backups",
57
126
  description: `List backup snapshots for a ${projectName} collection.`,
58
- inputSchema: {
59
- type: "object",
60
- properties: {
61
- collectionName: {
62
- type: "string",
63
- description: "Collection name to list backups for",
64
- },
65
- },
66
- required: ["collectionName"],
127
+ schema: z.object({
128
+ collectionName: z.string().describe("Collection name to list backups for"),
129
+ }),
130
+ annotations: TOOL_ANNOTATIONS["list_backups"],
131
+ handler: async (args, ctx) => {
132
+ const { collectionName } = args;
133
+ const fullName = collectionName.startsWith(ctx.collectionPrefix)
134
+ ? collectionName
135
+ : `${ctx.collectionPrefix}${collectionName}`;
136
+ const response = await ctx.api.get(`/api/collections/${fullName}/snapshots`);
137
+ const snapshots = response.data.snapshots || response.data;
138
+ if (!snapshots || snapshots.length === 0) {
139
+ return `No backups found for ${fullName}.`;
140
+ }
141
+ let result = `## Backups: ${fullName}\n\n`;
142
+ for (const s of snapshots) {
143
+ const sizeMB = s.size ? (s.size / (1024 * 1024)).toFixed(2) : "?";
144
+ result += `- **${s.name}** - ${sizeMB} MB`;
145
+ if (s.createdAt)
146
+ result += ` (${new Date(s.createdAt).toLocaleString()})`;
147
+ result += "\n";
148
+ }
149
+ return result;
67
150
  },
68
151
  },
69
152
  {
70
153
  name: "enable_quantization",
71
154
  description: `Enable scalar quantization on a ${projectName} collection to reduce memory usage.`,
72
- inputSchema: {
73
- type: "object",
74
- properties: {
75
- collectionName: {
76
- type: "string",
77
- description: "Collection name to enable quantization on",
78
- },
79
- quantile: {
80
- type: "number",
81
- description: "Quantile for quantization (0-1, default: 0.99)",
82
- default: 0.99,
83
- },
84
- },
85
- required: ["collectionName"],
155
+ schema: z.object({
156
+ collectionName: z.string().describe("Collection name to enable quantization on"),
157
+ quantile: z.number().optional().describe("Quantile for quantization (0-1, default: 0.99)"),
158
+ }),
159
+ annotations: TOOL_ANNOTATIONS["enable_quantization"],
160
+ handler: async (args, ctx) => {
161
+ const { collectionName, quantile = 0.99 } = args;
162
+ const fullName = collectionName.startsWith(ctx.collectionPrefix)
163
+ ? collectionName
164
+ : `${ctx.collectionPrefix}${collectionName}`;
165
+ const response = await ctx.api.post(`/api/collections/${fullName}/quantization`, { quantile });
166
+ const data = response.data;
167
+ let result = `## Quantization Enabled\n\n`;
168
+ result += `- **Collection:** ${fullName}\n`;
169
+ result += `- **Quantile:** ${quantile}\n`;
170
+ result += `- **Expected Reduction:** ${data.expectedReduction || "~4x memory reduction"}\n`;
171
+ return result;
86
172
  },
87
173
  },
88
174
  {
89
175
  name: "get_platform_stats",
90
176
  description: `Get cross-project platform statistics. Shows all projects, their collections, and aggregated metrics.`,
91
- inputSchema: {
92
- type: "object",
93
- properties: {},
177
+ schema: z.object({}),
178
+ annotations: TOOL_ANNOTATIONS["get_platform_stats"],
179
+ handler: async (_args, ctx) => {
180
+ const response = await ctx.api.get("/api/platform/stats");
181
+ const data = response.data;
182
+ let result = `## Platform Statistics\n\n`;
183
+ result += `- **Total Projects:** ${data.totalProjects ?? 0}\n`;
184
+ result += `- **Total Collections:** ${data.totalCollections ?? 0}\n\n`;
185
+ if (data.projects && data.projects.length > 0) {
186
+ result += `### Projects\n`;
187
+ for (const p of data.projects) {
188
+ result += `- **${p.project}**: ${p.collections} collections, ${p.totalVectors} vectors\n`;
189
+ }
190
+ }
191
+ return result;
94
192
  },
95
193
  },
96
194
  {
97
195
  name: "get_prediction_stats",
98
196
  description: `Get predictive loader stats for ${projectName}. Shows prediction accuracy, hit rates, and strategy breakdown.`,
99
- inputSchema: {
100
- type: "object",
101
- properties: {
102
- sessionId: {
103
- type: "string",
104
- description: "Session ID to get stats for. If omitted, returns aggregate stats.",
105
- },
106
- },
197
+ schema: z.object({
198
+ sessionId: z.string().optional().describe("Session ID to get stats for. If omitted, returns aggregate stats."),
199
+ }),
200
+ annotations: TOOL_ANNOTATIONS["get_prediction_stats"],
201
+ handler: async (args, ctx) => {
202
+ const { sessionId } = args;
203
+ const params = sessionId ? `?sessionId=${sessionId}` : "";
204
+ const response = await ctx.api.get(`/api/predictions/stats${params}`);
205
+ const data = response.data;
206
+ let result = `## Prediction Stats${sessionId ? ` (Session ${sessionId})` : ""}\n\n`;
207
+ result += `- **Total Predictions:** ${data.totalPredictions ?? 0}\n`;
208
+ result += `- **Hits:** ${data.totalHits ?? 0}\n`;
209
+ result += `- **Misses:** ${data.totalMisses ?? 0}\n`;
210
+ result += `- **Hit Rate:** ${data.hitRate !== undefined ? pct(data.hitRate) : "N/A"}\n\n`;
211
+ if (data.byStrategy && Object.keys(data.byStrategy).length > 0) {
212
+ result += `### By Strategy\n`;
213
+ for (const [strategy, stats] of Object.entries(data.byStrategy)) {
214
+ result += `- **${strategy}**: ${stats.predictions} predictions, ${stats.hits} hits (${pct(stats.hitRate)})\n`;
215
+ }
216
+ }
217
+ return result;
107
218
  },
108
219
  },
109
220
  ];
110
- const handlers = {
111
- get_tool_analytics: async (_args, ctx) => {
112
- const response = await ctx.api.get("/api/tool-analytics");
113
- const data = response.data;
114
- let result = `## Tool Analytics\n\n`;
115
- result += `- **Total Calls:** ${data.totalCalls ?? "N/A"}\n`;
116
- result += `- **Success Rate:** ${data.successRate !== undefined ? pct(data.successRate) : "N/A"}\n`;
117
- result += `- **Avg Duration:** ${data.avgDurationMs ? data.avgDurationMs + "ms" : "N/A"}\n\n`;
118
- if (data.topTools && data.topTools.length > 0) {
119
- result += `### Top Tools\n`;
120
- for (const t of data.topTools) {
121
- result += `- **${t.tool || t.name}**: ${t.count ?? t.calls} calls`;
122
- if (t.avgDurationMs || t.avgDuration)
123
- result += ` (avg ${t.avgDurationMs || t.avgDuration}ms)`;
124
- result += "\n";
125
- }
126
- result += "\n";
127
- }
128
- if (data.errorsByTool && Object.keys(data.errorsByTool).length > 0) {
129
- result += `### Errors by Tool\n`;
130
- for (const [tool, count] of Object.entries(data.errorsByTool)) {
131
- result += `- **${tool}**: ${count} errors\n`;
132
- }
133
- }
134
- return result;
135
- },
136
- get_knowledge_gaps: async (_args, ctx) => {
137
- const response = await ctx.api.get("/api/knowledge-gaps");
138
- const data = response.data;
139
- const queries = data.queries || data.gaps || data;
140
- if (!queries || (Array.isArray(queries) && queries.length === 0)) {
141
- return "No knowledge gaps identified.";
142
- }
143
- let result = `## Knowledge Gaps\n\n`;
144
- result += `Queries with low or no results:\n\n`;
145
- for (const q of Array.isArray(queries) ? queries : []) {
146
- result += `- **"${q.query}"**`;
147
- if (q.count)
148
- result += ` (${q.count} times)`;
149
- if (q.avgResultCount !== undefined)
150
- result += ` - avg results: ${q.avgResultCount}`;
151
- if (q.toolName)
152
- result += ` [${q.toolName}]`;
153
- result += "\n";
154
- }
155
- return result;
156
- },
157
- get_analytics: async (args, ctx) => {
158
- const { collectionName } = args;
159
- const fullName = collectionName.startsWith(ctx.collectionPrefix)
160
- ? collectionName
161
- : `${ctx.collectionPrefix}${collectionName}`;
162
- const response = await ctx.api.get(`/api/analytics/${fullName}`);
163
- const data = response.data;
164
- let result = `## Collection Analytics: ${collectionName}\n\n`;
165
- result += `- **Vectors:** ${data.vectorCount ?? data.vectors ?? "N/A"}\n`;
166
- result += `- **Files:** ${data.totalFiles ?? data.files ?? "N/A"}\n`;
167
- result += `- **Segments:** ${data.segments ?? "N/A"}\n`;
168
- result += `- **Optimizer:** ${data.optimizerStatus || data.optimizer || "N/A"}\n`;
169
- result += `- **Quantization:** ${data.quantization || "none"}\n`;
170
- result += `- **RAM Usage:** ${data.ramUsage || "N/A"}\n`;
171
- result += `- **Disk Usage:** ${data.diskUsage || "N/A"}\n`;
172
- if (data.languages && Object.keys(data.languages).length > 0) {
173
- result += `\n### Language Breakdown\n`;
174
- for (const [lang, count] of Object.entries(data.languages)) {
175
- result += `- ${lang}: ${count} files\n`;
176
- }
177
- }
178
- result += `\n- **Last Indexed:** ${data.lastIndexed ? new Date(data.lastIndexed).toLocaleString() : "Never"}\n`;
179
- return result;
180
- },
181
- backup_collection: async (args, ctx) => {
182
- const { collectionName } = args;
183
- const fullName = collectionName.startsWith(ctx.collectionPrefix)
184
- ? collectionName
185
- : `${ctx.collectionPrefix}${collectionName}`;
186
- const response = await ctx.api.post(`/api/collections/${fullName}/snapshots`);
187
- const data = response.data;
188
- let result = `## Backup Created\n\n`;
189
- result += `- **Collection:** ${fullName}\n`;
190
- result += `- **Snapshot:** ${data.name || data.snapshotName || "N/A"}\n`;
191
- result += `- **Created:** ${data.createdAt ? new Date(data.createdAt).toLocaleString() : new Date().toLocaleString()}\n`;
192
- return result;
193
- },
194
- list_backups: async (args, ctx) => {
195
- const { collectionName } = args;
196
- const fullName = collectionName.startsWith(ctx.collectionPrefix)
197
- ? collectionName
198
- : `${ctx.collectionPrefix}${collectionName}`;
199
- const response = await ctx.api.get(`/api/collections/${fullName}/snapshots`);
200
- const snapshots = response.data.snapshots || response.data;
201
- if (!snapshots || snapshots.length === 0) {
202
- return `No backups found for ${fullName}.`;
203
- }
204
- let result = `## Backups: ${fullName}\n\n`;
205
- for (const s of snapshots) {
206
- const sizeMB = s.size ? (s.size / (1024 * 1024)).toFixed(2) : "?";
207
- result += `- **${s.name}** - ${sizeMB} MB`;
208
- if (s.createdAt)
209
- result += ` (${new Date(s.createdAt).toLocaleString()})`;
210
- result += "\n";
211
- }
212
- return result;
213
- },
214
- get_platform_stats: async (_args, ctx) => {
215
- const response = await ctx.api.get("/api/platform/stats");
216
- const data = response.data;
217
- let result = `## Platform Statistics\n\n`;
218
- result += `- **Total Projects:** ${data.totalProjects ?? 0}\n`;
219
- result += `- **Total Collections:** ${data.totalCollections ?? 0}\n\n`;
220
- if (data.projects && data.projects.length > 0) {
221
- result += `### Projects\n`;
222
- for (const p of data.projects) {
223
- result += `- **${p.project}**: ${p.collections} collections, ${p.totalVectors} vectors\n`;
224
- }
225
- }
226
- return result;
227
- },
228
- get_prediction_stats: async (args, ctx) => {
229
- const { sessionId } = args;
230
- const params = sessionId ? `?sessionId=${sessionId}` : "";
231
- const response = await ctx.api.get(`/api/predictions/stats${params}`);
232
- const data = response.data;
233
- let result = `## Prediction Stats${sessionId ? ` (Session ${sessionId})` : ""}\n\n`;
234
- result += `- **Total Predictions:** ${data.totalPredictions ?? 0}\n`;
235
- result += `- **Hits:** ${data.totalHits ?? 0}\n`;
236
- result += `- **Misses:** ${data.totalMisses ?? 0}\n`;
237
- result += `- **Hit Rate:** ${data.hitRate !== undefined ? pct(data.hitRate) : "N/A"}\n\n`;
238
- if (data.byStrategy && Object.keys(data.byStrategy).length > 0) {
239
- result += `### By Strategy\n`;
240
- for (const [strategy, stats] of Object.entries(data.byStrategy)) {
241
- result += `- **${strategy}**: ${stats.predictions} predictions, ${stats.hits} hits (${pct(stats.hitRate)})\n`;
242
- }
243
- }
244
- return result;
245
- },
246
- enable_quantization: async (args, ctx) => {
247
- const { collectionName, quantile = 0.99 } = args;
248
- const fullName = collectionName.startsWith(ctx.collectionPrefix)
249
- ? collectionName
250
- : `${ctx.collectionPrefix}${collectionName}`;
251
- const response = await ctx.api.post(`/api/collections/${fullName}/quantization`, { quantile });
252
- const data = response.data;
253
- let result = `## Quantization Enabled\n\n`;
254
- result += `- **Collection:** ${fullName}\n`;
255
- result += `- **Quantile:** ${quantile}\n`;
256
- result += `- **Expected Reduction:** ${data.expectedReduction || "~4x memory reduction"}\n`;
257
- return result;
258
- },
259
- };
260
- return { tools, handlers };
261
221
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * Architecture tools module - ADRs, patterns, tech debt, and structure analysis.
3
3
  */
4
- import type { ToolModule } from "../types.js";
5
- export declare function createArchitectureTools(projectName: string): ToolModule;
4
+ import type { ToolSpec } from "../types.js";
5
+ export declare function createArchitectureTools(projectName: string): ToolSpec[];