@grec0/memory-bank-mcp 0.2.12 → 0.2.14
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.
|
@@ -1,23 +1,123 @@
|
|
|
1
1
|
import * as fs from 'fs/promises';
|
|
2
|
+
import * as fssync from 'fs';
|
|
2
3
|
import * as path from 'path';
|
|
3
4
|
import * as os from 'os';
|
|
4
5
|
import { ProjectVectorStore } from './projectVectorStore.js';
|
|
5
6
|
export class RegistryManager {
|
|
6
7
|
globalPath;
|
|
7
8
|
projectVectorStore;
|
|
9
|
+
storagePath;
|
|
8
10
|
constructor() {
|
|
9
11
|
this.globalPath = path.join(os.homedir(), '.memorybank', 'global_registry.json');
|
|
12
|
+
this.storagePath = process.env.MEMORYBANK_STORAGE_PATH || path.join(os.homedir(), '.memorybank');
|
|
10
13
|
this.projectVectorStore = new ProjectVectorStore();
|
|
11
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Discovers projects by scanning the projects directory
|
|
17
|
+
* Used for auto-recovery when registry.json is corrupted/empty
|
|
18
|
+
*/
|
|
19
|
+
async discoverProjectsFromDisk() {
|
|
20
|
+
const projectsDir = path.join(this.storagePath, 'projects');
|
|
21
|
+
if (!fssync.existsSync(projectsDir)) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const entries = await fs.readdir(projectsDir, { withFileTypes: true });
|
|
26
|
+
const projectIds = entries
|
|
27
|
+
.filter(e => e.isDirectory())
|
|
28
|
+
.map(e => e.name);
|
|
29
|
+
console.error(`Discovered ${projectIds.length} projects from disk: ${projectIds.join(', ')}`);
|
|
30
|
+
return projectIds;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error(`Error discovering projects from disk: ${error}`);
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ensures the registry exists and returns it
|
|
39
|
+
* If corrupted/empty, auto-recovers by scanning project folders
|
|
40
|
+
*/
|
|
12
41
|
async ensureRegistry() {
|
|
13
42
|
try {
|
|
14
43
|
await fs.mkdir(path.dirname(this.globalPath), { recursive: true });
|
|
15
44
|
const content = await fs.readFile(this.globalPath, 'utf-8');
|
|
16
|
-
|
|
45
|
+
// Validate JSON
|
|
46
|
+
if (!content || content.trim() === '') {
|
|
47
|
+
console.error('⚠️ Registry file is empty, attempting auto-recovery...');
|
|
48
|
+
return await this.autoRecoverRegistry();
|
|
49
|
+
}
|
|
50
|
+
const parsed = JSON.parse(content);
|
|
51
|
+
// Validate structure
|
|
52
|
+
if (!parsed || typeof parsed !== 'object' || !Array.isArray(parsed.projects)) {
|
|
53
|
+
console.error('⚠️ Registry file has invalid structure, attempting auto-recovery...');
|
|
54
|
+
await this.backupCorruptedRegistry(content);
|
|
55
|
+
return await this.autoRecoverRegistry();
|
|
56
|
+
}
|
|
57
|
+
// Check if registry is suspiciously empty (has folders but no projects)
|
|
58
|
+
if (parsed.projects.length === 0) {
|
|
59
|
+
const diskProjects = await this.discoverProjectsFromDisk();
|
|
60
|
+
if (diskProjects.length > 0) {
|
|
61
|
+
console.error(`⚠️ Registry is empty but ${diskProjects.length} projects exist on disk, attempting auto-recovery...`);
|
|
62
|
+
await this.backupCorruptedRegistry(content);
|
|
63
|
+
return await this.autoRecoverRegistry();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return parsed;
|
|
17
67
|
}
|
|
18
|
-
catch {
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error.code === 'ENOENT') {
|
|
70
|
+
// File doesn't exist, try auto-recovery
|
|
71
|
+
console.error('Registry file does not exist, attempting auto-recovery...');
|
|
72
|
+
return await this.autoRecoverRegistry();
|
|
73
|
+
}
|
|
74
|
+
// JSON parse error - backup and auto-recover
|
|
75
|
+
console.error(`Error reading registry: ${error.message}, attempting auto-recovery...`);
|
|
76
|
+
try {
|
|
77
|
+
const content = await fs.readFile(this.globalPath, 'utf-8');
|
|
78
|
+
await this.backupCorruptedRegistry(content);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Can't read for backup
|
|
82
|
+
}
|
|
83
|
+
return await this.autoRecoverRegistry();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Auto-recovers registry by discovering projects from disk
|
|
88
|
+
* Returns a minimal registry with project IDs - full data will be populated by sync
|
|
89
|
+
*/
|
|
90
|
+
async autoRecoverRegistry() {
|
|
91
|
+
const projectIds = await this.discoverProjectsFromDisk();
|
|
92
|
+
if (projectIds.length === 0) {
|
|
93
|
+
console.error('No projects found on disk, starting with empty registry');
|
|
19
94
|
return { projects: [] };
|
|
20
95
|
}
|
|
96
|
+
console.error(`✓ Auto-recovered ${projectIds.length} projects from disk`);
|
|
97
|
+
console.error(` Run 'memorybank_sync_projects' to populate full metadata`);
|
|
98
|
+
// Return minimal registry - sync will populate the rest
|
|
99
|
+
const projects = projectIds.map(projectId => ({
|
|
100
|
+
projectId,
|
|
101
|
+
path: '', // Will be populated by sync
|
|
102
|
+
description: '',
|
|
103
|
+
keywords: [],
|
|
104
|
+
lastActive: new Date().toISOString(),
|
|
105
|
+
status: 'ACTIVE'
|
|
106
|
+
}));
|
|
107
|
+
return { projects };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Backs up a corrupted registry file before overwriting
|
|
111
|
+
*/
|
|
112
|
+
async backupCorruptedRegistry(content) {
|
|
113
|
+
try {
|
|
114
|
+
const backupPath = `${this.globalPath}.backup-${Date.now()}`;
|
|
115
|
+
await fs.writeFile(backupPath, content, 'utf-8');
|
|
116
|
+
console.error(`Backed up corrupted registry to: ${backupPath}`);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
console.error(`Failed to backup corrupted registry: ${error}`);
|
|
120
|
+
}
|
|
21
121
|
}
|
|
22
122
|
async saveRegistry(registry) {
|
|
23
123
|
await fs.writeFile(this.globalPath, JSON.stringify(registry, null, 2), 'utf-8');
|
|
@@ -29,16 +129,27 @@ export class RegistryManager {
|
|
|
29
129
|
const existing = idx >= 0 ? registry.projects[idx] : null;
|
|
30
130
|
const card = {
|
|
31
131
|
projectId,
|
|
32
|
-
path
|
|
33
|
-
|
|
132
|
+
// Preserve existing workspace path if new one is empty/invalid
|
|
133
|
+
path: (workspacePath && workspacePath.trim() !== '') ? workspacePath : (existing?.path || workspacePath),
|
|
134
|
+
// Preserve existing description if new one is undefined or empty
|
|
135
|
+
description: (description !== undefined && description.trim() !== '') ? description : (existing?.description || ''),
|
|
136
|
+
// Preserve existing keywords if new array is empty
|
|
34
137
|
keywords: keywords.length > 0 ? keywords : (existing?.keywords || []),
|
|
35
138
|
lastActive: new Date().toISOString(),
|
|
36
139
|
status: 'ACTIVE',
|
|
37
140
|
// Enhanced fields - preserve existing if not provided
|
|
38
|
-
responsibilities: enhancedInfo?.responsibilities
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
141
|
+
responsibilities: enhancedInfo?.responsibilities !== undefined
|
|
142
|
+
? (enhancedInfo.responsibilities.length > 0 ? enhancedInfo.responsibilities : existing?.responsibilities)
|
|
143
|
+
: existing?.responsibilities,
|
|
144
|
+
owns: enhancedInfo?.owns !== undefined
|
|
145
|
+
? (enhancedInfo.owns.length > 0 ? enhancedInfo.owns : existing?.owns)
|
|
146
|
+
: existing?.owns,
|
|
147
|
+
exports: enhancedInfo?.exports !== undefined
|
|
148
|
+
? (enhancedInfo.exports.trim() !== '' ? enhancedInfo.exports : existing?.exports)
|
|
149
|
+
: existing?.exports,
|
|
150
|
+
projectType: enhancedInfo?.projectType !== undefined
|
|
151
|
+
? (enhancedInfo.projectType.trim() !== '' ? enhancedInfo.projectType : existing?.projectType)
|
|
152
|
+
: existing?.projectType,
|
|
42
153
|
};
|
|
43
154
|
if (idx >= 0) {
|
|
44
155
|
registry.projects[idx] = card;
|
|
@@ -378,6 +378,30 @@ export class VectorStore {
|
|
|
378
378
|
return new Map();
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* Gets all unique project IDs that have indexed chunks
|
|
383
|
+
* Useful for discovering which projects have code in the vector store
|
|
384
|
+
*/
|
|
385
|
+
async getIndexedProjectIds() {
|
|
386
|
+
await this.ensureInitialized();
|
|
387
|
+
if (!this.table) {
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
try {
|
|
391
|
+
const allChunks = await this.table.query().toArray();
|
|
392
|
+
const projectIds = new Set();
|
|
393
|
+
for (const chunk of allChunks) {
|
|
394
|
+
if (chunk.project_id) {
|
|
395
|
+
projectIds.add(chunk.project_id);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return Array.from(projectIds);
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
console.error(`Error getting indexed project IDs: ${error}`);
|
|
402
|
+
return [];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
381
405
|
}
|
|
382
406
|
/**
|
|
383
407
|
* Creates a vector store from environment variables
|
package/dist/common/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version of the MCP Kanban server
|
|
2
|
-
export const VERSION = "0.2.
|
|
2
|
+
export const VERSION = "0.2.14";
|
|
@@ -98,32 +98,44 @@ export async function generateProjectDocs(params, projectKnowledgeService, vecto
|
|
|
98
98
|
console.error(` - Estimated cost: $${totalCost.toFixed(4)}`);
|
|
99
99
|
// === AUTO-UPDATE GLOBAL REGISTRY ===
|
|
100
100
|
// Generate project summary and update registry with enriched info
|
|
101
|
-
if
|
|
101
|
+
// ONLY if generation was successful AND at least one document was generated/updated
|
|
102
|
+
if (result.success && (result.documentsGenerated.length > 0 || result.documentsUpdated.length > 0)) {
|
|
102
103
|
try {
|
|
103
104
|
console.error(`\n=== Updating Global Registry ===`);
|
|
104
105
|
const summary = await projectKnowledgeService.generateProjectSummary(projectId);
|
|
105
106
|
if (summary) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
107
|
+
// Validate that the summary has meaningful data before updating registry
|
|
108
|
+
const hasResponsibilities = summary.responsibilities && summary.responsibilities.length > 0;
|
|
109
|
+
const hasDescription = summary.description && summary.description.trim().length > 0;
|
|
110
|
+
if (!hasResponsibilities && !hasDescription) {
|
|
111
|
+
console.error(`Warning: Generated summary is empty, skipping registry update`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const registryManager = new RegistryManager();
|
|
115
|
+
let embeddingService;
|
|
116
|
+
if (process.env.OPENAI_API_KEY) {
|
|
117
|
+
try {
|
|
118
|
+
embeddingService = new EmbeddingService(process.env.OPENAI_API_KEY);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
console.error(`Warning: Could not init embedding service: ${e}`);
|
|
122
|
+
}
|
|
114
123
|
}
|
|
124
|
+
await registryManager.registerProject(projectId, workspaceRoot, summary.description, summary.keywords, embeddingService, {
|
|
125
|
+
responsibilities: summary.responsibilities,
|
|
126
|
+
owns: summary.owns,
|
|
127
|
+
exports: summary.exports,
|
|
128
|
+
projectType: summary.projectType,
|
|
129
|
+
});
|
|
130
|
+
console.error(`Registry updated for ${projectId}:`);
|
|
131
|
+
console.error(` - Description: ${summary.description.slice(0, 80)}...`);
|
|
132
|
+
console.error(` - Type: ${summary.projectType}`);
|
|
133
|
+
console.error(` - Responsibilities: ${summary.responsibilities?.length || 0}`);
|
|
134
|
+
message += ` Registry updated with project summary.`;
|
|
115
135
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
exports: summary.exports,
|
|
120
|
-
projectType: summary.projectType,
|
|
121
|
-
});
|
|
122
|
-
console.error(`Registry updated for ${projectId}:`);
|
|
123
|
-
console.error(` - Description: ${summary.description.slice(0, 80)}...`);
|
|
124
|
-
console.error(` - Type: ${summary.projectType}`);
|
|
125
|
-
console.error(` - Responsibilities: ${summary.responsibilities.length}`);
|
|
126
|
-
message += ` Registry updated with project summary.`;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
console.error(`Warning: Could not generate project summary, skipping registry update`);
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
catch (regError) {
|
|
@@ -131,6 +143,9 @@ export async function generateProjectDocs(params, projectKnowledgeService, vecto
|
|
|
131
143
|
// Don't fail the whole operation if registry update fails
|
|
132
144
|
}
|
|
133
145
|
}
|
|
146
|
+
else if (!result.success) {
|
|
147
|
+
console.error(`Skipping registry update because documentation generation failed`);
|
|
148
|
+
}
|
|
134
149
|
return {
|
|
135
150
|
success: result.success,
|
|
136
151
|
message,
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { RegistryManager } from '../common/registryManager.js';
|
|
2
2
|
import { EmbeddingService } from '../common/embeddingService.js';
|
|
3
|
+
import { VectorStore } from '../common/vectorStore.js';
|
|
4
|
+
import { ProjectKnowledgeService } from '../common/projectKnowledgeService.js';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import * as os from 'os';
|
|
3
8
|
export async function syncProjectsTool() {
|
|
4
9
|
if (!process.env.OPENAI_API_KEY) {
|
|
5
10
|
return {
|
|
@@ -10,11 +15,155 @@ export async function syncProjectsTool() {
|
|
|
10
15
|
try {
|
|
11
16
|
const registryManager = new RegistryManager();
|
|
12
17
|
const embeddingService = new EmbeddingService(process.env.OPENAI_API_KEY);
|
|
13
|
-
const
|
|
18
|
+
const vectorStore = new VectorStore();
|
|
19
|
+
const projectKnowledgeService = new ProjectKnowledgeService(process.env.OPENAI_API_KEY);
|
|
20
|
+
console.error("\n=== Starting Project Synchronization ===");
|
|
21
|
+
// Step 1: Discover ALL projects from multiple sources
|
|
22
|
+
console.error("\nStep 1: Discovering projects from all sources...");
|
|
23
|
+
// 1a. Find projects with indexed code
|
|
24
|
+
const indexedProjectIds = await vectorStore.getIndexedProjectIds();
|
|
25
|
+
console.error(` - Found ${indexedProjectIds.length} projects with indexed code`);
|
|
26
|
+
// 1b. Find projects with documentation folders (auto-recovery!)
|
|
27
|
+
const storagePath = process.env.MEMORYBANK_STORAGE_PATH || path.join(os.homedir(), '.memorybank');
|
|
28
|
+
const projectsDir = path.join(storagePath, 'projects');
|
|
29
|
+
let documentedProjectIds = [];
|
|
30
|
+
if (fs.existsSync(projectsDir)) {
|
|
31
|
+
const entries = fs.readdirSync(projectsDir, { withFileTypes: true });
|
|
32
|
+
documentedProjectIds = entries
|
|
33
|
+
.filter(e => e.isDirectory())
|
|
34
|
+
.map(e => e.name);
|
|
35
|
+
console.error(` - Found ${documentedProjectIds.length} projects with documentation folders`);
|
|
36
|
+
}
|
|
37
|
+
// 1c. Combine all discovered projects (unique)
|
|
38
|
+
const allProjectIds = Array.from(new Set([...indexedProjectIds, ...documentedProjectIds]));
|
|
39
|
+
console.error(` - Total unique projects discovered: ${allProjectIds.length}`);
|
|
40
|
+
if (allProjectIds.length > 0) {
|
|
41
|
+
console.error(` - Projects: ${allProjectIds.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
// Step 2: Sync existing registry to vector store
|
|
44
|
+
console.error("\nStep 2: Syncing existing registry to vector store...");
|
|
45
|
+
const registryResult = await registryManager.syncRegistry(embeddingService);
|
|
46
|
+
console.error(`Registry sync: ${registryResult.processed} processed, ${registryResult.failures} failures`);
|
|
47
|
+
// Step 3: For each discovered project, ensure it has documentation and registry entry
|
|
48
|
+
let docsGenerated = 0;
|
|
49
|
+
let docsSkipped = 0;
|
|
50
|
+
let docsFailed = 0;
|
|
51
|
+
let registryRecovered = 0;
|
|
52
|
+
console.error("\nStep 3: Ensuring documentation and registry for all discovered projects...");
|
|
53
|
+
for (const projectId of allProjectIds) {
|
|
54
|
+
try {
|
|
55
|
+
console.error(`\nProcessing project: ${projectId}`);
|
|
56
|
+
// Check if project has documentation
|
|
57
|
+
const hasDocumentation = projectKnowledgeService.isProjectInitialized(projectId);
|
|
58
|
+
const hasIndexedCode = indexedProjectIds.includes(projectId);
|
|
59
|
+
if (!hasDocumentation && hasIndexedCode) {
|
|
60
|
+
console.error(` - No documentation found, generating...`);
|
|
61
|
+
// Generate documentation (this will automatically update registry)
|
|
62
|
+
const chunks = await vectorStore.getAllChunks(projectId);
|
|
63
|
+
if (chunks.length > 0) {
|
|
64
|
+
const result = await projectKnowledgeService.generateAllDocuments(projectId, chunks, false // Don't force regeneration
|
|
65
|
+
);
|
|
66
|
+
if (result.success) {
|
|
67
|
+
console.error(` - Documentation generated successfully`);
|
|
68
|
+
// Generate and update registry
|
|
69
|
+
const summary = await projectKnowledgeService.generateProjectSummary(projectId);
|
|
70
|
+
if (summary) {
|
|
71
|
+
// Try to find existing workspace path from registry
|
|
72
|
+
let workspacePath = '';
|
|
73
|
+
const existingProject = await registryManager.getProject(projectId);
|
|
74
|
+
if (existingProject) {
|
|
75
|
+
workspacePath = existingProject.path;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Try to infer from chunks
|
|
79
|
+
const firstChunk = chunks[0];
|
|
80
|
+
if (firstChunk && firstChunk.file_path) {
|
|
81
|
+
// Extract workspace path (this is a guess, may not be perfect)
|
|
82
|
+
workspacePath = process.cwd();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await registryManager.registerProject(projectId, workspacePath, summary.description, summary.keywords, embeddingService, {
|
|
86
|
+
responsibilities: summary.responsibilities,
|
|
87
|
+
owns: summary.owns,
|
|
88
|
+
exports: summary.exports,
|
|
89
|
+
projectType: summary.projectType,
|
|
90
|
+
});
|
|
91
|
+
console.error(` - Registry updated with project summary`);
|
|
92
|
+
docsGenerated++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.error(` - Failed to generate documentation`);
|
|
97
|
+
docsFailed++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.error(` - No chunks found for project, skipping`);
|
|
102
|
+
docsSkipped++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (hasDocumentation) {
|
|
106
|
+
console.error(` - Documentation already exists, ensuring registry is up-to-date...`);
|
|
107
|
+
// Documentation exists, regenerate/update registry from it (RECOVERY!)
|
|
108
|
+
try {
|
|
109
|
+
const summary = await projectKnowledgeService.generateProjectSummary(projectId);
|
|
110
|
+
if (summary) {
|
|
111
|
+
const existingProject = await registryManager.getProject(projectId);
|
|
112
|
+
const workspacePath = existingProject?.path || process.cwd();
|
|
113
|
+
await registryManager.registerProject(projectId, workspacePath, summary.description, summary.keywords, embeddingService, {
|
|
114
|
+
responsibilities: summary.responsibilities,
|
|
115
|
+
owns: summary.owns,
|
|
116
|
+
exports: summary.exports,
|
|
117
|
+
projectType: summary.projectType,
|
|
118
|
+
});
|
|
119
|
+
console.error(` - Registry updated/recovered from documentation`);
|
|
120
|
+
registryRecovered++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error(` - Error recovering registry from docs: ${error}`);
|
|
125
|
+
}
|
|
126
|
+
docsSkipped++;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.error(` - No documentation and no indexed code, skipping`);
|
|
130
|
+
docsSkipped++;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.error(` - Error processing project ${projectId}: ${error}`);
|
|
135
|
+
docsFailed++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
console.error("\n=== Synchronization Complete ===");
|
|
139
|
+
console.error(`Projects discovered: ${allProjectIds.length} total`);
|
|
140
|
+
console.error(` - From indexed code: ${indexedProjectIds.length}`);
|
|
141
|
+
console.error(` - From documentation folders: ${documentedProjectIds.length}`);
|
|
142
|
+
console.error(`Registry synced: ${registryResult.processed} projects`);
|
|
143
|
+
console.error(`Registry recovered from docs: ${registryRecovered} projects`);
|
|
144
|
+
console.error(`Documentation generated: ${docsGenerated} projects`);
|
|
145
|
+
console.error(`Documentation skipped (already exists): ${docsSkipped} projects`);
|
|
146
|
+
console.error(`Failures: ${registryResult.failures + docsFailed}`);
|
|
14
147
|
return {
|
|
15
148
|
success: true,
|
|
16
|
-
message: `Synchronization complete.
|
|
17
|
-
details:
|
|
149
|
+
message: `Synchronization complete. Discovered ${allProjectIds.length} projects (${indexedProjectIds.length} indexed, ${documentedProjectIds.length} documented). Registry recovered: ${registryRecovered}, Docs generated: ${docsGenerated}, Failures: ${registryResult.failures + docsFailed}`,
|
|
150
|
+
details: {
|
|
151
|
+
discovery: {
|
|
152
|
+
total: allProjectIds.length,
|
|
153
|
+
indexed: indexedProjectIds.length,
|
|
154
|
+
documented: documentedProjectIds.length,
|
|
155
|
+
projects: allProjectIds
|
|
156
|
+
},
|
|
157
|
+
registrySync: registryResult,
|
|
158
|
+
registryRecovery: {
|
|
159
|
+
recovered: registryRecovered
|
|
160
|
+
},
|
|
161
|
+
documentationGeneration: {
|
|
162
|
+
generated: docsGenerated,
|
|
163
|
+
skipped: docsSkipped,
|
|
164
|
+
failed: docsFailed
|
|
165
|
+
}
|
|
166
|
+
}
|
|
18
167
|
};
|
|
19
168
|
}
|
|
20
169
|
catch (error) {
|
|
@@ -26,7 +175,26 @@ export async function syncProjectsTool() {
|
|
|
26
175
|
}
|
|
27
176
|
export const syncProjectsToolDefinition = {
|
|
28
177
|
name: "memorybank_sync_projects",
|
|
29
|
-
description:
|
|
178
|
+
description: `Sincroniza y recupera automáticamente todos los proyectos desde múltiples fuentes.
|
|
179
|
+
|
|
180
|
+
Esta herramienta realiza una sincronización completa con AUTO-RECUPERACIÓN:
|
|
181
|
+
|
|
182
|
+
DESCUBRIMIENTO MULTI-FUENTE:
|
|
183
|
+
1. Escanea carpetas de documentación (.memorybank/projects/*)
|
|
184
|
+
2. Escanea código indexado en vector store
|
|
185
|
+
3. Lee registry JSON existente (si existe)
|
|
186
|
+
|
|
187
|
+
RECUPERACIÓN AUTOMÁTICA:
|
|
188
|
+
- Si el registry.json se corrompe o vacía, lo reconstruye desde las carpetas de documentación
|
|
189
|
+
- Genera documentación para código indexado sin docs
|
|
190
|
+
- Actualiza registry con responsabilidades extraídas
|
|
191
|
+
|
|
192
|
+
Útil cuando:
|
|
193
|
+
- El registry.json se ha corrompido o vaciado (AUTO-RECUPERA desde carpetas!)
|
|
194
|
+
- Has indexado código pero no has generado documentación
|
|
195
|
+
- El registry está desactualizado o incompleto
|
|
196
|
+
- Necesitas poblar las responsabilidades de proyectos para el orquestador
|
|
197
|
+
- Has perdido proyectos del registry pero las carpetas siguen existiendo`,
|
|
30
198
|
inputSchema: {
|
|
31
199
|
type: "object",
|
|
32
200
|
properties: {}
|