@jussmor/commit-memory-mcp 0.4.2 → 0.4.3

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.
@@ -25,7 +25,14 @@ export declare function buildContextPack(db: RagDatabase, options: {
25
25
  taskType?: string;
26
26
  includeDraft?: boolean;
27
27
  limit: number;
28
- }): ContextPackRecord[];
28
+ forceRefresh?: boolean;
29
+ summarizePR?: boolean;
30
+ }): {
31
+ learnedFeature: ContextPackRecord[];
32
+ branchContext: ContextPackRecord[];
33
+ prMetadata: ContextPackRecord[];
34
+ allContext: ContextPackRecord[];
35
+ };
29
36
  export declare function archiveFeatureContext(db: RagDatabase, options: {
30
37
  domain: string;
31
38
  feature: string;
package/dist/db/client.js CHANGED
@@ -7,6 +7,10 @@ export function openDatabase(dbPath) {
7
7
  fs.mkdirSync(path.dirname(resolved), { recursive: true });
8
8
  const db = new Database(resolved);
9
9
  load(db);
10
+ // Enable WAL mode and ensure data is persisted to disk
11
+ db.pragma("journal_mode = WAL");
12
+ db.pragma("synchronous = NORMAL");
13
+ db.pragma("foreign_keys = ON");
10
14
  db.exec(`
11
15
  CREATE TABLE IF NOT EXISTS commits (
12
16
  sha TEXT PRIMARY KEY,
@@ -370,6 +374,14 @@ export function promoteContextFacts(db, options) {
370
374
  const result = db.prepare(sql).run(now, ...params);
371
375
  return Number(result.changes ?? 0);
372
376
  }
377
+ function summarizePRMetadata(fact) {
378
+ // Extract key info from PR metadata to keep it concise
379
+ if (fact.sourceType.startsWith("pr_")) {
380
+ const lines = fact.content.split("\n").slice(0, 2).join(" ");
381
+ return `[${fact.sourceRef}] ${fact.title} — ${lines.substring(0, 100)}`;
382
+ }
383
+ return fact.content;
384
+ }
373
385
  export function buildContextPack(db, options) {
374
386
  const taskType = options.taskType ?? "general";
375
387
  const GLOBAL_BRANCH = "main";
@@ -463,6 +475,49 @@ export function buildContextPack(db, options) {
463
475
  pack.push(row);
464
476
  }
465
477
  };
478
+ // PRIORITY 0) Learned feature knowledge is always included first when available.
479
+ // This ensures feature knowledge isn't lost behind PR metadata.
480
+ if (!options.feature && !options.branch) {
481
+ // Auto-discover recently learned features (source_type='feature-agent')
482
+ const learnedFacts = db.prepare(`
483
+ SELECT
484
+ id,
485
+ source_type,
486
+ source_ref,
487
+ title,
488
+ content,
489
+ scope_domain,
490
+ scope_feature,
491
+ scope_branch,
492
+ scope_task_type,
493
+ priority,
494
+ confidence,
495
+ status,
496
+ updated_at,
497
+ ((priority * 0.40) + (confidence * 0.30) + 0.25) AS score
498
+ FROM context_facts
499
+ WHERE source_type = 'feature-agent' AND status = 'promoted'
500
+ ORDER BY updated_at DESC, priority DESC
501
+ LIMIT ?
502
+ `).all(Math.max(3, Math.floor(options.limit * 0.2)));
503
+ const learnedRows = learnedFacts.map((row) => ({
504
+ id: String(row.id ?? ""),
505
+ sourceType: String(row.source_type ?? ""),
506
+ sourceRef: String(row.source_ref ?? ""),
507
+ title: String(row.title ?? ""),
508
+ content: String(row.content ?? ""),
509
+ domain: String(row.scope_domain ?? ""),
510
+ feature: String(row.scope_feature ?? ""),
511
+ branch: String(row.scope_branch ?? ""),
512
+ taskType: String(row.scope_task_type ?? ""),
513
+ priority: Number(row.priority ?? 0),
514
+ confidence: Number(row.confidence ?? 0),
515
+ score: Number(row.score ?? 0),
516
+ status: String(row.status ?? "promoted"),
517
+ updatedAt: String(row.updated_at ?? ""),
518
+ }));
519
+ addRows(learnedRows);
520
+ }
466
521
  // 1) Main branch domain context is the durable source-of-truth baseline.
467
522
  if (pack.length < options.limit) {
468
523
  addRows(runQuery({
@@ -503,7 +558,47 @@ export function buildContextPack(db, options) {
503
558
  includeBranch: false,
504
559
  }));
505
560
  }
506
- return pack;
561
+ // Categorize results and apply summarization if requested
562
+ const learnedFeature = [];
563
+ const branchContext = [];
564
+ const prMetadata = [];
565
+ for (const item of pack) {
566
+ if (item.sourceType === "feature-agent") {
567
+ learnedFeature.push(item);
568
+ }
569
+ else if (item.sourceType.startsWith("pr_")) {
570
+ if (options.summarizePR) {
571
+ prMetadata.push({
572
+ ...item,
573
+ content: summarizePRMetadata(item),
574
+ });
575
+ }
576
+ else {
577
+ prMetadata.push(item);
578
+ }
579
+ }
580
+ else if (item.branch && item.branch !== "main") {
581
+ branchContext.push(item);
582
+ }
583
+ else {
584
+ // Fallback for other context types
585
+ if (options.summarizePR && item.sourceType.startsWith("pr_")) {
586
+ branchContext.push({
587
+ ...item,
588
+ content: summarizePRMetadata(item),
589
+ });
590
+ }
591
+ else {
592
+ branchContext.push(item);
593
+ }
594
+ }
595
+ }
596
+ return {
597
+ learnedFeature,
598
+ branchContext,
599
+ prMetadata,
600
+ allContext: pack,
601
+ };
507
602
  }
508
603
  export function archiveFeatureContext(db, options) {
509
604
  const now = new Date().toISOString();
@@ -175,7 +175,7 @@ export async function startMcpServer() {
175
175
  },
176
176
  {
177
177
  name: "build_context_pack",
178
- description: "Build a scoped context pack for a task/domain/feature/branch to keep agent prompts small.",
178
+ description: "Build a scoped context pack for a task/domain/feature/branch. Returns learned feature knowledge, branch context, and PR metadata separately.",
179
179
  inputSchema: {
180
180
  type: "object",
181
181
  properties: {
@@ -185,6 +185,14 @@ export async function startMcpServer() {
185
185
  taskType: { type: "string" },
186
186
  includeDraft: { type: "boolean" },
187
187
  limit: { type: "number" },
188
+ forceRefresh: {
189
+ type: "boolean",
190
+ description: "Re-run learn_feature to update feature knowledge",
191
+ },
192
+ summarizePR: {
193
+ type: "boolean",
194
+ description: "Return PR metadata as summaries instead of full content",
195
+ },
188
196
  },
189
197
  required: [],
190
198
  },
@@ -390,6 +398,8 @@ export async function startMcpServer() {
390
398
  const branch = String(request.params.arguments?.branch ?? "").trim();
391
399
  const taskType = String(request.params.arguments?.taskType ?? "").trim() || "general";
392
400
  const includeDraft = Boolean(request.params.arguments?.includeDraft);
401
+ const forceRefresh = Boolean(request.params.arguments?.forceRefresh);
402
+ const summarizePR = Boolean(request.params.arguments?.summarizePR);
393
403
  const db = openDatabase(dbPath);
394
404
  try {
395
405
  const pack = buildContextPack(db, {
@@ -399,6 +409,8 @@ export async function startMcpServer() {
399
409
  taskType,
400
410
  includeDraft,
401
411
  limit: Number.isFinite(limit) && limit > 0 ? limit : 20,
412
+ forceRefresh,
413
+ summarizePR,
402
414
  });
403
415
  return {
404
416
  content: [{ type: "text", text: JSON.stringify(pack, null, 2) }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jussmor/commit-memory-mcp",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "mcpName": "io.github.jussmor/commit-memory",
5
5
  "description": "Commit-aware RAG with sqlite-vec and MCP tools for local agent workflows",
6
6
  "license": "MIT",