@grec0/memory-bank-mcp 0.1.1 → 0.1.3
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/README.md +160 -4
- package/dist/common/projectKnowledgeService.js +74 -0
- package/dist/index.js +393 -20
- package/dist/tools/analyzeCoverage.js +1 -1
- package/dist/tools/initializeMemoryBank.js +364 -0
- package/dist/tools/recordDecision.js +208 -0
- package/dist/tools/trackProgress.js +355 -0
- package/dist/tools/updateContext.js +201 -0
- package/package.json +1 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Track Progress tool for Memory Bank
|
|
3
|
+
* Updates the progress tracking document with tasks, milestones, and blockers
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
/**
|
|
8
|
+
* Parses existing progress data from the markdown content
|
|
9
|
+
*/
|
|
10
|
+
function parseExistingProgress(content) {
|
|
11
|
+
const result = {
|
|
12
|
+
completed: [],
|
|
13
|
+
inProgress: [],
|
|
14
|
+
blocked: [],
|
|
15
|
+
upcoming: [],
|
|
16
|
+
milestones: [],
|
|
17
|
+
blockers: [],
|
|
18
|
+
phase: "Development",
|
|
19
|
+
phaseStatus: "In Progress",
|
|
20
|
+
};
|
|
21
|
+
// Parse completed tasks
|
|
22
|
+
const completedMatch = content.match(/## Completed\n([\s\S]*?)(?=\n##|$)/);
|
|
23
|
+
if (completedMatch) {
|
|
24
|
+
const items = completedMatch[1].match(/- \[x\] .+/g) || [];
|
|
25
|
+
result.completed = items.map(i => i.replace(/- \[x\] /, ""));
|
|
26
|
+
}
|
|
27
|
+
// Parse in progress tasks
|
|
28
|
+
const inProgressMatch = content.match(/## In Progress\n([\s\S]*?)(?=\n##|$)/);
|
|
29
|
+
if (inProgressMatch) {
|
|
30
|
+
const items = inProgressMatch[1].match(/- \[ \] .+/g) || [];
|
|
31
|
+
result.inProgress = items.map(i => i.replace(/- \[ \] /, ""));
|
|
32
|
+
}
|
|
33
|
+
// Parse upcoming tasks
|
|
34
|
+
const upcomingMatch = content.match(/## Upcoming\n([\s\S]*?)(?=\n##|$)/);
|
|
35
|
+
if (upcomingMatch) {
|
|
36
|
+
const items = upcomingMatch[1].match(/- \[ \] .+/g) || [];
|
|
37
|
+
result.upcoming = items.map(i => i.replace(/- \[ \] /, ""));
|
|
38
|
+
}
|
|
39
|
+
// Parse phase
|
|
40
|
+
const phaseMatch = content.match(/\*\*Phase\*\*: (.+)/);
|
|
41
|
+
if (phaseMatch)
|
|
42
|
+
result.phase = phaseMatch[1];
|
|
43
|
+
const statusMatch = content.match(/\*\*Status\*\*: (.+)/);
|
|
44
|
+
if (statusMatch)
|
|
45
|
+
result.phaseStatus = statusMatch[1];
|
|
46
|
+
// Parse milestones from table
|
|
47
|
+
const tableMatch = content.match(/\| Milestone \| Status \| Target Date \| Notes \|[\s\S]*?(?=\n\n|\n##|$)/);
|
|
48
|
+
if (tableMatch) {
|
|
49
|
+
const lines = tableMatch[0].split("\n").slice(2);
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
const cells = line.split("|").map(c => c.trim()).filter(c => c);
|
|
52
|
+
if (cells.length >= 4) {
|
|
53
|
+
result.milestones.push({
|
|
54
|
+
name: cells[0],
|
|
55
|
+
status: cells[1],
|
|
56
|
+
targetDate: cells[2],
|
|
57
|
+
notes: cells[3],
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Parse blockers
|
|
63
|
+
const blockersMatch = content.match(/## Blockers\n([\s\S]*?)(?=\n##|$)/);
|
|
64
|
+
if (blockersMatch && !blockersMatch[1].includes("No blockers")) {
|
|
65
|
+
const items = blockersMatch[1].match(/- .+/g) || [];
|
|
66
|
+
result.blockers = items.map(i => i.replace(/- /, ""));
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generates the updated progress.md content
|
|
72
|
+
*/
|
|
73
|
+
function generateProgressContent(projectId, completed, inProgress, blocked, upcoming, milestones, blockers, phase, phaseStatus) {
|
|
74
|
+
const date = new Date().toISOString().split("T")[0];
|
|
75
|
+
// Format task lists
|
|
76
|
+
const completedList = completed.length > 0
|
|
77
|
+
? completed.map(t => `- [x] ${t}`).join("\n")
|
|
78
|
+
: "- [x] Project initialization";
|
|
79
|
+
const inProgressList = inProgress.length > 0
|
|
80
|
+
? inProgress.map(t => `- [ ] ${t}`).join("\n")
|
|
81
|
+
: "_No tasks in progress_";
|
|
82
|
+
const blockedList = blocked.length > 0
|
|
83
|
+
? blocked.map(t => `- [ ] ⚠️ ${t}`).join("\n")
|
|
84
|
+
: "";
|
|
85
|
+
const upcomingList = upcoming.length > 0
|
|
86
|
+
? upcoming.map(t => `- [ ] ${t}`).join("\n")
|
|
87
|
+
: "_No upcoming tasks defined_";
|
|
88
|
+
// Format milestones table
|
|
89
|
+
const milestonesRows = milestones.length > 0
|
|
90
|
+
? milestones.map(m => `| ${m.name} | ${m.status} | ${m.targetDate || "-"} | ${m.notes || "-"} |`).join("\n")
|
|
91
|
+
: "| Initial Setup | In Progress | - | Getting started |";
|
|
92
|
+
// Format blockers
|
|
93
|
+
const severityEmoji = {
|
|
94
|
+
low: "🟡",
|
|
95
|
+
medium: "🟠",
|
|
96
|
+
high: "🔴",
|
|
97
|
+
};
|
|
98
|
+
const blockersContent = blockers.length > 0
|
|
99
|
+
? blockers.map(b => `- ${severityEmoji[b.severity] || "🟡"} **${b.severity.toUpperCase()}**: ${b.description}`).join("\n")
|
|
100
|
+
: "_No blockers currently_";
|
|
101
|
+
return `# Progress Tracking
|
|
102
|
+
|
|
103
|
+
## Current Phase
|
|
104
|
+
**Phase**: ${phase}
|
|
105
|
+
**Status**: ${phaseStatus}
|
|
106
|
+
**Last Updated**: ${date}
|
|
107
|
+
|
|
108
|
+
## Completed
|
|
109
|
+
${completedList}
|
|
110
|
+
|
|
111
|
+
## In Progress
|
|
112
|
+
${inProgressList}
|
|
113
|
+
${blockedList ? `\n### Blocked\n${blockedList}` : ""}
|
|
114
|
+
|
|
115
|
+
## Upcoming
|
|
116
|
+
${upcomingList}
|
|
117
|
+
|
|
118
|
+
## Blockers
|
|
119
|
+
${blockersContent}
|
|
120
|
+
|
|
121
|
+
## Milestones
|
|
122
|
+
| Milestone | Status | Target Date | Notes |
|
|
123
|
+
|-----------|--------|-------------|-------|
|
|
124
|
+
${milestonesRows}
|
|
125
|
+
|
|
126
|
+
## Statistics
|
|
127
|
+
- **Completed**: ${completed.length} tasks
|
|
128
|
+
- **In Progress**: ${inProgress.length} tasks
|
|
129
|
+
- **Blocked**: ${blocked.length} tasks
|
|
130
|
+
- **Upcoming**: ${upcoming.length} tasks
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
*Update with \`memorybank_track_progress\` to track tasks and milestones.*
|
|
134
|
+
*Last updated: ${new Date().toISOString()}*
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Merges task arrays, avoiding duplicates
|
|
139
|
+
*/
|
|
140
|
+
function mergeTasks(existing, incoming) {
|
|
141
|
+
if (!incoming || incoming.length === 0)
|
|
142
|
+
return existing;
|
|
143
|
+
const merged = [...existing];
|
|
144
|
+
for (const task of incoming) {
|
|
145
|
+
if (!merged.some(t => t.toLowerCase() === task.toLowerCase())) {
|
|
146
|
+
merged.push(task);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return merged;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Updates the progress tracking document
|
|
153
|
+
*/
|
|
154
|
+
export async function trackProgress(params, storagePath = ".memorybank") {
|
|
155
|
+
const { projectId, progress = {}, milestone, blockers = [], phase, phaseStatus, } = params;
|
|
156
|
+
console.error(`\n=== Tracking Progress ===`);
|
|
157
|
+
console.error(`Project ID: ${projectId}`);
|
|
158
|
+
const docsPath = path.join(storagePath, "projects", projectId, "docs");
|
|
159
|
+
const progressPath = path.join(docsPath, "progress.md");
|
|
160
|
+
// Check if Memory Bank exists
|
|
161
|
+
if (!fs.existsSync(docsPath)) {
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
message: `Memory Bank not initialized for project "${projectId}". Run \`memorybank_initialize\` first.`,
|
|
165
|
+
projectId,
|
|
166
|
+
updatedSections: [],
|
|
167
|
+
stats: { completed: 0, inProgress: 0, blocked: 0, upcoming: 0, milestones: 0, blockers: 0 },
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Parse existing progress if file exists
|
|
171
|
+
let existing = {
|
|
172
|
+
completed: [],
|
|
173
|
+
inProgress: [],
|
|
174
|
+
blocked: [],
|
|
175
|
+
upcoming: [],
|
|
176
|
+
milestones: [],
|
|
177
|
+
blockers: [],
|
|
178
|
+
phase: "Development",
|
|
179
|
+
phaseStatus: "In Progress",
|
|
180
|
+
};
|
|
181
|
+
if (fs.existsSync(progressPath)) {
|
|
182
|
+
const content = fs.readFileSync(progressPath, "utf-8");
|
|
183
|
+
existing = parseExistingProgress(content);
|
|
184
|
+
console.error(` Found existing progress data`);
|
|
185
|
+
}
|
|
186
|
+
// Track updated sections
|
|
187
|
+
const updatedSections = [];
|
|
188
|
+
// Merge tasks
|
|
189
|
+
const completed = mergeTasks(existing.completed, progress.completed);
|
|
190
|
+
if (progress.completed?.length)
|
|
191
|
+
updatedSections.push("Completed");
|
|
192
|
+
// Move completed tasks from inProgress to completed
|
|
193
|
+
let inProgress = existing.inProgress.filter(t => !progress.completed?.some(c => c.toLowerCase() === t.toLowerCase()));
|
|
194
|
+
inProgress = mergeTasks(inProgress, progress.inProgress);
|
|
195
|
+
if (progress.inProgress?.length)
|
|
196
|
+
updatedSections.push("In Progress");
|
|
197
|
+
const blocked = mergeTasks(existing.blocked, progress.blocked);
|
|
198
|
+
if (progress.blocked?.length)
|
|
199
|
+
updatedSections.push("Blocked");
|
|
200
|
+
const upcoming = mergeTasks(existing.upcoming, progress.upcoming);
|
|
201
|
+
if (progress.upcoming?.length)
|
|
202
|
+
updatedSections.push("Upcoming");
|
|
203
|
+
// Update or add milestone
|
|
204
|
+
let milestones = [...existing.milestones];
|
|
205
|
+
if (milestone) {
|
|
206
|
+
const existingIndex = milestones.findIndex(m => m.name.toLowerCase() === milestone.name.toLowerCase());
|
|
207
|
+
const newMilestone = {
|
|
208
|
+
name: milestone.name,
|
|
209
|
+
status: milestone.status,
|
|
210
|
+
targetDate: milestone.targetDate || "-",
|
|
211
|
+
notes: milestone.notes || "-",
|
|
212
|
+
};
|
|
213
|
+
if (existingIndex >= 0) {
|
|
214
|
+
milestones[existingIndex] = newMilestone;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
milestones.push(newMilestone);
|
|
218
|
+
}
|
|
219
|
+
updatedSections.push("Milestones");
|
|
220
|
+
}
|
|
221
|
+
// Update phase if provided
|
|
222
|
+
const finalPhase = phase || existing.phase;
|
|
223
|
+
const finalPhaseStatus = phaseStatus || existing.phaseStatus;
|
|
224
|
+
if (phase || phaseStatus)
|
|
225
|
+
updatedSections.push("Phase");
|
|
226
|
+
// Convert blockers
|
|
227
|
+
const finalBlockers = blockers.length > 0 ? blockers : [];
|
|
228
|
+
if (blockers.length > 0)
|
|
229
|
+
updatedSections.push("Blockers");
|
|
230
|
+
// Generate new content
|
|
231
|
+
const newContent = generateProgressContent(projectId, completed, inProgress, blocked, upcoming, milestones, finalBlockers, finalPhase, finalPhaseStatus);
|
|
232
|
+
// Write to file
|
|
233
|
+
fs.writeFileSync(progressPath, newContent, "utf-8");
|
|
234
|
+
const stats = {
|
|
235
|
+
completed: completed.length,
|
|
236
|
+
inProgress: inProgress.length,
|
|
237
|
+
blocked: blocked.length,
|
|
238
|
+
upcoming: upcoming.length,
|
|
239
|
+
milestones: milestones.length,
|
|
240
|
+
blockers: finalBlockers.length,
|
|
241
|
+
};
|
|
242
|
+
console.error(` Updated sections: ${updatedSections.join(", ") || "None"}`);
|
|
243
|
+
console.error(` Stats: ${JSON.stringify(stats)}`);
|
|
244
|
+
console.error(`\n=== Progress Updated ===`);
|
|
245
|
+
return {
|
|
246
|
+
success: true,
|
|
247
|
+
message: `Progress updated for project "${projectId}". ${updatedSections.length > 0 ? `Updated: ${updatedSections.join(", ")}` : "No changes"}. Stats: ${stats.completed} completed, ${stats.inProgress} in progress, ${stats.upcoming} upcoming.`,
|
|
248
|
+
projectId,
|
|
249
|
+
updatedSections,
|
|
250
|
+
stats,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Tool definition for MCP
|
|
255
|
+
*/
|
|
256
|
+
export const trackProgressToolDefinition = {
|
|
257
|
+
name: "memorybank_track_progress",
|
|
258
|
+
description: `Actualiza el seguimiento de progreso del proyecto con tareas, milestones y blockers.
|
|
259
|
+
|
|
260
|
+
Permite:
|
|
261
|
+
- Marcar tareas como completadas, en progreso, bloqueadas o próximas
|
|
262
|
+
- Añadir/actualizar milestones con estado y fecha objetivo
|
|
263
|
+
- Registrar blockers con severidad (low/medium/high)
|
|
264
|
+
- Actualizar fase y estado del proyecto
|
|
265
|
+
|
|
266
|
+
Las tareas se fusionan inteligentemente evitando duplicados.
|
|
267
|
+
No usa IA - actualización directa del documento.`,
|
|
268
|
+
inputSchema: {
|
|
269
|
+
type: "object",
|
|
270
|
+
properties: {
|
|
271
|
+
projectId: {
|
|
272
|
+
type: "string",
|
|
273
|
+
description: "Identificador único del proyecto (OBLIGATORIO)",
|
|
274
|
+
},
|
|
275
|
+
progress: {
|
|
276
|
+
type: "object",
|
|
277
|
+
description: "Tareas a actualizar",
|
|
278
|
+
properties: {
|
|
279
|
+
completed: {
|
|
280
|
+
type: "array",
|
|
281
|
+
items: { type: "string" },
|
|
282
|
+
description: "Tareas completadas",
|
|
283
|
+
},
|
|
284
|
+
inProgress: {
|
|
285
|
+
type: "array",
|
|
286
|
+
items: { type: "string" },
|
|
287
|
+
description: "Tareas en progreso",
|
|
288
|
+
},
|
|
289
|
+
blocked: {
|
|
290
|
+
type: "array",
|
|
291
|
+
items: { type: "string" },
|
|
292
|
+
description: "Tareas bloqueadas",
|
|
293
|
+
},
|
|
294
|
+
upcoming: {
|
|
295
|
+
type: "array",
|
|
296
|
+
items: { type: "string" },
|
|
297
|
+
description: "Próximas tareas",
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
milestone: {
|
|
302
|
+
type: "object",
|
|
303
|
+
description: "Milestone a añadir o actualizar",
|
|
304
|
+
properties: {
|
|
305
|
+
name: {
|
|
306
|
+
type: "string",
|
|
307
|
+
description: "Nombre del milestone",
|
|
308
|
+
},
|
|
309
|
+
status: {
|
|
310
|
+
type: "string",
|
|
311
|
+
enum: ["pending", "in_progress", "completed"],
|
|
312
|
+
description: "Estado del milestone",
|
|
313
|
+
},
|
|
314
|
+
targetDate: {
|
|
315
|
+
type: "string",
|
|
316
|
+
description: "Fecha objetivo (opcional)",
|
|
317
|
+
},
|
|
318
|
+
notes: {
|
|
319
|
+
type: "string",
|
|
320
|
+
description: "Notas adicionales (opcional)",
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
required: ["name", "status"],
|
|
324
|
+
},
|
|
325
|
+
blockers: {
|
|
326
|
+
type: "array",
|
|
327
|
+
description: "Blockers a registrar",
|
|
328
|
+
items: {
|
|
329
|
+
type: "object",
|
|
330
|
+
properties: {
|
|
331
|
+
description: {
|
|
332
|
+
type: "string",
|
|
333
|
+
description: "Descripción del blocker",
|
|
334
|
+
},
|
|
335
|
+
severity: {
|
|
336
|
+
type: "string",
|
|
337
|
+
enum: ["low", "medium", "high"],
|
|
338
|
+
description: "Severidad del blocker",
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
required: ["description", "severity"],
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
phase: {
|
|
345
|
+
type: "string",
|
|
346
|
+
description: "Fase actual del proyecto (ej: Planning, Development, Testing, Deployment)",
|
|
347
|
+
},
|
|
348
|
+
phaseStatus: {
|
|
349
|
+
type: "string",
|
|
350
|
+
description: "Estado de la fase (ej: Not Started, In Progress, Completed)",
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
required: ["projectId"],
|
|
354
|
+
},
|
|
355
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Update Context tool for Memory Bank
|
|
3
|
+
* Updates the active context document with current session information
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
/**
|
|
8
|
+
* Parses the existing activeContext.md to extract session history
|
|
9
|
+
*/
|
|
10
|
+
function parseSessionHistory(content) {
|
|
11
|
+
const history = [];
|
|
12
|
+
// Find the Session History table
|
|
13
|
+
const tableMatch = content.match(/\| Date \| Mode \| Task \| Notes \|[\s\S]*?(?=\n\n|\n##|$)/);
|
|
14
|
+
if (!tableMatch)
|
|
15
|
+
return history;
|
|
16
|
+
const lines = tableMatch[0].split("\n").slice(2); // Skip header and separator
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const cells = line.split("|").map(c => c.trim()).filter(c => c);
|
|
19
|
+
if (cells.length >= 4) {
|
|
20
|
+
history.push({
|
|
21
|
+
date: cells[0],
|
|
22
|
+
mode: cells[1],
|
|
23
|
+
task: cells[2],
|
|
24
|
+
notes: cells[3],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return history;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generates the updated activeContext.md content
|
|
32
|
+
*/
|
|
33
|
+
function generateActiveContextContent(projectId, currentSession, recentChanges, openQuestions, nextSteps, notes, sessionHistory) {
|
|
34
|
+
const date = currentSession.date || new Date().toISOString().split("T")[0];
|
|
35
|
+
const mode = currentSession.mode || "development";
|
|
36
|
+
const task = currentSession.task || "Working on project";
|
|
37
|
+
// Add current session to history (limit to last 10)
|
|
38
|
+
const newHistory = [
|
|
39
|
+
{ date, mode, task, notes: notes || "Session updated" },
|
|
40
|
+
...sessionHistory,
|
|
41
|
+
].slice(0, 10);
|
|
42
|
+
// Build session history table
|
|
43
|
+
const historyRows = newHistory
|
|
44
|
+
.map(h => `| ${h.date} | ${h.mode} | ${h.task} | ${h.notes} |`)
|
|
45
|
+
.join("\n");
|
|
46
|
+
// Build recent changes list
|
|
47
|
+
const changesContent = recentChanges.length > 0
|
|
48
|
+
? recentChanges.map(c => `- ${c}`).join("\n")
|
|
49
|
+
: "- No recent changes recorded";
|
|
50
|
+
// Build open questions list
|
|
51
|
+
const questionsContent = openQuestions.length > 0
|
|
52
|
+
? openQuestions.map(q => `- ${q}`).join("\n")
|
|
53
|
+
: "- No open questions";
|
|
54
|
+
// Build next steps list
|
|
55
|
+
const stepsContent = nextSteps.length > 0
|
|
56
|
+
? nextSteps.map(s => `- [ ] ${s}`).join("\n")
|
|
57
|
+
: "- [ ] Continue development";
|
|
58
|
+
return `# Active Context
|
|
59
|
+
|
|
60
|
+
## Current Session
|
|
61
|
+
- **Date**: ${date}
|
|
62
|
+
- **Mode**: ${mode}
|
|
63
|
+
- **Current Task**: ${task}
|
|
64
|
+
|
|
65
|
+
## Session History
|
|
66
|
+
| Date | Mode | Task | Notes |
|
|
67
|
+
|------|------|------|-------|
|
|
68
|
+
${historyRows}
|
|
69
|
+
|
|
70
|
+
## Recent Changes
|
|
71
|
+
${changesContent}
|
|
72
|
+
|
|
73
|
+
## Open Questions
|
|
74
|
+
${questionsContent}
|
|
75
|
+
|
|
76
|
+
## Next Steps
|
|
77
|
+
${stepsContent}
|
|
78
|
+
|
|
79
|
+
## Active Considerations
|
|
80
|
+
${notes || "_No additional considerations_"}
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
*Last updated: ${new Date().toISOString()}*
|
|
84
|
+
*Update with \`memorybank_update_context\` to track session progress.*
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Updates the active context document
|
|
89
|
+
*/
|
|
90
|
+
export async function updateContext(params, storagePath = ".memorybank") {
|
|
91
|
+
const { projectId, currentSession = {}, recentChanges = [], openQuestions = [], nextSteps = [], notes = "", } = params;
|
|
92
|
+
console.error(`\n=== Updating Active Context ===`);
|
|
93
|
+
console.error(`Project ID: ${projectId}`);
|
|
94
|
+
const docsPath = path.join(storagePath, "projects", projectId, "docs");
|
|
95
|
+
const activeContextPath = path.join(docsPath, "activeContext.md");
|
|
96
|
+
// Check if Memory Bank exists
|
|
97
|
+
if (!fs.existsSync(docsPath)) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
message: `Memory Bank not initialized for project "${projectId}". Run \`memorybank_initialize\` first.`,
|
|
101
|
+
projectId,
|
|
102
|
+
updatedSections: [],
|
|
103
|
+
sessionHistory: 0,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Parse existing session history if file exists
|
|
107
|
+
let sessionHistory = [];
|
|
108
|
+
if (fs.existsSync(activeContextPath)) {
|
|
109
|
+
const existingContent = fs.readFileSync(activeContextPath, "utf-8");
|
|
110
|
+
sessionHistory = parseSessionHistory(existingContent);
|
|
111
|
+
console.error(` Found ${sessionHistory.length} previous sessions`);
|
|
112
|
+
}
|
|
113
|
+
// Track which sections were updated
|
|
114
|
+
const updatedSections = ["Current Session"];
|
|
115
|
+
if (recentChanges.length > 0)
|
|
116
|
+
updatedSections.push("Recent Changes");
|
|
117
|
+
if (openQuestions.length > 0)
|
|
118
|
+
updatedSections.push("Open Questions");
|
|
119
|
+
if (nextSteps.length > 0)
|
|
120
|
+
updatedSections.push("Next Steps");
|
|
121
|
+
if (notes)
|
|
122
|
+
updatedSections.push("Active Considerations");
|
|
123
|
+
// Generate new content
|
|
124
|
+
const newContent = generateActiveContextContent(projectId, currentSession, recentChanges, openQuestions, nextSteps, notes, sessionHistory);
|
|
125
|
+
// Write to file
|
|
126
|
+
fs.writeFileSync(activeContextPath, newContent, "utf-8");
|
|
127
|
+
console.error(` Updated sections: ${updatedSections.join(", ")}`);
|
|
128
|
+
console.error(` Session history: ${sessionHistory.length + 1} entries`);
|
|
129
|
+
console.error(`\n=== Context Updated ===`);
|
|
130
|
+
return {
|
|
131
|
+
success: true,
|
|
132
|
+
message: `Active context updated for project "${projectId}". Updated: ${updatedSections.join(", ")}. Session history: ${sessionHistory.length + 1} entries.`,
|
|
133
|
+
projectId,
|
|
134
|
+
updatedSections,
|
|
135
|
+
sessionHistory: sessionHistory.length + 1,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Tool definition for MCP
|
|
140
|
+
*/
|
|
141
|
+
export const updateContextToolDefinition = {
|
|
142
|
+
name: "memorybank_update_context",
|
|
143
|
+
description: `Actualiza el contexto activo del proyecto con información de la sesión actual.
|
|
144
|
+
|
|
145
|
+
Permite registrar:
|
|
146
|
+
- Sesión actual (fecha, modo de trabajo, tarea)
|
|
147
|
+
- Cambios recientes realizados
|
|
148
|
+
- Preguntas abiertas pendientes
|
|
149
|
+
- Próximos pasos planificados
|
|
150
|
+
- Notas y consideraciones
|
|
151
|
+
|
|
152
|
+
Mantiene un historial de las últimas 10 sesiones para tracking de progreso.
|
|
153
|
+
No usa IA - actualización directa del documento.`,
|
|
154
|
+
inputSchema: {
|
|
155
|
+
type: "object",
|
|
156
|
+
properties: {
|
|
157
|
+
projectId: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Identificador único del proyecto (OBLIGATORIO)",
|
|
160
|
+
},
|
|
161
|
+
currentSession: {
|
|
162
|
+
type: "object",
|
|
163
|
+
description: "Información de la sesión actual",
|
|
164
|
+
properties: {
|
|
165
|
+
date: {
|
|
166
|
+
type: "string",
|
|
167
|
+
description: "Fecha de la sesión (YYYY-MM-DD). Auto-genera si no se especifica",
|
|
168
|
+
},
|
|
169
|
+
mode: {
|
|
170
|
+
type: "string",
|
|
171
|
+
description: "Modo de trabajo: development, debugging, refactoring, review, planning, etc.",
|
|
172
|
+
},
|
|
173
|
+
task: {
|
|
174
|
+
type: "string",
|
|
175
|
+
description: "Descripción de la tarea actual",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
recentChanges: {
|
|
180
|
+
type: "array",
|
|
181
|
+
items: { type: "string" },
|
|
182
|
+
description: "Lista de cambios recientes realizados",
|
|
183
|
+
},
|
|
184
|
+
openQuestions: {
|
|
185
|
+
type: "array",
|
|
186
|
+
items: { type: "string" },
|
|
187
|
+
description: "Preguntas o dudas pendientes de resolver",
|
|
188
|
+
},
|
|
189
|
+
nextSteps: {
|
|
190
|
+
type: "array",
|
|
191
|
+
items: { type: "string" },
|
|
192
|
+
description: "Próximos pasos planificados",
|
|
193
|
+
},
|
|
194
|
+
notes: {
|
|
195
|
+
type: "string",
|
|
196
|
+
description: "Notas adicionales o consideraciones activas",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
required: ["projectId"],
|
|
200
|
+
},
|
|
201
|
+
};
|