@crowley/rag-mcp 1.0.4 → 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.
- package/dist/annotations.d.ts +16 -0
- package/dist/annotations.js +158 -0
- package/dist/context-enrichment.d.ts +2 -2
- package/dist/context-enrichment.js +37 -14
- package/dist/formatters.d.ts +2 -0
- package/dist/formatters.js +12 -0
- package/dist/index.js +64 -47
- package/dist/schemas.d.ts +97 -0
- package/dist/schemas.js +128 -0
- package/dist/tool-middleware.d.ts +40 -0
- package/dist/tool-middleware.js +216 -0
- package/dist/tool-registry.js +2 -1
- package/dist/tools/advanced.d.ts +2 -2
- package/dist/tools/advanced.js +200 -275
- package/dist/tools/agents.d.ts +2 -2
- package/dist/tools/agents.js +59 -78
- package/dist/tools/analytics.d.ts +2 -2
- package/dist/tools/analytics.js +170 -210
- package/dist/tools/architecture.d.ts +2 -2
- package/dist/tools/architecture.js +506 -661
- package/dist/tools/ask.d.ts +2 -2
- package/dist/tools/ask.js +164 -219
- package/dist/tools/cache.d.ts +2 -2
- package/dist/tools/cache.js +63 -82
- package/dist/tools/clustering.d.ts +2 -2
- package/dist/tools/clustering.js +154 -215
- package/dist/tools/confluence.d.ts +2 -2
- package/dist/tools/confluence.js +80 -116
- package/dist/tools/database.d.ts +2 -2
- package/dist/tools/database.js +303 -380
- package/dist/tools/feedback.d.ts +2 -2
- package/dist/tools/feedback.js +143 -184
- package/dist/tools/guidelines.d.ts +2 -2
- package/dist/tools/guidelines.js +123 -135
- package/dist/tools/indexing.d.ts +2 -2
- package/dist/tools/indexing.js +104 -100
- package/dist/tools/memory.d.ts +2 -2
- package/dist/tools/memory.js +299 -485
- package/dist/tools/pm.d.ts +2 -2
- package/dist/tools/pm.js +367 -615
- package/dist/tools/review.d.ts +2 -2
- package/dist/tools/review.js +142 -189
- package/dist/tools/search.d.ts +2 -2
- package/dist/tools/search.js +230 -305
- package/dist/tools/session.d.ts +2 -2
- package/dist/tools/session.js +288 -345
- package/dist/tools/suggestions.d.ts +2 -2
- package/dist/tools/suggestions.js +444 -255
- package/dist/types.d.ts +19 -2
- package/package.json +4 -2
package/dist/tools/clustering.js
CHANGED
|
@@ -3,249 +3,188 @@
|
|
|
3
3
|
* similarity recommendations, and learning extraction.
|
|
4
4
|
*/
|
|
5
5
|
import { truncate, pct, PREVIEW } from "../formatters.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { TOOL_ANNOTATIONS } from "../annotations.js";
|
|
6
8
|
/**
|
|
7
9
|
* Create the clustering tools module with project-specific descriptions.
|
|
8
10
|
*/
|
|
9
11
|
export function createClusteringTools(projectName) {
|
|
10
|
-
|
|
12
|
+
return [
|
|
11
13
|
{
|
|
12
14
|
name: "cluster_code",
|
|
13
15
|
description: `Cluster code in the ${projectName} codebase by similarity. Groups related files around seed points.`,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
16
|
+
schema: z.object({
|
|
17
|
+
seedIds: z.array(z.string()).describe("Seed point IDs to cluster around"),
|
|
18
|
+
limit: z.number().optional().describe("Max results per cluster (default: 5)"),
|
|
19
|
+
threshold: z.number().optional().describe("Minimum similarity threshold (0-1, default: 0.7)"),
|
|
20
|
+
}),
|
|
21
|
+
annotations: TOOL_ANNOTATIONS["cluster_code"],
|
|
22
|
+
handler: async (args, ctx) => {
|
|
23
|
+
const { seedIds, limit = 5, threshold = 0.7 } = args;
|
|
24
|
+
const response = await ctx.api.post("/api/clusters", {
|
|
25
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
26
|
+
seedIds,
|
|
27
|
+
limit,
|
|
28
|
+
threshold,
|
|
29
|
+
});
|
|
30
|
+
const data = response.data;
|
|
31
|
+
const clusters = data.clusters || data;
|
|
32
|
+
if (!clusters || (Array.isArray(clusters) && clusters.length === 0)) {
|
|
33
|
+
return "No clusters found.";
|
|
34
|
+
}
|
|
35
|
+
let result = `## Code Clusters\n\n`;
|
|
36
|
+
for (const cluster of Array.isArray(clusters) ? clusters : [clusters]) {
|
|
37
|
+
result += `### Seed: ${cluster.seedId || cluster.seed || "unknown"}\n`;
|
|
38
|
+
const files = cluster.similar || cluster.files || cluster.results || [];
|
|
39
|
+
for (const f of files) {
|
|
40
|
+
result += `- **${f.file || f.name}** (${pct(f.score || f.similarity)})`;
|
|
41
|
+
if (f.content)
|
|
42
|
+
result += `\n ${truncate(f.content, PREVIEW.SHORT)}`;
|
|
43
|
+
result += "\n";
|
|
44
|
+
}
|
|
45
|
+
result += "\n";
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
34
48
|
},
|
|
35
49
|
},
|
|
36
50
|
{
|
|
37
51
|
name: "find_duplicates",
|
|
38
52
|
description: `Find duplicate or near-duplicate code in ${projectName}. Groups similar files by content.`,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
schema: z.object({
|
|
54
|
+
collection: z.string().optional().describe("Collection to search (default: codebase)"),
|
|
55
|
+
limit: z.number().optional().describe("Max duplicate groups to return (default: 10)"),
|
|
56
|
+
threshold: z.number().optional().describe("Minimum similarity threshold (0-1, default: 0.9)"),
|
|
57
|
+
}),
|
|
58
|
+
annotations: TOOL_ANNOTATIONS["find_duplicates"],
|
|
59
|
+
handler: async (args, ctx) => {
|
|
60
|
+
const { collection, limit = 10, threshold = 0.9 } = args;
|
|
61
|
+
const fullCollection = collection
|
|
62
|
+
? (collection.startsWith(ctx.collectionPrefix) ? collection : `${ctx.collectionPrefix}${collection}`)
|
|
63
|
+
: `${ctx.collectionPrefix}codebase`;
|
|
64
|
+
const response = await ctx.api.post("/api/duplicates", {
|
|
65
|
+
collection: fullCollection,
|
|
66
|
+
limit,
|
|
67
|
+
threshold,
|
|
68
|
+
});
|
|
69
|
+
const data = response.data;
|
|
70
|
+
const groups = data.groups || data.duplicates || data;
|
|
71
|
+
if (!groups || (Array.isArray(groups) && groups.length === 0)) {
|
|
72
|
+
return "No duplicates found.";
|
|
73
|
+
}
|
|
74
|
+
let result = `## Duplicate Code Groups\n\n`;
|
|
75
|
+
let groupNum = 1;
|
|
76
|
+
for (const group of Array.isArray(groups) ? groups : [groups]) {
|
|
77
|
+
result += `### Group ${groupNum++}\n`;
|
|
78
|
+
const files = group.files || group.items || group.results || [];
|
|
79
|
+
const similarity = group.similarity || group.score;
|
|
80
|
+
if (similarity) {
|
|
81
|
+
result += `**Similarity:** ${pct(similarity)}\n`;
|
|
82
|
+
}
|
|
83
|
+
for (const f of files) {
|
|
84
|
+
result += `- **${f.file || f.name}**`;
|
|
85
|
+
if (f.content)
|
|
86
|
+
result += `\n ${truncate(f.content, 80)}`;
|
|
87
|
+
result += "\n";
|
|
88
|
+
}
|
|
89
|
+
result += "\n";
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
57
92
|
},
|
|
58
93
|
},
|
|
59
94
|
{
|
|
60
95
|
name: "recommend_similar",
|
|
61
96
|
description: `Recommend similar code based on positive and negative examples in ${projectName}.`,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
schema: z.object({
|
|
98
|
+
positiveIds: z.array(z.string()).describe("IDs of vectors to find similar code to"),
|
|
99
|
+
negativeIds: z.array(z.string()).optional().describe("IDs of vectors to avoid (dissimilar)"),
|
|
100
|
+
limit: z.number().optional().describe("Max results (default: 5)"),
|
|
101
|
+
}),
|
|
102
|
+
annotations: TOOL_ANNOTATIONS["recommend_similar"],
|
|
103
|
+
handler: async (args, ctx) => {
|
|
104
|
+
const { positiveIds, negativeIds, limit = 5 } = args;
|
|
105
|
+
const response = await ctx.api.post("/api/recommend", {
|
|
106
|
+
collection: `${ctx.collectionPrefix}codebase`,
|
|
107
|
+
positiveIds,
|
|
108
|
+
negativeIds,
|
|
109
|
+
limit,
|
|
110
|
+
});
|
|
111
|
+
const results = response.data.results || response.data;
|
|
112
|
+
if (!results || results.length === 0) {
|
|
113
|
+
return "No recommendations found.";
|
|
114
|
+
}
|
|
115
|
+
let result = `## Recommendations\n\n`;
|
|
116
|
+
for (const r of results) {
|
|
117
|
+
result += `- **${r.file || r.name}** (${pct(r.score || r.similarity)})`;
|
|
118
|
+
if (r.content)
|
|
119
|
+
result += `\n ${truncate(r.content, PREVIEW.SHORT)}`;
|
|
120
|
+
result += "\n";
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
82
123
|
},
|
|
83
124
|
},
|
|
84
125
|
{
|
|
85
126
|
name: "extract_learnings",
|
|
86
127
|
description: `Extract learnings and insights from text for ${projectName}. Identifies decisions, patterns, and concepts.`,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
collection: `${ctx.projectName}_codebase`,
|
|
118
|
-
seedIds,
|
|
119
|
-
limit,
|
|
120
|
-
threshold,
|
|
121
|
-
});
|
|
122
|
-
const data = response.data;
|
|
123
|
-
const clusters = data.clusters || data;
|
|
124
|
-
if (!clusters || (Array.isArray(clusters) && clusters.length === 0)) {
|
|
125
|
-
return "No clusters found.";
|
|
126
|
-
}
|
|
127
|
-
let result = `## Code Clusters\n\n`;
|
|
128
|
-
for (const cluster of Array.isArray(clusters) ? clusters : [clusters]) {
|
|
129
|
-
result += `### Seed: ${cluster.seedId || cluster.seed || "unknown"}\n`;
|
|
130
|
-
const files = cluster.similar || cluster.files || cluster.results || [];
|
|
131
|
-
for (const f of files) {
|
|
132
|
-
result += `- **${f.file || f.name}** (${pct(f.score || f.similarity)})`;
|
|
133
|
-
if (f.content)
|
|
134
|
-
result += `\n ${truncate(f.content, PREVIEW.SHORT)}`;
|
|
135
|
-
result += "\n";
|
|
136
|
-
}
|
|
137
|
-
result += "\n";
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
},
|
|
141
|
-
find_duplicates: async (args, ctx) => {
|
|
142
|
-
const { collection, limit = 10, threshold = 0.9 } = args;
|
|
143
|
-
const fullCollection = collection
|
|
144
|
-
? (collection.startsWith(ctx.collectionPrefix) ? collection : `${ctx.collectionPrefix}${collection}`)
|
|
145
|
-
: `${ctx.collectionPrefix}codebase`;
|
|
146
|
-
const response = await ctx.api.post("/api/duplicates", {
|
|
147
|
-
collection: fullCollection,
|
|
148
|
-
limit,
|
|
149
|
-
threshold,
|
|
150
|
-
});
|
|
151
|
-
const data = response.data;
|
|
152
|
-
const groups = data.groups || data.duplicates || data;
|
|
153
|
-
if (!groups || (Array.isArray(groups) && groups.length === 0)) {
|
|
154
|
-
return "No duplicates found.";
|
|
155
|
-
}
|
|
156
|
-
let result = `## Duplicate Code Groups\n\n`;
|
|
157
|
-
let groupNum = 1;
|
|
158
|
-
for (const group of Array.isArray(groups) ? groups : [groups]) {
|
|
159
|
-
result += `### Group ${groupNum++}\n`;
|
|
160
|
-
const files = group.files || group.items || group.results || [];
|
|
161
|
-
const similarity = group.similarity || group.score;
|
|
162
|
-
if (similarity) {
|
|
163
|
-
result += `**Similarity:** ${pct(similarity)}\n`;
|
|
164
|
-
}
|
|
165
|
-
for (const f of files) {
|
|
166
|
-
result += `- **${f.file || f.name}**`;
|
|
167
|
-
if (f.content)
|
|
168
|
-
result += `\n ${truncate(f.content, 80)}`;
|
|
128
|
+
schema: z.object({
|
|
129
|
+
text: z.string().describe("Text to extract learnings from"),
|
|
130
|
+
context: z.string().optional().describe("Additional context about the text"),
|
|
131
|
+
autoSave: z.boolean().optional().describe("Automatically save extracted learnings (default: false)"),
|
|
132
|
+
minConfidence: z.number().optional().describe("Minimum confidence threshold (0-1, default: 0.7)"),
|
|
133
|
+
}),
|
|
134
|
+
annotations: TOOL_ANNOTATIONS["extract_learnings"],
|
|
135
|
+
handler: async (args, ctx) => {
|
|
136
|
+
const { text, context, autoSave = false, minConfidence = 0.7 } = args;
|
|
137
|
+
const response = await ctx.api.post("/api/memory/extract", {
|
|
138
|
+
projectName: ctx.projectName,
|
|
139
|
+
text,
|
|
140
|
+
context,
|
|
141
|
+
autoSave,
|
|
142
|
+
minConfidence,
|
|
143
|
+
});
|
|
144
|
+
const data = response.data;
|
|
145
|
+
let result = `## Extracted Learnings\n\n`;
|
|
146
|
+
result += `**Summary:** ${data.summary || "N/A"}\n\n`;
|
|
147
|
+
if (data.learnings && data.learnings.length > 0) {
|
|
148
|
+
result += `### Learnings\n`;
|
|
149
|
+
for (const l of data.learnings) {
|
|
150
|
+
result += `- **[${l.type}]** (confidence: ${pct(l.confidence)}) ${l.content}\n`;
|
|
151
|
+
if (l.tags && l.tags.length > 0) {
|
|
152
|
+
result += ` Tags: ${l.tags.join(", ")}\n`;
|
|
153
|
+
}
|
|
154
|
+
if (l.reasoning) {
|
|
155
|
+
result += ` *Reasoning: ${l.reasoning}*\n`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
169
158
|
result += "\n";
|
|
170
159
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
collection: `${ctx.projectName}_codebase`,
|
|
179
|
-
positiveIds,
|
|
180
|
-
negativeIds,
|
|
181
|
-
limit,
|
|
182
|
-
});
|
|
183
|
-
const results = response.data.results || response.data;
|
|
184
|
-
if (!results || results.length === 0) {
|
|
185
|
-
return "No recommendations found.";
|
|
186
|
-
}
|
|
187
|
-
let result = `## Recommendations\n\n`;
|
|
188
|
-
for (const r of results) {
|
|
189
|
-
result += `- **${r.file || r.name}** (${pct(r.score || r.similarity)})`;
|
|
190
|
-
if (r.content)
|
|
191
|
-
result += `\n ${truncate(r.content, PREVIEW.SHORT)}`;
|
|
192
|
-
result += "\n";
|
|
193
|
-
}
|
|
194
|
-
return result;
|
|
195
|
-
},
|
|
196
|
-
extract_learnings: async (args, ctx) => {
|
|
197
|
-
const { text, context, autoSave = false, minConfidence = 0.7 } = args;
|
|
198
|
-
const response = await ctx.api.post("/api/memory/extract", {
|
|
199
|
-
projectName: ctx.projectName,
|
|
200
|
-
text,
|
|
201
|
-
context,
|
|
202
|
-
autoSave,
|
|
203
|
-
minConfidence,
|
|
204
|
-
});
|
|
205
|
-
const data = response.data;
|
|
206
|
-
let result = `## Extracted Learnings\n\n`;
|
|
207
|
-
result += `**Summary:** ${data.summary || "N/A"}\n\n`;
|
|
208
|
-
if (data.learnings && data.learnings.length > 0) {
|
|
209
|
-
result += `### Learnings\n`;
|
|
210
|
-
for (const l of data.learnings) {
|
|
211
|
-
result += `- **[${l.type}]** (confidence: ${pct(l.confidence)}) ${l.content}\n`;
|
|
212
|
-
if (l.tags && l.tags.length > 0) {
|
|
213
|
-
result += ` Tags: ${l.tags.join(", ")}\n`;
|
|
160
|
+
if (data.entities) {
|
|
161
|
+
if (data.entities.files && data.entities.files.length > 0) {
|
|
162
|
+
result += `### Referenced Files\n`;
|
|
163
|
+
for (const f of data.entities.files) {
|
|
164
|
+
result += `- ${f}\n`;
|
|
165
|
+
}
|
|
166
|
+
result += "\n";
|
|
214
167
|
}
|
|
215
|
-
if (
|
|
216
|
-
result +=
|
|
168
|
+
if (data.entities.functions && data.entities.functions.length > 0) {
|
|
169
|
+
result += `### Referenced Functions\n`;
|
|
170
|
+
for (const f of data.entities.functions) {
|
|
171
|
+
result += `- ${f}\n`;
|
|
172
|
+
}
|
|
173
|
+
result += "\n";
|
|
217
174
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
for (const f of data.entities.files) {
|
|
225
|
-
result += `- ${f}\n`;
|
|
175
|
+
if (data.entities.concepts && data.entities.concepts.length > 0) {
|
|
176
|
+
result += `### Concepts\n`;
|
|
177
|
+
for (const c of data.entities.concepts) {
|
|
178
|
+
result += `- ${c}\n`;
|
|
179
|
+
}
|
|
180
|
+
result += "\n";
|
|
226
181
|
}
|
|
227
|
-
result += "\n";
|
|
228
182
|
}
|
|
229
|
-
if (data.
|
|
230
|
-
result +=
|
|
231
|
-
for (const f of data.entities.functions) {
|
|
232
|
-
result += `- ${f}\n`;
|
|
233
|
-
}
|
|
234
|
-
result += "\n";
|
|
183
|
+
if (data.savedCount !== undefined) {
|
|
184
|
+
result += `**Saved:** ${data.savedCount} learnings\n`;
|
|
235
185
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
for (const c of data.entities.concepts) {
|
|
239
|
-
result += `- ${c}\n`;
|
|
240
|
-
}
|
|
241
|
-
result += "\n";
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (data.savedCount !== undefined) {
|
|
245
|
-
result += `**Saved:** ${data.savedCount} learnings\n`;
|
|
246
|
-
}
|
|
247
|
-
return result;
|
|
186
|
+
return result;
|
|
187
|
+
},
|
|
248
188
|
},
|
|
249
|
-
|
|
250
|
-
return { tools, handlers };
|
|
189
|
+
];
|
|
251
190
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Confluence tools module - search, index, status, and space listing
|
|
3
3
|
* for Confluence integration.
|
|
4
4
|
*/
|
|
5
|
-
import type {
|
|
5
|
+
import type { ToolSpec } from "../types.js";
|
|
6
6
|
/**
|
|
7
7
|
* Create the Confluence tools module with project-specific descriptions.
|
|
8
8
|
*/
|
|
9
|
-
export declare function createConfluenceTools(projectName: string):
|
|
9
|
+
export declare function createConfluenceTools(projectName: string): ToolSpec[];
|
package/dist/tools/confluence.js
CHANGED
|
@@ -3,145 +3,109 @@
|
|
|
3
3
|
* for Confluence integration.
|
|
4
4
|
*/
|
|
5
5
|
import { truncate, pct } from "../formatters.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { TOOL_ANNOTATIONS } from "../annotations.js";
|
|
6
8
|
/**
|
|
7
9
|
* Create the Confluence tools module with project-specific descriptions.
|
|
8
10
|
*/
|
|
9
11
|
export function createConfluenceTools(projectName) {
|
|
10
|
-
|
|
12
|
+
return [
|
|
11
13
|
{
|
|
12
14
|
name: "search_confluence",
|
|
13
15
|
description: `Search indexed Confluence documentation for ${projectName}. Returns relevant pages with content snippets.`,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
spaceKey:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
schema: z.object({
|
|
17
|
+
query: z.string().describe("Search query for Confluence content"),
|
|
18
|
+
limit: z.number().optional().describe("Max results (default: 5)"),
|
|
19
|
+
spaceKey: z.string().optional().describe("Filter by Confluence space key"),
|
|
20
|
+
}),
|
|
21
|
+
annotations: TOOL_ANNOTATIONS["search_confluence"],
|
|
22
|
+
handler: async (args, ctx) => {
|
|
23
|
+
const { query, limit = 5, spaceKey } = args;
|
|
24
|
+
const response = await ctx.api.post("/api/search", {
|
|
25
|
+
collection: `${ctx.collectionPrefix}confluence`,
|
|
26
|
+
query,
|
|
27
|
+
limit,
|
|
28
|
+
filters: spaceKey ? { spaceKey } : undefined,
|
|
29
|
+
});
|
|
30
|
+
const results = response.data.results;
|
|
31
|
+
if (!results || results.length === 0) {
|
|
32
|
+
return "No Confluence results found.";
|
|
33
|
+
}
|
|
34
|
+
return results
|
|
35
|
+
.map((r) => `### ${r.title || r.file || "Untitled"}\n` +
|
|
36
|
+
`**Score:** ${pct(r.score)}` +
|
|
37
|
+
(r.spaceKey ? ` | **Space:** ${r.spaceKey}` : "") +
|
|
38
|
+
(r.url ? ` | [View](${r.url})` : "") +
|
|
39
|
+
`\n\n${truncate(r.content || "", 600)}`)
|
|
40
|
+
.join("\n\n---\n\n");
|
|
32
41
|
},
|
|
33
42
|
},
|
|
34
43
|
{
|
|
35
44
|
name: "index_confluence",
|
|
36
45
|
description: `Index Confluence spaces/pages for ${projectName}. Requires Confluence credentials in RAG API.`,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
maxPages
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
}
|
|
46
|
+
schema: z.object({
|
|
47
|
+
spaceKeys: z.array(z.string()).optional().describe("Specific space keys to index (indexes all accessible if empty)"),
|
|
48
|
+
labels: z.array(z.string()).optional().describe("Filter pages by labels"),
|
|
49
|
+
maxPages: z.number().optional().describe("Maximum pages to index (default: 500)"),
|
|
50
|
+
force: z.boolean().optional().describe("Force re-index even if already indexed"),
|
|
51
|
+
}),
|
|
52
|
+
annotations: TOOL_ANNOTATIONS["index_confluence"],
|
|
53
|
+
handler: async (args, ctx) => {
|
|
54
|
+
const { spaceKeys, labels, maxPages = 500, force = false } = args;
|
|
55
|
+
const response = await ctx.api.post("/api/index/confluence", {
|
|
56
|
+
projectName: ctx.projectName,
|
|
57
|
+
spaceKeys,
|
|
58
|
+
labels,
|
|
59
|
+
maxPages,
|
|
60
|
+
force,
|
|
61
|
+
});
|
|
62
|
+
const data = response.data;
|
|
63
|
+
let result = `## Confluence Indexing\n\n`;
|
|
64
|
+
result += `- **Status:** ${data.status || "started"}\n`;
|
|
65
|
+
result += `- **Collection:** ${data.collection || `${ctx.collectionPrefix}confluence`}\n`;
|
|
66
|
+
result += `- **Options:**\n`;
|
|
67
|
+
if (spaceKeys && spaceKeys.length > 0) {
|
|
68
|
+
result += ` - Spaces: ${spaceKeys.join(", ")}\n`;
|
|
69
|
+
}
|
|
70
|
+
if (labels && labels.length > 0) {
|
|
71
|
+
result += ` - Labels: ${labels.join(", ")}\n`;
|
|
72
|
+
}
|
|
73
|
+
result += ` - Max Pages: ${maxPages}\n`;
|
|
74
|
+
result += ` - Force: ${force}\n`;
|
|
75
|
+
return result;
|
|
61
76
|
},
|
|
62
77
|
},
|
|
63
78
|
{
|
|
64
79
|
name: "get_confluence_status",
|
|
65
80
|
description: "Check if Confluence integration is configured and available.",
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
schema: z.object({}),
|
|
82
|
+
annotations: TOOL_ANNOTATIONS["get_confluence_status"],
|
|
83
|
+
handler: async (_args, ctx) => {
|
|
84
|
+
const response = await ctx.api.get("/api/confluence/status");
|
|
85
|
+
const data = response.data;
|
|
86
|
+
let result = `## Confluence Status\n\n`;
|
|
87
|
+
result += `- **Configured:** ${data.configured ? "Yes" : "No"}\n`;
|
|
88
|
+
result += `- **Message:** ${data.message || "N/A"}\n`;
|
|
89
|
+
return result;
|
|
69
90
|
},
|
|
70
91
|
},
|
|
71
92
|
{
|
|
72
93
|
name: "list_confluence_spaces",
|
|
73
94
|
description: "List available Confluence spaces that can be indexed.",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
95
|
+
schema: z.object({}),
|
|
96
|
+
annotations: TOOL_ANNOTATIONS["list_confluence_spaces"],
|
|
97
|
+
handler: async (_args, ctx) => {
|
|
98
|
+
const response = await ctx.api.get("/api/confluence/spaces");
|
|
99
|
+
const spaces = response.data.spaces || response.data;
|
|
100
|
+
if (!spaces || spaces.length === 0) {
|
|
101
|
+
return "No Confluence spaces available.";
|
|
102
|
+
}
|
|
103
|
+
let result = `## Confluence Spaces\n\n`;
|
|
104
|
+
for (const s of spaces) {
|
|
105
|
+
result += `- **${s.key}** - ${s.name} (${s.type || "global"})\n`;
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
77
108
|
},
|
|
78
109
|
},
|
|
79
110
|
];
|
|
80
|
-
const handlers = {
|
|
81
|
-
search_confluence: async (args, ctx) => {
|
|
82
|
-
const { query, limit = 5, spaceKey } = args;
|
|
83
|
-
const response = await ctx.api.post("/api/search", {
|
|
84
|
-
collection: `${ctx.collectionPrefix}confluence`,
|
|
85
|
-
query,
|
|
86
|
-
limit,
|
|
87
|
-
filters: spaceKey ? { spaceKey } : undefined,
|
|
88
|
-
});
|
|
89
|
-
const results = response.data.results;
|
|
90
|
-
if (!results || results.length === 0) {
|
|
91
|
-
return "No Confluence results found.";
|
|
92
|
-
}
|
|
93
|
-
return results
|
|
94
|
-
.map((r) => `### ${r.title || r.file || "Untitled"}\n` +
|
|
95
|
-
`**Score:** ${pct(r.score)}` +
|
|
96
|
-
(r.spaceKey ? ` | **Space:** ${r.spaceKey}` : "") +
|
|
97
|
-
(r.url ? ` | [View](${r.url})` : "") +
|
|
98
|
-
`\n\n${truncate(r.content || "", 600)}`)
|
|
99
|
-
.join("\n\n---\n\n");
|
|
100
|
-
},
|
|
101
|
-
index_confluence: async (args, ctx) => {
|
|
102
|
-
const { spaceKeys, labels, maxPages = 500, force = false } = args;
|
|
103
|
-
const response = await ctx.api.post("/api/index/confluence", {
|
|
104
|
-
projectName: ctx.projectName,
|
|
105
|
-
spaceKeys,
|
|
106
|
-
labels,
|
|
107
|
-
maxPages,
|
|
108
|
-
force,
|
|
109
|
-
});
|
|
110
|
-
const data = response.data;
|
|
111
|
-
let result = `## Confluence Indexing\n\n`;
|
|
112
|
-
result += `- **Status:** ${data.status || "started"}\n`;
|
|
113
|
-
result += `- **Collection:** ${data.collection || `${ctx.collectionPrefix}confluence`}\n`;
|
|
114
|
-
result += `- **Options:**\n`;
|
|
115
|
-
if (spaceKeys && spaceKeys.length > 0) {
|
|
116
|
-
result += ` - Spaces: ${spaceKeys.join(", ")}\n`;
|
|
117
|
-
}
|
|
118
|
-
if (labels && labels.length > 0) {
|
|
119
|
-
result += ` - Labels: ${labels.join(", ")}\n`;
|
|
120
|
-
}
|
|
121
|
-
result += ` - Max Pages: ${maxPages}\n`;
|
|
122
|
-
result += ` - Force: ${force}\n`;
|
|
123
|
-
return result;
|
|
124
|
-
},
|
|
125
|
-
get_confluence_status: async (_args, ctx) => {
|
|
126
|
-
const response = await ctx.api.get("/api/confluence/status");
|
|
127
|
-
const data = response.data;
|
|
128
|
-
let result = `## Confluence Status\n\n`;
|
|
129
|
-
result += `- **Configured:** ${data.configured ? "Yes" : "No"}\n`;
|
|
130
|
-
result += `- **Message:** ${data.message || "N/A"}\n`;
|
|
131
|
-
return result;
|
|
132
|
-
},
|
|
133
|
-
list_confluence_spaces: async (_args, ctx) => {
|
|
134
|
-
const response = await ctx.api.get("/api/confluence/spaces");
|
|
135
|
-
const spaces = response.data.spaces || response.data;
|
|
136
|
-
if (!spaces || spaces.length === 0) {
|
|
137
|
-
return "No Confluence spaces available.";
|
|
138
|
-
}
|
|
139
|
-
let result = `## Confluence Spaces\n\n`;
|
|
140
|
-
for (const s of spaces) {
|
|
141
|
-
result += `- **${s.key}** - ${s.name} (${s.type || "global"})\n`;
|
|
142
|
-
}
|
|
143
|
-
return result;
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
return { tools, handlers };
|
|
147
111
|
}
|
package/dist/tools/database.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Database Tools - Schema documentation, rules, enums, and validation.
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
5
|
-
export declare function createDatabaseTools(projectName: string):
|
|
4
|
+
import type { ToolSpec } from "../types.js";
|
|
5
|
+
export declare function createDatabaseTools(projectName: string): ToolSpec[];
|