@grec0/memory-bank-mcp 0.2.4 → 0.2.6

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.
@@ -474,6 +474,76 @@ export class AgentBoardSqlite {
474
474
  return lines.join('\n');
475
475
  }
476
476
  }
477
+ /**
478
+ * Save an orchestrator routing decision to the database
479
+ */
480
+ export function saveOrchestratorLog(log) {
481
+ const db = databaseManager.getConnection();
482
+ const result = db.prepare(`
483
+ INSERT INTO orchestrator_logs (
484
+ project_id, task_description, action, my_responsibilities,
485
+ delegations, suggested_imports, architecture_notes,
486
+ searches_performed, warning, success, model_used
487
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
488
+ `).run(log.projectId, log.taskDescription, log.action, JSON.stringify(log.myResponsibilities), JSON.stringify(log.delegations), JSON.stringify(log.suggestedImports), log.architectureNotes, JSON.stringify(log.searchesPerformed || []), log.warning || null, log.success ? 1 : 0, log.modelUsed);
489
+ // Flush for external readers (VSCode extension)
490
+ databaseManager.flushForExternalReaders();
491
+ console.error(`[Orchestrator] Saved routing log (ID: ${result.lastInsertRowid})`);
492
+ return result.lastInsertRowid;
493
+ }
494
+ /**
495
+ * Get orchestrator logs for a project
496
+ */
497
+ export function getOrchestratorLogs(projectId, limit = 50) {
498
+ const db = databaseManager.getConnection();
499
+ let query = `
500
+ SELECT * FROM orchestrator_logs
501
+ ${projectId ? 'WHERE project_id = ?' : ''}
502
+ ORDER BY timestamp DESC
503
+ LIMIT ?
504
+ `;
505
+ const params = projectId ? [projectId, limit] : [limit];
506
+ const rows = db.prepare(query).all(...params);
507
+ return rows.map(row => ({
508
+ id: row.id,
509
+ projectId: row.project_id,
510
+ taskDescription: row.task_description,
511
+ action: row.action,
512
+ myResponsibilities: JSON.parse(row.my_responsibilities || '[]'),
513
+ delegations: JSON.parse(row.delegations || '[]'),
514
+ suggestedImports: JSON.parse(row.suggested_imports || '[]'),
515
+ architectureNotes: row.architecture_notes,
516
+ searchesPerformed: JSON.parse(row.searches_performed || '[]'),
517
+ warning: row.warning,
518
+ success: row.success === 1,
519
+ modelUsed: row.model_used,
520
+ timestamp: row.timestamp,
521
+ }));
522
+ }
523
+ /**
524
+ * Get a single orchestrator log by ID
525
+ */
526
+ export function getOrchestratorLogById(id) {
527
+ const db = databaseManager.getConnection();
528
+ const row = db.prepare(`SELECT * FROM orchestrator_logs WHERE id = ?`).get(id);
529
+ if (!row)
530
+ return null;
531
+ return {
532
+ id: row.id,
533
+ projectId: row.project_id,
534
+ taskDescription: row.task_description,
535
+ action: row.action,
536
+ myResponsibilities: JSON.parse(row.my_responsibilities || '[]'),
537
+ delegations: JSON.parse(row.delegations || '[]'),
538
+ suggestedImports: JSON.parse(row.suggested_imports || '[]'),
539
+ architectureNotes: row.architecture_notes,
540
+ searchesPerformed: JSON.parse(row.searches_performed || '[]'),
541
+ warning: row.warning,
542
+ success: row.success === 1,
543
+ modelUsed: row.model_used,
544
+ timestamp: row.timestamp,
545
+ };
546
+ }
477
547
  // ============================================================================
478
548
  // Cleanup utilities
479
549
  // ============================================================================
@@ -7,7 +7,7 @@ import Database from 'better-sqlite3';
7
7
  import * as path from 'path';
8
8
  import * as os from 'os';
9
9
  import * as fs from 'fs';
10
- const SCHEMA_VERSION = 1;
10
+ const SCHEMA_VERSION = 2; // v2: Added orchestrator_logs table
11
11
  /**
12
12
  * SQL Schema for Agent Board
13
13
  */
@@ -90,6 +90,27 @@ CREATE TABLE IF NOT EXISTS messages (
90
90
  CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_id);
91
91
  CREATE INDEX IF NOT EXISTS idx_messages_time ON messages(timestamp);
92
92
 
93
+ -- Orchestrator Logs: Route task decisions and searches
94
+ CREATE TABLE IF NOT EXISTS orchestrator_logs (
95
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
96
+ project_id TEXT NOT NULL, -- Project that requested the routing
97
+ task_description TEXT NOT NULL, -- Original task description
98
+ action TEXT NOT NULL, -- proceed, delegate, mixed
99
+ my_responsibilities TEXT, -- JSON array of responsibilities
100
+ delegations TEXT, -- JSON array of delegations
101
+ suggested_imports TEXT, -- JSON array of imports
102
+ architecture_notes TEXT, -- Explanation from orchestrator
103
+ searches_performed TEXT, -- JSON array of searches done
104
+ warning TEXT, -- Any warnings
105
+ success INTEGER NOT NULL DEFAULT 1, -- 1=success, 0=failure
106
+ model_used TEXT, -- Model used for routing
107
+ timestamp TEXT NOT NULL DEFAULT (datetime('now'))
108
+ );
109
+
110
+ CREATE INDEX IF NOT EXISTS idx_orchestrator_project ON orchestrator_logs(project_id);
111
+ CREATE INDEX IF NOT EXISTS idx_orchestrator_time ON orchestrator_logs(timestamp);
112
+ CREATE INDEX IF NOT EXISTS idx_orchestrator_action ON orchestrator_logs(action);
113
+
93
114
  -- Schema versioning for future migrations
94
115
  CREATE TABLE IF NOT EXISTS schema_version (
95
116
  version INTEGER PRIMARY KEY,
@@ -159,10 +180,8 @@ class DatabaseManager {
159
180
  console.error(`[Database] Migrating schema from v${currentVersion} to v${SCHEMA_VERSION}`);
160
181
  // Run schema creation (IF NOT EXISTS makes it safe)
161
182
  this.db.exec(SCHEMA_SQL);
162
- // Record schema version
163
- if (currentVersion === 0) {
164
- this.db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
165
- }
183
+ // Record/update schema version
184
+ this.db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
166
185
  console.error(`[Database] Schema initialized at v${SCHEMA_VERSION}`);
167
186
  }
168
187
  }
@@ -1,2 +1,2 @@
1
1
  // Version of the MCP Kanban server
2
- export const VERSION = "0.2.3";
2
+ export const VERSION = "0.2.5";
@@ -9,6 +9,7 @@
9
9
  import OpenAI from "openai";
10
10
  import { RegistryManager } from "../common/registryManager.js";
11
11
  import { searchMemory } from "./searchMemory.js";
12
+ import { saveOrchestratorLog } from "../common/agentBoardSqlite.js";
12
13
  /**
13
14
  * Builds a context string describing all projects and their responsibilities
14
15
  */
@@ -226,15 +227,15 @@ export async function routeTaskTool(params, indexManager) {
226
227
  warning: 'AI routing unavailable. Proceeding without validation.',
227
228
  };
228
229
  }
230
+ // Model used for routing (needed for logging both success and error cases)
231
+ const model = process.env.MEMORYBANK_ROUTING_MODEL || "gpt-4o";
229
232
  try {
230
233
  const client = new OpenAI({ apiKey });
231
234
  const prompt = ROUTING_PROMPT
232
235
  .replace('{projectsContext}', projectsContext)
233
236
  .replace('{currentProject}', projectId)
234
237
  .replace('{taskDescription}', taskDescription);
235
- console.error(`Calling AI orchestrator with tool access...`);
236
- // Use chat completions with function calling
237
- const model = process.env.MEMORYBANK_ROUTING_MODEL || "gpt-4o";
238
+ console.error(`Calling AI orchestrator with tool access (${model})...`);
238
239
  // Initialize conversation
239
240
  const messages = [
240
241
  {
@@ -306,7 +307,7 @@ export async function routeTaskTool(params, indexManager) {
306
307
  const jsonMatch = finalResponse.match(/\{[\s\S]*\}/);
307
308
  if (!jsonMatch) {
308
309
  console.error(`Failed to parse orchestrator response`);
309
- return {
310
+ const parseErrorResult = {
310
311
  success: false,
311
312
  action: 'proceed',
312
313
  myResponsibilities: [],
@@ -315,6 +316,26 @@ export async function routeTaskTool(params, indexManager) {
315
316
  architectureNotes: 'Failed to parse AI response.',
316
317
  warning: 'Orchestrator analysis failed. Review task manually.',
317
318
  };
319
+ // Persist parse failure
320
+ try {
321
+ saveOrchestratorLog({
322
+ projectId: params.projectId,
323
+ taskDescription: params.taskDescription,
324
+ action: 'proceed',
325
+ myResponsibilities: [],
326
+ delegations: [],
327
+ suggestedImports: [],
328
+ architectureNotes: parseErrorResult.architectureNotes,
329
+ searchesPerformed: [],
330
+ warning: parseErrorResult.warning,
331
+ success: false,
332
+ modelUsed: model,
333
+ });
334
+ }
335
+ catch (persistError) {
336
+ console.error(`Warning: Failed to persist parse error log: ${persistError.message}`);
337
+ }
338
+ return parseErrorResult;
318
339
  }
319
340
  const result = JSON.parse(jsonMatch[0]);
320
341
  console.error(`\nOrchestrator Decision:`);
@@ -330,7 +351,7 @@ export async function routeTaskTool(params, indexManager) {
330
351
  console.error(` → ${d.targetProject}: ${d.taskTitle}`);
331
352
  }
332
353
  }
333
- return {
354
+ const routeResult = {
334
355
  success: true,
335
356
  action: result.action || 'proceed',
336
357
  myResponsibilities: result.myResponsibilities || [],
@@ -339,10 +360,30 @@ export async function routeTaskTool(params, indexManager) {
339
360
  architectureNotes: result.architectureNotes || '',
340
361
  warning: result.warning,
341
362
  };
363
+ // Persist to SQLite for extension visualization
364
+ try {
365
+ saveOrchestratorLog({
366
+ projectId: params.projectId,
367
+ taskDescription: params.taskDescription,
368
+ action: routeResult.action,
369
+ myResponsibilities: routeResult.myResponsibilities,
370
+ delegations: routeResult.delegations,
371
+ suggestedImports: routeResult.suggestedImports,
372
+ architectureNotes: routeResult.architectureNotes,
373
+ searchesPerformed: result.searchesPerformed || [],
374
+ warning: routeResult.warning,
375
+ success: true,
376
+ modelUsed: model,
377
+ });
378
+ }
379
+ catch (persistError) {
380
+ console.error(`Warning: Failed to persist orchestrator log: ${persistError.message}`);
381
+ }
382
+ return routeResult;
342
383
  }
343
384
  catch (error) {
344
385
  console.error(`Error in task routing: ${error.message}`);
345
- return {
386
+ const errorResult = {
346
387
  success: false,
347
388
  action: 'proceed',
348
389
  myResponsibilities: [],
@@ -351,6 +392,26 @@ export async function routeTaskTool(params, indexManager) {
351
392
  architectureNotes: `Error analyzing task: ${error.message}`,
352
393
  warning: 'Orchestrator failed. Review task distribution manually.',
353
394
  };
395
+ // Persist failed attempts too
396
+ try {
397
+ saveOrchestratorLog({
398
+ projectId: params.projectId,
399
+ taskDescription: params.taskDescription,
400
+ action: 'proceed',
401
+ myResponsibilities: [],
402
+ delegations: [],
403
+ suggestedImports: [],
404
+ architectureNotes: errorResult.architectureNotes,
405
+ searchesPerformed: [],
406
+ warning: errorResult.warning,
407
+ success: false,
408
+ modelUsed: model,
409
+ });
410
+ }
411
+ catch (persistError) {
412
+ console.error(`Warning: Failed to persist error log: ${persistError.message}`);
413
+ }
414
+ return errorResult;
354
415
  }
355
416
  }
356
417
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grec0/memory-bank-mcp",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "MCP server for semantic code indexing with Memory Bank - AI-powered codebase understanding",
5
5
  "license": "MIT",
6
6
  "author": "@grec0",