@grec0/memory-bank-mcp 0.1.41 → 0.2.1
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 +151 -4
- package/dist/common/projectKnowledgeService.js +66 -0
- package/dist/common/registryManager.js +36 -5
- package/dist/common/version.js +1 -1
- package/dist/index.js +15 -0
- package/dist/tools/generateProjectDocs.js +37 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/routeTask.js +302 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,6 +59,13 @@ With Memory Bank, AIs:
|
|
|
59
59
|
- **🆔 Identity Management**: Tracks who is doing what (GitHub Copilot, Cursor, etc.)
|
|
60
60
|
- **🔒 Atomic Locks**: File-system based locking safe across different processes/IDEs
|
|
61
61
|
|
|
62
|
+
### Task Orchestration (Smart Routing) 🧭 NEW
|
|
63
|
+
- **🎯 Intelligent Routing**: Analyzes tasks BEFORE implementation to determine ownership
|
|
64
|
+
- **📋 Enriched Project Registry**: Projects have responsibilities, ownership, and exports metadata
|
|
65
|
+
- **🤖 AI Reasoning**: Uses reasoning models to distribute work across projects
|
|
66
|
+
- **🔀 Auto-Delegation**: Automatically identifies what should be delegated to other projects
|
|
67
|
+
- **📦 Import Suggestions**: Recommends what to import from other projects instead of reimplementing
|
|
68
|
+
|
|
62
69
|
## 📋 Requirements
|
|
63
70
|
|
|
64
71
|
- **Node.js** >= 18.0.0
|
|
@@ -294,13 +301,16 @@ Reads generated documentation.
|
|
|
294
301
|
1. Index code
|
|
295
302
|
memorybank_index_code({ projectId: "my-project" })
|
|
296
303
|
|
|
297
|
-
2. Generate documentation
|
|
304
|
+
2. Generate documentation (also updates global registry)
|
|
298
305
|
memorybank_generate_project_docs({ projectId: "my-project" })
|
|
299
306
|
|
|
300
307
|
3. Query documentation at the start of each session
|
|
301
308
|
memorybank_get_project_docs({ projectId: "my-project", document: "activeContext" })
|
|
302
309
|
|
|
303
|
-
4.
|
|
310
|
+
4. Route task BEFORE implementing (mandatory in auto-index mode)
|
|
311
|
+
memorybank_route_task({ projectId: "my-project", taskDescription: "..." })
|
|
312
|
+
|
|
313
|
+
5. Search specific code
|
|
304
314
|
memorybank_search({ projectId: "my-project", query: "..." })
|
|
305
315
|
```
|
|
306
316
|
|
|
@@ -308,6 +318,21 @@ Reads generated documentation.
|
|
|
308
318
|
|
|
309
319
|
If you configure `MEMORYBANK_AUTO_UPDATE_DOCS=true`, documents will be automatically regenerated after each indexing. This is useful for keeping documentation always up to date but consumes more API tokens.
|
|
310
320
|
|
|
321
|
+
### Upgrading Existing Projects 🆕
|
|
322
|
+
|
|
323
|
+
If you have projects already initialized with a previous version, simply regenerate the docs to enable Task Orchestration:
|
|
324
|
+
|
|
325
|
+
```json
|
|
326
|
+
// For each existing project:
|
|
327
|
+
memorybank_generate_project_docs({ "projectId": "your-project", "force": true })
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
This will:
|
|
331
|
+
1. Regenerate all 6 markdown documents
|
|
332
|
+
2. **NEW**: Extract responsibilities, ownership, and exports
|
|
333
|
+
3. **NEW**: Update `global_registry.json` with enriched metadata
|
|
334
|
+
4. Enable `memorybank_route_task` to work with this project
|
|
335
|
+
|
|
311
336
|
---
|
|
312
337
|
|
|
313
338
|
## 🤖 Multi-Agent Coordination
|
|
@@ -382,6 +407,71 @@ memorybank_delegate_task({
|
|
|
382
407
|
})
|
|
383
408
|
```
|
|
384
409
|
|
|
410
|
+
### Task Orchestration (Smart Routing) 🧭 NEW
|
|
411
|
+
|
|
412
|
+
The **Task Orchestrator** analyzes tasks BEFORE implementation to prevent agents from creating code that belongs to other projects.
|
|
413
|
+
|
|
414
|
+
#### Why is this needed?
|
|
415
|
+
|
|
416
|
+
Without orchestration, agents often:
|
|
417
|
+
- ❌ Create DTOs in the API project when `lib-dtos` exists
|
|
418
|
+
- ❌ Duplicate utilities that are already in `shared-utils`
|
|
419
|
+
- ❌ Implement features that belong to other microservices
|
|
420
|
+
- ❌ Violate architectural boundaries unknowingly
|
|
421
|
+
|
|
422
|
+
With the orchestrator:
|
|
423
|
+
- ✅ Know exactly what belongs to this project
|
|
424
|
+
- ✅ Automatically delegate work to the right project
|
|
425
|
+
- ✅ Get import suggestions instead of reimplementing
|
|
426
|
+
- ✅ Respect ecosystem boundaries
|
|
427
|
+
|
|
428
|
+
#### How It Works
|
|
429
|
+
|
|
430
|
+
1. **Enriched Registry**: When you run `memorybank_generate_project_docs`, it automatically extracts:
|
|
431
|
+
- `responsibilities`: What this project is responsible for
|
|
432
|
+
- `owns`: Files/folders that belong to this project
|
|
433
|
+
- `exports`: What this project provides to others
|
|
434
|
+
- `projectType`: api, library, frontend, backend, etc.
|
|
435
|
+
|
|
436
|
+
2. **Route Before Implementing**: Call `memorybank_route_task` BEFORE any code changes:
|
|
437
|
+
```json
|
|
438
|
+
memorybank_route_task({
|
|
439
|
+
"projectId": "my-api",
|
|
440
|
+
"taskDescription": "Create DTOs for user management and expose REST endpoints"
|
|
441
|
+
})
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
3. **Orchestrator Response**:
|
|
445
|
+
```json
|
|
446
|
+
{
|
|
447
|
+
"action": "partial_delegate",
|
|
448
|
+
"myResponsibilities": [
|
|
449
|
+
"Create REST endpoints in src/controllers/",
|
|
450
|
+
"Implement business logic in src/services/"
|
|
451
|
+
],
|
|
452
|
+
"delegations": [
|
|
453
|
+
{
|
|
454
|
+
"targetProjectId": "lib-dtos",
|
|
455
|
+
"taskTitle": "Create UserDTO and UserResponseDTO",
|
|
456
|
+
"reason": "DTOs belong to lib-dtos per project responsibilities"
|
|
457
|
+
}
|
|
458
|
+
],
|
|
459
|
+
"suggestedImports": [
|
|
460
|
+
"import { UserDTO } from 'lib-dtos'"
|
|
461
|
+
],
|
|
462
|
+
"architectureNotes": "Use shared DTOs to maintain consistency across services"
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
#### Possible Actions
|
|
467
|
+
|
|
468
|
+
| Action | Meaning |
|
|
469
|
+
|--------|--------|
|
|
470
|
+
| `implement_here` | Everything belongs to this project, proceed |
|
|
471
|
+
| `delegate_all` | Nothing belongs here, delegate everything |
|
|
472
|
+
| `partial_delegate` | Some parts belong here, delegate the rest |
|
|
473
|
+
| `needs_clarification` | Task is ambiguous, ask user for details |
|
|
474
|
+
|
|
385
475
|
---
|
|
386
476
|
|
|
387
477
|
## 🔀 Multi-Project: Cross-Project Queries
|
|
@@ -524,9 +614,36 @@ Analyzes project indexing coverage.
|
|
|
524
614
|
}
|
|
525
615
|
```
|
|
526
616
|
|
|
617
|
+
### `memorybank_route_task` 🆕
|
|
618
|
+
|
|
619
|
+
Analyzes a task and determines what belongs to this project vs what should be delegated. **MUST be called BEFORE any implementation.**
|
|
620
|
+
|
|
621
|
+
**Parameters:**
|
|
622
|
+
- `projectId` **(REQUIRED)**: Project requesting the routing
|
|
623
|
+
- `taskDescription` **(REQUIRED)**: Detailed description of what needs to be implemented
|
|
624
|
+
|
|
625
|
+
**Example:**
|
|
626
|
+
```json
|
|
627
|
+
{
|
|
628
|
+
"projectId": "my-api",
|
|
629
|
+
"taskDescription": "Create user registration endpoint with validation and DTOs"
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
**Response:**
|
|
634
|
+
```json
|
|
635
|
+
{
|
|
636
|
+
"action": "partial_delegate",
|
|
637
|
+
"myResponsibilities": ["Create POST /users endpoint", "Add validation middleware"],
|
|
638
|
+
"delegations": [{ "targetProjectId": "lib-dtos", "taskTitle": "Create UserDTO" }],
|
|
639
|
+
"suggestedImports": ["import { UserDTO } from 'lib-dtos'"],
|
|
640
|
+
"architectureNotes": "Follow REST conventions, use shared DTOs"
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
527
644
|
### `memorybank_generate_project_docs`
|
|
528
645
|
|
|
529
|
-
Generates structured project documentation using AI with reasoning.
|
|
646
|
+
Generates structured project documentation using AI with reasoning. **Also automatically updates the global registry with enriched project metadata** (responsibilities, owns, exports, projectType).
|
|
530
647
|
|
|
531
648
|
**Parameters:**
|
|
532
649
|
- `projectId` **(REQUIRED)**: Project identifier
|
|
@@ -721,11 +838,13 @@ Memory Bank includes instruction templates in two formats to configure agent beh
|
|
|
721
838
|
**For active development with automatic synchronization.**
|
|
722
839
|
|
|
723
840
|
- ✅ Agent consults Memory Bank automatically
|
|
841
|
+
- ✅ **Routes tasks before implementing** (Rule 0.5)
|
|
724
842
|
- ✅ Reindexes EVERY file after modifying it
|
|
725
843
|
- ✅ Keeps Memory Bank always up to date
|
|
726
844
|
- ✅ Can read/write files directly
|
|
845
|
+
- ✅ **Auto-delegates to other projects** when appropriate
|
|
727
846
|
|
|
728
|
-
**Ideal for**: Active development, rapid iteration, teams
|
|
847
|
+
**Ideal for**: Active development, rapid iteration, teams, **multi-project ecosystems**.
|
|
729
848
|
|
|
730
849
|
### 3. Sandboxed Mode
|
|
731
850
|
|
|
@@ -889,9 +1008,37 @@ Claude: [executes memorybank_generate_project_docs({ projectId: "my-app" })]
|
|
|
889
1008
|
- techContext.md: Tech stack
|
|
890
1009
|
...
|
|
891
1010
|
|
|
1011
|
+
Also updated the global registry with project responsibilities.
|
|
892
1012
|
You can query them anytime with memorybank_get_project_docs
|
|
893
1013
|
```
|
|
894
1014
|
|
|
1015
|
+
### 5. Task Orchestration (Multi-Project) 🆕
|
|
1016
|
+
|
|
1017
|
+
```
|
|
1018
|
+
User: I need to add a UserDTO for the new registration endpoint
|
|
1019
|
+
Claude: [executes memorybank_route_task({
|
|
1020
|
+
projectId: "my-api",
|
|
1021
|
+
taskDescription: "Create UserDTO for registration endpoint"
|
|
1022
|
+
})]
|
|
1023
|
+
|
|
1024
|
+
The orchestrator analyzed your ecosystem and determined:
|
|
1025
|
+
|
|
1026
|
+
❌ DTOs should NOT be created in my-api
|
|
1027
|
+
✅ DTOs belong to lib-dtos project
|
|
1028
|
+
|
|
1029
|
+
I'll delegate the DTO creation to lib-dtos and import it:
|
|
1030
|
+
|
|
1031
|
+
[executes memorybank_delegate_task({
|
|
1032
|
+
projectId: "my-api",
|
|
1033
|
+
targetProjectId: "lib-dtos",
|
|
1034
|
+
title: "Create UserDTO",
|
|
1035
|
+
description: "DTO for user registration with email, password fields"
|
|
1036
|
+
})]
|
|
1037
|
+
|
|
1038
|
+
Task delegated! Once lib-dtos creates the DTO, you can:
|
|
1039
|
+
import { UserDTO } from 'lib-dtos'
|
|
1040
|
+
```
|
|
1041
|
+
|
|
895
1042
|
---
|
|
896
1043
|
|
|
897
1044
|
## 🔧 Configuration Files
|
|
@@ -1008,6 +1008,72 @@ ${chunk.content}
|
|
|
1008
1008
|
const files = fs.readdirSync(docsPath);
|
|
1009
1009
|
return files.filter(f => f.endsWith(".md"));
|
|
1010
1010
|
}
|
|
1011
|
+
// ==========================================
|
|
1012
|
+
// Project Summary Generation (for Registry)
|
|
1013
|
+
// ==========================================
|
|
1014
|
+
/**
|
|
1015
|
+
* Generates a structured summary of the project for the global registry.
|
|
1016
|
+
* Extracts responsibilities, ownership patterns, and project type from projectBrief.
|
|
1017
|
+
* This is called automatically after generateAllDocuments.
|
|
1018
|
+
*/
|
|
1019
|
+
async generateProjectSummary(projectId) {
|
|
1020
|
+
const projectBrief = this.getDocument(projectId, "projectBrief");
|
|
1021
|
+
const techContext = this.getDocument(projectId, "techContext");
|
|
1022
|
+
if (!projectBrief) {
|
|
1023
|
+
console.error(`Cannot generate project summary: projectBrief not found for ${projectId}`);
|
|
1024
|
+
return null;
|
|
1025
|
+
}
|
|
1026
|
+
console.error(`Generating project summary for registry: ${projectId}`);
|
|
1027
|
+
const prompt = `Analyze the following project documentation and extract a structured summary.
|
|
1028
|
+
|
|
1029
|
+
PROJECT BRIEF:
|
|
1030
|
+
${projectBrief.content}
|
|
1031
|
+
|
|
1032
|
+
${techContext ? `TECHNICAL CONTEXT:\n${techContext.content}` : ''}
|
|
1033
|
+
|
|
1034
|
+
Extract the following information in JSON format:
|
|
1035
|
+
{
|
|
1036
|
+
"description": "A concise 1-2 sentence description of what this project does",
|
|
1037
|
+
"responsibilities": ["List of 3-5 specific things this project is responsible for"],
|
|
1038
|
+
"owns": ["File patterns or types this project owns, e.g., '*DTO.ts', 'services/', 'controllers/'"],
|
|
1039
|
+
"projectType": "One of: api, library, frontend, backend, cli, service, monorepo, fullstack",
|
|
1040
|
+
"exports": "Package name if it's a library (e.g., '@company/lib-dtos'), or null if not applicable",
|
|
1041
|
+
"keywords": ["5-8 keywords describing this project"]
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
IMPORTANT:
|
|
1045
|
+
- Be specific about responsibilities - they help the orchestrator decide where code belongs
|
|
1046
|
+
- For "owns", think about what file patterns ONLY this project should create
|
|
1047
|
+
- If it's a library, identify what it exports/provides to other projects
|
|
1048
|
+
|
|
1049
|
+
Respond ONLY with the JSON object, no markdown or explanation.`;
|
|
1050
|
+
try {
|
|
1051
|
+
const result = await this.callResponsesAPI(prompt);
|
|
1052
|
+
// Parse JSON response
|
|
1053
|
+
const jsonMatch = result.content.match(/\{[\s\S]*\}/);
|
|
1054
|
+
if (!jsonMatch) {
|
|
1055
|
+
console.error(`Failed to parse project summary JSON for ${projectId}`);
|
|
1056
|
+
return null;
|
|
1057
|
+
}
|
|
1058
|
+
const summary = JSON.parse(jsonMatch[0]);
|
|
1059
|
+
console.error(`Project summary generated for ${projectId}:`);
|
|
1060
|
+
console.error(` - Type: ${summary.projectType}`);
|
|
1061
|
+
console.error(` - Responsibilities: ${summary.responsibilities?.length || 0}`);
|
|
1062
|
+
console.error(` - Owns: ${summary.owns?.length || 0}`);
|
|
1063
|
+
return {
|
|
1064
|
+
description: summary.description || '',
|
|
1065
|
+
responsibilities: summary.responsibilities || [],
|
|
1066
|
+
owns: summary.owns || [],
|
|
1067
|
+
projectType: summary.projectType || 'unknown',
|
|
1068
|
+
exports: summary.exports || undefined,
|
|
1069
|
+
keywords: summary.keywords || [],
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
catch (error) {
|
|
1073
|
+
console.error(`Error generating project summary: ${error}`);
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1011
1077
|
}
|
|
1012
1078
|
/**
|
|
1013
1079
|
* Creates a Project Knowledge Service from environment variables
|
|
@@ -22,10 +22,10 @@ export class RegistryManager {
|
|
|
22
22
|
async saveRegistry(registry) {
|
|
23
23
|
await fs.writeFile(this.globalPath, JSON.stringify(registry, null, 2), 'utf-8');
|
|
24
24
|
}
|
|
25
|
-
async registerProject(projectId, workspacePath, description, keywords = [], embeddingService) {
|
|
25
|
+
async registerProject(projectId, workspacePath, description, keywords = [], embeddingService, enhancedInfo) {
|
|
26
26
|
const registry = await this.ensureRegistry();
|
|
27
27
|
const idx = registry.projects.findIndex(p => p.projectId === projectId);
|
|
28
|
-
// Preserve existing
|
|
28
|
+
// Preserve existing data if not provided
|
|
29
29
|
const existing = idx >= 0 ? registry.projects[idx] : null;
|
|
30
30
|
const card = {
|
|
31
31
|
projectId,
|
|
@@ -33,7 +33,12 @@ export class RegistryManager {
|
|
|
33
33
|
description: description || existing?.description || '',
|
|
34
34
|
keywords: keywords.length > 0 ? keywords : (existing?.keywords || []),
|
|
35
35
|
lastActive: new Date().toISOString(),
|
|
36
|
-
status: 'ACTIVE'
|
|
36
|
+
status: 'ACTIVE',
|
|
37
|
+
// Enhanced fields - preserve existing if not provided
|
|
38
|
+
responsibilities: enhancedInfo?.responsibilities || existing?.responsibilities,
|
|
39
|
+
owns: enhancedInfo?.owns || existing?.owns,
|
|
40
|
+
exports: enhancedInfo?.exports || existing?.exports,
|
|
41
|
+
projectType: enhancedInfo?.projectType || existing?.projectType,
|
|
37
42
|
};
|
|
38
43
|
if (idx >= 0) {
|
|
39
44
|
registry.projects[idx] = card;
|
|
@@ -53,12 +58,30 @@ export class RegistryManager {
|
|
|
53
58
|
}
|
|
54
59
|
}
|
|
55
60
|
async updateProjectEmbedding(card, embeddingService) {
|
|
56
|
-
|
|
61
|
+
// Build rich text for embedding including responsibilities
|
|
62
|
+
const textParts = [
|
|
63
|
+
`Project: ${card.projectId}`,
|
|
64
|
+
`Description: ${card.description || ''}`,
|
|
65
|
+
`Keywords: ${card.keywords.join(', ')}`,
|
|
66
|
+
];
|
|
67
|
+
if (card.responsibilities && card.responsibilities.length > 0) {
|
|
68
|
+
textParts.push(`Responsibilities: ${card.responsibilities.join('. ')}`);
|
|
69
|
+
}
|
|
70
|
+
if (card.owns && card.owns.length > 0) {
|
|
71
|
+
textParts.push(`Owns: ${card.owns.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
if (card.projectType) {
|
|
74
|
+
textParts.push(`Type: ${card.projectType}`);
|
|
75
|
+
}
|
|
76
|
+
if (card.exports) {
|
|
77
|
+
textParts.push(`Exports: ${card.exports}`);
|
|
78
|
+
}
|
|
79
|
+
const text = textParts.join('\n');
|
|
57
80
|
const result = await embeddingService.generateEmbedding(card.projectId, text);
|
|
58
81
|
await this.projectVectorStore.upsertProject({
|
|
59
82
|
id: card.projectId,
|
|
60
83
|
vector: result.vector,
|
|
61
|
-
name: card.projectId,
|
|
84
|
+
name: card.projectId,
|
|
62
85
|
description: card.description || '',
|
|
63
86
|
tags: card.keywords,
|
|
64
87
|
path: card.path,
|
|
@@ -101,6 +124,14 @@ export class RegistryManager {
|
|
|
101
124
|
const registry = await this.ensureRegistry();
|
|
102
125
|
return registry.projects.find(p => p.projectId === projectId);
|
|
103
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Gets all projects from the registry.
|
|
129
|
+
* Useful for the orchestrator to analyze responsibilities across all projects.
|
|
130
|
+
*/
|
|
131
|
+
async getAllProjects() {
|
|
132
|
+
const registry = await this.ensureRegistry();
|
|
133
|
+
return registry.projects;
|
|
134
|
+
}
|
|
104
135
|
/**
|
|
105
136
|
* Syncs all projects from the JSON registry to the vector store.
|
|
106
137
|
* Useful for migrating existing projects to the new semantic discovery system.
|
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.2.1";
|
package/dist/index.js
CHANGED
|
@@ -83,6 +83,7 @@ import { manageAgentsTool, manageAgentsToolDefinition } from "./tools/manageAgen
|
|
|
83
83
|
import { discoverProjectsTool, discoverProjectsToolDefinition } from "./tools/discoverProjects.js";
|
|
84
84
|
import { delegateTaskTool, delegateTaskToolDefinition } from "./tools/delegateTask.js";
|
|
85
85
|
import { syncProjectsTool, syncProjectsToolDefinition } from "./tools/syncProjects.js";
|
|
86
|
+
import { routeTaskTool, routeTaskToolDefinition } from "./tools/routeTask.js";
|
|
86
87
|
import { RegistryManager } from "./common/registryManager.js";
|
|
87
88
|
import { VERSION } from "./common/version.js";
|
|
88
89
|
// Global services
|
|
@@ -864,6 +865,19 @@ server.tool(delegateTaskToolDefinition.name, delegateTaskToolDefinition.descript
|
|
|
864
865
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
865
866
|
};
|
|
866
867
|
});
|
|
868
|
+
// Tool: Route Task (Orchestrator)
|
|
869
|
+
server.tool(routeTaskToolDefinition.name, routeTaskToolDefinition.description, {
|
|
870
|
+
projectId: z.string().describe("ID del proyecto que está solicitando el enrutamiento"),
|
|
871
|
+
taskDescription: z.string().describe("Descripción detallada de la tarea a implementar")
|
|
872
|
+
}, async (args) => {
|
|
873
|
+
const result = await routeTaskTool({
|
|
874
|
+
projectId: args.projectId,
|
|
875
|
+
taskDescription: args.taskDescription
|
|
876
|
+
});
|
|
877
|
+
return {
|
|
878
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
879
|
+
};
|
|
880
|
+
});
|
|
867
881
|
/**
|
|
868
882
|
* Starts the stdio server
|
|
869
883
|
*/
|
|
@@ -900,6 +914,7 @@ async function startStdioServer() {
|
|
|
900
914
|
console.error(" - memorybank_complete_task: Marcar una tarea como completada");
|
|
901
915
|
console.error(" - memorybank_discover_projects: Descubrir otros proyectos en el ecosistema");
|
|
902
916
|
console.error(" - memorybank_delegate_task: Delegar tareas a otros proyectos");
|
|
917
|
+
console.error(" - memorybank_route_task: Orquestador - analiza y distribuye tareas");
|
|
903
918
|
console.error("");
|
|
904
919
|
console.error("Available resources:");
|
|
905
920
|
console.error(" - memory://{projectId}/active: Contexto activo");
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { AgentBoard } from "../common/agentBoard.js";
|
|
6
6
|
import { sessionLogger } from "../common/sessionLogger.js";
|
|
7
|
+
import { RegistryManager } from "../common/registryManager.js";
|
|
8
|
+
import { EmbeddingService } from "../common/embeddingService.js";
|
|
7
9
|
import { sessionState } from "../common/sessionState.js";
|
|
8
10
|
/**
|
|
9
11
|
* Generates project documentation using AI reasoning
|
|
@@ -94,6 +96,41 @@ export async function generateProjectDocs(params, projectKnowledgeService, vecto
|
|
|
94
96
|
console.error(` - Reasoning tokens: ${result.totalReasoningTokens}`);
|
|
95
97
|
console.error(` - Output tokens: ${result.totalOutputTokens}`);
|
|
96
98
|
console.error(` - Estimated cost: $${totalCost.toFixed(4)}`);
|
|
99
|
+
// === AUTO-UPDATE GLOBAL REGISTRY ===
|
|
100
|
+
// Generate project summary and update registry with enriched info
|
|
101
|
+
if (result.documentsGenerated.length > 0 || result.documentsUpdated.length > 0) {
|
|
102
|
+
try {
|
|
103
|
+
console.error(`\n=== Updating Global Registry ===`);
|
|
104
|
+
const summary = await projectKnowledgeService.generateProjectSummary(projectId);
|
|
105
|
+
if (summary) {
|
|
106
|
+
const registryManager = new RegistryManager();
|
|
107
|
+
let embeddingService;
|
|
108
|
+
if (process.env.OPENAI_API_KEY) {
|
|
109
|
+
try {
|
|
110
|
+
embeddingService = new EmbeddingService(process.env.OPENAI_API_KEY);
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
console.error(`Warning: Could not init embedding service: ${e}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
await registryManager.registerProject(projectId, workspaceRoot, summary.description, summary.keywords, embeddingService, {
|
|
117
|
+
responsibilities: summary.responsibilities,
|
|
118
|
+
owns: summary.owns,
|
|
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.`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (regError) {
|
|
130
|
+
console.error(`Warning: Failed to update registry: ${regError}`);
|
|
131
|
+
// Don't fail the whole operation if registry update fails
|
|
132
|
+
}
|
|
133
|
+
}
|
|
97
134
|
return {
|
|
98
135
|
success: result.success,
|
|
99
136
|
message,
|
package/dist/tools/index.js
CHANGED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task Routing Orchestrator
|
|
3
|
+
* Uses AI reasoning to analyze tasks and distribute work across projects
|
|
4
|
+
* based on their responsibilities. MANDATORY before any implementation.
|
|
5
|
+
*/
|
|
6
|
+
import OpenAI from "openai";
|
|
7
|
+
import { RegistryManager } from "../common/registryManager.js";
|
|
8
|
+
/**
|
|
9
|
+
* Builds a context string describing all projects and their responsibilities
|
|
10
|
+
*/
|
|
11
|
+
function buildProjectsContext(projects, currentProjectId) {
|
|
12
|
+
if (projects.length === 0) {
|
|
13
|
+
return "No other projects registered in the workspace.";
|
|
14
|
+
}
|
|
15
|
+
let context = "## Registered Projects in Workspace\n\n";
|
|
16
|
+
for (const project of projects) {
|
|
17
|
+
const isCurrent = project.projectId === currentProjectId;
|
|
18
|
+
context += `### ${project.projectId}${isCurrent ? ' (CURRENT - requesting agent)' : ''}\n`;
|
|
19
|
+
context += `- **Path**: ${project.path}\n`;
|
|
20
|
+
context += `- **Type**: ${project.projectType || 'unknown'}\n`;
|
|
21
|
+
context += `- **Description**: ${project.description || 'No description'}\n`;
|
|
22
|
+
if (project.responsibilities && project.responsibilities.length > 0) {
|
|
23
|
+
context += `- **Responsibilities**:\n`;
|
|
24
|
+
for (const resp of project.responsibilities) {
|
|
25
|
+
context += ` - ${resp}\n`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (project.owns && project.owns.length > 0) {
|
|
29
|
+
context += `- **Owns (file patterns)**: ${project.owns.join(', ')}\n`;
|
|
30
|
+
}
|
|
31
|
+
if (project.exports) {
|
|
32
|
+
context += `- **Exports**: ${project.exports}\n`;
|
|
33
|
+
}
|
|
34
|
+
context += '\n';
|
|
35
|
+
}
|
|
36
|
+
return context;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The main routing prompt for the AI orchestrator
|
|
40
|
+
*/
|
|
41
|
+
const ROUTING_PROMPT = `You are a Task Routing Orchestrator for a multi-project workspace. Your job is to analyze a task and determine which parts belong to which project based on their responsibilities.
|
|
42
|
+
|
|
43
|
+
{projectsContext}
|
|
44
|
+
|
|
45
|
+
## Task to Analyze
|
|
46
|
+
**From Project**: {currentProject}
|
|
47
|
+
**Task Description**: {taskDescription}
|
|
48
|
+
|
|
49
|
+
## Your Analysis
|
|
50
|
+
|
|
51
|
+
Analyze the task and determine:
|
|
52
|
+
1. What components/code need to be created or modified?
|
|
53
|
+
2. Which project is responsible for each component based on their declared responsibilities?
|
|
54
|
+
3. If something doesn't exist in any project, it can be created by the requesting project
|
|
55
|
+
4. If something SHOULD exist in another project (based on responsibilities), it must be delegated
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
- If a project is responsible for DTOs, ALL DTOs must be created there, not in the API
|
|
59
|
+
- If a project is responsible for services, shared services go there
|
|
60
|
+
- If a project is responsible for utils/common code, shared utilities go there
|
|
61
|
+
- The requesting project can ONLY implement what falls within its responsibilities
|
|
62
|
+
- When in doubt, check the "owns" patterns to see what file types belong where
|
|
63
|
+
|
|
64
|
+
## Response Format
|
|
65
|
+
Respond with a JSON object:
|
|
66
|
+
{
|
|
67
|
+
"action": "proceed" | "delegate" | "mixed",
|
|
68
|
+
"myResponsibilities": ["List of things the requesting project should implement"],
|
|
69
|
+
"delegations": [
|
|
70
|
+
{
|
|
71
|
+
"targetProject": "project-id",
|
|
72
|
+
"taskTitle": "Short title for the task",
|
|
73
|
+
"taskDescription": "Detailed description of what to create",
|
|
74
|
+
"reasoning": "Why this belongs to this project"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"suggestedImports": ["packages or modules to import after delegations complete"],
|
|
78
|
+
"architectureNotes": "Explanation of the distribution decision",
|
|
79
|
+
"warning": "Optional warning if something seems off"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
IMPORTANT:
|
|
83
|
+
- "action" is "proceed" if everything can be done by the requesting project
|
|
84
|
+
- "action" is "delegate" if everything needs to go to other projects
|
|
85
|
+
- "action" is "mixed" if some work is local and some needs delegation
|
|
86
|
+
- Be specific in taskDescription so the receiving project knows exactly what to create
|
|
87
|
+
- Always explain the reasoning based on project responsibilities
|
|
88
|
+
|
|
89
|
+
Respond ONLY with the JSON object.`;
|
|
90
|
+
/**
|
|
91
|
+
* Routes a task to the appropriate project(s) based on responsibilities
|
|
92
|
+
*/
|
|
93
|
+
export async function routeTaskTool(params) {
|
|
94
|
+
const { projectId, taskDescription } = params;
|
|
95
|
+
if (!taskDescription || taskDescription.trim() === '') {
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
action: 'proceed',
|
|
99
|
+
myResponsibilities: [],
|
|
100
|
+
delegations: [],
|
|
101
|
+
suggestedImports: [],
|
|
102
|
+
architectureNotes: 'No task description provided.',
|
|
103
|
+
warning: 'Please provide a task description to analyze.',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
console.error(`\n=== Task Routing Orchestrator ===`);
|
|
107
|
+
console.error(`Project: ${projectId}`);
|
|
108
|
+
console.error(`Task: ${taskDescription.slice(0, 100)}...`);
|
|
109
|
+
// Get all projects with their responsibilities
|
|
110
|
+
const registryManager = new RegistryManager();
|
|
111
|
+
const allProjects = await registryManager.getAllProjects();
|
|
112
|
+
console.error(`Found ${allProjects.length} projects in registry`);
|
|
113
|
+
// Check if we have any projects with responsibilities defined
|
|
114
|
+
const projectsWithResponsibilities = allProjects.filter(p => p.responsibilities && p.responsibilities.length > 0);
|
|
115
|
+
if (projectsWithResponsibilities.length === 0) {
|
|
116
|
+
console.error(`Warning: No projects have responsibilities defined`);
|
|
117
|
+
return {
|
|
118
|
+
success: true,
|
|
119
|
+
action: 'proceed',
|
|
120
|
+
myResponsibilities: ['All components (no other project responsibilities defined)'],
|
|
121
|
+
delegations: [],
|
|
122
|
+
suggestedImports: [],
|
|
123
|
+
architectureNotes: 'No other projects have responsibilities defined. You can proceed with the full implementation. Consider running memorybank_generate_project_docs on other projects to define their responsibilities.',
|
|
124
|
+
warning: 'No project responsibilities found in workspace. Run generate_project_docs on all projects first.',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Build context for the AI
|
|
128
|
+
const projectsContext = buildProjectsContext(allProjects, projectId);
|
|
129
|
+
// Call AI to analyze and route
|
|
130
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
131
|
+
if (!apiKey) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
action: 'proceed',
|
|
135
|
+
myResponsibilities: [],
|
|
136
|
+
delegations: [],
|
|
137
|
+
suggestedImports: [],
|
|
138
|
+
architectureNotes: 'OPENAI_API_KEY not configured. Cannot analyze task routing.',
|
|
139
|
+
warning: 'AI routing unavailable. Proceeding without validation.',
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const client = new OpenAI({ apiKey });
|
|
144
|
+
const prompt = ROUTING_PROMPT
|
|
145
|
+
.replace('{projectsContext}', projectsContext)
|
|
146
|
+
.replace('{currentProject}', projectId)
|
|
147
|
+
.replace('{taskDescription}', taskDescription);
|
|
148
|
+
console.error(`Calling AI orchestrator...`);
|
|
149
|
+
// Use reasoning model for better analysis
|
|
150
|
+
const model = process.env.MEMORYBANK_REASONING_MODEL || "gpt-5-mini";
|
|
151
|
+
const response = await client.responses.create({
|
|
152
|
+
model,
|
|
153
|
+
reasoning: {
|
|
154
|
+
effort: "medium",
|
|
155
|
+
},
|
|
156
|
+
input: [
|
|
157
|
+
{
|
|
158
|
+
role: "user",
|
|
159
|
+
content: prompt,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
max_output_tokens: 4000,
|
|
163
|
+
});
|
|
164
|
+
// Extract content from response
|
|
165
|
+
let content = "";
|
|
166
|
+
for (const item of response.output || []) {
|
|
167
|
+
if (item.type === "message" && item.content) {
|
|
168
|
+
for (const contentItem of item.content) {
|
|
169
|
+
if (contentItem.type === "output_text") {
|
|
170
|
+
content += contentItem.text;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Parse JSON response
|
|
176
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
177
|
+
if (!jsonMatch) {
|
|
178
|
+
console.error(`Failed to parse orchestrator response`);
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
action: 'proceed',
|
|
182
|
+
myResponsibilities: [],
|
|
183
|
+
delegations: [],
|
|
184
|
+
suggestedImports: [],
|
|
185
|
+
architectureNotes: 'Failed to parse AI response.',
|
|
186
|
+
warning: 'Orchestrator analysis failed. Review task manually.',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const result = JSON.parse(jsonMatch[0]);
|
|
190
|
+
console.error(`\nOrchestrator Decision:`);
|
|
191
|
+
console.error(` Action: ${result.action}`);
|
|
192
|
+
console.error(` My responsibilities: ${result.myResponsibilities?.length || 0}`);
|
|
193
|
+
console.error(` Delegations: ${result.delegations?.length || 0}`);
|
|
194
|
+
if (result.delegations && result.delegations.length > 0) {
|
|
195
|
+
console.error(`\n Delegations:`);
|
|
196
|
+
for (const d of result.delegations) {
|
|
197
|
+
console.error(` → ${d.targetProject}: ${d.taskTitle}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
success: true,
|
|
202
|
+
action: result.action || 'proceed',
|
|
203
|
+
myResponsibilities: result.myResponsibilities || [],
|
|
204
|
+
delegations: result.delegations || [],
|
|
205
|
+
suggestedImports: result.suggestedImports || [],
|
|
206
|
+
architectureNotes: result.architectureNotes || '',
|
|
207
|
+
warning: result.warning,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
console.error(`Error in task routing: ${error.message}`);
|
|
212
|
+
// Fallback to chat completions if responses API fails
|
|
213
|
+
if (error?.status === 404 || error?.code === "model_not_found") {
|
|
214
|
+
try {
|
|
215
|
+
const client = new OpenAI({ apiKey });
|
|
216
|
+
const prompt = ROUTING_PROMPT
|
|
217
|
+
.replace('{projectsContext}', projectsContext)
|
|
218
|
+
.replace('{currentProject}', projectId)
|
|
219
|
+
.replace('{taskDescription}', taskDescription);
|
|
220
|
+
const response = await client.chat.completions.create({
|
|
221
|
+
model: "gpt-4o",
|
|
222
|
+
messages: [
|
|
223
|
+
{
|
|
224
|
+
role: "system",
|
|
225
|
+
content: "You are a Task Routing Orchestrator. Analyze tasks and route them to the appropriate projects based on responsibilities. Respond with JSON only.",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
role: "user",
|
|
229
|
+
content: prompt,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
max_tokens: 4000,
|
|
233
|
+
});
|
|
234
|
+
const content = response.choices[0]?.message?.content || "";
|
|
235
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
236
|
+
if (jsonMatch) {
|
|
237
|
+
const result = JSON.parse(jsonMatch[0]);
|
|
238
|
+
return {
|
|
239
|
+
success: true,
|
|
240
|
+
action: result.action || 'proceed',
|
|
241
|
+
myResponsibilities: result.myResponsibilities || [],
|
|
242
|
+
delegations: result.delegations || [],
|
|
243
|
+
suggestedImports: result.suggestedImports || [],
|
|
244
|
+
architectureNotes: result.architectureNotes || '',
|
|
245
|
+
warning: result.warning,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch (fallbackError) {
|
|
250
|
+
console.error(`Fallback also failed: ${fallbackError}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
success: false,
|
|
255
|
+
action: 'proceed',
|
|
256
|
+
myResponsibilities: [],
|
|
257
|
+
delegations: [],
|
|
258
|
+
suggestedImports: [],
|
|
259
|
+
architectureNotes: `Error analyzing task: ${error.message}`,
|
|
260
|
+
warning: 'Orchestrator failed. Review task distribution manually.',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Tool definition for MCP
|
|
266
|
+
*/
|
|
267
|
+
export const routeTaskToolDefinition = {
|
|
268
|
+
name: "memorybank_route_task",
|
|
269
|
+
description: `🚨 OBLIGATORIO antes de implementar cualquier código.
|
|
270
|
+
|
|
271
|
+
Analiza una tarea y determina qué partes corresponden a qué proyecto según sus responsabilidades.
|
|
272
|
+
|
|
273
|
+
El orquestador:
|
|
274
|
+
1. Lee las responsabilidades de TODOS los proyectos del workspace
|
|
275
|
+
2. Analiza qué componentes necesita la tarea (DTOs, services, controllers, etc.)
|
|
276
|
+
3. Asigna cada componente al proyecto responsable
|
|
277
|
+
4. Devuelve un plan de acción con delegaciones
|
|
278
|
+
|
|
279
|
+
DEBES llamar esta herramienta ANTES de escribir código para evitar:
|
|
280
|
+
- Crear DTOs en un API cuando existe una lib-dtos
|
|
281
|
+
- Duplicar services que ya existen en otro proyecto
|
|
282
|
+
- Violar la separación de responsabilidades
|
|
283
|
+
|
|
284
|
+
La respuesta incluye:
|
|
285
|
+
- myResponsibilities: Lo que TÚ debes implementar
|
|
286
|
+
- delegations: Tareas a delegar a otros proyectos
|
|
287
|
+
- suggestedImports: Dependencias a usar tras las delegaciones`,
|
|
288
|
+
inputSchema: {
|
|
289
|
+
type: "object",
|
|
290
|
+
properties: {
|
|
291
|
+
projectId: {
|
|
292
|
+
type: "string",
|
|
293
|
+
description: "ID del proyecto que solicita el análisis (tu proyecto actual)",
|
|
294
|
+
},
|
|
295
|
+
taskDescription: {
|
|
296
|
+
type: "string",
|
|
297
|
+
description: "Descripción completa de la tarea a realizar",
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
required: ["projectId", "taskDescription"],
|
|
301
|
+
},
|
|
302
|
+
};
|