@agentbrain/mcp-server 1.4.66 → 1.4.70
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/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/load-context.d.ts +13 -0
- package/dist/tools/load-context.d.ts.map +1 -1
- package/dist/tools/load-context.js +343 -102
- package/dist/tools/load-context.js.map +1 -1
- package/dist/tools/save-context.d.ts +19 -13
- package/dist/tools/save-context.d.ts.map +1 -1
- package/dist/tools/save-context.js +58 -183
- package/dist/tools/save-context.js.map +1 -1
- package/dist/tools/save-error.d.ts +47 -0
- package/dist/tools/save-error.d.ts.map +1 -0
- package/dist/tools/save-error.js +109 -0
- package/dist/tools/save-error.js.map +1 -0
- package/dist/tools/setup-repo.d.ts +10 -0
- package/dist/tools/setup-repo.d.ts.map +1 -1
- package/dist/tools/setup-repo.js +153 -8
- package/dist/tools/setup-repo.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export interface SaveContextInput {
|
|
2
2
|
repo_path: string;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
files: Array<{
|
|
4
|
+
name: string;
|
|
5
|
+
content: string;
|
|
6
|
+
}>;
|
|
6
7
|
}
|
|
7
8
|
export interface SaveContextOutput {
|
|
8
9
|
success: boolean;
|
|
9
10
|
files_written: string[];
|
|
10
|
-
agent_detected: 'cursor' | 'windsurf' | 'claude' | 'unknown';
|
|
11
11
|
message: string;
|
|
12
12
|
}
|
|
13
13
|
export declare function saveContext(input: SaveContextInput): Promise<SaveContextOutput>;
|
|
@@ -21,17 +21,23 @@ export declare const saveContextSchema: {
|
|
|
21
21
|
type: string;
|
|
22
22
|
description: string;
|
|
23
23
|
};
|
|
24
|
-
|
|
25
|
-
type: string;
|
|
26
|
-
description: string;
|
|
27
|
-
};
|
|
28
|
-
dependency_map: {
|
|
29
|
-
type: string;
|
|
30
|
-
description: string;
|
|
31
|
-
};
|
|
32
|
-
patterns: {
|
|
24
|
+
files: {
|
|
33
25
|
type: string;
|
|
34
26
|
description: string;
|
|
27
|
+
items: {
|
|
28
|
+
type: string;
|
|
29
|
+
properties: {
|
|
30
|
+
name: {
|
|
31
|
+
type: string;
|
|
32
|
+
description: string;
|
|
33
|
+
};
|
|
34
|
+
content: {
|
|
35
|
+
type: string;
|
|
36
|
+
description: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
required: string[];
|
|
40
|
+
};
|
|
35
41
|
};
|
|
36
42
|
};
|
|
37
43
|
required: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save-context.d.ts","sourceRoot":"","sources":["../../src/tools/save-context.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,
|
|
1
|
+
{"version":3,"file":"save-context.d.ts","sourceRoot":"","sources":["../../src/tools/save-context.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgFrF;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4C7B,CAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// MCP tool: save_context - save agent-generated context to disk
|
|
2
|
-
import { writeFile, mkdir
|
|
2
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import { join, resolve } from 'node:path';
|
|
5
5
|
import { homedir } from 'node:os';
|
|
6
|
-
import { getGitHash, ensureGitignore } from '@agentbrain/core';
|
|
6
|
+
import { getGitHash, ensureGitignore, createAgentFilesShared } from '@agentbrain/core';
|
|
7
7
|
/**
|
|
8
8
|
* Expand path: handles ~, relative paths, etc.
|
|
9
9
|
*/
|
|
@@ -13,91 +13,8 @@ function expandPath(path) {
|
|
|
13
13
|
}
|
|
14
14
|
return resolve(path);
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Detect agent type from filesystem
|
|
18
|
-
*/
|
|
19
|
-
function detectAgentType(repoPath) {
|
|
20
|
-
if (existsSync(join(repoPath, '.cursor'))) {
|
|
21
|
-
return 'cursor';
|
|
22
|
-
}
|
|
23
|
-
if (existsSync(join(repoPath, '.windsurf'))) {
|
|
24
|
-
return 'windsurf';
|
|
25
|
-
}
|
|
26
|
-
if (existsSync(join(repoPath, 'CLAUDE.md'))) {
|
|
27
|
-
return 'claude';
|
|
28
|
-
}
|
|
29
|
-
return 'unknown';
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Get agent file content
|
|
33
|
-
*/
|
|
34
|
-
function getAgentFileContent(isModernFormat) {
|
|
35
|
-
const baseContent = `## AgentBrain Context
|
|
36
|
-
@.agentbrain/context.md
|
|
37
|
-
@.agentbrain/patterns.md
|
|
38
|
-
@.agentbrain/dependency-map.md
|
|
39
|
-
|
|
40
|
-
## Workflow
|
|
41
|
-
- Always read context at session start via load_context()
|
|
42
|
-
- Before any task: load_spec() or agentbrain spec "task"
|
|
43
|
-
- After commits: context auto-updates via git hook
|
|
44
|
-
- If stuck in a loop: detect_doom_loop() or agentbrain doom
|
|
45
|
-
- End of session: save_handoff() or agentbrain handoff
|
|
46
|
-
- If context feels stale: agentbrain init
|
|
47
|
-
|
|
48
|
-
## MCP Tools
|
|
49
|
-
- load_context() — full codebase context
|
|
50
|
-
- load_spec() — spec for current task
|
|
51
|
-
- detect_doom_loop() — check for stuck patterns
|
|
52
|
-
- save_handoff() — end of session handoff
|
|
53
|
-
- setup_repo() — first time MCP setup
|
|
54
|
-
- save_context() — save agent-generated context`;
|
|
55
|
-
if (isModernFormat) {
|
|
56
|
-
return `---
|
|
57
|
-
description: AgentBrain codebase context and workflow
|
|
58
|
-
alwaysApply: true
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
${baseContent}`;
|
|
62
|
-
}
|
|
63
|
-
return baseContent;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Check if agent file already contains AgentBrain section
|
|
67
|
-
*/
|
|
68
|
-
async function hasAgentBrainSection(filePath) {
|
|
69
|
-
if (!existsSync(filePath)) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
const content = await readFile(filePath, 'utf-8');
|
|
73
|
-
return content.includes('── AgentBrain ──');
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Update or append AgentBrain section to agent file
|
|
77
|
-
*/
|
|
78
|
-
async function updateOrAppendAgentSection(filePath, content) {
|
|
79
|
-
const marker = '# ── AgentBrain ──────────────────────────────';
|
|
80
|
-
const endMarker = '# ── End AgentBrain ──────────────────────────';
|
|
81
|
-
let existingContent = '';
|
|
82
|
-
if (existsSync(filePath)) {
|
|
83
|
-
existingContent = await readFile(filePath, 'utf-8');
|
|
84
|
-
}
|
|
85
|
-
// Check if AgentBrain section already exists
|
|
86
|
-
if (existingContent.includes(marker)) {
|
|
87
|
-
// Replace existing section
|
|
88
|
-
const beforeMarker = existingContent.substring(0, existingContent.indexOf(marker));
|
|
89
|
-
const afterMarker = existingContent.substring(existingContent.indexOf(endMarker) + endMarker.length);
|
|
90
|
-
const newContent = `${beforeMarker}${marker}\n${content}\n${endMarker}${afterMarker}`;
|
|
91
|
-
await writeFile(filePath, newContent, 'utf-8');
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
// Append new section
|
|
95
|
-
const agentBrainSection = `\n${marker}\n${content}\n${endMarker}\n`;
|
|
96
|
-
await writeFile(filePath, existingContent + agentBrainSection, 'utf-8');
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
16
|
export async function saveContext(input) {
|
|
100
|
-
const { repo_path,
|
|
17
|
+
const { repo_path, files } = input;
|
|
101
18
|
// Expand path to handle ~, relative paths, etc.
|
|
102
19
|
const expandedPath = expandPath(repo_path);
|
|
103
20
|
const contextDir = join(expandedPath, '.agentbrain');
|
|
@@ -106,36 +23,28 @@ export async function saveContext(input) {
|
|
|
106
23
|
if (!existsSync(contextDir)) {
|
|
107
24
|
await mkdir(contextDir, { recursive: true });
|
|
108
25
|
}
|
|
109
|
-
// Step 2: Write
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
await writeFile(patternsPath, patterns, 'utf-8');
|
|
116
|
-
filesWritten.push('.agentbrain/context.md', '.agentbrain/dependency-map.md', '.agentbrain/patterns.md');
|
|
26
|
+
// Step 2: Write all files
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const filePath = join(contextDir, file.name);
|
|
29
|
+
await writeFile(filePath, file.content, 'utf-8');
|
|
30
|
+
filesWritten.push(`.agentbrain/${file.name}`);
|
|
31
|
+
}
|
|
117
32
|
// Step 3: Get current git hash and write cache.json
|
|
118
33
|
const gitHash = await getGitHash(expandedPath);
|
|
34
|
+
// Build docs object dynamically
|
|
35
|
+
const docs = {};
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
const baseName = file.name.replace('.md', '');
|
|
38
|
+
docs[baseName] = {
|
|
39
|
+
type: baseName,
|
|
40
|
+
content: file.content,
|
|
41
|
+
savedAt: new Date().toISOString(),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
119
44
|
const cachePath = join(contextDir, 'cache.json');
|
|
120
45
|
const cache = {
|
|
121
46
|
gitHash,
|
|
122
|
-
docs
|
|
123
|
-
context: {
|
|
124
|
-
type: 'context',
|
|
125
|
-
content: context,
|
|
126
|
-
savedAt: new Date().toISOString(),
|
|
127
|
-
},
|
|
128
|
-
'dependency-map': {
|
|
129
|
-
type: 'dependency-map',
|
|
130
|
-
content: dependency_map,
|
|
131
|
-
savedAt: new Date().toISOString(),
|
|
132
|
-
},
|
|
133
|
-
patterns: {
|
|
134
|
-
type: 'patterns',
|
|
135
|
-
content: patterns,
|
|
136
|
-
savedAt: new Date().toISOString(),
|
|
137
|
-
},
|
|
138
|
-
},
|
|
47
|
+
docs,
|
|
139
48
|
savedAt: new Date().toISOString(),
|
|
140
49
|
};
|
|
141
50
|
await writeFile(cachePath, JSON.stringify(cache, null, 2), 'utf-8');
|
|
@@ -148,103 +57,69 @@ export async function saveContext(input) {
|
|
|
148
57
|
// (context.md, dependency-map.md, patterns.md, cache.json, setup-source.json)
|
|
149
58
|
try {
|
|
150
59
|
await ensureGitignore(expandedPath);
|
|
151
|
-
|
|
60
|
+
// Silent success - only log errors
|
|
152
61
|
}
|
|
153
62
|
catch (err) {
|
|
63
|
+
// Log errors to stderr for debugging
|
|
154
64
|
console.error('[save_context] .gitignore update failed:', err);
|
|
155
65
|
}
|
|
156
|
-
// Step 5
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
let message = '';
|
|
161
|
-
// Define all paths
|
|
162
|
-
const cursorrules = join(expandedPath, '.cursorrules');
|
|
163
|
-
const cursorRulesDir = join(expandedPath, '.cursor', 'rules');
|
|
164
|
-
const cursorModernFile = join(cursorRulesDir, 'agentbrain.mdc');
|
|
165
|
-
const windsurfrules = join(expandedPath, '.windsurfrules');
|
|
166
|
-
const windsurfRulesDir = join(expandedPath, '.windsurf', 'rules');
|
|
167
|
-
const windsurfModernFile = join(windsurfRulesDir, 'agentbrain.md');
|
|
168
|
-
const claudePath = join(expandedPath, 'CLAUDE.md');
|
|
169
|
-
// Exclusive if/else if/else - stop after first match
|
|
170
|
-
if (existsSync(cursorrules)) {
|
|
171
|
-
// Legacy Cursor file exists
|
|
172
|
-
await updateOrAppendAgentSection(cursorrules, legacyContent);
|
|
173
|
-
filesWritten.push('.cursorrules');
|
|
174
|
-
message = 'Updated existing .cursorrules';
|
|
175
|
-
}
|
|
176
|
-
else if (existsSync(cursorRulesDir)) {
|
|
177
|
-
// Modern Cursor directory exists
|
|
178
|
-
await updateOrAppendAgentSection(cursorModernFile, modernContent);
|
|
179
|
-
filesWritten.push('.cursor/rules/agentbrain.mdc');
|
|
180
|
-
message = 'Updated .cursor/rules/agentbrain.mdc';
|
|
181
|
-
}
|
|
182
|
-
else if (existsSync(windsurfRulesDir)) {
|
|
183
|
-
// Modern Windsurf directory exists
|
|
184
|
-
await updateOrAppendAgentSection(windsurfModernFile, legacyContent);
|
|
185
|
-
filesWritten.push('.windsurf/rules/agentbrain.md');
|
|
186
|
-
message = 'Updated .windsurf/rules/agentbrain.md';
|
|
187
|
-
}
|
|
188
|
-
else if (existsSync(windsurfrules)) {
|
|
189
|
-
// Legacy Windsurf file exists
|
|
190
|
-
await updateOrAppendAgentSection(windsurfrules, legacyContent);
|
|
191
|
-
filesWritten.push('.windsurfrules');
|
|
192
|
-
message = 'Updated existing .windsurfrules';
|
|
193
|
-
}
|
|
194
|
-
else if (existsSync(claudePath)) {
|
|
195
|
-
// Claude file exists
|
|
196
|
-
await updateOrAppendAgentSection(claudePath, legacyContent);
|
|
197
|
-
filesWritten.push('CLAUDE.md');
|
|
198
|
-
message = 'Updated existing CLAUDE.md';
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
// Nothing detected — create CLAUDE.md as safe default
|
|
202
|
-
// CLAUDE.md works across all agents
|
|
203
|
-
await updateOrAppendAgentSection(claudePath, legacyContent);
|
|
204
|
-
filesWritten.push('CLAUDE.md');
|
|
205
|
-
message = 'Created CLAUDE.md (universal format)';
|
|
206
|
-
}
|
|
207
|
-
// Determine agent type for response
|
|
208
|
-
let detectedAgent = detectAgentType(expandedPath);
|
|
209
|
-
// Extract agent file name from message for cleaner output
|
|
210
|
-
const agentFile = message.split(' ').slice(-1)[0];
|
|
66
|
+
// Step 5: Update agent files with ALL context files
|
|
67
|
+
const contextFileNames = files.map((f) => f.name);
|
|
68
|
+
const agentFilesUpdated = await createAgentFilesShared(expandedPath, contextFileNames);
|
|
69
|
+
filesWritten.push(...agentFilesUpdated);
|
|
211
70
|
const responseMessage = `Context saved to .agentbrain/
|
|
212
71
|
|
|
213
72
|
Files written: ${filesWritten.join(', ')}
|
|
214
|
-
Agent file: ${agentFile}
|
|
215
73
|
|
|
216
74
|
Call load_context() to verify context loads correctly.`;
|
|
217
75
|
return {
|
|
218
76
|
success: true,
|
|
219
77
|
files_written: filesWritten,
|
|
220
|
-
agent_detected: detectedAgent,
|
|
221
78
|
message: responseMessage,
|
|
222
79
|
};
|
|
223
80
|
}
|
|
224
81
|
export const saveContextSchema = {
|
|
225
82
|
name: 'save_context',
|
|
226
|
-
description: 'Save
|
|
83
|
+
description: 'Save context files to .agentbrain/ directory.\n\n' +
|
|
84
|
+
'IMPORTANT: Each file should own ONE concern only:\n' +
|
|
85
|
+
'- context.md: architecture, modules, data flows (no package versions, no schema details)\n' +
|
|
86
|
+
'- patterns.md: code patterns and conventions (no architecture overview)\n' +
|
|
87
|
+
'- decisions.md: tech stack decisions and why\n' +
|
|
88
|
+
'- schema.md: database models only (no module dependencies)\n' +
|
|
89
|
+
'- dependencies.md: package versions only (no module relationships)\n' +
|
|
90
|
+
'- dependency-map.md: module relationships only (no external packages)\n' +
|
|
91
|
+
'- testing.md: test patterns only (no untested function lists)\n' +
|
|
92
|
+
'- inventory.md: components and utilities list\n' +
|
|
93
|
+
'- environment.md: env vars from .env.example\n' +
|
|
94
|
+
'- branch-context.md: git branch + recent commits\n\n' +
|
|
95
|
+
'Do not duplicate information across files. If it belongs in schema.md, it should not also appear in context.md.',
|
|
227
96
|
inputSchema: {
|
|
228
97
|
type: 'object',
|
|
229
98
|
properties: {
|
|
230
99
|
repo_path: {
|
|
231
100
|
type: 'string',
|
|
232
|
-
description: 'Absolute path to
|
|
101
|
+
description: 'Absolute path to repository',
|
|
233
102
|
},
|
|
234
|
-
|
|
235
|
-
type: '
|
|
236
|
-
description: '
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
103
|
+
files: {
|
|
104
|
+
type: 'array',
|
|
105
|
+
description: 'Context files to save',
|
|
106
|
+
items: {
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: {
|
|
109
|
+
name: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
description: 'Filename e.g. context.md',
|
|
112
|
+
},
|
|
113
|
+
content: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
description: 'File content in markdown',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
required: ['name', 'content'],
|
|
119
|
+
},
|
|
245
120
|
},
|
|
246
121
|
},
|
|
247
|
-
required: ['repo_path', '
|
|
122
|
+
required: ['repo_path', 'files'],
|
|
248
123
|
},
|
|
249
124
|
};
|
|
250
125
|
//# sourceMappingURL=save-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save-context.js","sourceRoot":"","sources":["../../src/tools/save-context.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"save-context.js","sourceRoot":"","sources":["../../src/tools/save-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface SaveErrorInput {
|
|
2
|
+
repo_path: string;
|
|
3
|
+
problem: string;
|
|
4
|
+
solution: string;
|
|
5
|
+
context?: string;
|
|
6
|
+
tags?: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface SaveErrorOutput {
|
|
9
|
+
success: boolean;
|
|
10
|
+
message: string;
|
|
11
|
+
error_count: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function saveError(input: SaveErrorInput): Promise<SaveErrorOutput>;
|
|
14
|
+
export declare const saveErrorSchema: {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: string;
|
|
19
|
+
properties: {
|
|
20
|
+
repo_path: {
|
|
21
|
+
type: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
problem: {
|
|
25
|
+
type: string;
|
|
26
|
+
description: string;
|
|
27
|
+
};
|
|
28
|
+
solution: {
|
|
29
|
+
type: string;
|
|
30
|
+
description: string;
|
|
31
|
+
};
|
|
32
|
+
context: {
|
|
33
|
+
type: string;
|
|
34
|
+
description: string;
|
|
35
|
+
};
|
|
36
|
+
tags: {
|
|
37
|
+
type: string;
|
|
38
|
+
description: string;
|
|
39
|
+
items: {
|
|
40
|
+
type: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
required: string[];
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=save-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save-error.d.ts","sourceRoot":"","sources":["../../src/tools/save-error.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAoE/E;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC3B,CAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// MCP tool: save_error - save known error patterns to errors.md
|
|
2
|
+
import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
/**
|
|
7
|
+
* Expand path: handles ~, relative paths, etc.
|
|
8
|
+
*/
|
|
9
|
+
function expandPath(path) {
|
|
10
|
+
if (path.startsWith('~/') || path === '~') {
|
|
11
|
+
return path.replace('~', homedir());
|
|
12
|
+
}
|
|
13
|
+
return resolve(path);
|
|
14
|
+
}
|
|
15
|
+
export async function saveError(input) {
|
|
16
|
+
const { repo_path, problem, solution, context, tags } = input;
|
|
17
|
+
// Expand path to handle ~, relative paths, etc.
|
|
18
|
+
const expandedPath = expandPath(repo_path);
|
|
19
|
+
const contextDir = join(expandedPath, '.agentbrain');
|
|
20
|
+
const errorsPath = join(contextDir, 'errors.md');
|
|
21
|
+
// Step 1: Create .agentbrain directory if it doesn't exist
|
|
22
|
+
if (!existsSync(contextDir)) {
|
|
23
|
+
await mkdir(contextDir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
// Step 2: Check if errors.md exists and get current count
|
|
26
|
+
let errorCount = 0;
|
|
27
|
+
let needsHeader = false;
|
|
28
|
+
if (existsSync(errorsPath)) {
|
|
29
|
+
const existingContent = await readFile(errorsPath, 'utf-8');
|
|
30
|
+
// Count existing error entries (look for "## Error " patterns)
|
|
31
|
+
const matches = existingContent.match(/^## Error \d+:/gm);
|
|
32
|
+
errorCount = matches ? matches.length : 0;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
needsHeader = true;
|
|
36
|
+
}
|
|
37
|
+
// Increment count for new error
|
|
38
|
+
errorCount++;
|
|
39
|
+
// Step 3: Format the new error entry
|
|
40
|
+
const timestamp = new Date().toISOString();
|
|
41
|
+
const tagString = tags && tags.length > 0 ? `\n**Tags:** ${tags.join(', ')}` : '';
|
|
42
|
+
const contextString = context ? `\n\n**Context:**\n${context}` : '';
|
|
43
|
+
const errorEntry = `
|
|
44
|
+
## Error ${errorCount}: ${problem}
|
|
45
|
+
|
|
46
|
+
**Date:** ${timestamp}${tagString}
|
|
47
|
+
|
|
48
|
+
**Problem:**
|
|
49
|
+
${problem}
|
|
50
|
+
|
|
51
|
+
**Solution:**
|
|
52
|
+
${solution}${contextString}
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
`;
|
|
56
|
+
// Step 4: Write to file (with header if new file)
|
|
57
|
+
if (needsHeader) {
|
|
58
|
+
const header = `# Known Errors and Solutions
|
|
59
|
+
|
|
60
|
+
This file tracks common errors encountered in this codebase and their solutions.
|
|
61
|
+
Use this to avoid repeating mistakes and share knowledge across development sessions.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
`;
|
|
65
|
+
await writeFile(errorsPath, header + errorEntry, 'utf-8');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
await appendFile(errorsPath, errorEntry, 'utf-8');
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
success: true,
|
|
72
|
+
message: `Error #${errorCount} saved to .agentbrain/errors.md`,
|
|
73
|
+
error_count: errorCount,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export const saveErrorSchema = {
|
|
77
|
+
name: 'save_error',
|
|
78
|
+
description: 'Save a known error pattern and its solution to .agentbrain/errors.md. Use this to document common issues, bugs, or gotchas for future reference. No API key required - pure file I/O.',
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
82
|
+
repo_path: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Absolute path to the repository',
|
|
85
|
+
},
|
|
86
|
+
problem: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
description: 'Brief description of the problem or error (will be used as the title)',
|
|
89
|
+
},
|
|
90
|
+
solution: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'The solution, workaround, or fix for this problem',
|
|
93
|
+
},
|
|
94
|
+
context: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
description: 'Optional additional context (e.g., stack trace, code snippet, when it occurs)',
|
|
97
|
+
},
|
|
98
|
+
tags: {
|
|
99
|
+
type: 'array',
|
|
100
|
+
description: 'Optional tags for categorization (e.g., ["database", "auth", "performance"])',
|
|
101
|
+
items: {
|
|
102
|
+
type: 'string',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
required: ['repo_path', 'problem', 'solution'],
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=save-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save-error.js","sourceRoot":"","sources":["../../src/tools/save-error.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAEhE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEjC;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACrC,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAA;AACtB,CAAC;AAgBD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAqB;IACnD,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAE7D,gDAAgD;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAA;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IAEhD,2DAA2D;IAC3D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,0DAA0D;IAC1D,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,WAAW,GAAG,KAAK,CAAA;IAEvB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAC3D,+DAA+D;QAC/D,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACzD,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3C,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,IAAI,CAAA;IACpB,CAAC;IAED,gCAAgC;IAChC,UAAU,EAAE,CAAA;IAEZ,qCAAqC;IACrC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC1C,MAAM,SAAS,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACjF,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAEnE,MAAM,UAAU,GAAG;WACV,UAAU,KAAK,OAAO;;YAErB,SAAS,GAAG,SAAS;;;EAG/B,OAAO;;;EAGP,QAAQ,GAAG,aAAa;;;CAGzB,CAAA;IAEC,kDAAkD;IAClD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG;;;;;;CAMlB,CAAA;QACG,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,OAAO,CAAC,CAAA;IAC3D,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,UAAU,UAAU,iCAAiC;QAC9D,WAAW,EAAE,UAAU;KACxB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,YAAY;IAClB,WAAW,EACT,uLAAuL;IACzL,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iCAAiC;aAC/C;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uEAAuE;aACrF;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mDAAmD;aACjE;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+EAA+E;aAC7F;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,8EAA8E;gBAC3F,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;iBACf;aACF;SACF;QACD,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;KAC/C;CACF,CAAA"}
|
|
@@ -9,6 +9,16 @@ export interface SetupRepoOutput {
|
|
|
9
9
|
content: string;
|
|
10
10
|
}>;
|
|
11
11
|
hook_installed: boolean;
|
|
12
|
+
detected: {
|
|
13
|
+
languages: string[];
|
|
14
|
+
frameworks: string[];
|
|
15
|
+
hasTests: boolean;
|
|
16
|
+
dependencyFiles: string[];
|
|
17
|
+
schemaFiles: string[];
|
|
18
|
+
hasDocker: boolean;
|
|
19
|
+
hasCICD: boolean;
|
|
20
|
+
hasEnvExample: boolean;
|
|
21
|
+
};
|
|
12
22
|
instructions: string;
|
|
13
23
|
}
|
|
14
24
|
export declare function setupRepo(input: SetupRepoInput): Promise<SetupRepoOutput>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-repo.d.ts","sourceRoot":"","sources":["../../src/tools/setup-repo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup-repo.d.ts","sourceRoot":"","sources":["../../src/tools/setup-repo.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;IACF,cAAc,EAAE,OAAO,CAAA;IACvB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,EAAE,CAAA;QACnB,UAAU,EAAE,MAAM,EAAE,CAAA;QACpB,QAAQ,EAAE,OAAO,CAAA;QACjB,eAAe,EAAE,MAAM,EAAE,CAAA;QACzB,WAAW,EAAE,MAAM,EAAE,CAAA;QACrB,SAAS,EAAE,OAAO,CAAA;QAClB,OAAO,EAAE,OAAO,CAAA;QAChB,aAAa,EAAE,OAAO,CAAA;KACvB,CAAA;IACD,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CA+O/E;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;CAc3B,CAAA"}
|