@grec0/memory-bank-mcp 0.0.3 → 0.0.5

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.
@@ -0,0 +1,106 @@
1
+ import { z } from "zod";
2
+ import { getCard } from "../operations/cards.js";
3
+ import { getTasks } from "../operations/tasks.js";
4
+ import { getComments } from "../operations/comments.js";
5
+ import { getLabels } from "../operations/labels.js";
6
+ import { getProjects } from "../operations/projects.js";
7
+ import { getBoards } from "../operations/boards.js";
8
+ import { getLists } from "../operations/lists.js";
9
+ /**
10
+ * Zod schema for the getCardDetails function parameters
11
+ * @property {string} cardId - The ID of the card to get details for
12
+ */
13
+ export const getCardDetailsSchema = z.object({
14
+ cardId: z.string().describe("The ID of the card to get details for"),
15
+ });
16
+ /**
17
+ * Retrieves comprehensive details about a card including tasks, comments, labels, and analysis
18
+ *
19
+ * This function aggregates data from multiple sources to provide a complete view of a card,
20
+ * including its tasks, comments, and labels. It also calculates task completion percentage
21
+ * and performs analysis on the card's status.
22
+ *
23
+ * @param {GetCardDetailsParams} params - Parameters for retrieving card details
24
+ * @param {string} params.cardId - The ID of the card to get details for
25
+ * @returns {Promise<object>} Comprehensive card details including tasks, comments, labels, and analysis
26
+ * @throws {Error} If the card is not found or if the board ID cannot be determined
27
+ */
28
+ export async function getCardDetails(params) {
29
+ const { cardId } = params;
30
+ try {
31
+ // Get the card details
32
+ const card = await getCard(cardId);
33
+ if (!card) {
34
+ throw new Error(`Card with ID ${cardId} not found`);
35
+ }
36
+ // Get tasks for the card
37
+ const tasks = await getTasks(card.id);
38
+ // Get comments for the card
39
+ const comments = await getComments(card.id);
40
+ // Find the board ID by searching through all projects and boards
41
+ let boardId = null;
42
+ // Get all projects
43
+ const projectsResponse = await getProjects(1, 100);
44
+ const projects = projectsResponse.items;
45
+ // For each project, get its boards
46
+ for (const project of projects) {
47
+ if (boardId)
48
+ break; // Stop if we already found the board ID
49
+ const boards = await getBoards(project.id);
50
+ // For each board, get its lists
51
+ for (const board of boards) {
52
+ if (boardId)
53
+ break; // Stop if we already found the board ID
54
+ const lists = await getLists(board.id);
55
+ // Check if the card's list ID is in this board
56
+ const matchingList = lists.find((list) => list.id === card.listId);
57
+ if (matchingList) {
58
+ boardId = board.id;
59
+ break;
60
+ }
61
+ }
62
+ }
63
+ if (!boardId) {
64
+ throw new Error(`Could not determine board ID for card ${cardId}`);
65
+ }
66
+ const labels = await getLabels(boardId);
67
+ // Filter to just the labels assigned to this card
68
+ // Note: We need to get the labelIds from the card's data
69
+ // This might require additional API calls or data structure knowledge
70
+ // For now, we'll return all labels for the board
71
+ // Calculate task completion percentage
72
+ const completedTasks = tasks.filter((task) => task.isCompleted).length;
73
+ const totalTasks = tasks.length;
74
+ const completionPercentage = totalTasks > 0
75
+ ? Math.round((completedTasks / totalTasks) * 100)
76
+ : 0;
77
+ // Sort comments by date (newest first)
78
+ const sortedComments = comments.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
79
+ // Check if the most recent comment is likely from a human (not the LLM)
80
+ // This is a heuristic and might need adjustment
81
+ const hasRecentHumanFeedback = sortedComments.length > 0 &&
82
+ sortedComments[0].data &&
83
+ !sortedComments[0].data.text.includes("Implemented feature") &&
84
+ !sortedComments[0].data.text.includes("Awaiting human review");
85
+ return {
86
+ card,
87
+ taskItems: tasks,
88
+ taskStats: {
89
+ total: totalTasks,
90
+ completed: completedTasks,
91
+ completionPercentage,
92
+ },
93
+ comments: sortedComments,
94
+ labels,
95
+ analysis: {
96
+ hasRecentHumanFeedback,
97
+ isComplete: completionPercentage === 100,
98
+ needsAttention: hasRecentHumanFeedback || completedTasks === 0,
99
+ },
100
+ };
101
+ }
102
+ catch (error) {
103
+ console.error("Error in getCardDetails:", error);
104
+ throw error;
105
+ }
106
+ }
@@ -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
+ };
@@ -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";
@@ -15,13 +15,15 @@ export async function indexCode(params, indexManager, workspaceRoot) {
15
15
  : path.join(workspaceRoot, params.path)
16
16
  : workspaceRoot;
17
17
  console.error(`\nIndexing code at: ${targetPath}`);
18
+ console.error(`Project ID: ${params.projectId}`);
18
19
  console.error(`Workspace root: ${workspaceRoot}`);
19
20
  console.error(`Recursive: ${params.recursive !== false}`);
20
21
  console.error(`Force reindex: ${params.forceReindex || false}`);
21
- // Run indexing
22
+ // Run indexing - pass workspaceRoot for consistent path normalization
22
23
  const result = await indexManager.indexFiles({
24
+ projectId: params.projectId,
23
25
  rootPath: targetPath,
24
- projectRoot: workspaceRoot,
26
+ workspaceRoot: workspaceRoot, // Always normalize paths relative to workspace
25
27
  recursive: params.recursive !== false,
26
28
  forceReindex: params.forceReindex || false,
27
29
  });
@@ -17,8 +17,9 @@ export async function searchMemory(params, indexManager) {
17
17
  };
18
18
  }
19
19
  console.error(`\nSearching Memory Bank for: "${params.query}"`);
20
+ console.error(`Project ID: ${params.projectId}`);
20
21
  console.error(`Top K: ${params.topK || 10}`);
21
- console.error(`Min score: ${params.minScore || 0.7}`);
22
+ console.error(`Min score: ${params.minScore || 0.4}`);
22
23
  if (params.filterByFile) {
23
24
  console.error(`Filter by file: ${params.filterByFile}`);
24
25
  }
@@ -27,8 +28,9 @@ export async function searchMemory(params, indexManager) {
27
28
  }
28
29
  // Search
29
30
  const results = await indexManager.search(params.query, {
31
+ projectId: params.projectId,
30
32
  topK: params.topK || 10,
31
- minScore: params.minScore !== undefined ? params.minScore : 0.7,
33
+ minScore: params.minScore !== undefined ? params.minScore : 0.4,
32
34
  filterByFile: params.filterByFile,
33
35
  filterByLanguage: params.filterByLanguage,
34
36
  });
@@ -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
+ }
@@ -28,8 +28,8 @@ export async function writeFile(params, indexManager, workspaceRoot) {
28
28
  let chunksCreated = 0;
29
29
  if (autoReindex) {
30
30
  try {
31
- console.error(`Auto-reindexing ${params.path}...`);
32
- const reindexResult = await indexManager.reindexFile(filePath, workspaceRoot);
31
+ console.error(`Auto-reindexing ${params.path} for project ${params.projectId}...`);
32
+ const reindexResult = await indexManager.reindexFile(filePath, workspaceRoot, params.projectId);
33
33
  if (reindexResult.success) {
34
34
  reindexed = true;
35
35
  chunksCreated = reindexResult.chunksCreated;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grec0/memory-bank-mcp",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
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"