@vheins/local-memory-mcp 0.19.15 → 0.19.17

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.
@@ -3462,94 +3462,10 @@ var RealVectorStore = class {
3462
3462
  }
3463
3463
  };
3464
3464
 
3465
- // src/mcp/prompts/loader.ts
3465
+ // src/mcp/session.ts
3466
3466
  import fs4 from "fs";
3467
3467
  import path3 from "path";
3468
3468
  import { fileURLToPath } from "url";
3469
- import matter from "gray-matter";
3470
- var __filename = fileURLToPath(import.meta.url);
3471
- var __dirname = path3.dirname(__filename);
3472
- function findPromptDir() {
3473
- const candidates = [
3474
- // Production if chunked into dist/
3475
- "./prompts",
3476
- // Production if inlined into dist/mcp/
3477
- "../prompts",
3478
- // Dev: /src/mcp/prompts/definitions (next to loader.ts)
3479
- "./definitions"
3480
- ].map((relPath) => path3.resolve(__dirname, relPath));
3481
- for (const dir of candidates) {
3482
- if (fs4.existsSync(dir)) {
3483
- const files = fs4.readdirSync(dir);
3484
- if (files.some((f) => f.endsWith(".md"))) {
3485
- return dir;
3486
- }
3487
- }
3488
- }
3489
- return path3.resolve(__dirname, "./definitions");
3490
- }
3491
- var PROMPT_DIR = findPromptDir();
3492
- var promptCache = /* @__PURE__ */ new Map();
3493
- function listPromptFiles() {
3494
- if (!fs4.existsSync(PROMPT_DIR)) return [];
3495
- return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
3496
- }
3497
- function loadPromptFromMarkdown(name) {
3498
- const cached = promptCache.get(name);
3499
- if (cached) return cached;
3500
- const filePath = path3.join(PROMPT_DIR, `${name}.md`);
3501
- if (!fs4.existsSync(filePath)) {
3502
- throw new Error(`Prompt file not found: ${filePath}`);
3503
- }
3504
- const fileContent = fs4.readFileSync(filePath, "utf-8");
3505
- const { data, content } = matter(fileContent);
3506
- const result = {
3507
- name: data.name || name,
3508
- description: data.description || "",
3509
- arguments: data.arguments || [],
3510
- agent: data.agent,
3511
- content: content.trim()
3512
- };
3513
- promptCache.set(name, result);
3514
- return result;
3515
- }
3516
- function findServerInstructionsDir() {
3517
- const candidates = [
3518
- // Production if chunked into dist/
3519
- "./prompts/server",
3520
- // Production if inlined into dist/mcp/
3521
- "../prompts/server",
3522
- // Dev: /src/mcp/prompts/server (next to loader.ts)
3523
- "./server"
3524
- ].map((relPath) => path3.resolve(__dirname, relPath));
3525
- for (const dir of candidates) {
3526
- if (fs4.existsSync(dir)) {
3527
- const filePath = path3.join(dir, "instructions.md");
3528
- if (fs4.existsSync(filePath)) {
3529
- return dir;
3530
- }
3531
- }
3532
- }
3533
- return path3.resolve(__dirname, "./server");
3534
- }
3535
- var SERVER_DIR = findServerInstructionsDir();
3536
- var serverInstructionsCache = null;
3537
- function loadServerInstructions() {
3538
- if (serverInstructionsCache !== null) return serverInstructionsCache;
3539
- const filePath = path3.join(SERVER_DIR, "instructions.md");
3540
- if (!fs4.existsSync(filePath)) {
3541
- throw new Error(`Server instructions file not found: ${filePath}`);
3542
- }
3543
- const fileContent = fs4.readFileSync(filePath, "utf-8");
3544
- const { content } = matter(fileContent);
3545
- serverInstructionsCache = content.trim();
3546
- return serverInstructionsCache;
3547
- }
3548
-
3549
- // src/mcp/session.ts
3550
- import fs5 from "fs";
3551
- import path4 from "path";
3552
- import { fileURLToPath as fileURLToPath2 } from "url";
3553
3469
  function createSessionContext() {
3554
3470
  return {
3555
3471
  roots: [],
@@ -3567,7 +3483,7 @@ function getFilesystemRoots(session) {
3567
3483
  for (const root of session.roots) {
3568
3484
  if (!root.uri.startsWith("file://")) continue;
3569
3485
  try {
3570
- resolved.push(path4.resolve(fileURLToPath2(root.uri)));
3486
+ resolved.push(path3.resolve(fileURLToPath(root.uri)));
3571
3487
  } catch {
3572
3488
  }
3573
3489
  }
@@ -3576,19 +3492,19 @@ function getFilesystemRoots(session) {
3576
3492
  function isPathWithinRoots(targetPath, session) {
3577
3493
  const roots = getFilesystemRoots(session);
3578
3494
  if (roots.length === 0) return true;
3579
- const normalizedTarget = path4.resolve(targetPath);
3495
+ const normalizedTarget = path3.resolve(targetPath);
3580
3496
  return roots.some((rootPath) => {
3581
- const relative = path4.relative(rootPath, normalizedTarget);
3582
- return relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative);
3497
+ const relative = path3.relative(rootPath, normalizedTarget);
3498
+ return relative === "" || !relative.startsWith("..") && !path3.isAbsolute(relative);
3583
3499
  });
3584
3500
  }
3585
3501
  function findContainingRoot(targetPath, session) {
3586
3502
  const roots = getFilesystemRoots(session);
3587
3503
  if (roots.length === 0) return null;
3588
- const normalizedTarget = path4.resolve(targetPath);
3504
+ const normalizedTarget = path3.resolve(targetPath);
3589
3505
  for (const rootPath of roots) {
3590
- const relative = path4.relative(rootPath, normalizedTarget);
3591
- if (relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative)) {
3506
+ const relative = path3.relative(rootPath, normalizedTarget);
3507
+ if (relative === "" || !relative.startsWith("..") && !path3.isAbsolute(relative)) {
3592
3508
  return rootPath;
3593
3509
  }
3594
3510
  }
@@ -3597,20 +3513,20 @@ function findContainingRoot(targetPath, session) {
3597
3513
  function inferRepoFromSession(session) {
3598
3514
  const roots = getFilesystemRoots(session);
3599
3515
  if (roots.length === 1) {
3600
- return path4.basename(roots[0]);
3516
+ return path3.basename(roots[0]);
3601
3517
  }
3602
3518
  if (roots.length === 0) {
3603
3519
  if (!session) return void 0;
3604
3520
  const cwd = process.cwd();
3605
- return path4.basename(cwd);
3521
+ return path3.basename(cwd);
3606
3522
  }
3607
3523
  return void 0;
3608
3524
  }
3609
3525
  function inferOwnerFromGit(cwd) {
3610
3526
  try {
3611
- const gitConfigPath = path4.join(cwd, ".git", "config");
3612
- if (!fs5.existsSync(gitConfigPath)) return void 0;
3613
- const content = fs5.readFileSync(gitConfigPath, "utf-8");
3527
+ const gitConfigPath = path3.join(cwd, ".git", "config");
3528
+ if (!fs4.existsSync(gitConfigPath)) return void 0;
3529
+ const content = fs4.readFileSync(gitConfigPath, "utf-8");
3614
3530
  const match = content.match(
3615
3531
  /url\s*=\s*(?:git@github\.com:|https?:\/\/github\.com\/|git:\/\/github\.com\/)([^\/\s]+)/
3616
3532
  );
@@ -3632,7 +3548,7 @@ function inferOwnerFromSession(session) {
3632
3548
  if (gitOwner) return gitOwner;
3633
3549
  }
3634
3550
  if (roots.length === 1) {
3635
- const parts = roots[0].split(path4.sep).filter(Boolean);
3551
+ const parts = roots[0].split(path3.sep).filter(Boolean);
3636
3552
  if (parts.length >= 2) {
3637
3553
  return parts[parts.length - 2];
3638
3554
  }
@@ -3640,7 +3556,7 @@ function inferOwnerFromSession(session) {
3640
3556
  if (roots.length === 0) {
3641
3557
  if (!session) return void 0;
3642
3558
  const workdir = process.cwd();
3643
- const parts = workdir.split(path4.sep).filter(Boolean);
3559
+ const parts = workdir.split(path3.sep).filter(Boolean);
3644
3560
  if (parts.length >= 2) {
3645
3561
  return parts[parts.length - 2];
3646
3562
  }
@@ -3648,6 +3564,90 @@ function inferOwnerFromSession(session) {
3648
3564
  return void 0;
3649
3565
  }
3650
3566
 
3567
+ // src/mcp/prompts/loader.ts
3568
+ import fs5 from "fs";
3569
+ import path4 from "path";
3570
+ import { fileURLToPath as fileURLToPath2 } from "url";
3571
+ import matter from "gray-matter";
3572
+ var __filename = fileURLToPath2(import.meta.url);
3573
+ var __dirname = path4.dirname(__filename);
3574
+ function findPromptDir() {
3575
+ const candidates = [
3576
+ // Production if chunked into dist/
3577
+ "./prompts",
3578
+ // Production if inlined into dist/mcp/
3579
+ "../prompts",
3580
+ // Dev: /src/mcp/prompts/definitions (next to loader.ts)
3581
+ "./definitions"
3582
+ ].map((relPath) => path4.resolve(__dirname, relPath));
3583
+ for (const dir of candidates) {
3584
+ if (fs5.existsSync(dir)) {
3585
+ const files = fs5.readdirSync(dir);
3586
+ if (files.some((f) => f.endsWith(".md"))) {
3587
+ return dir;
3588
+ }
3589
+ }
3590
+ }
3591
+ return path4.resolve(__dirname, "./definitions");
3592
+ }
3593
+ var PROMPT_DIR = findPromptDir();
3594
+ var promptCache = /* @__PURE__ */ new Map();
3595
+ function listPromptFiles() {
3596
+ if (!fs5.existsSync(PROMPT_DIR)) return [];
3597
+ return fs5.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
3598
+ }
3599
+ function loadPromptFromMarkdown(name) {
3600
+ const cached = promptCache.get(name);
3601
+ if (cached) return cached;
3602
+ const filePath = path4.join(PROMPT_DIR, `${name}.md`);
3603
+ if (!fs5.existsSync(filePath)) {
3604
+ throw new Error(`Prompt file not found: ${filePath}`);
3605
+ }
3606
+ const fileContent = fs5.readFileSync(filePath, "utf-8");
3607
+ const { data, content } = matter(fileContent);
3608
+ const result = {
3609
+ name: data.name || name,
3610
+ description: data.description || "",
3611
+ arguments: data.arguments || [],
3612
+ agent: data.agent,
3613
+ content: content.trim()
3614
+ };
3615
+ promptCache.set(name, result);
3616
+ return result;
3617
+ }
3618
+ function findServerInstructionsDir() {
3619
+ const candidates = [
3620
+ // Production if chunked into dist/
3621
+ "./prompts/server",
3622
+ // Production if inlined into dist/mcp/
3623
+ "../prompts/server",
3624
+ // Dev: /src/mcp/prompts/server (next to loader.ts)
3625
+ "./server"
3626
+ ].map((relPath) => path4.resolve(__dirname, relPath));
3627
+ for (const dir of candidates) {
3628
+ if (fs5.existsSync(dir)) {
3629
+ const filePath = path4.join(dir, "instructions.md");
3630
+ if (fs5.existsSync(filePath)) {
3631
+ return dir;
3632
+ }
3633
+ }
3634
+ }
3635
+ return path4.resolve(__dirname, "./server");
3636
+ }
3637
+ var SERVER_DIR = findServerInstructionsDir();
3638
+ var serverInstructionsCache = null;
3639
+ function loadServerInstructions() {
3640
+ if (serverInstructionsCache !== null) return serverInstructionsCache;
3641
+ const filePath = path4.join(SERVER_DIR, "instructions.md");
3642
+ if (!fs5.existsSync(filePath)) {
3643
+ throw new Error(`Server instructions file not found: ${filePath}`);
3644
+ }
3645
+ const fileContent = fs5.readFileSync(filePath, "utf-8");
3646
+ const { content } = matter(fileContent);
3647
+ serverInstructionsCache = content.trim();
3648
+ return serverInstructionsCache;
3649
+ }
3650
+
3651
3651
  // src/mcp/tools/definitions/memory.ts
3652
3652
  var MEMORY_TOOL_DEFINITIONS = [
3653
3653
  {
@@ -3896,7 +3896,7 @@ var MEMORY_TOOL_DEFINITIONS = [
3896
3896
  {
3897
3897
  name: "memory-acknowledge",
3898
3898
  title: "Memory Acknowledge",
3899
- description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
3899
+ description: 'Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code. Example: { code: "MEM-123", status: "used" } or { code: "MEM-123", status: "irrelevant" }.',
3900
3900
  annotations: {
3901
3901
  readOnlyHint: false,
3902
3902
  idempotentHint: false,
@@ -6336,6 +6336,164 @@ var TOOL_DEFINITIONS = [
6336
6336
  ...KG_TOOL_DEFINITIONS
6337
6337
  ];
6338
6338
 
6339
+ // src/mcp/utils/completion.ts
6340
+ var MAX_COMPLETION_VALUES = 100;
6341
+ function rankCompletionValues(candidates, input) {
6342
+ const unique = [...new Set(candidates.filter(Boolean))];
6343
+ const needle = input.trim().toLowerCase();
6344
+ if (!needle) {
6345
+ return unique.slice(0, MAX_COMPLETION_VALUES);
6346
+ }
6347
+ return unique.map((value) => ({ value, score: scoreCompletionValue(value, needle) })).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.value.localeCompare(b.value)).map((entry) => entry.value);
6348
+ }
6349
+ function scoreCompletionValue(value, needle) {
6350
+ const haystack = value.toLowerCase();
6351
+ if (haystack === needle) return 100;
6352
+ if (haystack.startsWith(needle)) return 75;
6353
+ if (haystack.includes(needle)) return 50;
6354
+ const compactNeedle = needle.replace(/[\s_-]+/g, "");
6355
+ const compactHaystack = haystack.replace(/[\s_-]+/g, "");
6356
+ if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
6357
+ return 0;
6358
+ }
6359
+
6360
+ // src/mcp/utils/pagination.ts
6361
+ function encodeCursor(offset) {
6362
+ return Buffer.from(String(offset), "utf8").toString("base64");
6363
+ }
6364
+ function decodeCursor(cursor) {
6365
+ if (cursor === void 0 || cursor === null || cursor === "") {
6366
+ return 0;
6367
+ }
6368
+ if (typeof cursor !== "string" || cursor.trim() === "") {
6369
+ throw invalidPaginationParams("Invalid cursor");
6370
+ }
6371
+ let decoded;
6372
+ try {
6373
+ decoded = Buffer.from(cursor, "base64").toString("utf8");
6374
+ } catch {
6375
+ throw invalidPaginationParams("Invalid cursor");
6376
+ }
6377
+ if (!/^\d+$/.test(decoded)) {
6378
+ throw invalidPaginationParams("Invalid cursor");
6379
+ }
6380
+ const offset = Number.parseInt(decoded, 10);
6381
+ if (!Number.isFinite(offset) || offset < 0) {
6382
+ throw invalidPaginationParams("Invalid cursor");
6383
+ }
6384
+ return offset;
6385
+ }
6386
+ function invalidPaginationParams(message) {
6387
+ const error = new Error(message);
6388
+ error.code = -32602;
6389
+ return error;
6390
+ }
6391
+
6392
+ // src/mcp/resources/index.ts
6393
+ var DEFAULT_PAGE_SIZE = 25;
6394
+ var MAX_PAGE_SIZE = 100;
6395
+ function listResources(session, params) {
6396
+ const resources = [
6397
+ {
6398
+ uri: "repository://index",
6399
+ name: "Repository Index",
6400
+ title: "Repository Index",
6401
+ description: "List of all known repositories with memory/task counts and last activity",
6402
+ mimeType: "application/json",
6403
+ annotations: {
6404
+ audience: ["assistant"],
6405
+ priority: 1,
6406
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
6407
+ }
6408
+ },
6409
+ {
6410
+ uri: "session://roots",
6411
+ name: "Session Roots",
6412
+ title: "Session Roots",
6413
+ description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
6414
+ mimeType: "application/json",
6415
+ size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
6416
+ annotations: {
6417
+ audience: ["assistant"],
6418
+ priority: 0.95,
6419
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
6420
+ }
6421
+ }
6422
+ ];
6423
+ return paginateEntries("resources", resources, params);
6424
+ }
6425
+ function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
6426
+ if (resourceUri === "repository://{name}/memories" || resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}" || resourceUri === "repository://{name}/tasks" || resourceUri === "repository://{name}/tasks?status={status}&priority={priority}" || resourceUri === "repository://{name}/summary" || resourceUri === "repository://{name}/actions") {
6427
+ if (argumentName === "name") {
6428
+ return rankCompletionValues(dataSources.repos, argumentValue);
6429
+ }
6430
+ }
6431
+ if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
6432
+ if (argumentName === "tag") {
6433
+ return rankCompletionValues(dataSources.tags, argumentValue);
6434
+ }
6435
+ }
6436
+ throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
6437
+ }
6438
+ function paginateEntries(key, entries, params) {
6439
+ const limit = normalizeLimit(params?.limit);
6440
+ const offset = decodeCursor(params?.cursor);
6441
+ const sliced = entries.slice(offset, offset + limit);
6442
+ const nextOffset = offset + sliced.length;
6443
+ return {
6444
+ [key]: sliced,
6445
+ nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
6446
+ };
6447
+ }
6448
+ function normalizeLimit(limit) {
6449
+ if (typeof limit !== "number" || !Number.isFinite(limit)) {
6450
+ return DEFAULT_PAGE_SIZE;
6451
+ }
6452
+ return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
6453
+ }
6454
+ function invalidCompletionParams(message) {
6455
+ const error = new Error(message);
6456
+ error.code = -32602;
6457
+ return error;
6458
+ }
6459
+
6460
+ // src/mcp/prompts/registry.ts
6461
+ function createPromptDefinition(loaded) {
6462
+ return {
6463
+ name: loaded.name,
6464
+ description: loaded.description,
6465
+ arguments: loaded.arguments,
6466
+ agent: loaded.agent,
6467
+ messages: [
6468
+ {
6469
+ role: "user",
6470
+ content: {
6471
+ type: "text",
6472
+ text: loaded.content
6473
+ }
6474
+ }
6475
+ ]
6476
+ };
6477
+ }
6478
+ var PROMPTS = {};
6479
+ var promptFiles = listPromptFiles();
6480
+ for (const name of promptFiles) {
6481
+ try {
6482
+ PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
6483
+ } catch (e) {
6484
+ logger.warn(`Failed to load prompt ${name}: ${e}`);
6485
+ }
6486
+ }
6487
+ async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
6488
+ void name;
6489
+ void contextArguments;
6490
+ if (argName === "task_id") {
6491
+ const values = dataSources.tasks.map((t) => t.id);
6492
+ return rankCompletionValues(values, value);
6493
+ }
6494
+ return [];
6495
+ }
6496
+
6339
6497
  // src/mcp/tools/handoff.manage.ts
6340
6498
  import { randomUUID as randomUUID2 } from "crypto";
6341
6499
 
@@ -6456,19 +6614,19 @@ var MemoryScopeSchema = z2.object({
6456
6614
  });
6457
6615
  var MemoryTypeSchema = z2.enum(["code_fact", "decision", "mistake", "pattern", "task_archive"]);
6458
6616
  var TaskStatusSchema = z2.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
6459
- var TaskPrioritySchema = z2.number().min(1).max(5);
6617
+ var TaskPrioritySchema = z2.coerce.number().min(1).max(5);
6460
6618
  var HandoffStatusSchema = z2.enum(["pending", "accepted", "rejected", "expired"]);
6461
6619
  var SingleMemorySchema = z2.object({
6462
6620
  code: z2.string().max(20).optional(),
6463
6621
  type: MemoryTypeSchema,
6464
6622
  title: z2.string().min(3).max(255),
6465
6623
  content: z2.string().min(10),
6466
- importance: z2.number().min(1).max(5),
6624
+ importance: z2.coerce.number().min(1).max(5),
6467
6625
  agent: z2.string().min(1),
6468
6626
  role: z2.string().optional().default("unknown"),
6469
6627
  model: z2.string().min(1),
6470
6628
  scope: MemoryScopeSchema,
6471
- ttlDays: z2.number().min(1).optional(),
6629
+ ttlDays: z2.coerce.number().min(1).optional(),
6472
6630
  supersedes: z2.string().optional(),
6473
6631
  tags: z2.array(z2.string()).optional(),
6474
6632
  metadata: z2.record(z2.string(), z2.unknown()).optional(),
@@ -6521,12 +6679,12 @@ var MemoryStoreSchema = z3.object({
6521
6679
  type: MemoryTypeSchema,
6522
6680
  title: z3.string().min(3).max(255),
6523
6681
  content: z3.string().min(10),
6524
- importance: z3.number().min(1).max(5),
6682
+ importance: z3.coerce.number().min(1).max(5),
6525
6683
  agent: z3.string().min(1),
6526
6684
  role: z3.string().optional().default("unknown"),
6527
6685
  model: z3.string().min(1),
6528
6686
  scope: MemoryScopeSchema,
6529
- ttlDays: z3.number().min(1).optional(),
6687
+ ttlDays: z3.coerce.number().min(1).optional(),
6530
6688
  supersedes: z3.string().optional(),
6531
6689
  tags: z3.array(z3.string()).optional(),
6532
6690
  metadata: z3.record(z3.string(), z3.unknown()).optional(),
@@ -6542,7 +6700,7 @@ var MemoryUpdateSchema = z3.object({
6542
6700
  type: MemoryTypeSchema.optional(),
6543
6701
  title: z3.string().min(3).max(255).optional(),
6544
6702
  content: z3.string().min(10).optional(),
6545
- importance: z3.number().min(1).max(5).optional(),
6703
+ importance: z3.coerce.number().min(1).max(5).optional(),
6546
6704
  agent: z3.string().optional(),
6547
6705
  role: z3.string().optional(),
6548
6706
  status: z3.enum(["active", "archived"]).optional(),
@@ -6564,9 +6722,9 @@ var MemorySearchSchema = z3.object({
6564
6722
  owner: z3.string().min(1),
6565
6723
  repo: z3.string().min(1).transform(normalizeRepo),
6566
6724
  types: z3.array(MemoryTypeSchema).optional(),
6567
- minImportance: z3.number().min(1).max(5).optional(),
6568
- limit: z3.number().min(1).max(100).default(5),
6569
- offset: z3.number().min(0).default(0),
6725
+ minImportance: z3.coerce.number().min(1).max(5).optional(),
6726
+ limit: z3.coerce.number().min(1).max(100).default(5),
6727
+ offset: z3.coerce.number().min(0).default(0),
6570
6728
  includeRecap: z3.boolean().default(false),
6571
6729
  current_file_path: z3.string().optional(),
6572
6730
  include_archived: z3.boolean().default(false),
@@ -6579,7 +6737,9 @@ var MemoryAcknowledgeSchema = z3.object({
6579
6737
  code: z3.string().max(20).optional(),
6580
6738
  owner: z3.string().min(1),
6581
6739
  repo: z3.string().min(1).transform(normalizeRepo),
6582
- status: z3.enum(["used", "irrelevant", "contradictory"]),
6740
+ status: z3.enum(["used", "irrelevant", "contradictory"]).describe(
6741
+ `Usage status. Use "used" after generating code from a memory, "irrelevant" if the memory didn't help, or "contradictory" if it conflicts with current understanding.`
6742
+ ),
6583
6743
  application_context: z3.string().min(10).optional(),
6584
6744
  structured: z3.boolean().default(false)
6585
6745
  }).refine((data) => data.memory_id !== void 0 || data.code !== void 0, {
@@ -6588,8 +6748,8 @@ var MemoryAcknowledgeSchema = z3.object({
6588
6748
  var MemoryRecapSchema = z3.object({
6589
6749
  owner: z3.string().min(1, "owner is required \u2014 provide it explicitly or configure MCP workspace roots"),
6590
6750
  repo: z3.string().min(1, "repo is required \u2014 provide it explicitly or configure MCP workspace roots").transform(normalizeRepo),
6591
- limit: z3.number().min(1).max(50).default(20),
6592
- offset: z3.number().min(0).default(0),
6751
+ limit: z3.coerce.number().min(1).max(50).default(20),
6752
+ offset: z3.coerce.number().min(0).default(0),
6593
6753
  structured: z3.boolean().default(false)
6594
6754
  });
6595
6755
  var MemoryDeleteSchema = z3.object({
@@ -6629,8 +6789,8 @@ var MemorySynthesizeSchema = z3.object({
6629
6789
  include_summary: z3.boolean().default(true),
6630
6790
  include_tasks: z3.boolean().default(true),
6631
6791
  use_tools: z3.boolean().default(true),
6632
- max_iterations: z3.number().int().min(1).max(5).default(3),
6633
- max_tokens: z3.number().int().min(128).max(4e3).default(1200),
6792
+ max_iterations: z3.coerce.number().int().min(1).max(5).default(3),
6793
+ max_tokens: z3.coerce.number().int().min(128).max(4e3).default(1200),
6634
6794
  structured: z3.boolean().default(false)
6635
6795
  });
6636
6796
 
@@ -6696,7 +6856,7 @@ var SingleTaskCreateSchema = z4.object({
6696
6856
  metadata: TaskMetadataSchema,
6697
6857
  parent_id: z4.string().optional(),
6698
6858
  depends_on: z4.string().optional(),
6699
- est_tokens: z4.number().int().min(0).optional()
6859
+ est_tokens: z4.coerce.number().int().min(0).optional()
6700
6860
  });
6701
6861
  var TaskStatusListSchema = z4.string().refine(
6702
6862
  (val) => {
@@ -6725,7 +6885,7 @@ var TaskCreateSchema = z4.object({
6725
6885
  metadata: z4.record(z4.string(), z4.unknown()).optional(),
6726
6886
  parent_id: z4.string().optional(),
6727
6887
  depends_on: z4.string().optional(),
6728
- est_tokens: z4.number().int().min(0).optional(),
6888
+ est_tokens: z4.coerce.number().int().min(0).optional(),
6729
6889
  // Allow bulk tasks
6730
6890
  tasks: z4.array(SingleTaskCreateSchema).min(1).optional(),
6731
6891
  structured: z4.boolean().default(false)
@@ -6763,7 +6923,7 @@ var TaskUpdateSchema = z4.object({
6763
6923
  suggested_skills: z4.array(z4.string()).optional(),
6764
6924
  parent_id: z4.string().optional(),
6765
6925
  depends_on: z4.string().optional(),
6766
- est_tokens: z4.number().int().min(0).optional(),
6926
+ est_tokens: z4.coerce.number().int().min(0).optional(),
6767
6927
  commit_id: z4.string().optional(),
6768
6928
  changed_files: z4.array(z4.string()).optional(),
6769
6929
  force: z4.boolean().optional(),
@@ -6782,8 +6942,8 @@ var TaskListSchema = z4.object({
6782
6942
  status: TaskStatusListSchema.default("backlog,pending,in_progress,blocked"),
6783
6943
  phase: z4.string().optional(),
6784
6944
  query: z4.string().optional(),
6785
- limit: z4.number().min(1).max(100).default(15),
6786
- offset: z4.number().min(0).default(0),
6945
+ limit: z4.coerce.number().min(1).max(100).default(15),
6946
+ offset: z4.coerce.number().min(0).default(0),
6787
6947
  structured: z4.boolean().default(false)
6788
6948
  });
6789
6949
  var TaskSearchSchema = z4.object({
@@ -6792,9 +6952,9 @@ var TaskSearchSchema = z4.object({
6792
6952
  query: z4.string().min(1),
6793
6953
  status: z4.string().optional(),
6794
6954
  phase: z4.string().optional(),
6795
- priority: z4.number().min(1).max(5).optional(),
6796
- limit: z4.number().min(1).max(100).default(10),
6797
- offset: z4.number().min(0).default(0),
6955
+ priority: z4.coerce.number().min(1).max(5).optional(),
6956
+ limit: z4.coerce.number().min(1).max(100).default(10),
6957
+ offset: z4.coerce.number().min(0).default(0),
6798
6958
  structured: z4.boolean().default(false)
6799
6959
  });
6800
6960
  var TaskDeleteSchema = z4.object({
@@ -6854,8 +7014,8 @@ var HandoffListSchema = z5.object({
6854
7014
  status: HandoffStatusSchema.optional(),
6855
7015
  from_agent: z5.string().min(1).optional(),
6856
7016
  to_agent: z5.string().min(1).optional(),
6857
- limit: z5.number().min(1).max(100).default(20),
6858
- offset: z5.number().min(0).default(0),
7017
+ limit: z5.coerce.number().min(1).max(100).default(20),
7018
+ offset: z5.coerce.number().min(0).default(0),
6859
7019
  structured: z5.boolean().default(false)
6860
7020
  });
6861
7021
  var TaskClaimSchema = z5.object({
@@ -6877,8 +7037,8 @@ var ClaimListSchema = z5.object({
6877
7037
  repo: z5.string().transform(normalizeRepo).optional().default(""),
6878
7038
  agent: z5.string().min(1).optional(),
6879
7039
  active_only: z5.boolean().default(true),
6880
- limit: z5.number().min(1).max(100).default(20),
6881
- offset: z5.number().min(0).default(0),
7040
+ limit: z5.coerce.number().min(1).max(100).default(20),
7041
+ offset: z5.coerce.number().min(0).default(0),
6882
7042
  structured: z5.boolean().default(false)
6883
7043
  });
6884
7044
  var ClaimReleaseSchema = z5.object({
@@ -6958,8 +7118,8 @@ var StandardSearchSchema = z6.object({
6958
7118
  owner: z6.string().optional().default(""),
6959
7119
  repo: z6.string().transform(normalizeRepo).optional(),
6960
7120
  is_global: z6.boolean().optional(),
6961
- limit: z6.number().min(1).max(100).default(20),
6962
- offset: z6.number().min(0).default(0),
7121
+ limit: z6.coerce.number().min(1).max(100).default(20),
7122
+ offset: z6.coerce.number().min(0).default(0),
6963
7123
  structured: z6.boolean().default(false)
6964
7124
  });
6965
7125
  var StandardDeleteSchema = z6.object({
@@ -6993,7 +7153,7 @@ var AgentContextSchema = z7.object({
6993
7153
  repo: z7.string().min(1),
6994
7154
  objective: z7.string().optional(),
6995
7155
  type_filter: z7.enum(["code_fact", "decision", "mistake", "pattern", "task_archive"]).optional(),
6996
- limit: z7.number().min(1).max(100).default(5),
7156
+ limit: z7.coerce.number().min(1).max(100).default(5),
6997
7157
  structured: z7.boolean().default(false)
6998
7158
  });
6999
7159
  var DecisionLogSchema = z7.object({
@@ -7372,164 +7532,6 @@ async function handleClaimRelease(args, storage) {
7372
7532
  });
7373
7533
  }
7374
7534
 
7375
- // src/mcp/utils/completion.ts
7376
- var MAX_COMPLETION_VALUES = 100;
7377
- function rankCompletionValues(candidates, input) {
7378
- const unique = [...new Set(candidates.filter(Boolean))];
7379
- const needle = input.trim().toLowerCase();
7380
- if (!needle) {
7381
- return unique.slice(0, MAX_COMPLETION_VALUES);
7382
- }
7383
- return unique.map((value) => ({ value, score: scoreCompletionValue(value, needle) })).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.value.localeCompare(b.value)).map((entry) => entry.value);
7384
- }
7385
- function scoreCompletionValue(value, needle) {
7386
- const haystack = value.toLowerCase();
7387
- if (haystack === needle) return 100;
7388
- if (haystack.startsWith(needle)) return 75;
7389
- if (haystack.includes(needle)) return 50;
7390
- const compactNeedle = needle.replace(/[\s_-]+/g, "");
7391
- const compactHaystack = haystack.replace(/[\s_-]+/g, "");
7392
- if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
7393
- return 0;
7394
- }
7395
-
7396
- // src/mcp/utils/pagination.ts
7397
- function encodeCursor(offset) {
7398
- return Buffer.from(String(offset), "utf8").toString("base64");
7399
- }
7400
- function decodeCursor(cursor) {
7401
- if (cursor === void 0 || cursor === null || cursor === "") {
7402
- return 0;
7403
- }
7404
- if (typeof cursor !== "string" || cursor.trim() === "") {
7405
- throw invalidPaginationParams("Invalid cursor");
7406
- }
7407
- let decoded;
7408
- try {
7409
- decoded = Buffer.from(cursor, "base64").toString("utf8");
7410
- } catch {
7411
- throw invalidPaginationParams("Invalid cursor");
7412
- }
7413
- if (!/^\d+$/.test(decoded)) {
7414
- throw invalidPaginationParams("Invalid cursor");
7415
- }
7416
- const offset = Number.parseInt(decoded, 10);
7417
- if (!Number.isFinite(offset) || offset < 0) {
7418
- throw invalidPaginationParams("Invalid cursor");
7419
- }
7420
- return offset;
7421
- }
7422
- function invalidPaginationParams(message) {
7423
- const error = new Error(message);
7424
- error.code = -32602;
7425
- return error;
7426
- }
7427
-
7428
- // src/mcp/prompts/registry.ts
7429
- function createPromptDefinition(loaded) {
7430
- return {
7431
- name: loaded.name,
7432
- description: loaded.description,
7433
- arguments: loaded.arguments,
7434
- agent: loaded.agent,
7435
- messages: [
7436
- {
7437
- role: "user",
7438
- content: {
7439
- type: "text",
7440
- text: loaded.content
7441
- }
7442
- }
7443
- ]
7444
- };
7445
- }
7446
- var PROMPTS = {};
7447
- var promptFiles = listPromptFiles();
7448
- for (const name of promptFiles) {
7449
- try {
7450
- PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
7451
- } catch (e) {
7452
- logger.warn(`Failed to load prompt ${name}: ${e}`);
7453
- }
7454
- }
7455
- async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
7456
- void name;
7457
- void contextArguments;
7458
- if (argName === "task_id") {
7459
- const values = dataSources.tasks.map((t) => t.id);
7460
- return rankCompletionValues(values, value);
7461
- }
7462
- return [];
7463
- }
7464
-
7465
- // src/mcp/resources/index.ts
7466
- var DEFAULT_PAGE_SIZE = 25;
7467
- var MAX_PAGE_SIZE = 100;
7468
- function listResources(session, params) {
7469
- const resources = [
7470
- {
7471
- uri: "repository://index",
7472
- name: "Repository Index",
7473
- title: "Repository Index",
7474
- description: "List of all known repositories with memory/task counts and last activity",
7475
- mimeType: "application/json",
7476
- annotations: {
7477
- audience: ["assistant"],
7478
- priority: 1,
7479
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
7480
- }
7481
- },
7482
- {
7483
- uri: "session://roots",
7484
- name: "Session Roots",
7485
- title: "Session Roots",
7486
- description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
7487
- mimeType: "application/json",
7488
- size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
7489
- annotations: {
7490
- audience: ["assistant"],
7491
- priority: 0.95,
7492
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
7493
- }
7494
- }
7495
- ];
7496
- return paginateEntries("resources", resources, params);
7497
- }
7498
- function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
7499
- if (resourceUri === "repository://{name}/memories" || resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}" || resourceUri === "repository://{name}/tasks" || resourceUri === "repository://{name}/tasks?status={status}&priority={priority}" || resourceUri === "repository://{name}/summary" || resourceUri === "repository://{name}/actions") {
7500
- if (argumentName === "name") {
7501
- return rankCompletionValues(dataSources.repos, argumentValue);
7502
- }
7503
- }
7504
- if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
7505
- if (argumentName === "tag") {
7506
- return rankCompletionValues(dataSources.tags, argumentValue);
7507
- }
7508
- }
7509
- throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
7510
- }
7511
- function paginateEntries(key, entries, params) {
7512
- const limit = normalizeLimit(params?.limit);
7513
- const offset = decodeCursor(params?.cursor);
7514
- const sliced = entries.slice(offset, offset + limit);
7515
- const nextOffset = offset + sliced.length;
7516
- return {
7517
- [key]: sliced,
7518
- nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
7519
- };
7520
- }
7521
- function normalizeLimit(limit) {
7522
- if (typeof limit !== "number" || !Number.isFinite(limit)) {
7523
- return DEFAULT_PAGE_SIZE;
7524
- }
7525
- return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
7526
- }
7527
- function invalidCompletionParams(message) {
7528
- const error = new Error(message);
7529
- error.code = -32602;
7530
- return error;
7531
- }
7532
-
7533
7535
  // src/mcp/tools/standard.shared.ts
7534
7536
  function toContextSlug(value) {
7535
7537
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -7548,20 +7550,30 @@ function buildStandardVectorText(standard) {
7548
7550
  }
7549
7551
 
7550
7552
  export {
7551
- listPromptFiles,
7552
- loadPromptFromMarkdown,
7553
- loadServerInstructions,
7553
+ logger,
7554
+ addLogSink,
7555
+ createFileSink,
7556
+ parseRepoInput,
7557
+ normalizeRepo,
7558
+ SQLiteStore,
7559
+ RealVectorStore,
7560
+ TOOL_DEFINITIONS,
7561
+ rankCompletionValues,
7562
+ listResources,
7563
+ completeResourceArgument,
7554
7564
  createSessionContext,
7555
7565
  getFilesystemRoots,
7556
7566
  isPathWithinRoots,
7557
7567
  findContainingRoot,
7558
7568
  inferRepoFromSession,
7559
7569
  inferOwnerFromSession,
7560
- logger,
7561
- addLogSink,
7562
- createFileSink,
7563
- parseRepoInput,
7564
- normalizeRepo,
7570
+ listPromptFiles,
7571
+ loadPromptFromMarkdown,
7572
+ loadServerInstructions,
7573
+ PROMPTS,
7574
+ completePromptArgument,
7575
+ createMcpResponse,
7576
+ getPrimaryTextContent,
7565
7577
  TaskStatusSchema,
7566
7578
  MemoryStoreSchema,
7567
7579
  MemoryUpdateSchema,
@@ -7593,9 +7605,6 @@ export {
7593
7605
  DeleteRelationSchema,
7594
7606
  DeleteObservationSchema,
7595
7607
  KGBackfillSchema,
7596
- TOOL_DEFINITIONS,
7597
- createMcpResponse,
7598
- getPrimaryTextContent,
7599
7608
  UUID_REGEX,
7600
7609
  handleHandoffCreate,
7601
7610
  handleHandoffList,
@@ -7604,12 +7613,5 @@ export {
7604
7613
  handleClaimList,
7605
7614
  handleClaimRelease,
7606
7615
  toContextSlug,
7607
- buildStandardVectorText,
7608
- rankCompletionValues,
7609
- PROMPTS,
7610
- completePromptArgument,
7611
- listResources,
7612
- completeResourceArgument,
7613
- SQLiteStore,
7614
- RealVectorStore
7616
+ buildStandardVectorText
7615
7617
  };
@@ -15,7 +15,7 @@ import {
15
15
  handleTaskClaim,
16
16
  listResources,
17
17
  logger
18
- } from "../chunk-BPQ42JEQ.js";
18
+ } from "../chunk-7O3T3GQF.js";
19
19
 
20
20
  // src/dashboard/server.ts
21
21
  import express from "express";
@@ -62,7 +62,7 @@ import {
62
62
  parseRepoInput,
63
63
  rankCompletionValues,
64
64
  toContextSlug
65
- } from "../chunk-BPQ42JEQ.js";
65
+ } from "../chunk-7O3T3GQF.js";
66
66
 
67
67
  // src/mcp/server.ts
68
68
  import { serveStdio } from "@modelcontextprotocol/server/stdio";
@@ -75,8 +75,8 @@ import path from "path";
75
75
  import { fileURLToPath } from "url";
76
76
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
77
77
  var pkgVersion = "0.1.0";
78
- if ("0.19.15") {
79
- pkgVersion = "0.19.15";
78
+ if ("0.19.17") {
79
+ pkgVersion = "0.19.17";
80
80
  } else {
81
81
  let searchDir = __dirname;
82
82
  for (let i = 0; i < 5; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vheins/local-memory-mcp",
3
- "version": "0.19.15",
3
+ "version": "0.19.17",
4
4
  "description": "MCP Local Memory Service for coding copilot agents",
5
5
  "mcpName": "io.github.vheins/local-memory-mcp",
6
6
  "type": "module",