@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/advanced.js
CHANGED
|
@@ -3,313 +3,238 @@
|
|
|
3
3
|
* import suggestions, type context, and behavior patterns.
|
|
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 advanced tools module with project-specific descriptions.
|
|
8
10
|
*/
|
|
9
11
|
export function createAdvancedTools(projectName) {
|
|
10
|
-
|
|
12
|
+
return [
|
|
11
13
|
{
|
|
12
14
|
name: "merge_memories",
|
|
13
15
|
description: `Consolidate duplicate memories for ${projectName}. Finds similar memories and merges them using LLM to reduce clutter.`,
|
|
14
|
-
|
|
15
|
-
type: "
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
16
|
+
schema: z.object({
|
|
17
|
+
type: z.string().optional().describe("Filter by memory type (decision, insight, context, todo, conversation, note, or all). Default: all"),
|
|
18
|
+
threshold: z.number().optional().describe("Similarity threshold for merging (0.5-1.0, default: 0.9). Lower = more aggressive merging."),
|
|
19
|
+
dryRun: z.boolean().optional().describe("If true, preview merge candidates without making changes (default: true)."),
|
|
20
|
+
limit: z.number().optional().describe("Max clusters to process (default: 50)."),
|
|
21
|
+
}),
|
|
22
|
+
annotations: TOOL_ANNOTATIONS["merge_memories"],
|
|
23
|
+
handler: async (args, ctx) => {
|
|
24
|
+
const { type = "all", threshold = 0.9, dryRun = true, limit = 50 } = args;
|
|
25
|
+
const response = await ctx.api.post("/api/memory/merge", {
|
|
26
|
+
type,
|
|
27
|
+
threshold,
|
|
28
|
+
dryRun,
|
|
29
|
+
limit,
|
|
30
|
+
});
|
|
31
|
+
const data = response.data;
|
|
32
|
+
let result = `## Memory Merge${dryRun ? " (Dry Run)" : ""}\n\n`;
|
|
33
|
+
result += `- **Memories Scanned:** ${data.totalFound ?? 0}\n`;
|
|
34
|
+
result += `- **Merge Clusters Found:** ${data.totalMerged ?? 0}\n`;
|
|
35
|
+
result += `- **Threshold:** ${threshold}\n`;
|
|
36
|
+
if (dryRun) {
|
|
37
|
+
result += `\n*This was a dry run. Set dryRun=false to apply merges.*\n`;
|
|
38
|
+
}
|
|
39
|
+
if (data.merged && data.merged.length > 0) {
|
|
40
|
+
result += `\n### Merge Candidates\n\n`;
|
|
41
|
+
for (const cluster of data.merged.slice(0, 10)) {
|
|
42
|
+
const origCount = cluster.original?.length ?? 0;
|
|
43
|
+
result += `**Cluster (${origCount} memories → 1):**\n`;
|
|
44
|
+
if (cluster.original) {
|
|
45
|
+
for (const orig of cluster.original.slice(0, 3)) {
|
|
46
|
+
result += ` - ${truncate(orig.content || "", 80)}\n`;
|
|
47
|
+
}
|
|
48
|
+
if (origCount > 3) {
|
|
49
|
+
result += ` - ... and ${origCount - 3} more\n`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
result += ` **→ Merged:** ${truncate(cluster.merged?.content || "", 120)}\n\n`;
|
|
53
|
+
}
|
|
54
|
+
if (data.merged.length > 10) {
|
|
55
|
+
result += `... and ${data.merged.length - 10} more clusters\n`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
38
59
|
},
|
|
39
60
|
},
|
|
40
61
|
{
|
|
41
62
|
name: "get_completion_context",
|
|
42
63
|
description: `Get code completion context for ${projectName}. Finds similar patterns, imports, and symbols from the codebase to aid code completion.`,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
schema: z.object({
|
|
65
|
+
currentFile: z.string().describe("Path of the file being edited"),
|
|
66
|
+
currentCode: z.string().describe("Current code snippet or file content"),
|
|
67
|
+
language: z.string().optional().describe("Programming language filter (optional)"),
|
|
68
|
+
limit: z.number().optional().describe("Max results (default: 5)"),
|
|
69
|
+
}),
|
|
70
|
+
annotations: TOOL_ANNOTATIONS["get_completion_context"],
|
|
71
|
+
handler: async (args, ctx) => {
|
|
72
|
+
const { currentFile, currentCode, language, limit = 5 } = args;
|
|
73
|
+
const response = await ctx.api.post("/api/code/completion-context", {
|
|
74
|
+
currentFile,
|
|
75
|
+
currentCode,
|
|
76
|
+
language,
|
|
77
|
+
limit,
|
|
78
|
+
});
|
|
79
|
+
const data = response.data;
|
|
80
|
+
let result = `## Completion Context\n\n`;
|
|
81
|
+
if (data.patterns && data.patterns.length > 0) {
|
|
82
|
+
result += `### Similar Patterns (${data.patterns.length})\n\n`;
|
|
83
|
+
for (const p of data.patterns) {
|
|
84
|
+
result += `**${p.file}** (${pct(p.score)} match)\n`;
|
|
85
|
+
result += "```\n" + truncate(p.content, 300) + "\n```\n\n";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
result += "No similar patterns found.\n\n";
|
|
90
|
+
}
|
|
91
|
+
if (data.imports && data.imports.length > 0) {
|
|
92
|
+
result += `### Imports from Similar Files\n`;
|
|
93
|
+
result += data.imports.map((i) => `- \`${i}\``).join("\n");
|
|
94
|
+
result += "\n\n";
|
|
95
|
+
}
|
|
96
|
+
if (data.symbols && data.symbols.length > 0) {
|
|
97
|
+
result += `### Available Symbols\n`;
|
|
98
|
+
result += data.symbols.map((s) => `- \`${s}\``).join("\n");
|
|
99
|
+
result += "\n";
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
65
102
|
},
|
|
66
103
|
},
|
|
67
104
|
{
|
|
68
105
|
name: "get_import_suggestions",
|
|
69
106
|
description: `Suggest missing imports for ${projectName}. Analyzes similar files to find commonly used imports not present in your current file.`,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
107
|
+
schema: z.object({
|
|
108
|
+
currentFile: z.string().describe("Path of the file being edited"),
|
|
109
|
+
currentCode: z.string().describe("Current code content"),
|
|
110
|
+
language: z.string().optional().describe("Programming language filter (optional)"),
|
|
111
|
+
limit: z.number().optional().describe("Max suggestions (default: 10)"),
|
|
112
|
+
}),
|
|
113
|
+
annotations: TOOL_ANNOTATIONS["get_import_suggestions"],
|
|
114
|
+
handler: async (args, ctx) => {
|
|
115
|
+
const { currentFile, currentCode, language, limit = 10 } = args;
|
|
116
|
+
const response = await ctx.api.post("/api/code/import-suggestions", {
|
|
117
|
+
currentFile,
|
|
118
|
+
currentCode,
|
|
119
|
+
language,
|
|
120
|
+
limit,
|
|
121
|
+
});
|
|
122
|
+
const data = response.data;
|
|
123
|
+
let result = `## Import Suggestions\n\n`;
|
|
124
|
+
if (data.currentImports && data.currentImports.length > 0) {
|
|
125
|
+
result += `**Current Imports (${data.currentImports.length}):** ${data.currentImports.map((i) => `\`${i}\``).join(", ")}\n\n`;
|
|
126
|
+
}
|
|
127
|
+
if (data.suggestions && data.suggestions.length > 0) {
|
|
128
|
+
result += `### Suggested Imports\n\n`;
|
|
129
|
+
for (const s of data.suggestions) {
|
|
130
|
+
result += `- **\`${s.importPath}\`** — used in ${s.frequency} similar files`;
|
|
131
|
+
if (s.usedBy && s.usedBy.length > 0) {
|
|
132
|
+
result += ` (${s.usedBy.map((f) => truncate(f, 40)).join(", ")})`;
|
|
133
|
+
}
|
|
134
|
+
result += "\n";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
result += "No additional imports suggested.\n";
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
92
141
|
},
|
|
93
142
|
},
|
|
94
143
|
{
|
|
95
144
|
name: "get_type_context",
|
|
96
145
|
description: `Look up type/interface/class definitions and usage in ${projectName}. Finds where a type is defined and how it's used across the codebase.`,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
146
|
+
schema: z.object({
|
|
147
|
+
typeName: z.string().optional().describe("Name of the type/interface/class to look up"),
|
|
148
|
+
code: z.string().optional().describe("Code containing types to look up (alternative to typeName)"),
|
|
149
|
+
currentFile: z.string().optional().describe("Current file to exclude from results"),
|
|
150
|
+
limit: z.number().optional().describe("Max results per category (default: 5)"),
|
|
151
|
+
}),
|
|
152
|
+
annotations: TOOL_ANNOTATIONS["get_type_context"],
|
|
153
|
+
handler: async (args, ctx) => {
|
|
154
|
+
const { typeName, code, currentFile, limit = 5 } = args;
|
|
155
|
+
if (!typeName && !code) {
|
|
156
|
+
return "Error: Either typeName or code is required.";
|
|
157
|
+
}
|
|
158
|
+
const response = await ctx.api.post("/api/code/type-context", {
|
|
159
|
+
typeName,
|
|
160
|
+
code,
|
|
161
|
+
currentFile,
|
|
162
|
+
limit,
|
|
163
|
+
});
|
|
164
|
+
const data = response.data;
|
|
165
|
+
let result = `## Type Context${typeName ? `: ${typeName}` : ""}\n\n`;
|
|
166
|
+
if (data.definitions && data.definitions.length > 0) {
|
|
167
|
+
result += `### Definitions (${data.definitions.length})\n\n`;
|
|
168
|
+
for (const d of data.definitions) {
|
|
169
|
+
result += `**${d.file}** (${pct(d.score)} match)\n`;
|
|
170
|
+
result += "```\n" + truncate(d.content, 400) + "\n```\n\n";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
result += "No type definitions found.\n\n";
|
|
175
|
+
}
|
|
176
|
+
if (data.usages && data.usages.length > 0) {
|
|
177
|
+
result += `### Usage Examples (${data.usages.length})\n\n`;
|
|
178
|
+
for (const u of data.usages) {
|
|
179
|
+
result += `**${u.file}** (${pct(u.score)} match)\n`;
|
|
180
|
+
result += "```\n" + truncate(u.content, 300) + "\n```\n\n";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
118
184
|
},
|
|
119
185
|
},
|
|
120
186
|
{
|
|
121
187
|
name: "get_behavior_patterns",
|
|
122
188
|
description: `Analyze user workflow patterns for ${projectName}. Shows peak hours, tool preferences, common sequences, and session statistics.`,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
threshold,
|
|
145
|
-
dryRun,
|
|
146
|
-
limit,
|
|
147
|
-
});
|
|
148
|
-
const data = response.data;
|
|
149
|
-
let result = `## Memory Merge${dryRun ? " (Dry Run)" : ""}\n\n`;
|
|
150
|
-
result += `- **Memories Scanned:** ${data.totalFound ?? 0}\n`;
|
|
151
|
-
result += `- **Merge Clusters Found:** ${data.totalMerged ?? 0}\n`;
|
|
152
|
-
result += `- **Threshold:** ${threshold}\n`;
|
|
153
|
-
if (dryRun) {
|
|
154
|
-
result += `\n*This was a dry run. Set dryRun=false to apply merges.*\n`;
|
|
155
|
-
}
|
|
156
|
-
if (data.merged && data.merged.length > 0) {
|
|
157
|
-
result += `\n### Merge Candidates\n\n`;
|
|
158
|
-
for (const cluster of data.merged.slice(0, 10)) {
|
|
159
|
-
const origCount = cluster.original?.length ?? 0;
|
|
160
|
-
result += `**Cluster (${origCount} memories → 1):**\n`;
|
|
161
|
-
if (cluster.original) {
|
|
162
|
-
for (const orig of cluster.original.slice(0, 3)) {
|
|
163
|
-
result += ` - ${truncate(orig.content || "", 80)}\n`;
|
|
164
|
-
}
|
|
165
|
-
if (origCount > 3) {
|
|
166
|
-
result += ` - ... and ${origCount - 3} more\n`;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
result += ` **→ Merged:** ${truncate(cluster.merged?.content || "", 120)}\n\n`;
|
|
189
|
+
schema: z.object({
|
|
190
|
+
days: z.number().optional().describe("Number of days to analyze (default: 7)"),
|
|
191
|
+
sessionId: z.string().optional().describe("Filter to a specific session (optional)"),
|
|
192
|
+
}),
|
|
193
|
+
annotations: TOOL_ANNOTATIONS["get_behavior_patterns"],
|
|
194
|
+
handler: async (args, ctx) => {
|
|
195
|
+
const { days = 7, sessionId } = args;
|
|
196
|
+
const params = new URLSearchParams();
|
|
197
|
+
params.set("days", String(days));
|
|
198
|
+
if (sessionId)
|
|
199
|
+
params.set("sessionId", sessionId);
|
|
200
|
+
const response = await ctx.api.get(`/api/behavior-patterns?${params.toString()}`);
|
|
201
|
+
const data = response.data;
|
|
202
|
+
let result = `## Behavior Patterns (last ${days} days)\n\n`;
|
|
203
|
+
// Session stats
|
|
204
|
+
const ss = data.sessionStats;
|
|
205
|
+
if (ss) {
|
|
206
|
+
result += `### Session Statistics\n`;
|
|
207
|
+
result += `- **Total Sessions:** ${ss.totalSessions}\n`;
|
|
208
|
+
result += `- **Avg Tools/Session:** ${ss.avgToolsPerSession}\n`;
|
|
209
|
+
result += `- **Avg Duration:** ${ss.avgDurationMinutes} min\n\n`;
|
|
170
210
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
get_completion_context: async (args, ctx) => {
|
|
178
|
-
const { currentFile, currentCode, language, limit = 5 } = args;
|
|
179
|
-
const response = await ctx.api.post("/api/code/completion-context", {
|
|
180
|
-
currentFile,
|
|
181
|
-
currentCode,
|
|
182
|
-
language,
|
|
183
|
-
limit,
|
|
184
|
-
});
|
|
185
|
-
const data = response.data;
|
|
186
|
-
let result = `## Completion Context\n\n`;
|
|
187
|
-
if (data.patterns && data.patterns.length > 0) {
|
|
188
|
-
result += `### Similar Patterns (${data.patterns.length})\n\n`;
|
|
189
|
-
for (const p of data.patterns) {
|
|
190
|
-
result += `**${p.file}** (${pct(p.score)} match)\n`;
|
|
191
|
-
result += "```\n" + truncate(p.content, 300) + "\n```\n\n";
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
result += "No similar patterns found.\n\n";
|
|
196
|
-
}
|
|
197
|
-
if (data.imports && data.imports.length > 0) {
|
|
198
|
-
result += `### Imports from Similar Files\n`;
|
|
199
|
-
result += data.imports.map((i) => `- \`${i}\``).join("\n");
|
|
200
|
-
result += "\n\n";
|
|
201
|
-
}
|
|
202
|
-
if (data.symbols && data.symbols.length > 0) {
|
|
203
|
-
result += `### Available Symbols\n`;
|
|
204
|
-
result += data.symbols.map((s) => `- \`${s}\``).join("\n");
|
|
205
|
-
result += "\n";
|
|
206
|
-
}
|
|
207
|
-
return result;
|
|
208
|
-
},
|
|
209
|
-
get_import_suggestions: async (args, ctx) => {
|
|
210
|
-
const { currentFile, currentCode, language, limit = 10 } = args;
|
|
211
|
-
const response = await ctx.api.post("/api/code/import-suggestions", {
|
|
212
|
-
currentFile,
|
|
213
|
-
currentCode,
|
|
214
|
-
language,
|
|
215
|
-
limit,
|
|
216
|
-
});
|
|
217
|
-
const data = response.data;
|
|
218
|
-
let result = `## Import Suggestions\n\n`;
|
|
219
|
-
if (data.currentImports && data.currentImports.length > 0) {
|
|
220
|
-
result += `**Current Imports (${data.currentImports.length}):** ${data.currentImports.map((i) => `\`${i}\``).join(", ")}\n\n`;
|
|
221
|
-
}
|
|
222
|
-
if (data.suggestions && data.suggestions.length > 0) {
|
|
223
|
-
result += `### Suggested Imports\n\n`;
|
|
224
|
-
for (const s of data.suggestions) {
|
|
225
|
-
result += `- **\`${s.importPath}\`** — used in ${s.frequency} similar files`;
|
|
226
|
-
if (s.usedBy && s.usedBy.length > 0) {
|
|
227
|
-
result += ` (${s.usedBy.map((f) => truncate(f, 40)).join(", ")})`;
|
|
211
|
+
// Peak hours
|
|
212
|
+
if (data.peakHours && data.peakHours.length > 0) {
|
|
213
|
+
result += `### Peak Hours\n`;
|
|
214
|
+
const top5 = data.peakHours.slice(0, 5);
|
|
215
|
+
for (const h of top5) {
|
|
216
|
+
result += `- **${String(h.hour).padStart(2, "0")}:00** — ${h.count} calls\n`;
|
|
228
217
|
}
|
|
229
218
|
result += "\n";
|
|
230
219
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const { typeName, code, currentFile, limit = 5 } = args;
|
|
239
|
-
if (!typeName && !code) {
|
|
240
|
-
return "Error: Either typeName or code is required.";
|
|
241
|
-
}
|
|
242
|
-
const response = await ctx.api.post("/api/code/type-context", {
|
|
243
|
-
typeName,
|
|
244
|
-
code,
|
|
245
|
-
currentFile,
|
|
246
|
-
limit,
|
|
247
|
-
});
|
|
248
|
-
const data = response.data;
|
|
249
|
-
let result = `## Type Context${typeName ? `: ${typeName}` : ""}\n\n`;
|
|
250
|
-
if (data.definitions && data.definitions.length > 0) {
|
|
251
|
-
result += `### Definitions (${data.definitions.length})\n\n`;
|
|
252
|
-
for (const d of data.definitions) {
|
|
253
|
-
result += `**${d.file}** (${pct(d.score)} match)\n`;
|
|
254
|
-
result += "```\n" + truncate(d.content, 400) + "\n```\n\n";
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
result += "No type definitions found.\n\n";
|
|
259
|
-
}
|
|
260
|
-
if (data.usages && data.usages.length > 0) {
|
|
261
|
-
result += `### Usage Examples (${data.usages.length})\n\n`;
|
|
262
|
-
for (const u of data.usages) {
|
|
263
|
-
result += `**${u.file}** (${pct(u.score)} match)\n`;
|
|
264
|
-
result += "```\n" + truncate(u.content, 300) + "\n```\n\n";
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return result;
|
|
268
|
-
},
|
|
269
|
-
get_behavior_patterns: async (args, ctx) => {
|
|
270
|
-
const { days = 7, sessionId } = args;
|
|
271
|
-
const params = new URLSearchParams();
|
|
272
|
-
params.set("days", String(days));
|
|
273
|
-
if (sessionId)
|
|
274
|
-
params.set("sessionId", sessionId);
|
|
275
|
-
const response = await ctx.api.get(`/api/behavior-patterns?${params.toString()}`);
|
|
276
|
-
const data = response.data;
|
|
277
|
-
let result = `## Behavior Patterns (last ${days} days)\n\n`;
|
|
278
|
-
// Session stats
|
|
279
|
-
const ss = data.sessionStats;
|
|
280
|
-
if (ss) {
|
|
281
|
-
result += `### Session Statistics\n`;
|
|
282
|
-
result += `- **Total Sessions:** ${ss.totalSessions}\n`;
|
|
283
|
-
result += `- **Avg Tools/Session:** ${ss.avgToolsPerSession}\n`;
|
|
284
|
-
result += `- **Avg Duration:** ${ss.avgDurationMinutes} min\n\n`;
|
|
285
|
-
}
|
|
286
|
-
// Peak hours
|
|
287
|
-
if (data.peakHours && data.peakHours.length > 0) {
|
|
288
|
-
result += `### Peak Hours\n`;
|
|
289
|
-
const top5 = data.peakHours.slice(0, 5);
|
|
290
|
-
for (const h of top5) {
|
|
291
|
-
result += `- **${String(h.hour).padStart(2, "0")}:00** — ${h.count} calls\n`;
|
|
292
|
-
}
|
|
293
|
-
result += "\n";
|
|
294
|
-
}
|
|
295
|
-
// Tool preferences
|
|
296
|
-
if (data.toolPreferences && data.toolPreferences.length > 0) {
|
|
297
|
-
result += `### Tool Preferences\n`;
|
|
298
|
-
for (const t of data.toolPreferences.slice(0, 10)) {
|
|
299
|
-
result += `- **${t.tool}**: ${t.count} calls (avg ${t.avgDuration}ms)\n`;
|
|
220
|
+
// Tool preferences
|
|
221
|
+
if (data.toolPreferences && data.toolPreferences.length > 0) {
|
|
222
|
+
result += `### Tool Preferences\n`;
|
|
223
|
+
for (const t of data.toolPreferences.slice(0, 10)) {
|
|
224
|
+
result += `- **${t.tool}**: ${t.count} calls (avg ${t.avgDuration}ms)\n`;
|
|
225
|
+
}
|
|
226
|
+
result += "\n";
|
|
300
227
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
result +=
|
|
228
|
+
// Workflows
|
|
229
|
+
if (data.workflows && data.workflows.length > 0) {
|
|
230
|
+
result += `### Common Workflows\n`;
|
|
231
|
+
for (const w of data.workflows.slice(0, 10)) {
|
|
232
|
+
result += `- ${w.sequence.join(" → ")} (${w.count}x)\n`;
|
|
233
|
+
}
|
|
234
|
+
result += "\n";
|
|
308
235
|
}
|
|
309
|
-
result
|
|
310
|
-
}
|
|
311
|
-
return result;
|
|
236
|
+
return result;
|
|
237
|
+
},
|
|
312
238
|
},
|
|
313
|
-
|
|
314
|
-
return { tools, handlers };
|
|
239
|
+
];
|
|
315
240
|
}
|
package/dist/tools/agents.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent tools module - run specialized agents and list agent types.
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { ToolSpec } from "../types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Create the agent tools module with project-specific descriptions.
|
|
7
7
|
*/
|
|
8
|
-
export declare function createAgentTools(projectName: string):
|
|
8
|
+
export declare function createAgentTools(projectName: string): ToolSpec[];
|