@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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confluence tools module - search, index, status, and space listing
|
|
3
|
+
* for Confluence integration.
|
|
4
|
+
*/
|
|
5
|
+
import { truncate, pct } from "../formatters.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the Confluence tools module with project-specific descriptions.
|
|
8
|
+
*/
|
|
9
|
+
export function createConfluenceTools(projectName) {
|
|
10
|
+
const tools = [
|
|
11
|
+
{
|
|
12
|
+
name: "search_confluence",
|
|
13
|
+
description: `Search indexed Confluence documentation for ${projectName}. Returns relevant pages with content snippets.`,
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
query: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Search query for Confluence content",
|
|
20
|
+
},
|
|
21
|
+
limit: {
|
|
22
|
+
type: "number",
|
|
23
|
+
description: "Max results (default: 5)",
|
|
24
|
+
default: 5,
|
|
25
|
+
},
|
|
26
|
+
spaceKey: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Filter by Confluence space key",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["query"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "index_confluence",
|
|
36
|
+
description: `Index Confluence spaces/pages for ${projectName}. Requires Confluence credentials in RAG API.`,
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
spaceKeys: {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: { type: "string" },
|
|
43
|
+
description: "Specific space keys to index (indexes all accessible if empty)",
|
|
44
|
+
},
|
|
45
|
+
labels: {
|
|
46
|
+
type: "array",
|
|
47
|
+
items: { type: "string" },
|
|
48
|
+
description: "Filter pages by labels",
|
|
49
|
+
},
|
|
50
|
+
maxPages: {
|
|
51
|
+
type: "number",
|
|
52
|
+
description: "Maximum pages to index (default: 500)",
|
|
53
|
+
default: 500,
|
|
54
|
+
},
|
|
55
|
+
force: {
|
|
56
|
+
type: "boolean",
|
|
57
|
+
description: "Force re-index even if already indexed",
|
|
58
|
+
default: false,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "get_confluence_status",
|
|
65
|
+
description: "Check if Confluence integration is configured and available.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "list_confluence_spaces",
|
|
73
|
+
description: "List available Confluence spaces that can be indexed.",
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
|
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
|
+
}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Tools - Schema documentation, rules, enums, and validation.
|
|
3
|
+
*/
|
|
4
|
+
export function createDatabaseTools(projectName) {
|
|
5
|
+
const tools = [
|
|
6
|
+
{
|
|
7
|
+
name: "record_table",
|
|
8
|
+
description: `Record a database table definition with its purpose, columns, and relationships. Use this to document the database schema for ${projectName}.`,
|
|
9
|
+
inputSchema: {
|
|
10
|
+
type: "object",
|
|
11
|
+
properties: {
|
|
12
|
+
tableName: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Name of the table (e.g., 'claims', 'documents')",
|
|
15
|
+
},
|
|
16
|
+
purpose: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "What this table is for and when it's used",
|
|
19
|
+
},
|
|
20
|
+
columns: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Key columns and their purposes (format: 'column_name: description')",
|
|
23
|
+
},
|
|
24
|
+
relationships: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Relationships to other tables (FK references)",
|
|
27
|
+
},
|
|
28
|
+
indexes: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Important indexes and their purpose",
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Business rules and constraints for this table",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["tableName", "purpose", "columns"],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "get_table_info",
|
|
42
|
+
description: "Get documented information about a database table including its purpose, columns, relationships, and rules.",
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
tableName: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "Table name to look up (or 'all' to list all tables)",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["tableName"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "record_db_rule",
|
|
56
|
+
description: "Record a database rule or constraint that should be followed. Use this for data integrity rules, naming conventions, or query patterns.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
ruleName: {
|
|
61
|
+
type: "string",
|
|
62
|
+
description: "Short name for the rule",
|
|
63
|
+
},
|
|
64
|
+
description: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Detailed description of the rule",
|
|
67
|
+
},
|
|
68
|
+
scope: {
|
|
69
|
+
type: "string",
|
|
70
|
+
enum: ["global", "table", "column", "query", "migration"],
|
|
71
|
+
description: "Where this rule applies",
|
|
72
|
+
},
|
|
73
|
+
examples: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "Good and bad examples of applying this rule",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
required: ["ruleName", "description", "scope"],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "get_db_rules",
|
|
83
|
+
description: `Get database rules and constraints for ${projectName}. Filter by scope or get all rules.`,
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: "object",
|
|
86
|
+
properties: {
|
|
87
|
+
scope: {
|
|
88
|
+
type: "string",
|
|
89
|
+
enum: ["global", "table", "column", "query", "migration", "all"],
|
|
90
|
+
description: "Filter by scope (default: all)",
|
|
91
|
+
default: "all",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "record_enum",
|
|
98
|
+
description: "Record a database enum type with its values and usage. Use this to document allowed values for status fields, types, etc.",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
enumName: {
|
|
103
|
+
type: "string",
|
|
104
|
+
description: "Name of the enum (e.g., 'ClaimStatus', 'DocumentType')",
|
|
105
|
+
},
|
|
106
|
+
values: {
|
|
107
|
+
type: "string",
|
|
108
|
+
description: "List of enum values with descriptions (format: 'value: description')",
|
|
109
|
+
},
|
|
110
|
+
usedIn: {
|
|
111
|
+
type: "string",
|
|
112
|
+
description: "Tables and columns where this enum is used",
|
|
113
|
+
},
|
|
114
|
+
transitions: {
|
|
115
|
+
type: "string",
|
|
116
|
+
description: "Allowed state transitions (for status enums)",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ["enumName", "values"],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "get_enums",
|
|
124
|
+
description: `Get documented enum types for ${projectName} database.`,
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: "object",
|
|
127
|
+
properties: {
|
|
128
|
+
enumName: {
|
|
129
|
+
type: "string",
|
|
130
|
+
description: "Specific enum to look up (or empty for all)",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "check_db_schema",
|
|
137
|
+
description: "Check if a proposed database change follows the documented rules and patterns. Use before creating migrations.",
|
|
138
|
+
inputSchema: {
|
|
139
|
+
type: "object",
|
|
140
|
+
properties: {
|
|
141
|
+
change: {
|
|
142
|
+
type: "string",
|
|
143
|
+
description: "Description of the proposed change (new table, column, index, etc.)",
|
|
144
|
+
},
|
|
145
|
+
sql: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Optional SQL or Prisma schema for the change",
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
required: ["change"],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "suggest_db_schema",
|
|
155
|
+
description: "Get suggestions for database schema design for a new feature or data requirement.",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
type: "object",
|
|
158
|
+
properties: {
|
|
159
|
+
requirement: {
|
|
160
|
+
type: "string",
|
|
161
|
+
description: "What data needs to be stored or what feature needs support",
|
|
162
|
+
},
|
|
163
|
+
relatedTables: {
|
|
164
|
+
type: "string",
|
|
165
|
+
description: "Existing tables that might be related",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ["requirement"],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
];
|
|
172
|
+
const handlers = {
|
|
173
|
+
async record_table(args, ctx) {
|
|
174
|
+
const { tableName, purpose, columns, relationships, indexes, rules } = args;
|
|
175
|
+
const content = `## Table: ${tableName}
|
|
176
|
+
|
|
177
|
+
**Purpose:** ${purpose}
|
|
178
|
+
|
|
179
|
+
### Columns
|
|
180
|
+
${columns}
|
|
181
|
+
|
|
182
|
+
${relationships ? `### Relationships\n${relationships}\n` : ""}
|
|
183
|
+
${indexes ? `### Indexes\n${indexes}\n` : ""}
|
|
184
|
+
${rules ? `### Business Rules\n${rules}` : ""}`;
|
|
185
|
+
await ctx.api.post("/api/memory", {
|
|
186
|
+
projectName: ctx.projectName,
|
|
187
|
+
content,
|
|
188
|
+
type: "context",
|
|
189
|
+
tags: ["database", "schema", "table", tableName.toLowerCase()],
|
|
190
|
+
relatedTo: `table:${tableName}`,
|
|
191
|
+
metadata: {
|
|
192
|
+
tableType: "table",
|
|
193
|
+
tableName,
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
return `Recorded table **${tableName}** documentation.\n\nUse \`get_table_info "${tableName}"\` to retrieve it later.`;
|
|
197
|
+
},
|
|
198
|
+
async get_table_info(args, ctx) {
|
|
199
|
+
const { tableName } = args;
|
|
200
|
+
const response = await ctx.api.post("/api/memory/recall", {
|
|
201
|
+
projectName: ctx.projectName,
|
|
202
|
+
query: tableName === "all" ? "database table schema" : `table ${tableName}`,
|
|
203
|
+
tag: "table",
|
|
204
|
+
limit: tableName === "all" ? 20 : 5,
|
|
205
|
+
});
|
|
206
|
+
const tables = response.data.results || [];
|
|
207
|
+
if (tables.length === 0) {
|
|
208
|
+
return `No documentation found for ${tableName === "all" ? "any tables" : `table "${tableName}"`}.\n\nUse \`record_table\` to document tables.`;
|
|
209
|
+
}
|
|
210
|
+
let result = tableName === "all"
|
|
211
|
+
? `# Database Tables (${tables.length})\n\n`
|
|
212
|
+
: `# Table: ${tableName}\n\n`;
|
|
213
|
+
tables.forEach((t) => {
|
|
214
|
+
result += t.memory.content + "\n\n---\n\n";
|
|
215
|
+
});
|
|
216
|
+
return result;
|
|
217
|
+
},
|
|
218
|
+
async record_db_rule(args, ctx) {
|
|
219
|
+
const { ruleName, description, scope, examples } = args;
|
|
220
|
+
const content = `## DB Rule: ${ruleName}
|
|
221
|
+
|
|
222
|
+
**Scope:** ${scope}
|
|
223
|
+
|
|
224
|
+
${description}
|
|
225
|
+
|
|
226
|
+
${examples ? `### Examples\n${examples}` : ""}`;
|
|
227
|
+
await ctx.api.post("/api/memory", {
|
|
228
|
+
projectName: ctx.projectName,
|
|
229
|
+
content,
|
|
230
|
+
type: "decision",
|
|
231
|
+
tags: ["database", "rule", scope],
|
|
232
|
+
relatedTo: `db-rule:${ruleName}`,
|
|
233
|
+
metadata: {
|
|
234
|
+
ruleType: "db-rule",
|
|
235
|
+
ruleName,
|
|
236
|
+
scope,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
return `Recorded database rule: **${ruleName}** (scope: ${scope})`;
|
|
240
|
+
},
|
|
241
|
+
async get_db_rules(args, ctx) {
|
|
242
|
+
const { scope = "all" } = args;
|
|
243
|
+
const response = await ctx.api.post("/api/memory/recall", {
|
|
244
|
+
projectName: ctx.projectName,
|
|
245
|
+
query: scope === "all"
|
|
246
|
+
? "database rule constraint"
|
|
247
|
+
: `database rule ${scope}`,
|
|
248
|
+
tag: "rule",
|
|
249
|
+
limit: 15,
|
|
250
|
+
});
|
|
251
|
+
const rules = response.data.results || [];
|
|
252
|
+
if (rules.length === 0) {
|
|
253
|
+
return `No database rules found${scope !== "all" ? ` for scope "${scope}"` : ""}.\n\nUse \`record_db_rule\` to document rules.`;
|
|
254
|
+
}
|
|
255
|
+
let result = `# Database Rules (${rules.length})\n\n`;
|
|
256
|
+
rules.forEach((r) => {
|
|
257
|
+
const m = r.memory;
|
|
258
|
+
result += m.content + "\n\n---\n\n";
|
|
259
|
+
});
|
|
260
|
+
return result;
|
|
261
|
+
},
|
|
262
|
+
async record_enum(args, ctx) {
|
|
263
|
+
const { enumName, values, usedIn, transitions } = args;
|
|
264
|
+
const content = `## Enum: ${enumName}
|
|
265
|
+
|
|
266
|
+
### Values
|
|
267
|
+
${values}
|
|
268
|
+
|
|
269
|
+
${usedIn ? `### Used In\n${usedIn}\n` : ""}
|
|
270
|
+
${transitions ? `### State Transitions\n${transitions}` : ""}`;
|
|
271
|
+
await ctx.api.post("/api/memory", {
|
|
272
|
+
projectName: ctx.projectName,
|
|
273
|
+
content,
|
|
274
|
+
type: "context",
|
|
275
|
+
tags: ["database", "schema", "enum", enumName.toLowerCase()],
|
|
276
|
+
relatedTo: `enum:${enumName}`,
|
|
277
|
+
metadata: {
|
|
278
|
+
tableType: "enum",
|
|
279
|
+
enumName,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
return `Recorded enum **${enumName}** documentation.`;
|
|
283
|
+
},
|
|
284
|
+
async get_enums(args, ctx) {
|
|
285
|
+
const { enumName } = args;
|
|
286
|
+
const response = await ctx.api.post("/api/memory/recall", {
|
|
287
|
+
projectName: ctx.projectName,
|
|
288
|
+
query: enumName
|
|
289
|
+
? `enum ${enumName}`
|
|
290
|
+
: "database enum type values",
|
|
291
|
+
tag: "enum",
|
|
292
|
+
limit: 15,
|
|
293
|
+
});
|
|
294
|
+
const enums = response.data.results || [];
|
|
295
|
+
if (enums.length === 0) {
|
|
296
|
+
return `No enum documentation found${enumName ? ` for "${enumName}"` : ""}.\n\nUse \`record_enum\` to document enums.`;
|
|
297
|
+
}
|
|
298
|
+
let result = `# Database Enums (${enums.length})\n\n`;
|
|
299
|
+
enums.forEach((e) => {
|
|
300
|
+
result += e.memory.content + "\n\n---\n\n";
|
|
301
|
+
});
|
|
302
|
+
return result;
|
|
303
|
+
},
|
|
304
|
+
async check_db_schema(args, ctx) {
|
|
305
|
+
const { change, sql } = args;
|
|
306
|
+
// Get relevant rules and existing schema
|
|
307
|
+
const [rulesRes, tablesRes] = await Promise.all([
|
|
308
|
+
ctx.api.post("/api/memory/recall", {
|
|
309
|
+
projectName: ctx.projectName,
|
|
310
|
+
query: "database rule constraint naming convention",
|
|
311
|
+
tag: "rule",
|
|
312
|
+
limit: 10,
|
|
313
|
+
}),
|
|
314
|
+
ctx.api.post("/api/memory/recall", {
|
|
315
|
+
projectName: ctx.projectName,
|
|
316
|
+
query: change,
|
|
317
|
+
tag: "table",
|
|
318
|
+
limit: 5,
|
|
319
|
+
}),
|
|
320
|
+
]);
|
|
321
|
+
const rules = rulesRes.data.results || [];
|
|
322
|
+
const relatedTables = tablesRes.data.results || [];
|
|
323
|
+
let result = `# Schema Change Review\n\n`;
|
|
324
|
+
result += `**Proposed Change:** ${change}\n\n`;
|
|
325
|
+
if (sql) {
|
|
326
|
+
result += `**SQL/Schema:**\n\`\`\`sql\n${sql}\n\`\`\`\n\n`;
|
|
327
|
+
}
|
|
328
|
+
result += `## Applicable Rules (${rules.length})\n`;
|
|
329
|
+
if (rules.length === 0) {
|
|
330
|
+
result += `_No database rules documented. Consider adding rules with \`record_db_rule\`._\n\n`;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
rules.forEach((r) => {
|
|
334
|
+
const m = r.memory;
|
|
335
|
+
result += `- **${m.metadata?.ruleName || m.relatedTo}** (${m.metadata?.scope || "general"})\n`;
|
|
336
|
+
});
|
|
337
|
+
result += "\n";
|
|
338
|
+
}
|
|
339
|
+
result += `## Related Tables (${relatedTables.length})\n`;
|
|
340
|
+
if (relatedTables.length === 0) {
|
|
341
|
+
result += `_No documented tables found related to this change._\n\n`;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
relatedTables.forEach((t) => {
|
|
345
|
+
result += `- ${t.memory.metadata?.tableName || t.memory.relatedTo}\n`;
|
|
346
|
+
});
|
|
347
|
+
result += "\n";
|
|
348
|
+
}
|
|
349
|
+
result += `## Checklist\n`;
|
|
350
|
+
result += `- [ ] Follows naming conventions\n`;
|
|
351
|
+
result += `- [ ] Has appropriate indexes\n`;
|
|
352
|
+
result += `- [ ] Foreign keys properly defined\n`;
|
|
353
|
+
result += `- [ ] NOT NULL constraints where needed\n`;
|
|
354
|
+
result += `- [ ] Default values appropriate\n`;
|
|
355
|
+
result += `- [ ] Multi-tenant (partnerId) considered\n`;
|
|
356
|
+
result += `- [ ] Migration is reversible\n`;
|
|
357
|
+
return result;
|
|
358
|
+
},
|
|
359
|
+
async suggest_db_schema(args, ctx) {
|
|
360
|
+
const { requirement, relatedTables } = args;
|
|
361
|
+
// Get existing schema patterns and rules
|
|
362
|
+
const [rulesRes, tablesRes, enumsRes] = await Promise.all([
|
|
363
|
+
ctx.api.post("/api/memory/recall", {
|
|
364
|
+
projectName: ctx.projectName,
|
|
365
|
+
query: "database rule naming convention pattern",
|
|
366
|
+
tag: "rule",
|
|
367
|
+
limit: 5,
|
|
368
|
+
}),
|
|
369
|
+
ctx.api.post("/api/memory/recall", {
|
|
370
|
+
projectName: ctx.projectName,
|
|
371
|
+
query: relatedTables || requirement,
|
|
372
|
+
tag: "table",
|
|
373
|
+
limit: 5,
|
|
374
|
+
}),
|
|
375
|
+
ctx.api.post("/api/memory/recall", {
|
|
376
|
+
projectName: ctx.projectName,
|
|
377
|
+
query: requirement,
|
|
378
|
+
tag: "enum",
|
|
379
|
+
limit: 3,
|
|
380
|
+
}),
|
|
381
|
+
]);
|
|
382
|
+
const rules = rulesRes.data.results || [];
|
|
383
|
+
const tables = tablesRes.data.results || [];
|
|
384
|
+
const enums = enumsRes.data.results || [];
|
|
385
|
+
let result = `# Schema Suggestion\n\n`;
|
|
386
|
+
result += `**Requirement:** ${requirement}\n\n`;
|
|
387
|
+
if (relatedTables) {
|
|
388
|
+
result += `**Related Tables:** ${relatedTables}\n\n`;
|
|
389
|
+
}
|
|
390
|
+
result += `## Existing Context\n\n`;
|
|
391
|
+
if (tables.length > 0) {
|
|
392
|
+
result += `### Related Tables\n`;
|
|
393
|
+
tables.forEach((t) => {
|
|
394
|
+
result += `- **${t.memory.metadata?.tableName || t.memory.relatedTo}**\n`;
|
|
395
|
+
});
|
|
396
|
+
result += "\n";
|
|
397
|
+
}
|
|
398
|
+
if (enums.length > 0) {
|
|
399
|
+
result += `### Available Enums\n`;
|
|
400
|
+
enums.forEach((e) => {
|
|
401
|
+
result += `- ${e.memory.metadata?.enumName || e.memory.relatedTo}\n`;
|
|
402
|
+
});
|
|
403
|
+
result += "\n";
|
|
404
|
+
}
|
|
405
|
+
if (rules.length > 0) {
|
|
406
|
+
result += `### Rules to Follow\n`;
|
|
407
|
+
rules.forEach((r) => {
|
|
408
|
+
result += `- ${r.memory.metadata?.ruleName || r.memory.relatedTo}: ${r.memory.content.slice(0, 100)}...\n`;
|
|
409
|
+
});
|
|
410
|
+
result += "\n";
|
|
411
|
+
}
|
|
412
|
+
result += `## Suggestions\n\n`;
|
|
413
|
+
result += `Based on the existing schema patterns:\n\n`;
|
|
414
|
+
result += `1. **Table naming**: Use snake_case, plural (e.g., \`notifications\`)\n`;
|
|
415
|
+
result += `2. **Primary key**: UUID with \`gen_random_uuid()\`\n`;
|
|
416
|
+
result += `3. **Timestamps**: Include \`created_at\`, \`updated_at\`\n`;
|
|
417
|
+
result += `4. **Multi-tenant**: Add \`partner_id UUID NOT NULL\` with FK\n`;
|
|
418
|
+
result += `5. **Soft delete**: Consider \`deleted_at\` timestamp\n`;
|
|
419
|
+
result += `6. **Status fields**: Use PostgreSQL ENUMs\n`;
|
|
420
|
+
result += `\n## Next Steps\n`;
|
|
421
|
+
result += `1. Design the schema using suggestions above\n`;
|
|
422
|
+
result += `2. Run \`check_db_schema\` to validate\n`;
|
|
423
|
+
result += `3. Create Prisma migration\n`;
|
|
424
|
+
result += `4. Document with \`record_table\` after creation\n`;
|
|
425
|
+
return result;
|
|
426
|
+
},
|
|
427
|
+
};
|
|
428
|
+
return { tools, handlers };
|
|
429
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feedback tools module - search feedback, memory feedback, query suggestions,
|
|
3
|
+
* and quality metrics.
|
|
4
|
+
*/
|
|
5
|
+
import type { ToolModule } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the feedback tools module with project-specific descriptions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createFeedbackTools(projectName: string): ToolModule;
|