@vheins/local-memory-mcp 0.16.3 → 0.17.0

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.
@@ -60,7 +60,7 @@ import {
60
60
  toContextSlug,
61
61
  updateSessionFromInitialize,
62
62
  updateSessionRoots
63
- } from "../chunk-MSP4MIT7.js";
63
+ } from "../chunk-SITVJ6EA.js";
64
64
 
65
65
  // src/mcp/server.ts
66
66
  import readline from "readline";
@@ -133,7 +133,7 @@ function getSuggestedRepos(db2, session2) {
133
133
  }
134
134
  function getSuggestedTags(db2) {
135
135
  const values = /* @__PURE__ */ new Set();
136
- const memories = db2.memories.getRecentMemories("", 1e3);
136
+ const memories = db2.memories.getRecentMemories("", "", 1e3);
137
137
  for (const memory of memories) {
138
138
  for (const tag of memory.tags || []) {
139
139
  if (typeof tag === "string" && tag.trim()) {
@@ -146,7 +146,7 @@ function getSuggestedTags(db2) {
146
146
  function getSuggestedTasks(db2, session2, contextArguments) {
147
147
  const repo = typeof contextArguments.repo === "string" && contextArguments.repo.trim() ? contextArguments.repo.trim() : inferRepoFromSession(session2);
148
148
  if (!repo) return [];
149
- return db2.tasks.getTasksByRepo(repo, void 0, 100).map((task) => ({
149
+ return db2.tasks.getTasksByRepo("", repo, void 0, 100).map((task) => ({
150
150
  id: task.id,
151
151
  task_code: task.task_code,
152
152
  title: task.title
@@ -196,7 +196,7 @@ var ENTITY_CONFIG = {
196
196
  memory: { prefix: "MEM", table: "memories", column: "code" },
197
197
  standard: { prefix: "STD", table: "coding_standards", column: "code" }
198
198
  };
199
- function generateNextCode(repo, entityType, storage, batchCodes) {
199
+ function generateNextCode(owner, repo, entityType, storage, batchCodes) {
200
200
  const config = ENTITY_CONFIG[entityType];
201
201
  const pattern = `${config.prefix}-%`;
202
202
  const offset = config.prefix.length + 2;
@@ -204,9 +204,9 @@ function generateNextCode(repo, entityType, storage, batchCodes) {
204
204
  `
205
205
  SELECT MAX(CAST(SUBSTR(${config.column}, ?) AS INTEGER)) as max_seq
206
206
  FROM ${config.table}
207
- WHERE repo = ? AND ${config.column} LIKE ?
207
+ WHERE owner = ? AND repo = ? AND ${config.column} LIKE ?
208
208
  `
209
- ).get(offset, repo, pattern);
209
+ ).get(offset, owner, repo, pattern);
210
210
  let nextSeq = (row?.max_seq ?? 0) + 1;
211
211
  if (batchCodes) {
212
212
  for (const code of batchCodes) {
@@ -247,6 +247,7 @@ async function storeSingleMemory(params, db2, vectors2) {
247
247
  if (!resolvedSupersedes && params.type !== "task_archive") {
248
248
  const conflict = await db2.memoryVectors.checkConflicts(
249
249
  params.content,
250
+ params.scope.owner,
250
251
  params.scope.repo,
251
252
  params.type,
252
253
  vectors2,
@@ -277,7 +278,7 @@ async function storeSingleMemory(params, db2, vectors2) {
277
278
  }
278
279
  const entry = {
279
280
  id: randomUUID(),
280
- code: params.code || generateNextCode(params.scope.repo, "memory", db2),
281
+ code: params.code || generateNextCode(params.scope.owner ?? "", params.scope.repo, "memory", db2),
281
282
  type: params.type,
282
283
  title: params.title,
283
284
  content: params.content,
@@ -285,7 +286,7 @@ async function storeSingleMemory(params, db2, vectors2) {
285
286
  agent: params.agent,
286
287
  role: params.role,
287
288
  model: params.model,
288
- scope: params.scope,
289
+ scope: { ...params.scope, owner: params.scope.owner },
289
290
  created_at: now,
290
291
  updated_at: now,
291
292
  completed_at: null,
@@ -339,7 +340,14 @@ async function handleMemoryStore(params, db2, vectors2) {
339
340
  const expires_at = mem.ttlDays != null ? new Date(createdAtTime + mem.ttlDays * 864e5).toISOString() : null;
340
341
  const resolvedSupersedes = resolveMemorySupersedes(mem.supersedes, db2);
341
342
  if (!resolvedSupersedes && mem.type !== "task_archive") {
342
- const conflict = await db2.memoryVectors.checkConflicts(mem.content, mem.scope.repo, mem.type, vectors2, 0.55);
343
+ const conflict = await db2.memoryVectors.checkConflicts(
344
+ mem.content,
345
+ mem.scope.owner,
346
+ mem.scope.repo,
347
+ mem.type,
348
+ vectors2,
349
+ 0.55
350
+ );
343
351
  if (conflict) {
344
352
  return createMcpResponse(
345
353
  {
@@ -363,7 +371,7 @@ async function handleMemoryStore(params, db2, vectors2) {
363
371
  if (mem.scope.language && !tags.includes(mem.scope.language.toLowerCase())) {
364
372
  tags.push(mem.scope.language.toLowerCase());
365
373
  }
366
- const code = mem.code || generateNextCode(mem.scope.repo, "memory", db2, batchCodes);
374
+ const code = mem.code || generateNextCode(mem.scope.owner ?? "", mem.scope.repo, "memory", db2, batchCodes);
367
375
  batchCodes.add(code);
368
376
  entries.push({
369
377
  id: randomUUID(),
@@ -375,7 +383,7 @@ async function handleMemoryStore(params, db2, vectors2) {
375
383
  agent: mem.agent,
376
384
  role: mem.role,
377
385
  model: mem.model,
378
- scope: mem.scope,
386
+ scope: { ...mem.scope, owner: mem.scope.owner },
379
387
  created_at: now,
380
388
  updated_at: now,
381
389
  completed_at: null,
@@ -489,7 +497,7 @@ async function handleMemoryUpdate(params, db2, vectors2) {
489
497
  if (validated.content !== void 0) {
490
498
  await vectors2.upsert(resolvedId, validated.content);
491
499
  }
492
- db2.actions.logAction("update", existing.scope.repo, { memoryId: resolvedId, resultCount: 1 });
500
+ db2.actions.logAction("update", existing.scope.owner, existing.scope.repo, { memoryId: resolvedId, resultCount: 1 });
493
501
  logger.info("[Tool] memory.update", { repo: existing.scope.repo, id: resolvedId, fields: Object.keys(updates) });
494
502
  return createMcpResponse(
495
503
  {
@@ -543,6 +551,7 @@ async function handleMemorySearch(params, db2, vectors2) {
543
551
  const fetchLimit = (validated.offset + validated.limit) * 3;
544
552
  const similarityResults = db2.memoryVectors.searchBySimilarity(
545
553
  searchQuery,
554
+ validated.owner,
546
555
  validated.repo,
547
556
  fetchLimit,
548
557
  validated.include_archived,
@@ -672,7 +681,7 @@ async function handleMemorySummarize(params, db2) {
672
681
  const summary = validated.signals.join("\n- ");
673
682
  const fullSummary = `Project summary:
674
683
  - ${summary}`;
675
- db2.summaries.upsertSummary(validated.repo, fullSummary);
684
+ db2.summaries.upsertSummary(validated.owner, validated.repo, fullSummary);
676
685
  const content = `Updated summary for repo "${validated.repo}" with ${validated.signals.length} signals:
677
686
 
678
687
  ${fullSummary}`;
@@ -713,11 +722,16 @@ function extractAcceptedElicitationContent(result) {
713
722
  async function handleMemoryRecap(params, db2) {
714
723
  const validated = MemoryRecapSchema.parse(params);
715
724
  logger.info("[Tool] memory.recap", { repo: validated.repo, limit: validated.limit, offset: validated.offset });
716
- const stats = db2.memories.getStats(validated.repo);
717
- const total = db2.memories.getTotalCount(validated.repo, false, ["task_archive"]);
718
- const rows = db2.memories.getRecentMemories(validated.repo, validated.limit, validated.offset, false, [
719
- "task_archive"
720
- ]);
725
+ const stats = db2.memories.getStats(validated.owner, validated.repo);
726
+ const total = db2.memories.getTotalCount(validated.owner, validated.repo, false, ["task_archive"]);
727
+ const rows = db2.memories.getRecentMemories(
728
+ validated.owner,
729
+ validated.repo,
730
+ validated.limit,
731
+ validated.offset,
732
+ false,
733
+ ["task_archive"]
734
+ );
721
735
  const COLUMNS = ["id", "code", "title", "type", "importance"];
722
736
  const topRows = rows.map((row) => [row.id, row.code || "-", row.title ?? "Untitled", row.type, row.importance]);
723
737
  const byType = {};
@@ -782,19 +796,19 @@ function capitalize2(str) {
782
796
  // src/mcp/tools/task.manage.ts
783
797
  import { randomUUID as randomUUID2 } from "crypto";
784
798
  var UUID_REGEX3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
785
- function resolveParentId(value, repo, storage, localCodeMap) {
799
+ function resolveParentId(value, owner, repo, storage, localCodeMap) {
786
800
  if (!value) return null;
787
801
  if (UUID_REGEX3.test(value)) return value;
788
802
  if (localCodeMap?.has(value)) return localCodeMap.get(value);
789
- const parent = storage.tasks.getTaskByCode(repo, value);
803
+ const parent = storage.tasks.getTaskByCode(owner, repo, value);
790
804
  if (!parent) throw new Error(`parent_id: task with code '${value}' not found in repo '${repo}'`);
791
805
  return parent.id;
792
806
  }
793
- function resolveDependsOn(value, repo, storage, localCodeMap) {
807
+ function resolveDependsOn(value, owner, repo, storage, localCodeMap) {
794
808
  if (!value) return null;
795
809
  if (UUID_REGEX3.test(value)) return value;
796
810
  if (localCodeMap?.has(value)) return localCodeMap.get(value);
797
- const task = storage.tasks.getTaskByCode(repo, value);
811
+ const task = storage.tasks.getTaskByCode(owner, repo, value);
798
812
  if (!task) throw new Error(`depends_on: task with code '${value}' not found in repo '${repo}'`);
799
813
  return task.id;
800
814
  }
@@ -911,7 +925,7 @@ Comments & History:
911
925
  agent: task.agent || "system",
912
926
  role: task.role || "unknown",
913
927
  model: "system",
914
- scope: { repo },
928
+ scope: { repo, owner: task.owner || "" },
915
929
  tags: ["task-archive", ...task.tags],
916
930
  metadata
917
931
  },
@@ -925,6 +939,7 @@ Comments & History:
925
939
  async function handleTaskList(args, storage) {
926
940
  const validated = TaskListSchema.parse(args);
927
941
  const {
942
+ owner,
928
943
  repo,
929
944
  status = "backlog,pending,in_progress,blocked",
930
945
  phase,
@@ -937,7 +952,7 @@ async function handleTaskList(args, storage) {
937
952
  if (status !== "all") {
938
953
  statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
939
954
  }
940
- const tasks = storage.tasks.getTasksByMultipleStatuses(repo, statuses, limit, offset, query);
955
+ const tasks = storage.tasks.getTasksByMultipleStatuses(owner, repo, statuses, limit, offset, query);
941
956
  const filteredTasks = phase ? tasks.filter((t) => t.phase.toLowerCase() === phase.toLowerCase()) : tasks;
942
957
  const COLUMNS = ["id", "task_code", "title", "status", "priority", "updated_at", "comments_count"];
943
958
  const rows = filteredTasks.map((t) => [
@@ -977,7 +992,7 @@ async function handleTaskList(args, storage) {
977
992
  }
978
993
  async function handleTaskCreate(args, storage) {
979
994
  const parsed = TaskCreateSchema.parse(args);
980
- const { repo, tasks: bulkTasks, ...singleTask } = parsed;
995
+ const { owner, repo, tasks: bulkTasks, ...singleTask } = parsed;
981
996
  if (bulkTasks) {
982
997
  const createdTasks = [];
983
998
  const tasksToInsert = [];
@@ -986,13 +1001,13 @@ async function handleTaskCreate(args, storage) {
986
1001
  const batchCodes = /* @__PURE__ */ new Set();
987
1002
  for (const taskData of bulkTasks) {
988
1003
  if (!taskData.task_code) {
989
- taskData.task_code = generateNextCode(repo, "task", storage, batchCodes);
1004
+ taskData.task_code = generateNextCode(owner ?? "", repo, "task", storage, batchCodes);
990
1005
  }
991
1006
  batchCodes.add(taskData.task_code);
992
1007
  }
993
1008
  const allCodes = bulkTasks.map((t) => t.task_code);
994
- const existingCodes = storage.tasks.getExistingTaskCodes(repo, allCodes);
995
- const initialStats = storage.taskStats.getTaskStats(repo);
1009
+ const existingCodes = storage.tasks.getExistingTaskCodes(owner, repo, allCodes);
1010
+ const initialStats = storage.taskStats.getTaskStats(owner, repo);
996
1011
  let pendingInRequestCount = 0;
997
1012
  const localCodeMap = /* @__PURE__ */ new Map();
998
1013
  for (const taskData of bulkTasks) {
@@ -1027,6 +1042,7 @@ async function handleTaskCreate(args, storage) {
1027
1042
  const taskId2 = localCodeMap.get(code);
1028
1043
  const task2 = {
1029
1044
  id: taskId2,
1045
+ owner,
1030
1046
  repo,
1031
1047
  task_code: code,
1032
1048
  phase: taskData.phase,
@@ -1048,8 +1064,8 @@ async function handleTaskCreate(args, storage) {
1048
1064
  commit_id: null,
1049
1065
  changed_files: [],
1050
1066
  metadata: taskData.metadata || {},
1051
- parent_id: resolveParentId(taskData.parent_id, repo, storage, localCodeMap),
1052
- depends_on: resolveDependsOn(taskData.depends_on, repo, storage, localCodeMap)
1067
+ parent_id: resolveParentId(taskData.parent_id, owner, repo, storage, localCodeMap),
1068
+ depends_on: resolveDependsOn(taskData.depends_on, owner, repo, storage, localCodeMap)
1053
1069
  };
1054
1070
  tasksToInsert.push(task2);
1055
1071
  createdTasks.push(code);
@@ -1083,15 +1099,15 @@ async function handleTaskCreate(args, storage) {
1083
1099
  if (!phase || !title || !description) {
1084
1100
  throw new Error("Missing required fields for single task creation (phase, title, description)");
1085
1101
  }
1086
- const resolvedCode = task_code || generateNextCode(repo, "task", storage);
1087
- if (storage.tasks.isTaskCodeDuplicate(repo, resolvedCode)) {
1102
+ const resolvedCode = task_code || generateNextCode(owner ?? "", repo, "task", storage);
1103
+ if (storage.tasks.isTaskCodeDuplicate(owner, repo, resolvedCode)) {
1088
1104
  throw new Error(`Duplicate task_code: '${resolvedCode}' already exists in repository '${repo}'`);
1089
1105
  }
1090
1106
  if (status !== "backlog" && status !== "pending" && status !== void 0) {
1091
1107
  throw new Error("New tasks must be created with status 'backlog' or 'pending'.");
1092
1108
  }
1093
1109
  if (status === "pending") {
1094
- const stats = storage.taskStats.getTaskStats(repo);
1110
+ const stats = storage.taskStats.getTaskStats(owner, repo);
1095
1111
  if (stats.todo >= 10) {
1096
1112
  throw new Error(
1097
1113
  `Cannot create task as 'pending'. Maximum of 10 pending tasks reached. Please use status 'backlog' for new tasks instead.`
@@ -1108,6 +1124,7 @@ async function handleTaskCreate(args, storage) {
1108
1124
  }
1109
1125
  const task = {
1110
1126
  id: taskId,
1127
+ owner,
1111
1128
  repo,
1112
1129
  task_code: resolvedCode,
1113
1130
  phase,
@@ -1129,8 +1146,8 @@ async function handleTaskCreate(args, storage) {
1129
1146
  commit_id: null,
1130
1147
  changed_files: [],
1131
1148
  metadata: metadata || {},
1132
- parent_id: resolveParentId(parent_id, repo, storage),
1133
- depends_on: resolveDependsOn(depends_on, repo, storage)
1149
+ parent_id: resolveParentId(parent_id, owner, repo, storage),
1150
+ depends_on: resolveDependsOn(depends_on, owner, repo, storage)
1134
1151
  };
1135
1152
  storage.tasks.insertTask(task);
1136
1153
  return createMcpResponse(
@@ -1245,10 +1262,10 @@ function addRequiredStringField(properties, required, task, field, schema) {
1245
1262
  }
1246
1263
  async function handleTaskUpdate(args, storage, vectors2) {
1247
1264
  const updateData = TaskUpdateSchema.parse(args);
1248
- const { repo, id, ids, comment, force, ...updates } = updateData;
1265
+ const { owner, repo, id, ids, comment, force, ...updates } = updateData;
1249
1266
  let resolvedId = id;
1250
1267
  if (!resolvedId && !ids && updates.task_code) {
1251
- const found = storage.tasks.getTaskByCode(repo, updates.task_code);
1268
+ const found = storage.tasks.getTaskByCode(owner, repo, updates.task_code);
1252
1269
  if (!found) throw new Error(`Task not found: ${updates.task_code}`);
1253
1270
  resolvedId = found.id;
1254
1271
  }
@@ -1293,10 +1310,10 @@ async function handleTaskUpdate(args, storage, vectors2) {
1293
1310
  }
1294
1311
  const finalUpdates = { ...updates };
1295
1312
  if (updates.parent_id !== void 0) {
1296
- finalUpdates.parent_id = resolveParentId(updates.parent_id, repo, storage);
1313
+ finalUpdates.parent_id = resolveParentId(updates.parent_id, owner, repo, storage);
1297
1314
  }
1298
1315
  if (updates.depends_on !== void 0) {
1299
- finalUpdates.depends_on = resolveDependsOn(updates.depends_on, repo, storage);
1316
+ finalUpdates.depends_on = resolveDependsOn(updates.depends_on, owner, repo, storage);
1300
1317
  }
1301
1318
  if (updates.phase !== void 0 || updates.tags !== void 0) {
1302
1319
  let currentTags = updates.tags || existingTask.tags || [];
@@ -1322,6 +1339,7 @@ async function handleTaskUpdate(args, storage, vectors2) {
1322
1339
  storage.taskComments.insertTaskComment({
1323
1340
  id: randomUUID2(),
1324
1341
  task_id: targetId,
1342
+ owner,
1325
1343
  repo,
1326
1344
  comment: comment || `Status updated to ${updates.status}`,
1327
1345
  agent: updates.agent || existingTask.agent || "unknown",
@@ -1382,12 +1400,12 @@ async function handleTaskUpdate(args, storage, vectors2) {
1382
1400
  }
1383
1401
  async function handleTaskDelete(args, storage) {
1384
1402
  const validated = TaskDeleteSchema.parse(args);
1385
- const { repo, id, ids, task_code } = validated;
1403
+ const { owner, repo, id, ids, task_code } = validated;
1386
1404
  const resolvedIds = [];
1387
1405
  if (ids) resolvedIds.push(...ids);
1388
1406
  if (id) resolvedIds.push(id);
1389
1407
  if (task_code) {
1390
- const task = storage.tasks.getTaskByCode(repo, task_code);
1408
+ const task = storage.tasks.getTaskByCode(owner, repo, task_code);
1391
1409
  if (!task) throw new Error(`Task not found: ${task_code}`);
1392
1410
  resolvedIds.push(task.id);
1393
1411
  }
@@ -1426,10 +1444,14 @@ async function handleMemorySynthesize(params, db2, vectors2, options = {}) {
1426
1444
  if (!repo) {
1427
1445
  throw new Error("repo is required when repo cannot be inferred from active MCP roots");
1428
1446
  }
1429
- const recap = await handleMemoryRecap({ repo, limit: 8, offset: 0 }, db2);
1447
+ const repoOwner = validated.owner;
1448
+ const recap = await handleMemoryRecap({ owner: repoOwner, repo, limit: 8, offset: 0 }, db2);
1430
1449
  const recapText = getPrimaryTextContent(recap);
1431
- const summary = validated.include_summary ? db2.summaries.getSummary(repo)?.summary : "";
1432
- const taskSnapshot = validated.include_tasks ? await handleTaskList({ repo, status: "backlog,pending,in_progress,blocked", limit: 15, offset: 0 }, db2) : null;
1450
+ const summary = validated.include_summary ? db2.summaries.getSummary(repoOwner, repo)?.summary : "";
1451
+ const taskSnapshot = validated.include_tasks ? await handleTaskList(
1452
+ { owner: repoOwner, repo, status: "backlog,pending,in_progress,blocked", limit: 15, offset: 0 },
1453
+ db2
1454
+ ) : null;
1433
1455
  const taskText = taskSnapshot ? getPrimaryTextContent(taskSnapshot) : "";
1434
1456
  const systemPrompt = [
1435
1457
  "You are a repository memory synthesizer.",
@@ -1493,7 +1515,7 @@ ${contextBlock || "No additional context provided."}`
1493
1515
  content: [
1494
1516
  {
1495
1517
  type: "text",
1496
- text: await executeSamplingTool(toolUse.name, toolUse.input, db2, vectors2)
1518
+ text: await executeSamplingTool(toolUse.name, toolUse.input, db2, vectors2, repoOwner)
1497
1519
  }
1498
1520
  ]
1499
1521
  }))
@@ -1603,11 +1625,12 @@ function buildSamplingTools(session2, useTools) {
1603
1625
  }
1604
1626
  ];
1605
1627
  }
1606
- async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
1628
+ async function executeSamplingTool(toolName, rawInput, db2, vectors2, owner) {
1607
1629
  switch (toolName) {
1608
1630
  case "memory_search": {
1609
1631
  const response = await handleMemorySearch(
1610
1632
  {
1633
+ owner,
1611
1634
  repo: rawInput.repo,
1612
1635
  query: rawInput.query,
1613
1636
  limit: rawInput.limit ?? 5
@@ -1620,6 +1643,7 @@ async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
1620
1643
  case "memory_recap": {
1621
1644
  const response = await handleMemoryRecap(
1622
1645
  {
1646
+ owner,
1623
1647
  repo: rawInput.repo,
1624
1648
  limit: rawInput.limit ?? 8,
1625
1649
  offset: 0
@@ -1631,6 +1655,7 @@ async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
1631
1655
  case "task_list": {
1632
1656
  const response = await handleTaskList(
1633
1657
  {
1658
+ owner,
1634
1659
  repo: rawInput.repo,
1635
1660
  status: rawInput.status,
1636
1661
  search: rawInput.search,
@@ -1810,7 +1835,8 @@ async function storeSingleStandard(params, db2, vectors2) {
1810
1835
  const conflict = db2.standards.checkConflicts(
1811
1836
  params.content,
1812
1837
  incomingVersion,
1813
- params.repo,
1838
+ params.owner,
1839
+ params.repo ?? void 0,
1814
1840
  incomingLanguage,
1815
1841
  incomingStack,
1816
1842
  0.82
@@ -1837,7 +1863,7 @@ async function storeSingleStandard(params, db2, vectors2) {
1837
1863
  const now = (/* @__PURE__ */ new Date()).toISOString();
1838
1864
  const entry = {
1839
1865
  id: randomUUID3(),
1840
- code: generateNextCode(params.repo || "__global__", "standard", db2),
1866
+ code: generateNextCode(params.owner, params.repo || "__global__", "standard", db2),
1841
1867
  title: params.name,
1842
1868
  content: params.content,
1843
1869
  parent_id: resolveStandardParentId(params.parent_id, db2),
@@ -1846,6 +1872,7 @@ async function storeSingleStandard(params, db2, vectors2) {
1846
1872
  language: params.language || null,
1847
1873
  stack: params.stack || [],
1848
1874
  is_global: params.is_global !== false,
1875
+ owner: params.owner,
1849
1876
  repo: params.repo || null,
1850
1877
  tags: params.tags || [],
1851
1878
  metadata: params.metadata,
@@ -1889,7 +1916,8 @@ async function handleStandardStore(params, db2, vectors2) {
1889
1916
  const conflict = db2.standards.checkConflicts(
1890
1917
  std.content,
1891
1918
  incomingVersion,
1892
- void 0,
1919
+ validated.owner,
1920
+ validated.repo,
1893
1921
  incomingLanguage,
1894
1922
  incomingStack,
1895
1923
  0.82
@@ -1914,7 +1942,7 @@ async function handleStandardStore(params, db2, vectors2) {
1914
1942
  );
1915
1943
  }
1916
1944
  const now = (/* @__PURE__ */ new Date()).toISOString();
1917
- const code = generateNextCode(standardRepo, "standard", db2, batchCodes);
1945
+ const code = generateNextCode(validated.owner ?? "", standardRepo, "standard", db2, batchCodes);
1918
1946
  batchCodes.add(code);
1919
1947
  entries.push({
1920
1948
  id: randomUUID3(),
@@ -1927,6 +1955,7 @@ async function handleStandardStore(params, db2, vectors2) {
1927
1955
  language: std.language || null,
1928
1956
  stack: std.stack || [],
1929
1957
  is_global: std.is_global !== false,
1958
+ owner: validated.owner,
1930
1959
  repo: null,
1931
1960
  tags: std.tags || [],
1932
1961
  metadata: std.metadata,
@@ -1963,6 +1992,7 @@ async function handleStandardStore(params, db2, vectors2) {
1963
1992
  version: validated.version,
1964
1993
  language: validated.language,
1965
1994
  stack: validated.stack,
1995
+ owner: validated.owner,
1966
1996
  repo: validated.repo,
1967
1997
  is_global: validated.is_global,
1968
1998
  tags: validated.tags,
@@ -2357,12 +2387,12 @@ async function handleStandardDelete(params, db2, vectors2) {
2357
2387
  // src/mcp/tools/task.get.ts
2358
2388
  async function handleTaskGet(args, storage) {
2359
2389
  const validated = TaskGetSchema.parse(args);
2360
- const { repo, id, task_code, structured: isStructuredRequest } = validated;
2390
+ const { owner, repo, id, task_code, structured: isStructuredRequest } = validated;
2361
2391
  let task;
2362
2392
  if (id) {
2363
2393
  task = storage.tasks.getTaskById(id);
2364
2394
  } else if (task_code) {
2365
- task = storage.tasks.getTaskByCode(repo, task_code);
2395
+ task = storage.tasks.getTaskByCode(owner, repo, task_code);
2366
2396
  } else {
2367
2397
  throw new Error("Either id or task_code must be provided");
2368
2398
  }
@@ -2398,10 +2428,14 @@ async function handleTaskGet(args, storage) {
2398
2428
  if (task.comments_count !== void 0) lines.push(`Comments: ${task.comments_count}`);
2399
2429
  if (task.coordination) {
2400
2430
  if (task.coordination.active_claim_count > 0) {
2401
- lines.push(`Claim: ${task.coordination.active_claim_agent || "?"} (${task.coordination.active_claim_role || ""}) since ${task.coordination.active_claim_claimed_at || ""}`);
2431
+ lines.push(
2432
+ `Claim: ${task.coordination.active_claim_agent || "?"} (${task.coordination.active_claim_role || ""}) since ${task.coordination.active_claim_claimed_at || ""}`
2433
+ );
2402
2434
  }
2403
2435
  if (task.coordination.pending_handoff_count > 0) {
2404
- lines.push(`Handoff: ${task.coordination.pending_handoff_summary || ""} \u2192 ${task.coordination.pending_handoff_to_agent || "?"}`);
2436
+ lines.push(
2437
+ `Handoff: ${task.coordination.pending_handoff_summary || ""} \u2192 ${task.coordination.pending_handoff_to_agent || "?"}`
2438
+ );
2405
2439
  }
2406
2440
  }
2407
2441
  lines.push(`Created: ${task.created_at}`);
@@ -2446,17 +2480,27 @@ async function handleTaskGet(args, storage) {
2446
2480
  // src/mcp/tools/task.search.ts
2447
2481
  async function handleTaskSearch(args, storage) {
2448
2482
  const validated = TaskSearchSchema.parse(args);
2449
- const { repo, query, status, limit, offset, structured: isStructuredRequest = false, phase, priority } = validated;
2483
+ const {
2484
+ owner,
2485
+ repo,
2486
+ query,
2487
+ status,
2488
+ limit,
2489
+ offset,
2490
+ structured: isStructuredRequest = false,
2491
+ phase,
2492
+ priority
2493
+ } = validated;
2450
2494
  let tasks;
2451
2495
  if (status) {
2452
2496
  const statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
2453
2497
  if (statuses.length > 1) {
2454
- tasks = storage.tasks.getTasksByMultipleStatuses(repo, statuses, void 0, void 0, query);
2498
+ tasks = storage.tasks.getTasksByMultipleStatuses(owner, repo, statuses, void 0, void 0, query);
2455
2499
  } else {
2456
- tasks = storage.tasks.getTasksByRepo(repo, status, void 0, void 0, query);
2500
+ tasks = storage.tasks.getTasksByRepo(owner, repo, status, void 0, void 0, query);
2457
2501
  }
2458
2502
  } else {
2459
- tasks = storage.tasks.getTasksByRepo(repo, void 0, void 0, void 0, query);
2503
+ tasks = storage.tasks.getTasksByRepo(owner, repo, void 0, void 0, void 0, query);
2460
2504
  }
2461
2505
  if (phase) {
2462
2506
  const phaseLower = phase.toLowerCase();
@@ -2676,9 +2720,9 @@ function createRouter(db2, vectors2, options) {
2676
2720
  resultCount: Array.isArray(sc?.results) ? sc.results.length : sc?.count || 0
2677
2721
  };
2678
2722
  if (isWrite) {
2679
- db2.actions.logAction(actionType, repo, logOptions);
2723
+ db2.actions.logAction(actionType, "", repo, logOptions);
2680
2724
  } else {
2681
- await db2.withWrite(() => db2.actions.logAction(actionType, repo, logOptions));
2725
+ await db2.withWrite(() => db2.actions.logAction(actionType, "", repo, logOptions));
2682
2726
  }
2683
2727
  } catch (e) {
2684
2728
  logger.error("Failed to log action", { toolName, error: String(e) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vheins/local-memory-mcp",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "MCP Local Memory Service for coding copilot agents",
5
5
  "mcpName": "io.github.vheins/local-memory-mcp",
6
6
  "type": "module",