@grec0/memory-bank-mcp 0.1.37 → 0.1.39
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/common/indexManager.js +6 -0
- package/dist/common/projectVectorStore.js +79 -0
- package/dist/common/registryManager.js +74 -2
- package/dist/common/version.js +1 -1
- package/dist/index.js +8 -0
- package/dist/tools/discoverProjects.js +11 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/indexCode.js +15 -0
- package/dist/tools/syncProjects.js +34 -0
- package/package.json +1 -1
|
@@ -37,6 +37,12 @@ export class IndexManager {
|
|
|
37
37
|
this.projectKnowledgeService = service;
|
|
38
38
|
console.error("Project Knowledge Service attached to Index Manager");
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Gets the Embedding Service instance
|
|
42
|
+
*/
|
|
43
|
+
getEmbeddingService() {
|
|
44
|
+
return this.embeddingService;
|
|
45
|
+
}
|
|
40
46
|
/**
|
|
41
47
|
* Enables or disables auto-update of project docs after indexing
|
|
42
48
|
*/
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as lancedb from "@lancedb/lancedb";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
export class ProjectVectorStore {
|
|
4
|
+
db = null;
|
|
5
|
+
table = null;
|
|
6
|
+
dbPath;
|
|
7
|
+
tableName;
|
|
8
|
+
constructor(dbPath = ".memorybank", tableName = "projects") {
|
|
9
|
+
this.dbPath = dbPath;
|
|
10
|
+
this.tableName = tableName;
|
|
11
|
+
}
|
|
12
|
+
async initialize() {
|
|
13
|
+
try {
|
|
14
|
+
if (!fs.existsSync(this.dbPath)) {
|
|
15
|
+
fs.mkdirSync(this.dbPath, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
this.db = await lancedb.connect(this.dbPath);
|
|
18
|
+
const tableNames = await this.db.tableNames();
|
|
19
|
+
if (tableNames.includes(this.tableName)) {
|
|
20
|
+
this.table = await this.db.openTable(this.tableName);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.error(`Error initializing project vector store: ${error}`);
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async ensureInitialized() {
|
|
29
|
+
if (!this.db) {
|
|
30
|
+
await this.initialize();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async upsertProject(record) {
|
|
34
|
+
await this.ensureInitialized();
|
|
35
|
+
try {
|
|
36
|
+
if (!this.table) {
|
|
37
|
+
this.table = await this.db.createTable(this.tableName, [record]);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Delete existing if any (LanceDB update/merge is tricky, delete+insert is safer for single records)
|
|
41
|
+
try {
|
|
42
|
+
await this.table.delete(`id = '${record.id}'`);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
// Ignore if not found or delete fails
|
|
46
|
+
}
|
|
47
|
+
await this.table.add([record]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(`Error upserting project: ${error}`);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async search(queryVector, limit = 10) {
|
|
56
|
+
await this.ensureInitialized();
|
|
57
|
+
if (!this.table)
|
|
58
|
+
return [];
|
|
59
|
+
try {
|
|
60
|
+
const results = await this.table.search(queryVector).limit(limit).toArray();
|
|
61
|
+
return results.map((r) => ({
|
|
62
|
+
project: {
|
|
63
|
+
id: r.id,
|
|
64
|
+
vector: r.vector,
|
|
65
|
+
name: r.name,
|
|
66
|
+
description: r.description,
|
|
67
|
+
tags: r.tags,
|
|
68
|
+
path: r.path,
|
|
69
|
+
lastActive: r.lastActive
|
|
70
|
+
},
|
|
71
|
+
score: 1 - (r._distance || 0) // Convert distance to score if needed
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error(`Error searching projects: ${error}`);
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import * as os from 'os';
|
|
4
|
+
import { ProjectVectorStore } from './projectVectorStore.js';
|
|
4
5
|
export class RegistryManager {
|
|
5
6
|
globalPath;
|
|
7
|
+
projectVectorStore;
|
|
6
8
|
constructor() {
|
|
7
9
|
this.globalPath = path.join(os.homedir(), '.memorybank', 'global_registry.json');
|
|
10
|
+
this.projectVectorStore = new ProjectVectorStore();
|
|
8
11
|
}
|
|
9
12
|
async ensureRegistry() {
|
|
10
13
|
try {
|
|
@@ -19,7 +22,7 @@ export class RegistryManager {
|
|
|
19
22
|
async saveRegistry(registry) {
|
|
20
23
|
await fs.writeFile(this.globalPath, JSON.stringify(registry, null, 2), 'utf-8');
|
|
21
24
|
}
|
|
22
|
-
async registerProject(projectId, workspacePath, description, keywords = []) {
|
|
25
|
+
async registerProject(projectId, workspacePath, description, keywords = [], embeddingService) {
|
|
23
26
|
const registry = await this.ensureRegistry();
|
|
24
27
|
const idx = registry.projects.findIndex(p => p.projectId === projectId);
|
|
25
28
|
// Preserve existing description/keywords if not provided
|
|
@@ -39,11 +42,56 @@ export class RegistryManager {
|
|
|
39
42
|
registry.projects.push(card);
|
|
40
43
|
}
|
|
41
44
|
await this.saveRegistry(registry);
|
|
45
|
+
// Update vector store if embedding service provides
|
|
46
|
+
if (embeddingService) {
|
|
47
|
+
try {
|
|
48
|
+
await this.updateProjectEmbedding(card, embeddingService);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error(`Failed to update project embedding: ${error}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async updateProjectEmbedding(card, embeddingService) {
|
|
56
|
+
const text = `Project: ${card.projectId}\nDescription: ${card.description || ''}\nKeywords: ${card.keywords.join(', ')}`;
|
|
57
|
+
const result = await embeddingService.generateEmbedding(card.projectId, text);
|
|
58
|
+
await this.projectVectorStore.upsertProject({
|
|
59
|
+
id: card.projectId,
|
|
60
|
+
vector: result.vector,
|
|
61
|
+
name: card.projectId, // Using ID as name for now if name not available
|
|
62
|
+
description: card.description || '',
|
|
63
|
+
tags: card.keywords,
|
|
64
|
+
path: card.path,
|
|
65
|
+
lastActive: new Date(card.lastActive).getTime()
|
|
66
|
+
});
|
|
42
67
|
}
|
|
43
|
-
async discoverProjects(query) {
|
|
68
|
+
async discoverProjects(query, embeddingService) {
|
|
44
69
|
const registry = await this.ensureRegistry();
|
|
45
70
|
if (!query || query.trim() === '')
|
|
46
71
|
return registry.projects;
|
|
72
|
+
// Try semantic search if service available
|
|
73
|
+
if (embeddingService) {
|
|
74
|
+
try {
|
|
75
|
+
const queryEmbedding = await embeddingService.generateEmbedding('search-query', query);
|
|
76
|
+
const results = await this.projectVectorStore.search(queryEmbedding.vector);
|
|
77
|
+
// Map back to ProjectCards
|
|
78
|
+
const projectIds = new Set(results.map(r => r.project.id));
|
|
79
|
+
// Return found projects, maintain order from vector search
|
|
80
|
+
const foundProjects = [];
|
|
81
|
+
for (const res of results) {
|
|
82
|
+
const card = registry.projects.find(p => p.projectId === res.project.id);
|
|
83
|
+
if (card)
|
|
84
|
+
foundProjects.push(card);
|
|
85
|
+
}
|
|
86
|
+
// If we found something, return it. If very few, maybe fallback or mix?
|
|
87
|
+
// For now, if we have semantic results, use them.
|
|
88
|
+
if (foundProjects.length > 0)
|
|
89
|
+
return foundProjects;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error(`Semantic search failed, falling back to text: ${error}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
47
95
|
const q = query.toLowerCase();
|
|
48
96
|
return registry.projects.filter(p => p.projectId.toLowerCase().includes(q) ||
|
|
49
97
|
(p.description && p.description.toLowerCase().includes(q)) ||
|
|
@@ -53,4 +101,28 @@ export class RegistryManager {
|
|
|
53
101
|
const registry = await this.ensureRegistry();
|
|
54
102
|
return registry.projects.find(p => p.projectId === projectId);
|
|
55
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Syncs all projects from the JSON registry to the vector store.
|
|
106
|
+
* Useful for migrating existing projects to the new semantic discovery system.
|
|
107
|
+
*/
|
|
108
|
+
async syncRegistry(embeddingService) {
|
|
109
|
+
const registry = await this.ensureRegistry();
|
|
110
|
+
let processed = 0;
|
|
111
|
+
let failures = 0;
|
|
112
|
+
console.error(`Syncing ${registry.projects.length} projects to vector store...`);
|
|
113
|
+
for (const project of registry.projects) {
|
|
114
|
+
try {
|
|
115
|
+
await this.updateProjectEmbedding(project, embeddingService);
|
|
116
|
+
processed++;
|
|
117
|
+
if (processed % 10 === 0) {
|
|
118
|
+
console.error(`Synced ${processed}/${registry.projects.length} projects`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error(`Failed to sync project ${project.projectId}: ${error}`);
|
|
123
|
+
failures++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { processed, failures };
|
|
127
|
+
}
|
|
56
128
|
}
|
package/dist/common/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version of the MCP Kanban server
|
|
2
|
-
export const VERSION = "0.1.
|
|
2
|
+
export const VERSION = "0.1.39";
|
package/dist/index.js
CHANGED
|
@@ -82,6 +82,7 @@ import { trackProgress, trackProgressToolDefinition } from "./tools/trackProgres
|
|
|
82
82
|
import { manageAgentsTool, manageAgentsToolDefinition } from "./tools/manageAgents.js";
|
|
83
83
|
import { discoverProjectsTool, discoverProjectsToolDefinition } from "./tools/discoverProjects.js";
|
|
84
84
|
import { delegateTaskTool, delegateTaskToolDefinition } from "./tools/delegateTask.js";
|
|
85
|
+
import { syncProjectsTool, syncProjectsToolDefinition } from "./tools/syncProjects.js";
|
|
85
86
|
import { RegistryManager } from "./common/registryManager.js";
|
|
86
87
|
import { VERSION } from "./common/version.js";
|
|
87
88
|
// Global services
|
|
@@ -837,6 +838,13 @@ server.tool(discoverProjectsToolDefinition.name, discoverProjectsToolDefinition.
|
|
|
837
838
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
838
839
|
};
|
|
839
840
|
});
|
|
841
|
+
// Tool: Sync Projects
|
|
842
|
+
server.tool(syncProjectsToolDefinition.name, syncProjectsToolDefinition.description, {}, async () => {
|
|
843
|
+
const result = await syncProjectsTool();
|
|
844
|
+
return {
|
|
845
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
846
|
+
};
|
|
847
|
+
});
|
|
840
848
|
// Tool: Delegate Task
|
|
841
849
|
server.tool(delegateTaskToolDefinition.name, delegateTaskToolDefinition.description, {
|
|
842
850
|
projectId: z.string().describe("ID del proyecto origen (quien pide)"),
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { RegistryManager } from '../common/registryManager.js';
|
|
2
|
+
import { EmbeddingService } from '../common/embeddingService.js';
|
|
2
3
|
export async function discoverProjectsTool(params) {
|
|
3
4
|
const registryManager = new RegistryManager();
|
|
4
|
-
|
|
5
|
+
let embeddingService;
|
|
6
|
+
if (process.env.OPENAI_API_KEY) {
|
|
7
|
+
try {
|
|
8
|
+
embeddingService = new EmbeddingService(process.env.OPENAI_API_KEY);
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
console.error("Failed to init embedding service for discovery:", e);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const projects = await registryManager.discoverProjects(params.query, embeddingService);
|
|
5
15
|
return {
|
|
6
16
|
success: true,
|
|
7
17
|
projectCount: projects.length,
|
package/dist/tools/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./readFile.js";
|
|
|
10
10
|
export * from "./writeFile.js";
|
|
11
11
|
export * from "./getStats.js";
|
|
12
12
|
export * from "./analyzeCoverage.js";
|
|
13
|
+
export * from "./syncProjects.js";
|
|
13
14
|
// Export Project Knowledge Layer tools
|
|
14
15
|
export * from "./generateProjectDocs.js";
|
|
15
16
|
export * from "./getProjectDocs.js";
|
package/dist/tools/indexCode.js
CHANGED
|
@@ -6,6 +6,7 @@ import * as path from "path";
|
|
|
6
6
|
import { AgentBoard } from "../common/agentBoard.js";
|
|
7
7
|
import { sessionLogger } from "../common/sessionLogger.js";
|
|
8
8
|
import { sessionState } from "../common/sessionState.js";
|
|
9
|
+
import { RegistryManager } from "../common/registryManager.js";
|
|
9
10
|
/**
|
|
10
11
|
* Indexes code from a directory or file
|
|
11
12
|
*/
|
|
@@ -44,6 +45,20 @@ export async function indexCode(params, indexManager, workspaceRoot) {
|
|
|
44
45
|
console.error(`Workspace root: ${workspaceRoot}`);
|
|
45
46
|
console.error(`Recursive: ${params.recursive !== false}`);
|
|
46
47
|
console.error(`Force reindex: ${params.forceReindex || false}`);
|
|
48
|
+
// Register project and update embedding
|
|
49
|
+
try {
|
|
50
|
+
const registryManager = new RegistryManager();
|
|
51
|
+
const embeddingService = indexManager.getEmbeddingService();
|
|
52
|
+
// Try to get description/keywords from indexManager or project files could be an enhancement
|
|
53
|
+
// For now, we ensure registration with what we have
|
|
54
|
+
await registryManager.registerProject(params.projectId, workspaceRoot, undefined, // Preserve existing description
|
|
55
|
+
[], // Preserve/empty keywords
|
|
56
|
+
embeddingService);
|
|
57
|
+
console.error(`Project ${params.projectId} registered/updated in global registry and vector store`);
|
|
58
|
+
}
|
|
59
|
+
catch (regError) {
|
|
60
|
+
console.error(`Failed to register project: ${regError}`);
|
|
61
|
+
}
|
|
47
62
|
// Run indexing - pass workspaceRoot for consistent path normalization
|
|
48
63
|
const result = await indexManager.indexFiles({
|
|
49
64
|
projectId: params.projectId,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RegistryManager } from '../common/registryManager.js';
|
|
2
|
+
import { EmbeddingService } from '../common/embeddingService.js';
|
|
3
|
+
export async function syncProjectsTool() {
|
|
4
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
5
|
+
return {
|
|
6
|
+
success: false,
|
|
7
|
+
message: "OPENAI_API_KEY environment variable is required for syncing projects."
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const registryManager = new RegistryManager();
|
|
12
|
+
const embeddingService = new EmbeddingService(process.env.OPENAI_API_KEY);
|
|
13
|
+
const result = await registryManager.syncRegistry(embeddingService);
|
|
14
|
+
return {
|
|
15
|
+
success: true,
|
|
16
|
+
message: `Synchronization complete. Processed: ${result.processed}, Failures: ${result.failures}`,
|
|
17
|
+
details: result
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
message: `Error during synchronization: ${error}`
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export const syncProjectsToolDefinition = {
|
|
28
|
+
name: "memorybank_sync_projects",
|
|
29
|
+
description: "Sincroniza todos los proyectos del registro JSON al store vectorial para habilitar la búsqueda semántica. Útil para migrar datos existentes.",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {}
|
|
33
|
+
}
|
|
34
|
+
};
|