@grec0/memory-bank-mcp 0.0.3 → 0.0.4
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 +494 -420
- package/dist/common/chunker.js +166 -534
- package/dist/common/embeddingService.js +39 -51
- package/dist/common/fileScanner.js +123 -58
- package/dist/common/indexManager.js +135 -102
- package/dist/common/projectKnowledgeService.js +627 -0
- package/dist/common/setup.js +49 -0
- package/dist/common/utils.js +215 -0
- package/dist/common/vectorStore.js +80 -67
- package/dist/index.js +77 -9
- package/dist/operations/boardMemberships.js +186 -0
- package/dist/operations/boards.js +268 -0
- package/dist/operations/cards.js +426 -0
- package/dist/operations/comments.js +249 -0
- package/dist/operations/labels.js +258 -0
- package/dist/operations/lists.js +157 -0
- package/dist/operations/projects.js +102 -0
- package/dist/operations/tasks.js +238 -0
- package/dist/tools/analyzeCoverage.js +46 -66
- package/dist/tools/board-summary.js +151 -0
- package/dist/tools/card-details.js +106 -0
- package/dist/tools/create-card-with-tasks.js +81 -0
- package/dist/tools/generateProjectDocs.js +133 -0
- package/dist/tools/getProjectDocs.js +126 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/indexCode.js +0 -1
- package/dist/tools/searchMemory.js +2 -2
- package/dist/tools/workflow-actions.js +145 -0
- package/package.json +2 -2
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createCard } from "../operations/cards.js";
|
|
3
|
+
import { createTask } from "../operations/tasks.js";
|
|
4
|
+
import { createComment } from "../operations/comments.js";
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for the createCardWithTasks function parameters
|
|
7
|
+
* @property {string} listId - The ID of the list to create the card in
|
|
8
|
+
* @property {string} name - The name of the card
|
|
9
|
+
* @property {string} [description] - The description of the card
|
|
10
|
+
* @property {string[]} [tasks] - Array of task descriptions to create
|
|
11
|
+
* @property {string} [comment] - Optional comment to add to the card
|
|
12
|
+
* @property {number} [position] - Optional position for the card in the list
|
|
13
|
+
*/
|
|
14
|
+
export const createCardWithTasksSchema = z.object({
|
|
15
|
+
listId: z.string().describe("The ID of the list to create the card in"),
|
|
16
|
+
name: z.string().describe("The name of the card"),
|
|
17
|
+
description: z.string().optional().describe("The description of the card"),
|
|
18
|
+
tasks: z.array(z.string()).optional().describe("Array of task descriptions to create"),
|
|
19
|
+
comment: z.string().optional().describe("Optional comment to add to the card"),
|
|
20
|
+
position: z.number().optional().describe("Optional position for the card in the list"),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new card with tasks, description, and optional comment in a single operation
|
|
24
|
+
*
|
|
25
|
+
* This function streamlines the process of creating a card with associated tasks and comments
|
|
26
|
+
* by handling all the necessary API calls in a single function.
|
|
27
|
+
*
|
|
28
|
+
* @param {CreateCardWithTasksParams} params - Parameters for creating a card with tasks
|
|
29
|
+
* @param {string} params.listId - The ID of the list to create the card in
|
|
30
|
+
* @param {string} params.name - The name of the card
|
|
31
|
+
* @param {string} [params.description] - The description of the card
|
|
32
|
+
* @param {string[]} [params.tasks] - Array of task descriptions to create
|
|
33
|
+
* @param {string} [params.comment] - Optional comment to add to the card
|
|
34
|
+
* @param {number} [params.position] - Optional position for the card in the list
|
|
35
|
+
* @returns {Promise<object>} The created card, tasks, and comment
|
|
36
|
+
* @throws {Error} If there's an error creating the card, tasks, or comment
|
|
37
|
+
*/
|
|
38
|
+
export async function createCardWithTasks(params) {
|
|
39
|
+
const { listId, name, description, tasks, comment, position = 65535 } = params;
|
|
40
|
+
try {
|
|
41
|
+
// Create the card
|
|
42
|
+
const card = await createCard({
|
|
43
|
+
listId,
|
|
44
|
+
name,
|
|
45
|
+
description: description || "",
|
|
46
|
+
position,
|
|
47
|
+
});
|
|
48
|
+
// Create tasks if provided
|
|
49
|
+
const createdTasks = [];
|
|
50
|
+
if (tasks && tasks.length > 0) {
|
|
51
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
52
|
+
const taskName = tasks[i];
|
|
53
|
+
// Calculate position for each task (65535, 131070, 196605, etc.)
|
|
54
|
+
const taskPosition = 65535 * (i + 1);
|
|
55
|
+
const task = await createTask({
|
|
56
|
+
cardId: card.id,
|
|
57
|
+
name: taskName,
|
|
58
|
+
position: taskPosition,
|
|
59
|
+
});
|
|
60
|
+
createdTasks.push(task);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Add a comment if provided
|
|
64
|
+
let createdComment = null;
|
|
65
|
+
if (comment) {
|
|
66
|
+
createdComment = await createComment({
|
|
67
|
+
cardId: card.id,
|
|
68
|
+
text: comment,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
card,
|
|
73
|
+
tasks: createdTasks,
|
|
74
|
+
comment: createdComment,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error("Error in createCardWithTasks:", error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for generating project documentation
|
|
3
|
+
* Uses the Project Knowledge Service to create structured markdown docs
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generates project documentation using AI reasoning
|
|
7
|
+
*/
|
|
8
|
+
export async function generateProjectDocs(params, projectKnowledgeService, vectorStore) {
|
|
9
|
+
try {
|
|
10
|
+
console.error("\n=== Generating Project Documentation ===");
|
|
11
|
+
console.error(`Project ID: ${params.projectId || "default"}`);
|
|
12
|
+
console.error(`Force regeneration: ${params.force || false}`);
|
|
13
|
+
// Get all chunks from the vector store
|
|
14
|
+
const chunks = await vectorStore.getAllChunks(params.projectId);
|
|
15
|
+
if (chunks.length === 0) {
|
|
16
|
+
return {
|
|
17
|
+
success: false,
|
|
18
|
+
message: "No indexed code found. Please run memorybank_index_code first to index your project.",
|
|
19
|
+
result: {
|
|
20
|
+
success: false,
|
|
21
|
+
documentsGenerated: [],
|
|
22
|
+
documentsUpdated: [],
|
|
23
|
+
documentsSkipped: [],
|
|
24
|
+
totalReasoningTokens: 0,
|
|
25
|
+
totalOutputTokens: 0,
|
|
26
|
+
errors: ["No chunks available for documentation generation"],
|
|
27
|
+
},
|
|
28
|
+
tokenUsage: {
|
|
29
|
+
reasoningTokens: 0,
|
|
30
|
+
outputTokens: 0,
|
|
31
|
+
estimatedCost: "$0.00",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
console.error(`Found ${chunks.length} code chunks to analyze`);
|
|
36
|
+
// Generate documents
|
|
37
|
+
const result = await projectKnowledgeService.generateAllDocuments(chunks, params.force || false);
|
|
38
|
+
// Calculate estimated cost (approximate rates for gpt-5-mini)
|
|
39
|
+
// Reasoning tokens are typically more expensive
|
|
40
|
+
const reasoningCostPer1K = 0.003; // $0.003 per 1K reasoning tokens
|
|
41
|
+
const outputCostPer1K = 0.012; // $0.012 per 1K output tokens
|
|
42
|
+
const reasoningCost = (result.totalReasoningTokens / 1000) * reasoningCostPer1K;
|
|
43
|
+
const outputCost = (result.totalOutputTokens / 1000) * outputCostPer1K;
|
|
44
|
+
const totalCost = reasoningCost + outputCost;
|
|
45
|
+
// Build response message
|
|
46
|
+
let message = "";
|
|
47
|
+
if (result.documentsGenerated.length > 0) {
|
|
48
|
+
message += `Generated ${result.documentsGenerated.length} new document(s): ${result.documentsGenerated.join(", ")}. `;
|
|
49
|
+
}
|
|
50
|
+
if (result.documentsUpdated.length > 0) {
|
|
51
|
+
message += `Updated ${result.documentsUpdated.length} document(s): ${result.documentsUpdated.join(", ")}. `;
|
|
52
|
+
}
|
|
53
|
+
if (result.documentsSkipped.length > 0) {
|
|
54
|
+
message += `Skipped ${result.documentsSkipped.length} unchanged document(s). `;
|
|
55
|
+
}
|
|
56
|
+
if (result.errors.length > 0) {
|
|
57
|
+
message += `Errors: ${result.errors.join("; ")}`;
|
|
58
|
+
}
|
|
59
|
+
if (!message) {
|
|
60
|
+
message = "All documents are up to date.";
|
|
61
|
+
}
|
|
62
|
+
console.error(`\nGeneration complete:`);
|
|
63
|
+
console.error(` - Generated: ${result.documentsGenerated.length}`);
|
|
64
|
+
console.error(` - Updated: ${result.documentsUpdated.length}`);
|
|
65
|
+
console.error(` - Skipped: ${result.documentsSkipped.length}`);
|
|
66
|
+
console.error(` - Reasoning tokens: ${result.totalReasoningTokens}`);
|
|
67
|
+
console.error(` - Output tokens: ${result.totalOutputTokens}`);
|
|
68
|
+
console.error(` - Estimated cost: $${totalCost.toFixed(4)}`);
|
|
69
|
+
return {
|
|
70
|
+
success: result.success,
|
|
71
|
+
message,
|
|
72
|
+
result,
|
|
73
|
+
tokenUsage: {
|
|
74
|
+
reasoningTokens: result.totalReasoningTokens,
|
|
75
|
+
outputTokens: result.totalOutputTokens,
|
|
76
|
+
estimatedCost: `$${totalCost.toFixed(4)}`,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error(`Error generating project docs: ${error.message}`);
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
message: `Failed to generate project documentation: ${error.message}`,
|
|
85
|
+
result: {
|
|
86
|
+
success: false,
|
|
87
|
+
documentsGenerated: [],
|
|
88
|
+
documentsUpdated: [],
|
|
89
|
+
documentsSkipped: [],
|
|
90
|
+
totalReasoningTokens: 0,
|
|
91
|
+
totalOutputTokens: 0,
|
|
92
|
+
errors: [error.message],
|
|
93
|
+
},
|
|
94
|
+
tokenUsage: {
|
|
95
|
+
reasoningTokens: 0,
|
|
96
|
+
outputTokens: 0,
|
|
97
|
+
estimatedCost: "$0.00",
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Tool definition for MCP
|
|
104
|
+
*/
|
|
105
|
+
export const generateProjectDocsToolDefinition = {
|
|
106
|
+
name: "memorybank_generate_project_docs",
|
|
107
|
+
description: `Genera documentación estructurada del proyecto usando IA con razonamiento avanzado (gpt-5-mini).
|
|
108
|
+
|
|
109
|
+
Crea 6 documentos markdown que proporcionan una visión global del proyecto:
|
|
110
|
+
- projectBrief.md: Descripción general del proyecto
|
|
111
|
+
- productContext.md: Perspectiva de negocio y usuarios
|
|
112
|
+
- systemPatterns.md: Patrones de arquitectura y diseño
|
|
113
|
+
- techContext.md: Stack tecnológico y dependencias
|
|
114
|
+
- activeContext.md: Estado actual de desarrollo
|
|
115
|
+
- progress.md: Seguimiento de cambios
|
|
116
|
+
|
|
117
|
+
Esta herramienta complementa la búsqueda semántica precisa con conocimiento global del proyecto.
|
|
118
|
+
Útil para que agentes menos avanzados comprendan mejor el contexto completo.`,
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
projectId: {
|
|
123
|
+
type: "string",
|
|
124
|
+
description: "ID del proyecto (opcional, usa 'default' si no se especifica)",
|
|
125
|
+
},
|
|
126
|
+
force: {
|
|
127
|
+
type: "boolean",
|
|
128
|
+
description: "Forzar regeneración de todos los documentos aunque no hayan cambiado",
|
|
129
|
+
default: false,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool for reading project documentation
|
|
3
|
+
* Retrieves generated markdown documents for project context
|
|
4
|
+
*/
|
|
5
|
+
const VALID_DOC_TYPES = [
|
|
6
|
+
"projectBrief",
|
|
7
|
+
"productContext",
|
|
8
|
+
"systemPatterns",
|
|
9
|
+
"techContext",
|
|
10
|
+
"activeContext",
|
|
11
|
+
"progress",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves project documentation
|
|
15
|
+
*/
|
|
16
|
+
export async function getProjectDocs(params, projectKnowledgeService) {
|
|
17
|
+
try {
|
|
18
|
+
const format = params.format || "full";
|
|
19
|
+
const requestedDoc = params.document?.toLowerCase();
|
|
20
|
+
// Check if any documents exist
|
|
21
|
+
if (!projectKnowledgeService.hasDocuments()) {
|
|
22
|
+
return {
|
|
23
|
+
success: false,
|
|
24
|
+
message: "No project documentation has been generated yet. Run memorybank_generate_project_docs first.",
|
|
25
|
+
stats: {
|
|
26
|
+
documentCount: 0,
|
|
27
|
+
totalReasoningTokens: 0,
|
|
28
|
+
totalOutputTokens: 0,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Get stats
|
|
33
|
+
const stats = projectKnowledgeService.getStats();
|
|
34
|
+
const statsResult = {
|
|
35
|
+
documentCount: stats.documentCount,
|
|
36
|
+
totalReasoningTokens: stats.totalReasoningTokens,
|
|
37
|
+
totalOutputTokens: stats.totalOutputTokens,
|
|
38
|
+
lastGenerated: stats.lastGenerated?.toISOString(),
|
|
39
|
+
};
|
|
40
|
+
// Handle summary request
|
|
41
|
+
if (requestedDoc === "summary" || format === "summary") {
|
|
42
|
+
const summary = projectKnowledgeService.getDocumentsSummary();
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
message: `Retrieved summary of ${stats.documentCount} project documents.`,
|
|
46
|
+
summary,
|
|
47
|
+
stats: statsResult,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Handle "all" or no specific document
|
|
51
|
+
if (!requestedDoc || requestedDoc === "all") {
|
|
52
|
+
const documents = projectKnowledgeService.getAllDocuments();
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
message: `Retrieved ${documents.length} project documents.`,
|
|
56
|
+
documents,
|
|
57
|
+
stats: statsResult,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Handle specific document request
|
|
61
|
+
// Normalize document name (allow both "projectBrief" and "projectbrief")
|
|
62
|
+
const normalizedDoc = VALID_DOC_TYPES.find(t => t.toLowerCase() === requestedDoc.replace(".md", "").replace("_", ""));
|
|
63
|
+
if (!normalizedDoc) {
|
|
64
|
+
return {
|
|
65
|
+
success: false,
|
|
66
|
+
message: `Invalid document type: "${params.document}". Valid types are: ${VALID_DOC_TYPES.join(", ")}`,
|
|
67
|
+
stats: statsResult,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const document = projectKnowledgeService.getDocument(normalizedDoc);
|
|
71
|
+
if (!document) {
|
|
72
|
+
return {
|
|
73
|
+
success: false,
|
|
74
|
+
message: `Document "${normalizedDoc}" has not been generated yet.`,
|
|
75
|
+
stats: statsResult,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
success: true,
|
|
80
|
+
message: `Retrieved document: ${normalizedDoc}`,
|
|
81
|
+
documents: [document],
|
|
82
|
+
stats: statsResult,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error(`Error getting project docs: ${error.message}`);
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
message: `Failed to retrieve project documentation: ${error.message}`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Tool definition for MCP
|
|
95
|
+
*/
|
|
96
|
+
export const getProjectDocsToolDefinition = {
|
|
97
|
+
name: "memorybank_get_project_docs",
|
|
98
|
+
description: `Lee la documentación del proyecto generada por IA.
|
|
99
|
+
|
|
100
|
+
Recupera documentos markdown estructurados que proporcionan contexto global del proyecto:
|
|
101
|
+
- projectBrief: Descripción general del proyecto
|
|
102
|
+
- productContext: Perspectiva de negocio y usuarios
|
|
103
|
+
- systemPatterns: Patrones de arquitectura y diseño
|
|
104
|
+
- techContext: Stack tecnológico y dependencias
|
|
105
|
+
- activeContext: Estado actual de desarrollo
|
|
106
|
+
- progress: Seguimiento de cambios
|
|
107
|
+
|
|
108
|
+
Usa esta herramienta al inicio de cada sesión para cargar contexto global.
|
|
109
|
+
Complementa la búsqueda semántica precisa (memorybank_search) con visión de alto nivel.`,
|
|
110
|
+
inputSchema: {
|
|
111
|
+
type: "object",
|
|
112
|
+
properties: {
|
|
113
|
+
document: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "Documento específico a recuperar. Opciones: projectBrief, productContext, systemPatterns, techContext, activeContext, progress, all, summary",
|
|
116
|
+
default: "summary",
|
|
117
|
+
},
|
|
118
|
+
format: {
|
|
119
|
+
type: "string",
|
|
120
|
+
enum: ["full", "summary"],
|
|
121
|
+
description: "Formato de salida: 'full' devuelve contenido completo, 'summary' devuelve resumen de todos los docs",
|
|
122
|
+
default: "full",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
package/dist/tools/index.js
CHANGED
|
@@ -10,3 +10,6 @@ export * from "./readFile.js";
|
|
|
10
10
|
export * from "./writeFile.js";
|
|
11
11
|
export * from "./getStats.js";
|
|
12
12
|
export * from "./analyzeCoverage.js";
|
|
13
|
+
// Export Project Knowledge Layer tools
|
|
14
|
+
export * from "./generateProjectDocs.js";
|
|
15
|
+
export * from "./getProjectDocs.js";
|
package/dist/tools/indexCode.js
CHANGED
|
@@ -21,7 +21,6 @@ export async function indexCode(params, indexManager, workspaceRoot) {
|
|
|
21
21
|
// Run indexing
|
|
22
22
|
const result = await indexManager.indexFiles({
|
|
23
23
|
rootPath: targetPath,
|
|
24
|
-
projectRoot: workspaceRoot,
|
|
25
24
|
recursive: params.recursive !== false,
|
|
26
25
|
forceReindex: params.forceReindex || false,
|
|
27
26
|
});
|
|
@@ -18,7 +18,7 @@ export async function searchMemory(params, indexManager) {
|
|
|
18
18
|
}
|
|
19
19
|
console.error(`\nSearching Memory Bank for: "${params.query}"`);
|
|
20
20
|
console.error(`Top K: ${params.topK || 10}`);
|
|
21
|
-
console.error(`Min score: ${params.minScore || 0.
|
|
21
|
+
console.error(`Min score: ${params.minScore || 0.4}`);
|
|
22
22
|
if (params.filterByFile) {
|
|
23
23
|
console.error(`Filter by file: ${params.filterByFile}`);
|
|
24
24
|
}
|
|
@@ -28,7 +28,7 @@ export async function searchMemory(params, indexManager) {
|
|
|
28
28
|
// Search
|
|
29
29
|
const results = await indexManager.search(params.query, {
|
|
30
30
|
topK: params.topK || 10,
|
|
31
|
-
minScore: params.minScore !== undefined ? params.minScore : 0.
|
|
31
|
+
minScore: params.minScore !== undefined ? params.minScore : 0.4,
|
|
32
32
|
filterByFile: params.filterByFile,
|
|
33
33
|
filterByLanguage: params.filterByLanguage,
|
|
34
34
|
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getCard, moveCard } from "../operations/cards.js";
|
|
3
|
+
import { createComment } from "../operations/comments.js";
|
|
4
|
+
import { getLists } from "../operations/lists.js";
|
|
5
|
+
import { getBoard } from "../operations/boards.js";
|
|
6
|
+
import { getTask, updateTask } from "../operations/tasks.js";
|
|
7
|
+
/**
|
|
8
|
+
* Zod schema for the workflow action parameters
|
|
9
|
+
* @property {string} action - The workflow action to perform (start_working, mark_completed, move_to_testing, move_to_done)
|
|
10
|
+
* @property {string} cardId - The ID of the card to perform the action on
|
|
11
|
+
* @property {string} [comment] - Optional comment to add with the action
|
|
12
|
+
* @property {string[]} [taskIds] - Optional task IDs to mark as completed (for mark_completed action)
|
|
13
|
+
* @property {string} [boardId] - Optional board ID (if not provided, will attempt to determine from card)
|
|
14
|
+
*/
|
|
15
|
+
export const workflowActionSchema = z.object({
|
|
16
|
+
action: z.enum([
|
|
17
|
+
"start_working",
|
|
18
|
+
"mark_completed",
|
|
19
|
+
"move_to_testing",
|
|
20
|
+
"move_to_done",
|
|
21
|
+
]).describe("The workflow action to perform"),
|
|
22
|
+
cardId: z.string().describe("The ID of the card to perform the action on"),
|
|
23
|
+
comment: z.string().optional().describe("Optional comment to add with the action"),
|
|
24
|
+
taskIds: z.array(z.string()).optional().describe("Optional task IDs to mark as completed (for mark_completed action)"),
|
|
25
|
+
boardId: z.string().optional().describe("Optional board ID (if not provided, will attempt to determine from card)"),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Performs a workflow action on a card (start working, mark completed, move to testing, move to done)
|
|
29
|
+
*
|
|
30
|
+
* This function handles common workflow actions for cards in a Kanban board, including
|
|
31
|
+
* moving cards between lists, marking tasks as completed, and adding comments to document progress.
|
|
32
|
+
*
|
|
33
|
+
* @param {WorkflowActionParams} params - Parameters for the workflow action
|
|
34
|
+
* @param {string} params.action - The workflow action to perform (start_working, mark_completed, move_to_testing, move_to_done)
|
|
35
|
+
* @param {string} params.cardId - The ID of the card to perform the action on
|
|
36
|
+
* @param {string} [params.comment] - Optional comment to add with the action
|
|
37
|
+
* @param {string[]} [params.taskIds] - Optional task IDs to mark as completed (for mark_completed action)
|
|
38
|
+
* @param {string} [params.boardId] - Optional board ID (if not provided, will attempt to determine from card)
|
|
39
|
+
* @returns {Promise<object>} The result of the workflow action
|
|
40
|
+
* @throws {Error} If the card or board is not found, or if the action cannot be performed
|
|
41
|
+
*/
|
|
42
|
+
export async function performWorkflowAction(params) {
|
|
43
|
+
const { action, cardId, comment, taskIds, boardId: providedBoardId } = params;
|
|
44
|
+
try {
|
|
45
|
+
// Get the card details
|
|
46
|
+
const card = await getCard(cardId);
|
|
47
|
+
if (!card) {
|
|
48
|
+
throw new Error(`Card with ID ${cardId} not found`);
|
|
49
|
+
}
|
|
50
|
+
// Use the provided boardId or try to determine it
|
|
51
|
+
let boardId = providedBoardId;
|
|
52
|
+
if (!boardId) {
|
|
53
|
+
// Try to get the boardId from the card response
|
|
54
|
+
// @ts-ignore - Some card responses include boardId
|
|
55
|
+
boardId = card.boardId;
|
|
56
|
+
}
|
|
57
|
+
if (!boardId) {
|
|
58
|
+
throw new Error(`Could not determine board ID for card ${cardId}. Please provide a boardId parameter.`);
|
|
59
|
+
}
|
|
60
|
+
// Get the board
|
|
61
|
+
const board = await getBoard(boardId);
|
|
62
|
+
if (!board) {
|
|
63
|
+
throw new Error(`Board with ID ${boardId} not found`);
|
|
64
|
+
}
|
|
65
|
+
// Get all lists on the board
|
|
66
|
+
const boardLists = await getLists(boardId);
|
|
67
|
+
// Find the target list based on the action
|
|
68
|
+
let targetList;
|
|
69
|
+
let actionComment = comment;
|
|
70
|
+
switch (action) {
|
|
71
|
+
case "start_working":
|
|
72
|
+
targetList = boardLists.find((list) => list.name.toLowerCase() === "in progress");
|
|
73
|
+
actionComment = comment || "🚀 Started working on this card.";
|
|
74
|
+
break;
|
|
75
|
+
case "mark_completed":
|
|
76
|
+
// This action doesn't move the card, just completes tasks
|
|
77
|
+
if (taskIds && taskIds.length > 0) {
|
|
78
|
+
// Mark all specified tasks as completed
|
|
79
|
+
const taskUpdates = await Promise.all(taskIds.map(async (taskId) => {
|
|
80
|
+
// First get the task to get its current properties
|
|
81
|
+
const task = await getTask(taskId);
|
|
82
|
+
// Then update it with the same properties plus isCompleted=true
|
|
83
|
+
return updateTask(taskId, {
|
|
84
|
+
name: task.name,
|
|
85
|
+
position: task.position,
|
|
86
|
+
// Use the API's method for marking as completed
|
|
87
|
+
// The updateTask function will handle this correctly
|
|
88
|
+
});
|
|
89
|
+
}));
|
|
90
|
+
// Add a comment if provided
|
|
91
|
+
if (comment) {
|
|
92
|
+
await createComment({
|
|
93
|
+
cardId,
|
|
94
|
+
text: comment,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
success: true,
|
|
99
|
+
action,
|
|
100
|
+
cardId,
|
|
101
|
+
tasksCompleted: taskUpdates.length,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw new Error("No task IDs provided for mark_completed action");
|
|
106
|
+
}
|
|
107
|
+
case "move_to_testing":
|
|
108
|
+
targetList = boardLists.find((list) => list.name.toLowerCase() === "testing" ||
|
|
109
|
+
list.name.toLowerCase() === "review");
|
|
110
|
+
actionComment = comment ||
|
|
111
|
+
"✅ Implementation completed and ready for testing.";
|
|
112
|
+
break;
|
|
113
|
+
case "move_to_done":
|
|
114
|
+
targetList = boardLists.find((list) => list.name.toLowerCase() === "done");
|
|
115
|
+
actionComment = comment ||
|
|
116
|
+
"🎉 All work completed and verified.";
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
throw new Error(`Unknown action: ${action}`);
|
|
120
|
+
}
|
|
121
|
+
if (!targetList) {
|
|
122
|
+
throw new Error(`Target list not found for action: ${action}`);
|
|
123
|
+
}
|
|
124
|
+
// Move the card to the target list
|
|
125
|
+
const updatedCard = await moveCard(cardId, targetList.id);
|
|
126
|
+
// Add a comment
|
|
127
|
+
const newComment = await createComment({
|
|
128
|
+
cardId,
|
|
129
|
+
text: actionComment || "",
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
action,
|
|
134
|
+
cardId,
|
|
135
|
+
listId: targetList.id,
|
|
136
|
+
listName: targetList.name,
|
|
137
|
+
card: updatedCard,
|
|
138
|
+
comment: newComment,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
console.error(`Error in performWorkflowAction (${action}):`, error);
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grec0/memory-bank-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "MCP server for semantic code indexing with Memory Bank - AI-powered codebase understanding",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "@grec0",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@lancedb/lancedb": "^0.9.0",
|
|
41
41
|
"@modelcontextprotocol/sdk": "1.6.1",
|
|
42
42
|
"@types/node": "^22",
|
|
43
|
+
"gpt-tokenizer": "3.4.0",
|
|
43
44
|
"ignore": "^5.3.0",
|
|
44
|
-
"js-tiktoken": "^1.0.21",
|
|
45
45
|
"openai": "^4.0.0",
|
|
46
46
|
"zod": "^3.22.4",
|
|
47
47
|
"zod-to-json-schema": "^3.23.5"
|