@vheins/local-memory-mcp 0.19.3 → 0.19.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.
@@ -61,7 +61,7 @@ import {
61
61
  parseRepoInput,
62
62
  rankCompletionValues,
63
63
  toContextSlug
64
- } from "../chunk-R45NRES5.js";
64
+ } from "../chunk-ZSGQQS5F.js";
65
65
 
66
66
  // src/mcp/server.ts
67
67
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
@@ -74,8 +74,8 @@ import path from "path";
74
74
  import { fileURLToPath } from "url";
75
75
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
76
76
  var pkgVersion = "0.1.0";
77
- if ("0.19.3") {
78
- pkgVersion = "0.19.3";
77
+ if ("0.19.5") {
78
+ pkgVersion = "0.19.5";
79
79
  } else {
80
80
  let searchDir = __dirname;
81
81
  for (let i = 0; i < 5; i++) {
@@ -154,7 +154,6 @@ function generateNextCode(owner, repo, entityType, storage, batchCodes) {
154
154
 
155
155
  // src/mcp/tools/kg-archivist.ts
156
156
  import { randomUUID } from "crypto";
157
- import nlp from "compromise";
158
157
  var MAX_CONTENT_LENGTH = 5e3;
159
158
  var PRONOUNS = /* @__PURE__ */ new Set([
160
159
  "i",
@@ -354,8 +353,9 @@ function isExcludedNoun(candidate) {
354
353
  if (/^\d+$/.test(candidate)) return true;
355
354
  return false;
356
355
  }
357
- function extractEntities(content) {
356
+ async function extractEntities(content) {
358
357
  if (!content || content.trim().length === 0) return [];
358
+ const { default: nlp } = await import("compromise");
359
359
  const text = content.length > MAX_CONTENT_LENGTH ? content.slice(0, MAX_CONTENT_LENGTH) : content;
360
360
  const doc = nlp(text);
361
361
  const seen = /* @__PURE__ */ new Set();
@@ -386,11 +386,11 @@ function extractEntities(content) {
386
386
  }
387
387
  return entities;
388
388
  }
389
- function saveExtractions(content, title, owner, repo, db2) {
389
+ async function saveExtractions(content, title, owner, repo, db2) {
390
390
  if (!content || content.trim().length === 0) return;
391
391
  let entities;
392
392
  try {
393
- entities = extractEntities(content);
393
+ entities = await extractEntities(content);
394
394
  } catch (err) {
395
395
  logger.warn("[KG-Archivist] Entity extraction failed, skipping", {
396
396
  error: String(err)
@@ -507,7 +507,7 @@ async function storeSingleMemory(params, db2, vectors2) {
507
507
  logger.warn("Failed to generate vector embedding", { error: String(error) });
508
508
  }
509
509
  try {
510
- saveExtractions(entry.content, entry.title, entry.scope.owner, entry.scope.repo, db2);
510
+ await saveExtractions(entry.content, entry.title, entry.scope.owner, entry.scope.repo, db2);
511
511
  } catch (error) {
512
512
  logger.warn("[KG-Archivist] NLP extraction failed, memory stored without KG enrichment", {
513
513
  error: String(error)
@@ -614,7 +614,7 @@ async function handleMemoryStore(params, db2, vectors2) {
614
614
  logger.warn("Failed to generate vector embedding", { error: String(error) });
615
615
  }
616
616
  try {
617
- saveExtractions(entry.content, entry.title, entry.scope.owner, entry.scope.repo, db2);
617
+ await saveExtractions(entry.content, entry.title, entry.scope.owner, entry.scope.repo, db2);
618
618
  } catch (error) {
619
619
  logger.warn("[KG-Archivist] NLP extraction failed, memory stored without KG enrichment", {
620
620
  error: String(error)
@@ -3419,6 +3419,55 @@ async function handleKGBackfill(args, db2) {
3419
3419
  };
3420
3420
  const scanRepos = repo ? [repo] : db2.system.listRepoNavigation().map((r) => r.repo);
3421
3421
  stats.reposScanned = scanRepos.length;
3422
+ const pendingOps = [];
3423
+ for (const r of scanRepos) {
3424
+ const currentOwner = owner || "unknown";
3425
+ if (source === "memories" || source === "both") {
3426
+ const rows = db2.db.prepare("SELECT title, content FROM memories WHERE repo = ?").all(r);
3427
+ for (let i = 0; i < rows.length; i++) {
3428
+ const row = rows[i];
3429
+ const text = `${row.content || ""} ${row.title || ""}`;
3430
+ try {
3431
+ const entities = await extractEntities(text);
3432
+ if (entities.length > 0) {
3433
+ pendingOps.push({
3434
+ entities,
3435
+ repo: r,
3436
+ owner: currentOwner,
3437
+ observationText: `Mentioned in memory: ${row.title || "untitled"}`
3438
+ });
3439
+ }
3440
+ } catch {
3441
+ stats.errors++;
3442
+ }
3443
+ stats.itemsProcessed++;
3444
+ if ((i + 1) % 100 === 0) {
3445
+ logger.info(`[kg-backfill] Processed ${i + 1}/${rows.length} memories in repo "${r}"`);
3446
+ }
3447
+ }
3448
+ }
3449
+ if (source === "standards" || source === "both") {
3450
+ const rows = db2.db.prepare("SELECT title, content FROM coding_standards WHERE repo = ?").all(r);
3451
+ for (let i = 0; i < rows.length; i++) {
3452
+ const row = rows[i];
3453
+ const text = `${row.content || ""} ${row.title || ""}`;
3454
+ try {
3455
+ const entities = await extractEntities(text);
3456
+ if (entities.length > 0) {
3457
+ pendingOps.push({
3458
+ entities,
3459
+ repo: r,
3460
+ owner: currentOwner,
3461
+ observationText: `Mentioned in standard: ${row.title || "untitled"}`
3462
+ });
3463
+ }
3464
+ } catch {
3465
+ stats.errors++;
3466
+ }
3467
+ stats.itemsProcessed++;
3468
+ }
3469
+ }
3470
+ }
3422
3471
  const insertEntity = db2.db.prepare(
3423
3472
  `INSERT OR IGNORE INTO entities (name, type, description, repo, owner, created_at, updated_at)
3424
3473
  VALUES (?, ?, ?, ?, ?, ?, ?)`
@@ -3429,66 +3478,12 @@ async function handleKGBackfill(args, db2) {
3429
3478
  );
3430
3479
  const now = (/* @__PURE__ */ new Date()).toISOString();
3431
3480
  const transaction = db2.db.transaction(() => {
3432
- for (const r of scanRepos) {
3433
- const currentOwner = owner || "unknown";
3434
- if (source === "memories" || source === "both") {
3435
- const rows = db2.db.prepare("SELECT title, content FROM memories WHERE repo = ?").all(r);
3436
- for (let i = 0; i < rows.length; i++) {
3437
- const row = rows[i];
3438
- const content = `${row.content || ""} ${row.title || ""}`;
3439
- let entities;
3440
- try {
3441
- entities = extractEntities(content);
3442
- } catch {
3443
- stats.errors++;
3444
- continue;
3445
- }
3446
- for (const ent of entities) {
3447
- insertEntity.run(ent.name, ent.type, null, r, currentOwner, now, now);
3448
- stats.entitiesCreated++;
3449
- insertObservation.run(
3450
- randomUUID6(),
3451
- ent.name,
3452
- `Mentioned in memory: ${row.title || "untitled"}`,
3453
- r,
3454
- currentOwner,
3455
- now
3456
- );
3457
- stats.observationsCreated++;
3458
- }
3459
- stats.itemsProcessed++;
3460
- if ((i + 1) % 100 === 0) {
3461
- logger.info(`[kg-backfill] Processed ${i + 1}/${rows.length} memories in repo "${r}"`);
3462
- }
3463
- }
3464
- }
3465
- if (source === "standards" || source === "both") {
3466
- const rows = db2.db.prepare("SELECT title, content FROM coding_standards WHERE repo = ?").all(r);
3467
- for (let i = 0; i < rows.length; i++) {
3468
- const row = rows[i];
3469
- const content = `${row.content || ""} ${row.title || ""}`;
3470
- let entities;
3471
- try {
3472
- entities = extractEntities(content);
3473
- } catch {
3474
- stats.errors++;
3475
- continue;
3476
- }
3477
- for (const ent of entities) {
3478
- insertEntity.run(ent.name, ent.type, null, r, currentOwner, now, now);
3479
- stats.entitiesCreated++;
3480
- insertObservation.run(
3481
- randomUUID6(),
3482
- ent.name,
3483
- `Mentioned in standard: ${row.title || "untitled"}`,
3484
- r,
3485
- currentOwner,
3486
- now
3487
- );
3488
- stats.observationsCreated++;
3489
- }
3490
- stats.itemsProcessed++;
3491
- }
3481
+ for (const op of pendingOps) {
3482
+ for (const ent of op.entities) {
3483
+ insertEntity.run(ent.name, ent.type, null, op.repo, op.owner, now, now);
3484
+ stats.entitiesCreated++;
3485
+ insertObservation.run(randomUUID6(), ent.name, op.observationText, op.repo, op.owner, now);
3486
+ stats.observationsCreated++;
3492
3487
  }
3493
3488
  }
3494
3489
  });
@@ -3835,8 +3830,8 @@ function registerAllResources(server, store, _vectors, session) {
3835
3830
  mimeType: "application/json"
3836
3831
  },
3837
3832
  async (uri, _extra) => {
3838
- const repos2 = db2.system.listRepoNavigation();
3839
- const payload = JSON.stringify(repos2, null, 2);
3833
+ const repos = db2.system.listRepoNavigation();
3834
+ const payload = JSON.stringify(repos, null, 2);
3840
3835
  return {
3841
3836
  contents: [
3842
3837
  {
@@ -3869,15 +3864,29 @@ function registerAllResources(server, store, _vectors, session) {
3869
3864
  };
3870
3865
  }
3871
3866
  );
3872
- const repos = getRepos();
3873
- const tags = getTags();
3867
+ function reposLazy() {
3868
+ let cached = null;
3869
+ return () => {
3870
+ if (cached === null) cached = getRepos();
3871
+ return cached;
3872
+ };
3873
+ }
3874
+ function tagsLazy() {
3875
+ let cached = null;
3876
+ return () => {
3877
+ if (cached === null) cached = getTags();
3878
+ return cached;
3879
+ };
3880
+ }
3881
+ const reposFn = reposLazy();
3882
+ const tagsFn = tagsLazy();
3874
3883
  server.registerResource(
3875
3884
  "repository-memories",
3876
3885
  new ResourceTemplate("repository://{name}/memories{?search,type,tag,limit,offset}", {
3877
3886
  list: void 0,
3878
3887
  complete: {
3879
- name: async (value) => rankCompletionValues(repos, value),
3880
- tag: async (value) => rankCompletionValues(tags, value)
3888
+ name: async (value) => rankCompletionValues(reposFn(), value),
3889
+ tag: async (value) => rankCompletionValues(tagsFn(), value)
3881
3890
  }
3882
3891
  }),
3883
3892
  {
@@ -3941,7 +3950,7 @@ function registerAllResources(server, store, _vectors, session) {
3941
3950
  new ResourceTemplate("repository://{name}/tasks{?status,priority,limit,offset}", {
3942
3951
  list: void 0,
3943
3952
  complete: {
3944
- name: async (value) => rankCompletionValues(repos, value)
3953
+ name: async (value) => rankCompletionValues(reposFn(), value)
3945
3954
  }
3946
3955
  }),
3947
3956
  {
@@ -4010,7 +4019,7 @@ function registerAllResources(server, store, _vectors, session) {
4010
4019
  new ResourceTemplate("repository://{name}/summary", {
4011
4020
  list: void 0,
4012
4021
  complete: {
4013
- name: async (value) => rankCompletionValues(repos, value)
4022
+ name: async (value) => rankCompletionValues(reposFn(), value)
4014
4023
  }
4015
4024
  }),
4016
4025
  {
@@ -4038,7 +4047,7 @@ function registerAllResources(server, store, _vectors, session) {
4038
4047
  new ResourceTemplate("repository://{name}/actions{?limit,offset}", {
4039
4048
  list: void 0,
4040
4049
  complete: {
4041
- name: async (value) => rankCompletionValues(repos, value)
4050
+ name: async (value) => rankCompletionValues(reposFn(), value)
4042
4051
  }
4043
4052
  }),
4044
4053
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vheins/local-memory-mcp",
3
- "version": "0.19.3",
3
+ "version": "0.19.5",
4
4
  "description": "MCP Local Memory Service for coding copilot agents",
5
5
  "mcpName": "io.github.vheins/local-memory-mcp",
6
6
  "type": "module",