@vheins/local-memory-mcp 0.18.13 → 0.19.1

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.
@@ -1,131 +1,5 @@
1
- // src/mcp/capabilities.ts
2
- import { fileURLToPath as fileURLToPath2 } from "url";
3
- import path2 from "path";
4
-
5
- // src/mcp/prompts/loader.ts
6
- import fs from "fs";
7
- import path from "path";
8
- import { fileURLToPath } from "url";
9
- import matter from "gray-matter";
10
- var __filename = fileURLToPath(import.meta.url);
11
- var __dirname = path.dirname(__filename);
12
- function findPromptDir() {
13
- const candidates = [
14
- // Production if chunked into dist/
15
- "./prompts",
16
- // Production if inlined into dist/mcp/
17
- "../prompts",
18
- // Dev: /src/mcp/prompts/definitions (next to loader.ts)
19
- "./definitions"
20
- ].map((relPath) => path.resolve(__dirname, relPath));
21
- for (const dir of candidates) {
22
- if (fs.existsSync(dir)) {
23
- const files = fs.readdirSync(dir);
24
- if (files.some((f) => f.endsWith(".md"))) {
25
- return dir;
26
- }
27
- }
28
- }
29
- return path.resolve(__dirname, "./definitions");
30
- }
31
- var PROMPT_DIR = findPromptDir();
32
- function listPromptFiles() {
33
- if (!fs.existsSync(PROMPT_DIR)) return [];
34
- return fs.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
35
- }
36
- function loadPromptFromMarkdown(name) {
37
- const filePath = path.join(PROMPT_DIR, `${name}.md`);
38
- if (!fs.existsSync(filePath)) {
39
- throw new Error(`Prompt file not found: ${filePath}`);
40
- }
41
- const fileContent = fs.readFileSync(filePath, "utf-8");
42
- const { data, content } = matter(fileContent);
43
- return {
44
- name: data.name || name,
45
- description: data.description || "",
46
- arguments: data.arguments || [],
47
- agent: data.agent,
48
- content: content.trim()
49
- };
50
- }
51
- function findServerInstructionsDir() {
52
- const candidates = [
53
- // Production if chunked into dist/
54
- "./prompts/server",
55
- // Production if inlined into dist/mcp/
56
- "../prompts/server",
57
- // Dev: /src/mcp/prompts/server (next to loader.ts)
58
- "./server"
59
- ].map((relPath) => path.resolve(__dirname, relPath));
60
- for (const dir of candidates) {
61
- if (fs.existsSync(dir)) {
62
- const filePath = path.join(dir, "instructions.md");
63
- if (fs.existsSync(filePath)) {
64
- return dir;
65
- }
66
- }
67
- }
68
- return path.resolve(__dirname, "./server");
69
- }
70
- var SERVER_DIR = findServerInstructionsDir();
71
- function loadServerInstructions() {
72
- const filePath = path.join(SERVER_DIR, "instructions.md");
73
- if (!fs.existsSync(filePath)) {
74
- throw new Error(`Server instructions file not found: ${filePath}`);
75
- }
76
- const fileContent = fs.readFileSync(filePath, "utf-8");
77
- const { content } = matter(fileContent);
78
- return content.trim();
79
- }
80
-
81
- // src/mcp/capabilities.ts
82
- var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
83
- var pkgVersion = "0.1.0";
84
- if ("0.18.13") {
85
- pkgVersion = "0.18.13";
86
- } else {
87
- let searchDir = __dirname2;
88
- for (let i = 0; i < 5; i++) {
89
- const candidate = path2.join(searchDir, "package.json");
90
- try {
91
- if (fs.existsSync(candidate)) {
92
- const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
93
- if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
94
- pkgVersion = pkg.version;
95
- break;
96
- }
97
- }
98
- } catch {
99
- }
100
- searchDir = path2.dirname(searchDir);
101
- }
102
- }
103
- var MCP_PROTOCOL_VERSION = "2025-03-26";
104
- var SERVER_INSTRUCTIONS = loadServerInstructions();
105
- var CAPABILITIES = {
106
- serverInfo: {
107
- name: "local-memory-mcp",
108
- version: pkgVersion,
109
- instructions: SERVER_INSTRUCTIONS
110
- },
111
- capabilities: {
112
- completions: {},
113
- logging: {},
114
- resources: {
115
- subscribe: true,
116
- listChanged: true
117
- },
118
- tools: {
119
- listChanged: false
120
- },
121
- prompts: {
122
- listChanged: true
123
- }
124
- }
125
- };
126
-
127
1
  // src/mcp/utils/logger.ts
128
- import fs2 from "fs";
2
+ import fs from "fs";
129
3
  var LEVELS = {
130
4
  debug: 0,
131
5
  info: 1,
@@ -225,31 +99,17 @@ var logger = {
225
99
  log("emergency", message, context);
226
100
  }
227
101
  };
228
- function setLogLevel(level) {
229
- const raw = level.toLowerCase();
230
- const normalized = LEVEL_ALIASES[raw] || raw;
231
- if (!(normalized in LEVELS)) {
232
- const error = new Error(`Invalid log level: ${level}`);
233
- error.code = -32602;
234
- throw error;
235
- }
236
- currentLevel = normalized;
237
- return currentLevel;
238
- }
239
- function getLogLevel() {
240
- return currentLevel;
241
- }
242
102
  function addLogSink(sink) {
243
103
  sinks.add(sink);
244
104
  return () => sinks.delete(sink);
245
105
  }
246
106
  var LOG_LEVEL_VALUES = Object.keys(LEVELS);
247
107
  function createFileSink(logDir, maxFiles = 5) {
248
- fs2.mkdirSync(logDir, { recursive: true });
249
- const existing = fs2.readdirSync(logDir).filter((f) => f.startsWith("mcp-") && f.endsWith(".log")).sort();
108
+ fs.mkdirSync(logDir, { recursive: true });
109
+ const existing = fs.readdirSync(logDir).filter((f) => f.startsWith("mcp-") && f.endsWith(".log")).sort();
250
110
  while (existing.length >= maxFiles) {
251
111
  try {
252
- fs2.unlinkSync(`${logDir}/${existing.shift()}`);
112
+ fs.unlinkSync(`${logDir}/${existing.shift()}`);
253
113
  } catch {
254
114
  }
255
115
  }
@@ -259,7 +119,7 @@ function createFileSink(logDir, maxFiles = 5) {
259
119
  const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${payload.level.toUpperCase()}] [pid:${process.pid}] ${JSON.stringify(payload.data)}
260
120
  `;
261
121
  try {
262
- fs2.appendFileSync(logFile, line);
122
+ fs.appendFileSync(logFile, line);
263
123
  } catch {
264
124
  }
265
125
  };
@@ -267,8 +127,8 @@ function createFileSink(logDir, maxFiles = 5) {
267
127
 
268
128
  // src/mcp/storage/sqlite.ts
269
129
  import Database from "better-sqlite3";
270
- import path4 from "path";
271
- import fs4 from "fs";
130
+ import path2 from "path";
131
+ import fs3 from "fs";
272
132
  import os from "os";
273
133
 
274
134
  // src/mcp/storage/migrations.ts
@@ -504,6 +364,50 @@ var MigrationManager = class {
504
364
  CREATE INDEX IF NOT EXISTS idx_claims_task_id ON claims(task_id);
505
365
  CREATE INDEX IF NOT EXISTS idx_claims_agent ON claims(agent);
506
366
  CREATE INDEX IF NOT EXISTS idx_claims_claimed_at ON claims(claimed_at);
367
+
368
+ CREATE TABLE IF NOT EXISTS entities (
369
+ name TEXT PRIMARY KEY,
370
+ type TEXT NOT NULL DEFAULT 'unknown',
371
+ description TEXT,
372
+ repo TEXT NOT NULL DEFAULT '',
373
+ owner TEXT NOT NULL DEFAULT '',
374
+ created_at TEXT NOT NULL,
375
+ updated_at TEXT NOT NULL
376
+ );
377
+
378
+ CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
379
+ CREATE INDEX IF NOT EXISTS idx_entities_repo ON entities(repo);
380
+
381
+ CREATE TABLE IF NOT EXISTS relations (
382
+ from_entity TEXT NOT NULL,
383
+ to_entity TEXT NOT NULL,
384
+ relation_type TEXT NOT NULL,
385
+ repo TEXT NOT NULL DEFAULT '',
386
+ owner TEXT NOT NULL DEFAULT '',
387
+ created_at TEXT NOT NULL,
388
+ PRIMARY KEY (from_entity, to_entity, relation_type),
389
+ FOREIGN KEY (from_entity) REFERENCES entities(name) ON DELETE CASCADE,
390
+ FOREIGN KEY (to_entity) REFERENCES entities(name) ON DELETE CASCADE
391
+ );
392
+
393
+ CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity);
394
+ CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity);
395
+ CREATE INDEX IF NOT EXISTS idx_relations_type ON relations(relation_type);
396
+ CREATE INDEX IF NOT EXISTS idx_relations_repo ON relations(repo);
397
+
398
+ CREATE TABLE IF NOT EXISTS observations (
399
+ id TEXT PRIMARY KEY,
400
+ entity_name TEXT NOT NULL,
401
+ observation TEXT NOT NULL,
402
+ repo TEXT NOT NULL DEFAULT '',
403
+ owner TEXT NOT NULL DEFAULT '',
404
+ created_at TEXT NOT NULL,
405
+ FOREIGN KEY (entity_name) REFERENCES entities(name) ON DELETE CASCADE
406
+ );
407
+
408
+ CREATE INDEX IF NOT EXISTS idx_observations_entity ON observations(entity_name);
409
+ CREATE INDEX IF NOT EXISTS idx_observations_repo ON observations(repo);
410
+ CREATE INDEX IF NOT EXISTS idx_observations_created_at ON observations(created_at);
507
411
  `);
508
412
  const columnsToAdd = [
509
413
  { name: "title", table: "memories", definition: "ALTER TABLE memories ADD COLUMN title TEXT" },
@@ -1561,7 +1465,7 @@ var MemoryEntity = class extends BaseEntity {
1561
1465
  );
1562
1466
  }
1563
1467
  listMemoriesForDashboard(options) {
1564
- let {
1468
+ const {
1565
1469
  owner,
1566
1470
  repo,
1567
1471
  type,
@@ -1572,9 +1476,9 @@ var MemoryEntity = class extends BaseEntity {
1572
1476
  search,
1573
1477
  offset = 0,
1574
1478
  limit = 50,
1575
- sortBy = "created_at",
1576
1479
  sortOrder = "DESC"
1577
1480
  } = options;
1481
+ let sortBy = options.sortBy ?? "created_at";
1578
1482
  const ALLOWED_SORT_COLUMNS = /* @__PURE__ */ new Set([
1579
1483
  "created_at",
1580
1484
  "updated_at",
@@ -3199,8 +3103,8 @@ var HandoffEntity = class extends BaseEntity {
3199
3103
 
3200
3104
  // src/mcp/storage/write-lock.ts
3201
3105
  import lockfile from "proper-lockfile";
3202
- import path3 from "path";
3203
- import fs3 from "fs";
3106
+ import path from "path";
3107
+ import fs2 from "fs";
3204
3108
  var LOCK_STALE_MS = 3e4;
3205
3109
  var LOCK_RETRY_DELAY_MS = 200;
3206
3110
  var LOCK_RETRY_COUNT = 250;
@@ -3209,9 +3113,9 @@ var WriteLock = class {
3209
3113
  locked = false;
3210
3114
  constructor(dbPath) {
3211
3115
  this.lockTarget = dbPath;
3212
- if (!fs3.existsSync(dbPath)) {
3213
- fs3.mkdirSync(path3.dirname(dbPath), { recursive: true });
3214
- fs3.writeFileSync(dbPath, "");
3116
+ if (!fs2.existsSync(dbPath)) {
3117
+ fs2.mkdirSync(path.dirname(dbPath), { recursive: true });
3118
+ fs2.writeFileSync(dbPath, "");
3215
3119
  }
3216
3120
  }
3217
3121
  /**
@@ -3263,13 +3167,13 @@ var WriteLock = class {
3263
3167
  // src/mcp/storage/sqlite.ts
3264
3168
  function resolveDbPath() {
3265
3169
  if (process.env.MEMORY_DB_PATH) return process.env.MEMORY_DB_PATH;
3266
- const standardConfigDir = process.platform === "win32" ? path4.join(os.homedir(), ".local-memory-mcp") : process.platform === "darwin" ? path4.join(os.homedir(), "Library", "Application Support", "local-memory-mcp") : path4.join(os.homedir(), ".config", "local-memory-mcp");
3267
- const standardPath = path4.join(standardConfigDir, "memory.db");
3268
- if (fs4.existsSync(standardPath)) return standardPath;
3269
- const legacyPath = path4.join(os.homedir(), ".config", "local-memory-mcp", "memory.db");
3270
- if (fs4.existsSync(legacyPath)) return legacyPath;
3271
- const localCwdFile = path4.join(process.cwd(), "storage", "memory.db");
3272
- if (fs4.existsSync(localCwdFile)) return localCwdFile;
3170
+ const standardConfigDir = process.platform === "win32" ? path2.join(os.homedir(), ".local-memory-mcp") : process.platform === "darwin" ? path2.join(os.homedir(), "Library", "Application Support", "local-memory-mcp") : path2.join(os.homedir(), ".config", "local-memory-mcp");
3171
+ const standardPath = path2.join(standardConfigDir, "memory.db");
3172
+ if (fs3.existsSync(standardPath)) return standardPath;
3173
+ const legacyPath = path2.join(os.homedir(), ".config", "local-memory-mcp", "memory.db");
3174
+ if (fs3.existsSync(legacyPath)) return legacyPath;
3175
+ const localCwdFile = path2.join(process.cwd(), "storage", "memory.db");
3176
+ if (fs3.existsSync(localCwdFile)) return localCwdFile;
3273
3177
  return standardPath;
3274
3178
  }
3275
3179
  var DB_PATH = resolveDbPath();
@@ -3292,9 +3196,9 @@ var SQLiteStore = class _SQLiteStore {
3292
3196
  const finalPath = dbPath ?? DB_PATH;
3293
3197
  this.dbPathInstance = finalPath;
3294
3198
  if (finalPath !== ":memory:") {
3295
- const dbDir = path4.dirname(finalPath);
3296
- if (!fs4.existsSync(dbDir)) {
3297
- fs4.mkdirSync(dbDir, { recursive: true });
3199
+ const dbDir = path2.dirname(finalPath);
3200
+ if (!fs3.existsSync(dbDir)) {
3201
+ fs3.mkdirSync(dbDir, { recursive: true });
3298
3202
  }
3299
3203
  }
3300
3204
  this.db = new Database(finalPath);
@@ -3353,12 +3257,12 @@ var SQLiteStore = class _SQLiteStore {
3353
3257
  */
3354
3258
  _attemptRecovery(dbPath) {
3355
3259
  const backupPath = dbPath + ".backup";
3356
- if (fs4.existsSync(backupPath)) {
3260
+ if (fs3.existsSync(backupPath)) {
3357
3261
  logger.warn("[SQLiteStore] Attempting recovery from backup", { backupPath });
3358
3262
  try {
3359
3263
  const corruptPath = `${dbPath}.corrupt_${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15)}`;
3360
- fs4.copyFileSync(dbPath, corruptPath);
3361
- fs4.copyFileSync(backupPath, dbPath);
3264
+ fs3.copyFileSync(dbPath, corruptPath);
3265
+ fs3.copyFileSync(backupPath, dbPath);
3362
3266
  logger.warn("[SQLiteStore] Recovery successful. Corrupt file saved to", { corruptPath });
3363
3267
  } catch (err) {
3364
3268
  logger.error("[SQLiteStore] Recovery failed", { error: String(err) });
@@ -3376,7 +3280,7 @@ var SQLiteStore = class _SQLiteStore {
3376
3280
  try {
3377
3281
  this.db.pragma("wal_checkpoint(PASSIVE)");
3378
3282
  const backupPath = this.dbPathInstance + ".backup";
3379
- fs4.copyFileSync(this.dbPathInstance, backupPath);
3283
+ fs3.copyFileSync(this.dbPathInstance, backupPath);
3380
3284
  } catch (err) {
3381
3285
  logger.warn("[SQLiteStore] Backup failed", { error: String(err) });
3382
3286
  }
@@ -3499,8 +3403,8 @@ var RealVectorStore = class {
3499
3403
  };
3500
3404
 
3501
3405
  // src/mcp/session.ts
3502
- import path5 from "path";
3503
- import { fileURLToPath as fileURLToPath3 } from "url";
3406
+ import path3 from "path";
3407
+ import { fileURLToPath } from "url";
3504
3408
  function createSessionContext() {
3505
3409
  return {
3506
3410
  roots: [],
@@ -3512,60 +3416,13 @@ function createSessionContext() {
3512
3416
  supportsElicitationUrl: false
3513
3417
  };
3514
3418
  }
3515
- function updateSessionFromInitialize(session, params) {
3516
- const capabilities = params?.capabilities || {};
3517
- session.clientInfo = params?.clientInfo;
3518
- session.clientCapabilities = capabilities;
3519
- session.supportsRoots = Boolean(capabilities.roots);
3520
- session.supportsSampling = Boolean(capabilities.sampling);
3521
- const sampling = capabilities.sampling;
3522
- session.supportsSamplingTools = Boolean(sampling?.tools);
3523
- session.supportsElicitation = Boolean(capabilities.elicitation);
3524
- session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
3525
- session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
3526
- }
3527
- function supportsElicitationMode(capability, mode) {
3528
- if (!capability || typeof capability !== "object") {
3529
- return false;
3530
- }
3531
- const cap = capability;
3532
- if (mode === "form") {
3533
- return Object.keys(cap).length === 0 || typeof cap.form === "object";
3534
- }
3535
- return typeof cap.url === "object";
3536
- }
3537
- function updateSessionRoots(session, roots) {
3538
- const normalized = normalizeRoots(roots);
3539
- const previous = JSON.stringify(session.roots);
3540
- const next = JSON.stringify(normalized);
3541
- session.roots = normalized;
3542
- return previous !== next;
3543
- }
3544
- function normalizeRoots(roots) {
3545
- if (!Array.isArray(roots)) return [];
3546
- const seen = /* @__PURE__ */ new Set();
3547
- const normalized = [];
3548
- for (const root of roots) {
3549
- if (!root || typeof root !== "object") continue;
3550
- const r = root;
3551
- const uri = typeof r.uri === "string" ? r.uri : void 0;
3552
- const name = typeof r.name === "string" ? r.name : void 0;
3553
- if (!uri || seen.has(uri)) continue;
3554
- seen.add(uri);
3555
- normalized.push({ uri, name });
3556
- }
3557
- return normalized;
3558
- }
3559
- function extractRootsFromResult(result) {
3560
- return normalizeRoots(result?.roots);
3561
- }
3562
3419
  function getFilesystemRoots(session) {
3563
3420
  if (!session) return [];
3564
3421
  const resolved = [];
3565
3422
  for (const root of session.roots) {
3566
3423
  if (!root.uri.startsWith("file://")) continue;
3567
3424
  try {
3568
- resolved.push(path5.resolve(fileURLToPath3(root.uri)));
3425
+ resolved.push(path3.resolve(fileURLToPath(root.uri)));
3569
3426
  } catch {
3570
3427
  }
3571
3428
  }
@@ -3574,19 +3431,19 @@ function getFilesystemRoots(session) {
3574
3431
  function isPathWithinRoots(targetPath, session) {
3575
3432
  const roots = getFilesystemRoots(session);
3576
3433
  if (roots.length === 0) return true;
3577
- const normalizedTarget = path5.resolve(targetPath);
3434
+ const normalizedTarget = path3.resolve(targetPath);
3578
3435
  return roots.some((rootPath) => {
3579
- const relative = path5.relative(rootPath, normalizedTarget);
3580
- return relative === "" || !relative.startsWith("..") && !path5.isAbsolute(relative);
3436
+ const relative = path3.relative(rootPath, normalizedTarget);
3437
+ return relative === "" || !relative.startsWith("..") && !path3.isAbsolute(relative);
3581
3438
  });
3582
3439
  }
3583
3440
  function findContainingRoot(targetPath, session) {
3584
3441
  const roots = getFilesystemRoots(session);
3585
3442
  if (roots.length === 0) return null;
3586
- const normalizedTarget = path5.resolve(targetPath);
3443
+ const normalizedTarget = path3.resolve(targetPath);
3587
3444
  for (const rootPath of roots) {
3588
- const relative = path5.relative(rootPath, normalizedTarget);
3589
- if (relative === "" || !relative.startsWith("..") && !path5.isAbsolute(relative)) {
3445
+ const relative = path3.relative(rootPath, normalizedTarget);
3446
+ if (relative === "" || !relative.startsWith("..") && !path3.isAbsolute(relative)) {
3590
3447
  return rootPath;
3591
3448
  }
3592
3449
  }
@@ -3595,14 +3452,14 @@ function findContainingRoot(targetPath, session) {
3595
3452
  function inferRepoFromSession(session) {
3596
3453
  const roots = getFilesystemRoots(session);
3597
3454
  if (roots.length === 1) {
3598
- return path5.basename(roots[0]);
3455
+ return path3.basename(roots[0]);
3599
3456
  }
3600
3457
  return void 0;
3601
3458
  }
3602
3459
  function inferOwnerFromSession(session) {
3603
3460
  const roots = getFilesystemRoots(session);
3604
3461
  if (roots.length === 1) {
3605
- const parts = roots[0].split(path5.sep).filter(Boolean);
3462
+ const parts = roots[0].split(path3.sep).filter(Boolean);
3606
3463
  if (parts.length >= 2) {
3607
3464
  return parts[parts.length - 2];
3608
3465
  }
@@ -3610,6 +3467,82 @@ function inferOwnerFromSession(session) {
3610
3467
  return void 0;
3611
3468
  }
3612
3469
 
3470
+ // src/mcp/prompts/loader.ts
3471
+ import fs4 from "fs";
3472
+ import path4 from "path";
3473
+ import { fileURLToPath as fileURLToPath2 } from "url";
3474
+ import matter from "gray-matter";
3475
+ var __filename = fileURLToPath2(import.meta.url);
3476
+ var __dirname = path4.dirname(__filename);
3477
+ function findPromptDir() {
3478
+ const candidates = [
3479
+ // Production if chunked into dist/
3480
+ "./prompts",
3481
+ // Production if inlined into dist/mcp/
3482
+ "../prompts",
3483
+ // Dev: /src/mcp/prompts/definitions (next to loader.ts)
3484
+ "./definitions"
3485
+ ].map((relPath) => path4.resolve(__dirname, relPath));
3486
+ for (const dir of candidates) {
3487
+ if (fs4.existsSync(dir)) {
3488
+ const files = fs4.readdirSync(dir);
3489
+ if (files.some((f) => f.endsWith(".md"))) {
3490
+ return dir;
3491
+ }
3492
+ }
3493
+ }
3494
+ return path4.resolve(__dirname, "./definitions");
3495
+ }
3496
+ var PROMPT_DIR = findPromptDir();
3497
+ function listPromptFiles() {
3498
+ if (!fs4.existsSync(PROMPT_DIR)) return [];
3499
+ return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
3500
+ }
3501
+ function loadPromptFromMarkdown(name) {
3502
+ const filePath = path4.join(PROMPT_DIR, `${name}.md`);
3503
+ if (!fs4.existsSync(filePath)) {
3504
+ throw new Error(`Prompt file not found: ${filePath}`);
3505
+ }
3506
+ const fileContent = fs4.readFileSync(filePath, "utf-8");
3507
+ const { data, content } = matter(fileContent);
3508
+ return {
3509
+ name: data.name || name,
3510
+ description: data.description || "",
3511
+ arguments: data.arguments || [],
3512
+ agent: data.agent,
3513
+ content: content.trim()
3514
+ };
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) => path4.resolve(__dirname, relPath));
3525
+ for (const dir of candidates) {
3526
+ if (fs4.existsSync(dir)) {
3527
+ const filePath = path4.join(dir, "instructions.md");
3528
+ if (fs4.existsSync(filePath)) {
3529
+ return dir;
3530
+ }
3531
+ }
3532
+ }
3533
+ return path4.resolve(__dirname, "./server");
3534
+ }
3535
+ var SERVER_DIR = findServerInstructionsDir();
3536
+ function loadServerInstructions() {
3537
+ const filePath = path4.join(SERVER_DIR, "instructions.md");
3538
+ if (!fs4.existsSync(filePath)) {
3539
+ throw new Error(`Server instructions file not found: ${filePath}`);
3540
+ }
3541
+ const fileContent = fs4.readFileSync(filePath, "utf-8");
3542
+ const { content } = matter(fileContent);
3543
+ return content.trim();
3544
+ }
3545
+
3613
3546
  // src/mcp/tools/definitions/memory.ts
3614
3547
  var MEMORY_TOOL_DEFINITIONS = [
3615
3548
  {
@@ -5595,180 +5528,640 @@ var STANDARD_TOOL_DEFINITIONS = [
5595
5528
  }
5596
5529
  ];
5597
5530
 
5598
- // src/mcp/tools/definitions/index.ts
5599
- var TOOL_DEFINITIONS = [
5600
- ...MEMORY_TOOL_DEFINITIONS,
5601
- ...TASK_TOOL_DEFINITIONS,
5602
- ...HANDOFF_TOOL_DEFINITIONS,
5603
- ...STANDARD_TOOL_DEFINITIONS
5604
- ];
5605
-
5606
- // src/mcp/utils/pagination.ts
5607
- function encodeCursor(offset) {
5608
- return Buffer.from(String(offset), "utf8").toString("base64");
5609
- }
5610
- function decodeCursor(cursor) {
5611
- if (cursor === void 0 || cursor === null || cursor === "") {
5612
- return 0;
5613
- }
5614
- if (typeof cursor !== "string" || cursor.trim() === "") {
5615
- throw invalidPaginationParams("Invalid cursor");
5616
- }
5617
- let decoded;
5618
- try {
5619
- decoded = Buffer.from(cursor, "base64").toString("utf8");
5620
- } catch {
5621
- throw invalidPaginationParams("Invalid cursor");
5622
- }
5623
- if (!/^\d+$/.test(decoded)) {
5624
- throw invalidPaginationParams("Invalid cursor");
5625
- }
5626
- const offset = Number.parseInt(decoded, 10);
5627
- if (!Number.isFinite(offset) || offset < 0) {
5628
- throw invalidPaginationParams("Invalid cursor");
5629
- }
5630
- return offset;
5631
- }
5632
- function invalidPaginationParams(message) {
5633
- const error = new Error(message);
5634
- error.code = -32602;
5635
- return error;
5636
- }
5637
-
5638
- // src/mcp/utils/completion.ts
5639
- var MAX_COMPLETION_VALUES = 100;
5640
- function rankCompletionValues(candidates, input) {
5641
- const unique = [...new Set(candidates.filter(Boolean))];
5642
- const needle = input.trim().toLowerCase();
5643
- if (!needle) {
5644
- return unique.slice(0, MAX_COMPLETION_VALUES);
5645
- }
5646
- 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);
5647
- }
5648
- function scoreCompletionValue(value, needle) {
5649
- const haystack = value.toLowerCase();
5650
- if (haystack === needle) return 100;
5651
- if (haystack.startsWith(needle)) return 75;
5652
- if (haystack.includes(needle)) return 50;
5653
- const compactNeedle = needle.replace(/[\s_-]+/g, "");
5654
- const compactHaystack = haystack.replace(/[\s_-]+/g, "");
5655
- if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
5656
- return 0;
5657
- }
5658
-
5659
- // src/mcp/resources/index.ts
5660
- var DEFAULT_PAGE_SIZE = 25;
5661
- var MAX_PAGE_SIZE = 100;
5662
- function listResources(session, params) {
5663
- const resources = [
5664
- {
5665
- uri: "repository://index",
5666
- name: "Repository Index",
5667
- title: "Repository Index",
5668
- description: "List of all known repositories with memory/task counts and last activity",
5669
- mimeType: "application/json",
5670
- annotations: {
5671
- audience: ["assistant"],
5672
- priority: 1,
5673
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5674
- }
5531
+ // src/mcp/tools/definitions/agent.ts
5532
+ var AGENT_TOOL_DEFINITIONS = [
5533
+ {
5534
+ name: "agent-context",
5535
+ title: "Agent Context Recall",
5536
+ description: "Returns relevant context for the current agent session. Auto-detects active repo, searches relevant memories, lists active tasks, and surfaces recent decisions formatted as a single context block ready for injection into agent prompts.",
5537
+ annotations: {
5538
+ readOnlyHint: true,
5539
+ idempotentHint: true,
5540
+ openWorldHint: false
5675
5541
  },
5676
- {
5677
- uri: "session://roots",
5678
- name: "Session Roots",
5679
- title: "Session Roots",
5680
- description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
5681
- mimeType: "application/json",
5682
- size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
5683
- annotations: {
5684
- audience: ["assistant"],
5685
- priority: 0.95,
5686
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5542
+ inputSchema: {
5543
+ type: "object",
5544
+ properties: {
5545
+ owner: {
5546
+ type: "string",
5547
+ description: "Organization/namespace (e.g., GitHub org or username). Auto-detected from session when omitted."
5548
+ },
5549
+ repo: {
5550
+ type: "string",
5551
+ description: "Repository/project name. Auto-detected from session when omitted."
5552
+ },
5553
+ objective: {
5554
+ type: "string",
5555
+ description: "Current agent objective to search relevant memories around."
5556
+ },
5557
+ type_filter: {
5558
+ type: "string",
5559
+ description: "Memory type to filter by (e.g., 'decision', 'code_fact', 'pattern', 'mistake'). Default: all."
5560
+ },
5561
+ limit: {
5562
+ type: "number",
5563
+ minimum: 1,
5564
+ maximum: 100,
5565
+ default: 5,
5566
+ description: "Maximum number of memories to return."
5567
+ },
5568
+ structured: {
5569
+ type: "boolean",
5570
+ default: false,
5571
+ description: "If true, returns structured JSON results."
5572
+ }
5687
5573
  }
5574
+ },
5575
+ outputSchema: {
5576
+ type: "object",
5577
+ properties: {
5578
+ schema: { type: "string", enum: ["agent-context"] },
5579
+ repo: { type: "string" },
5580
+ objective: { type: "string" },
5581
+ memories: {
5582
+ type: "array",
5583
+ items: {
5584
+ type: "object",
5585
+ properties: {
5586
+ id: { type: "string" },
5587
+ code: { type: "string" },
5588
+ title: { type: "string" },
5589
+ type: { type: "string" },
5590
+ importance: { type: "number" }
5591
+ }
5592
+ }
5593
+ },
5594
+ decisions: {
5595
+ type: "array",
5596
+ items: {
5597
+ type: "object",
5598
+ properties: {
5599
+ id: { type: "string" },
5600
+ code: { type: "string" },
5601
+ title: { type: "string" },
5602
+ importance: { type: "number" }
5603
+ }
5604
+ }
5605
+ },
5606
+ tasks: {
5607
+ type: "array",
5608
+ items: {
5609
+ type: "object",
5610
+ properties: {
5611
+ task_code: { type: "string" },
5612
+ title: { type: "string" },
5613
+ status: { type: "string" },
5614
+ priority: { type: "number" }
5615
+ }
5616
+ }
5617
+ }
5618
+ },
5619
+ required: ["schema", "repo", "memories", "decisions", "tasks"]
5688
5620
  }
5689
- ];
5690
- return paginateEntries("resources", resources, params);
5691
- }
5692
- function listResourceTemplates(params) {
5693
- const templates = [
5694
- // ── Memory ──────────────────────────────────────────────────────────────
5695
- {
5696
- uriTemplate: "repository://{name}/memories",
5697
- name: "Repository Memories",
5698
- title: "Repository Memories",
5699
- description: "All active memory entries for a specific repository",
5700
- mimeType: "application/json",
5701
- annotations: { audience: ["assistant"], priority: 0.85 }
5621
+ },
5622
+ {
5623
+ name: "decision-log",
5624
+ title: "Decision Logger",
5625
+ description: "Logs a structured decision as a memory entry. Accepts a summary of what was decided, the context/situation, the rationale, and optional alternatives considered. Internally reuses the memory-store handler with type='decision' and importance=4. Owner and repo are auto-inferred from session when omitted.",
5626
+ annotations: {
5627
+ readOnlyHint: false,
5628
+ idempotentHint: false,
5629
+ openWorldHint: false
5702
5630
  },
5703
- {
5704
- uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
5705
- name: "Filtered Repository Memories",
5706
- title: "Filtered Repository Memories",
5707
- description: "Filter or search memories within a repository by keyword, type, or tag",
5708
- mimeType: "application/json",
5709
- annotations: { audience: ["assistant"], priority: 0.8 }
5631
+ inputSchema: {
5632
+ type: "object",
5633
+ properties: {
5634
+ summary: {
5635
+ type: "string",
5636
+ description: "What was decided (used as the memory title). Max 255 characters."
5637
+ },
5638
+ context: {
5639
+ type: "string",
5640
+ description: "The situation or context surrounding the decision. Min 10 characters."
5641
+ },
5642
+ rationale: {
5643
+ type: "string",
5644
+ description: "Why this decision was made. Min 10 characters."
5645
+ },
5646
+ alternatives: {
5647
+ type: "array",
5648
+ items: { type: "string" },
5649
+ description: "Alternatives that were considered (optional)."
5650
+ },
5651
+ tags: {
5652
+ type: "array",
5653
+ items: { type: "string" },
5654
+ description: "Additional tags to apply (auto-includes 'decision')."
5655
+ },
5656
+ owner: {
5657
+ type: "string",
5658
+ description: "Organization/namespace. Auto-detected from session when omitted."
5659
+ },
5660
+ repo: {
5661
+ type: "string",
5662
+ description: "Repository/project name. Auto-detected from session when omitted."
5663
+ },
5664
+ structured: {
5665
+ type: "boolean",
5666
+ default: false,
5667
+ description: "If true, returns structured JSON results."
5668
+ }
5669
+ },
5670
+ required: ["summary", "context", "rationale"]
5710
5671
  },
5711
- {
5712
- uriTemplate: "memory://{id}",
5713
- name: "Memory Detail",
5714
- title: "Memory Detail",
5715
- description: "Full content and statistics for a specific memory UUID",
5716
- mimeType: "application/json",
5717
- annotations: { audience: ["assistant"], priority: 0.75 }
5672
+ outputSchema: {
5673
+ type: "object",
5674
+ properties: {
5675
+ success: { type: "boolean" },
5676
+ id: { type: "string" },
5677
+ code: { type: "string" },
5678
+ repo: { type: "string" },
5679
+ type: { type: "string", enum: ["decision"] },
5680
+ title: { type: "string" }
5681
+ }
5682
+ }
5683
+ },
5684
+ {
5685
+ name: "session-summarize",
5686
+ title: "Session Summarizer",
5687
+ description: "Persists a session summary as a task_archive memory entry. Accepts a session summary, optional key decisions made, optional next steps, and optional tags. Internally reuses the memory-store handler with type='task_archive' and importance=3. Owner and repo are auto-inferred from session when omitted.",
5688
+ annotations: {
5689
+ readOnlyHint: false,
5690
+ idempotentHint: false,
5691
+ openWorldHint: false
5718
5692
  },
5719
- // ── Tasks ────────────────────────────────────────────────────────────────
5720
- {
5721
- uriTemplate: "repository://{name}/tasks",
5722
- name: "Repository Tasks",
5723
- title: "Repository Tasks",
5724
- description: "All active tasks for a specific repository",
5725
- mimeType: "application/json",
5726
- annotations: { audience: ["assistant"], priority: 0.9 }
5693
+ inputSchema: {
5694
+ type: "object",
5695
+ properties: {
5696
+ summary: {
5697
+ type: "string",
5698
+ description: "Session summary text. Min 10 characters."
5699
+ },
5700
+ key_decisions: {
5701
+ type: "array",
5702
+ items: { type: "string" },
5703
+ description: "Key decisions made during this session (optional)."
5704
+ },
5705
+ next_steps: {
5706
+ type: "array",
5707
+ items: { type: "string" },
5708
+ description: "Next steps or follow-up actions (optional)."
5709
+ },
5710
+ tags: {
5711
+ type: "array",
5712
+ items: { type: "string" },
5713
+ description: "Additional tags to apply (auto-includes 'session-summary')."
5714
+ },
5715
+ owner: {
5716
+ type: "string",
5717
+ description: "Organization/namespace. Auto-detected from session when omitted."
5718
+ },
5719
+ repo: {
5720
+ type: "string",
5721
+ description: "Repository/project name. Auto-detected from session when omitted."
5722
+ },
5723
+ structured: {
5724
+ type: "boolean",
5725
+ default: false,
5726
+ description: "If true, returns structured JSON results."
5727
+ }
5728
+ },
5729
+ required: ["summary"]
5730
+ },
5731
+ outputSchema: {
5732
+ type: "object",
5733
+ properties: {
5734
+ success: { type: "boolean" },
5735
+ id: { type: "string" },
5736
+ code: { type: "string" },
5737
+ repo: { type: "string" },
5738
+ type: { type: "string", enum: ["task_archive"] },
5739
+ title: { type: "string" }
5740
+ }
5741
+ }
5742
+ },
5743
+ // ── Upstream compatibility aliases ──────────────────────────────────────
5744
+ {
5745
+ name: "remember_fact",
5746
+ title: "Remember Fact (Upstream)",
5747
+ description: "Upstream-compatible alias for memory-store. Stores a single fact as a memory entry. Accepts the same arguments as memory-store. Owner and repo are auto-inferred from session when omitted.",
5748
+ annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },
5749
+ inputSchema: {
5750
+ type: "object",
5751
+ properties: {
5752
+ owner: { type: "string", description: "Auto-detected from session." },
5753
+ repo: { type: "string", description: "Auto-detected from session." },
5754
+ title: { type: "string", description: "Title for the fact/memory." },
5755
+ content: { type: "string", description: "The fact content to store." },
5756
+ type: { type: "string", default: "code_fact" },
5757
+ importance: { type: "number", default: 3 },
5758
+ tags: { type: "array", items: { type: "string" } }
5759
+ },
5760
+ required: ["content"]
5761
+ },
5762
+ outputSchema: {
5763
+ type: "object",
5764
+ properties: { success: { type: "boolean" }, id: { type: "string" }, code: { type: "string" } }
5765
+ }
5766
+ },
5767
+ {
5768
+ name: "remember_facts",
5769
+ title: "Remember Facts (Upstream Bulk)",
5770
+ description: "Upstream-compatible alias for bulk memory-store. Stores multiple facts at once.",
5771
+ annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: false },
5772
+ inputSchema: {
5773
+ type: "object",
5774
+ properties: {
5775
+ owner: { type: "string" },
5776
+ repo: { type: "string" },
5777
+ facts: { type: "array", items: { type: "object" }, description: "Array of fact objects." }
5778
+ },
5779
+ required: ["facts"]
5780
+ },
5781
+ outputSchema: { type: "object", properties: { success: { type: "boolean" }, count: { type: "number" } } }
5782
+ },
5783
+ {
5784
+ name: "recall",
5785
+ title: "Recall (Upstream)",
5786
+ description: "Upstream-compatible alias for memory-search. Searches stored memories by query.",
5787
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
5788
+ inputSchema: {
5789
+ type: "object",
5790
+ properties: {
5791
+ owner: { type: "string" },
5792
+ repo: { type: "string" },
5793
+ query: { type: "string", description: "Search query." },
5794
+ type: { type: "string", description: "Filter by memory type." },
5795
+ limit: { type: "number", default: 10 }
5796
+ },
5797
+ required: ["query"]
5798
+ },
5799
+ outputSchema: { type: "object", properties: { memories: { type: "array", items: { type: "object" } } } }
5800
+ },
5801
+ {
5802
+ name: "forget",
5803
+ title: "Forget (Upstream)",
5804
+ description: "Upstream-compatible alias for memory-delete. Deletes a stored memory by id or code.",
5805
+ annotations: { readOnlyHint: false, idempotentHint: false, destructiveHint: true, openWorldHint: true },
5806
+ inputSchema: {
5807
+ type: "object",
5808
+ properties: {
5809
+ owner: { type: "string" },
5810
+ repo: { type: "string" },
5811
+ id: { type: "string", description: "Memory ID to delete." },
5812
+ code: { type: "string", description: "Memory code to delete." }
5813
+ },
5814
+ required: []
5815
+ },
5816
+ outputSchema: { type: "object", properties: { success: { type: "boolean" } } }
5817
+ }
5818
+ ];
5819
+
5820
+ // src/mcp/tools/definitions/knowledge-graph.ts
5821
+ var KG_TOOL_DEFINITIONS = [
5822
+ {
5823
+ name: "create_entity",
5824
+ title: "KG Create Entity",
5825
+ description: "Creates a new knowledge graph entity. Entities represent nodes in the knowledge graph (e.g., concepts, people, systems). Name must be unique per repo. Owner and repo are auto-inferred from session when omitted.",
5826
+ annotations: {
5827
+ readOnlyHint: false,
5828
+ idempotentHint: false,
5829
+ destructiveHint: false,
5830
+ openWorldHint: false
5831
+ },
5832
+ inputSchema: {
5833
+ type: "object",
5834
+ properties: {
5835
+ name: {
5836
+ type: "string",
5837
+ description: "Unique entity name (acts as primary key per repo)."
5838
+ },
5839
+ type: {
5840
+ type: "string",
5841
+ default: "unknown",
5842
+ description: "Entity type for categorization (e.g., 'person', 'system', 'concept')."
5843
+ },
5844
+ description: {
5845
+ type: "string",
5846
+ description: "Optional description of the entity."
5847
+ },
5848
+ owner: {
5849
+ type: "string",
5850
+ description: "Organization/namespace. Auto-detected from session when omitted."
5851
+ },
5852
+ repo: {
5853
+ type: "string",
5854
+ description: "Repository/project name. Auto-detected from session when omitted."
5855
+ },
5856
+ structured: {
5857
+ type: "boolean",
5858
+ default: false,
5859
+ description: "If true, returns structured JSON results."
5860
+ }
5861
+ },
5862
+ required: ["name"]
5863
+ },
5864
+ outputSchema: {
5865
+ type: "object",
5866
+ properties: {
5867
+ success: { type: "boolean" },
5868
+ entity: {
5869
+ type: "object",
5870
+ properties: {
5871
+ name: { type: "string" },
5872
+ type: { type: "string" },
5873
+ description: { type: "string" },
5874
+ repo: { type: "string" },
5875
+ owner: { type: "string" }
5876
+ }
5877
+ }
5878
+ }
5879
+ }
5880
+ },
5881
+ {
5882
+ name: "delete_entity",
5883
+ title: "KG Delete Entity",
5884
+ description: "Deletes a knowledge graph entity by name. All related relations and observations are automatically removed via CASCADE. Owner and repo are auto-inferred from session when omitted.",
5885
+ annotations: {
5886
+ readOnlyHint: false,
5887
+ idempotentHint: false,
5888
+ destructiveHint: true,
5889
+ openWorldHint: false
5890
+ },
5891
+ inputSchema: {
5892
+ type: "object",
5893
+ properties: {
5894
+ name: {
5895
+ type: "string",
5896
+ description: "Name of the entity to delete."
5897
+ },
5898
+ owner: {
5899
+ type: "string",
5900
+ description: "Organization/namespace. Auto-detected from session when omitted."
5901
+ },
5902
+ repo: {
5903
+ type: "string",
5904
+ description: "Repository/project name. Auto-detected from session when omitted."
5905
+ },
5906
+ structured: {
5907
+ type: "boolean",
5908
+ default: false,
5909
+ description: "If true, returns structured JSON results."
5910
+ }
5911
+ },
5912
+ required: ["name"]
5913
+ },
5914
+ outputSchema: {
5915
+ type: "object",
5916
+ properties: {
5917
+ success: { type: "boolean" },
5918
+ deletedCount: { type: "number" }
5919
+ }
5920
+ }
5921
+ },
5922
+ {
5923
+ name: "create_relation",
5924
+ title: "KG Create Relation",
5925
+ description: "Creates a directed relation between two existing knowledge graph entities. Both from_entity and to_entity must already exist. The composite key (from_entity, to_entity, relation_type) must be unique. Owner and repo are auto-inferred from session when omitted.",
5926
+ annotations: {
5927
+ readOnlyHint: false,
5928
+ idempotentHint: false,
5929
+ destructiveHint: false,
5930
+ openWorldHint: false
5931
+ },
5932
+ inputSchema: {
5933
+ type: "object",
5934
+ properties: {
5935
+ from_entity: {
5936
+ type: "string",
5937
+ description: "Source entity name (must exist)."
5938
+ },
5939
+ to_entity: {
5940
+ type: "string",
5941
+ description: "Target entity name (must exist)."
5942
+ },
5943
+ relation_type: {
5944
+ type: "string",
5945
+ description: "Type of relation (e.g., 'depends_on', 'implements', 'part_of')."
5946
+ },
5947
+ owner: {
5948
+ type: "string",
5949
+ description: "Organization/namespace. Auto-detected from session when omitted."
5950
+ },
5951
+ repo: {
5952
+ type: "string",
5953
+ description: "Repository/project name. Auto-detected from session when omitted."
5954
+ },
5955
+ structured: {
5956
+ type: "boolean",
5957
+ default: false,
5958
+ description: "If true, returns structured JSON results."
5959
+ }
5960
+ },
5961
+ required: ["from_entity", "to_entity", "relation_type"]
5962
+ },
5963
+ outputSchema: {
5964
+ type: "object",
5965
+ properties: {
5966
+ success: { type: "boolean" },
5967
+ relation: {
5968
+ type: "object",
5969
+ properties: {
5970
+ from_entity: { type: "string" },
5971
+ to_entity: { type: "string" },
5972
+ relation_type: { type: "string" }
5973
+ }
5974
+ }
5975
+ }
5976
+ }
5977
+ },
5978
+ {
5979
+ name: "delete_relation",
5980
+ title: "KG Delete Relation",
5981
+ description: "Deletes a relation by its composite key (from_entity, to_entity, relation_type). Owner and repo are auto-inferred from session when omitted.",
5982
+ annotations: {
5983
+ readOnlyHint: false,
5984
+ idempotentHint: false,
5985
+ destructiveHint: true,
5986
+ openWorldHint: false
5727
5987
  },
5728
- {
5729
- uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
5730
- name: "Filtered Repository Tasks",
5731
- title: "Filtered Repository Tasks",
5732
- description: "Filter tasks within a repository by status or priority level",
5733
- mimeType: "application/json",
5734
- annotations: { audience: ["assistant"], priority: 0.85 }
5988
+ inputSchema: {
5989
+ type: "object",
5990
+ properties: {
5991
+ from_entity: {
5992
+ type: "string",
5993
+ description: "Source entity name."
5994
+ },
5995
+ to_entity: {
5996
+ type: "string",
5997
+ description: "Target entity name."
5998
+ },
5999
+ relation_type: {
6000
+ type: "string",
6001
+ description: "Relation type."
6002
+ },
6003
+ owner: {
6004
+ type: "string",
6005
+ description: "Organization/namespace. Auto-detected from session when omitted."
6006
+ },
6007
+ repo: {
6008
+ type: "string",
6009
+ description: "Repository/project name. Auto-detected from session when omitted."
6010
+ },
6011
+ structured: {
6012
+ type: "boolean",
6013
+ default: false,
6014
+ description: "If true, returns structured JSON results."
6015
+ }
6016
+ },
6017
+ required: ["from_entity", "to_entity", "relation_type"]
5735
6018
  },
5736
- {
5737
- uriTemplate: "task://{id}",
5738
- name: "Task Detail",
5739
- title: "Task Detail",
5740
- description: "Full content and comments for a specific task UUID",
5741
- mimeType: "application/json",
5742
- annotations: { audience: ["assistant"], priority: 0.8 }
6019
+ outputSchema: {
6020
+ type: "object",
6021
+ properties: {
6022
+ success: { type: "boolean" },
6023
+ deletedCount: { type: "number" }
6024
+ }
6025
+ }
6026
+ },
6027
+ {
6028
+ name: "delete_observation",
6029
+ title: "KG Delete Observation",
6030
+ description: "Deletes an observation by its ID. Observation IDs are UUIDs returned when observations are created. Owner and repo are auto-inferred from session when omitted.",
6031
+ annotations: {
6032
+ readOnlyHint: false,
6033
+ idempotentHint: false,
6034
+ destructiveHint: true,
6035
+ openWorldHint: false
5743
6036
  },
5744
- // ── Repository extras ────────────────────────────────────────────────────
5745
- {
5746
- uriTemplate: "repository://{name}/summary",
5747
- name: "Repository Summary",
5748
- title: "Repository Summary",
5749
- description: "High-level architectural summary for a repository",
5750
- mimeType: "text/plain",
5751
- annotations: { audience: ["assistant"], priority: 0.95 }
6037
+ inputSchema: {
6038
+ type: "object",
6039
+ properties: {
6040
+ id: {
6041
+ type: "string",
6042
+ description: "UUID of the observation to delete."
6043
+ },
6044
+ owner: {
6045
+ type: "string",
6046
+ description: "Organization/namespace. Auto-detected from session when omitted."
6047
+ },
6048
+ repo: {
6049
+ type: "string",
6050
+ description: "Repository/project name. Auto-detected from session when omitted."
6051
+ },
6052
+ structured: {
6053
+ type: "boolean",
6054
+ default: false,
6055
+ description: "If true, returns structured JSON results."
6056
+ }
6057
+ },
6058
+ required: ["id"]
5752
6059
  },
6060
+ outputSchema: {
6061
+ type: "object",
6062
+ properties: {
6063
+ success: { type: "boolean" },
6064
+ deletedCount: { type: "number" }
6065
+ }
6066
+ }
6067
+ }
6068
+ ];
6069
+
6070
+ // src/mcp/tools/definitions/index.ts
6071
+ var TOOL_DEFINITIONS = [
6072
+ ...MEMORY_TOOL_DEFINITIONS,
6073
+ ...TASK_TOOL_DEFINITIONS,
6074
+ ...HANDOFF_TOOL_DEFINITIONS,
6075
+ ...STANDARD_TOOL_DEFINITIONS,
6076
+ ...AGENT_TOOL_DEFINITIONS,
6077
+ ...KG_TOOL_DEFINITIONS
6078
+ ];
6079
+
6080
+ // src/mcp/utils/completion.ts
6081
+ var MAX_COMPLETION_VALUES = 100;
6082
+ function rankCompletionValues(candidates, input) {
6083
+ const unique = [...new Set(candidates.filter(Boolean))];
6084
+ const needle = input.trim().toLowerCase();
6085
+ if (!needle) {
6086
+ return unique.slice(0, MAX_COMPLETION_VALUES);
6087
+ }
6088
+ 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);
6089
+ }
6090
+ function scoreCompletionValue(value, needle) {
6091
+ const haystack = value.toLowerCase();
6092
+ if (haystack === needle) return 100;
6093
+ if (haystack.startsWith(needle)) return 75;
6094
+ if (haystack.includes(needle)) return 50;
6095
+ const compactNeedle = needle.replace(/[\s_-]+/g, "");
6096
+ const compactHaystack = haystack.replace(/[\s_-]+/g, "");
6097
+ if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
6098
+ return 0;
6099
+ }
6100
+
6101
+ // src/mcp/utils/pagination.ts
6102
+ function encodeCursor(offset) {
6103
+ return Buffer.from(String(offset), "utf8").toString("base64");
6104
+ }
6105
+ function decodeCursor(cursor) {
6106
+ if (cursor === void 0 || cursor === null || cursor === "") {
6107
+ return 0;
6108
+ }
6109
+ if (typeof cursor !== "string" || cursor.trim() === "") {
6110
+ throw invalidPaginationParams("Invalid cursor");
6111
+ }
6112
+ let decoded;
6113
+ try {
6114
+ decoded = Buffer.from(cursor, "base64").toString("utf8");
6115
+ } catch {
6116
+ throw invalidPaginationParams("Invalid cursor");
6117
+ }
6118
+ if (!/^\d+$/.test(decoded)) {
6119
+ throw invalidPaginationParams("Invalid cursor");
6120
+ }
6121
+ const offset = Number.parseInt(decoded, 10);
6122
+ if (!Number.isFinite(offset) || offset < 0) {
6123
+ throw invalidPaginationParams("Invalid cursor");
6124
+ }
6125
+ return offset;
6126
+ }
6127
+ function invalidPaginationParams(message) {
6128
+ const error = new Error(message);
6129
+ error.code = -32602;
6130
+ return error;
6131
+ }
6132
+
6133
+ // src/mcp/resources/index.ts
6134
+ var DEFAULT_PAGE_SIZE = 25;
6135
+ var MAX_PAGE_SIZE = 100;
6136
+ function listResources(session, params) {
6137
+ const resources = [
5753
6138
  {
5754
- uriTemplate: "repository://{name}/actions",
5755
- name: "Repository Actions",
5756
- title: "Repository Actions",
5757
- description: "Audit log of agent tool actions scoped to a repository",
6139
+ uri: "repository://index",
6140
+ name: "Repository Index",
6141
+ title: "Repository Index",
6142
+ description: "List of all known repositories with memory/task counts and last activity",
5758
6143
  mimeType: "application/json",
5759
- annotations: { audience: ["assistant"], priority: 0.6 }
6144
+ annotations: {
6145
+ audience: ["assistant"],
6146
+ priority: 1,
6147
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
6148
+ }
5760
6149
  },
5761
- // ── Action detail ────────────────────────────────────────────────────────
5762
6150
  {
5763
- uriTemplate: "action://{id}",
5764
- name: "Action Detail",
5765
- title: "Action Detail",
5766
- description: "Full details of a specific audit log entry by integer ID",
6151
+ uri: "session://roots",
6152
+ name: "Session Roots",
6153
+ title: "Session Roots",
6154
+ description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
5767
6155
  mimeType: "application/json",
5768
- annotations: { audience: ["assistant"], priority: 0.55 }
6156
+ size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
6157
+ annotations: {
6158
+ audience: ["assistant"],
6159
+ priority: 0.95,
6160
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
6161
+ }
5769
6162
  }
5770
6163
  ];
5771
- return paginateEntries("resourceTemplates", templates, params);
6164
+ return paginateEntries("resources", resources, params);
5772
6165
  }
5773
6166
  function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
5774
6167
  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") {
@@ -5783,234 +6176,6 @@ function completeResourceArgument(resourceUri, argumentName, argumentValue, _con
5783
6176
  }
5784
6177
  throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
5785
6178
  }
5786
- function readResource(uri, db, session) {
5787
- logger.info("[Tool] resource.read", { uri });
5788
- if (uri === "repository://index") {
5789
- const repos = db.system.listRepoNavigation();
5790
- const payload = JSON.stringify(repos, null, 2);
5791
- return {
5792
- contents: [
5793
- {
5794
- uri,
5795
- mimeType: "application/json",
5796
- text: payload,
5797
- size: Buffer.byteLength(payload, "utf8"),
5798
- annotations: {
5799
- audience: ["assistant"],
5800
- priority: 1,
5801
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5802
- }
5803
- }
5804
- ]
5805
- };
5806
- }
5807
- if (uri === "session://roots") {
5808
- const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
5809
- return {
5810
- contents: [
5811
- {
5812
- uri,
5813
- mimeType: "application/json",
5814
- text: payload,
5815
- size: Buffer.byteLength(payload, "utf8"),
5816
- annotations: {
5817
- audience: ["assistant"],
5818
- priority: 0.95,
5819
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5820
- }
5821
- }
5822
- ]
5823
- };
5824
- }
5825
- const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
5826
- if (memoryIdMatch) {
5827
- const id = memoryIdMatch[1];
5828
- const entry = db.memories.getByIdWithStats(id);
5829
- if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
5830
- const payload = JSON.stringify(entry, null, 2);
5831
- return {
5832
- contents: [
5833
- {
5834
- uri,
5835
- mimeType: "application/json",
5836
- text: payload,
5837
- size: Buffer.byteLength(payload, "utf8"),
5838
- annotations: {
5839
- audience: ["assistant"],
5840
- priority: 0.75,
5841
- lastModified: entry.updated_at || entry.created_at
5842
- }
5843
- }
5844
- ]
5845
- };
5846
- }
5847
- const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
5848
- if (taskIdMatch) {
5849
- const id = taskIdMatch[1];
5850
- const task = db.tasks.getTaskById(id);
5851
- if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
5852
- const payload = JSON.stringify(task, null, 2);
5853
- return {
5854
- contents: [
5855
- {
5856
- uri,
5857
- mimeType: "application/json",
5858
- text: payload,
5859
- size: Buffer.byteLength(payload, "utf8"),
5860
- annotations: {
5861
- audience: ["assistant"],
5862
- priority: 0.8,
5863
- lastModified: task.updated_at || task.created_at
5864
- }
5865
- }
5866
- ]
5867
- };
5868
- }
5869
- const repoBase = parseRepoUri(uri);
5870
- if (repoBase) {
5871
- const { name, path: repoPath, query } = repoBase;
5872
- if (repoPath === "summary") {
5873
- const summary = db.summaries.getSummary("", name);
5874
- const text = summary?.summary || `No summary available for repository: ${name}`;
5875
- return {
5876
- contents: [
5877
- {
5878
- uri,
5879
- mimeType: "text/plain",
5880
- text,
5881
- size: Buffer.byteLength(text, "utf8"),
5882
- annotations: {
5883
- audience: ["assistant"],
5884
- priority: 0.95,
5885
- lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
5886
- }
5887
- }
5888
- ]
5889
- };
5890
- }
5891
- if (repoPath === "memories") {
5892
- const search = query.get("search") || "";
5893
- const type = query.get("type");
5894
- const tag = query.get("tag");
5895
- const result = db.memories.listMemoriesForDashboard({
5896
- repo: name,
5897
- type: type || void 0,
5898
- tag: tag || void 0,
5899
- search: search || void 0,
5900
- limit: 50
5901
- });
5902
- const entries = result.items;
5903
- const payload = JSON.stringify(entries, null, 2);
5904
- return {
5905
- contents: [
5906
- {
5907
- uri,
5908
- mimeType: "application/json",
5909
- text: payload,
5910
- size: Buffer.byteLength(payload, "utf8"),
5911
- annotations: {
5912
- audience: ["assistant"],
5913
- priority: 0.85,
5914
- lastModified: deriveLastModifiedFromCollection(
5915
- entries.map((e) => e.updated_at || e.created_at)
5916
- )
5917
- }
5918
- }
5919
- ]
5920
- };
5921
- }
5922
- if (repoPath === "tasks") {
5923
- const status = query.get("status");
5924
- const priority = query.get("priority");
5925
- const owner = parseRepoInput(name).owner;
5926
- let tasks;
5927
- if (status && status !== "all") {
5928
- const statuses = status.split(",").map((s) => s.trim());
5929
- tasks = db.tasks.getTasksByMultipleStatuses(owner, name, statuses);
5930
- } else {
5931
- tasks = db.tasks.getTasksByMultipleStatuses(owner, name, ["backlog", "pending", "in_progress", "blocked"]);
5932
- }
5933
- if (priority) {
5934
- const p = Number(priority);
5935
- if (!isNaN(p)) {
5936
- tasks = tasks.filter((t) => t.priority === p);
5937
- }
5938
- }
5939
- const payload = JSON.stringify(tasks, null, 2);
5940
- return {
5941
- contents: [
5942
- {
5943
- uri,
5944
- mimeType: "application/json",
5945
- text: payload,
5946
- size: Buffer.byteLength(payload, "utf8"),
5947
- annotations: {
5948
- audience: ["assistant"],
5949
- priority: 0.9,
5950
- lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
5951
- }
5952
- }
5953
- ]
5954
- };
5955
- }
5956
- if (repoPath === "actions") {
5957
- const actions = db.actions.getRecentActions("", name, 100);
5958
- const payload = JSON.stringify(actions, null, 2);
5959
- return {
5960
- contents: [
5961
- {
5962
- uri,
5963
- mimeType: "application/json",
5964
- text: payload,
5965
- size: Buffer.byteLength(payload, "utf8"),
5966
- annotations: {
5967
- audience: ["assistant"],
5968
- priority: 0.6,
5969
- lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
5970
- }
5971
- }
5972
- ]
5973
- };
5974
- }
5975
- }
5976
- const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
5977
- if (actionIdMatch) {
5978
- const id = Number(actionIdMatch[1]);
5979
- const action = db.actions.getActionById(id);
5980
- if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
5981
- const payload = JSON.stringify(action, null, 2);
5982
- return {
5983
- contents: [
5984
- {
5985
- uri,
5986
- mimeType: "application/json",
5987
- text: payload,
5988
- size: Buffer.byteLength(payload, "utf8"),
5989
- annotations: {
5990
- audience: ["assistant"],
5991
- priority: 0.55,
5992
- lastModified: action.created_at
5993
- }
5994
- }
5995
- ]
5996
- };
5997
- }
5998
- throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
5999
- }
6000
- function parseRepoUri(uri) {
6001
- const prefix = "repository://";
6002
- if (!uri.startsWith(prefix)) return null;
6003
- const rest = uri.slice(prefix.length);
6004
- const queryStart = rest.indexOf("?");
6005
- const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
6006
- const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
6007
- const slashIdx = withoutQuery.indexOf("/");
6008
- if (slashIdx === -1) return null;
6009
- const name = withoutQuery.slice(0, slashIdx);
6010
- const path6 = withoutQuery.slice(slashIdx + 1);
6011
- if (!name || !path6) return null;
6012
- return { name, path: path6, query: new URLSearchParams(queryString) };
6013
- }
6014
6179
  function paginateEntries(key, entries, params) {
6015
6180
  const limit = normalizeLimit(params?.limit);
6016
6181
  const offset = decodeCursor(params?.cursor);
@@ -6027,16 +6192,6 @@ function normalizeLimit(limit) {
6027
6192
  }
6028
6193
  return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
6029
6194
  }
6030
- function deriveLastModifiedFromCollection(values) {
6031
- const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
6032
- return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
6033
- }
6034
- function resourceNotFound(message, uri) {
6035
- const error = new Error(message);
6036
- error.code = -32002;
6037
- error.data = { uri };
6038
- return error;
6039
- }
6040
6195
  function invalidCompletionParams(message) {
6041
6196
  const error = new Error(message);
6042
6197
  error.code = -32602;
@@ -6070,51 +6225,6 @@ for (const name of promptFiles) {
6070
6225
  logger.warn(`Failed to load prompt ${name}: ${e}`);
6071
6226
  }
6072
6227
  }
6073
- async function listPrompts(db, session, params) {
6074
- const allPrompts = Object.values(PROMPTS).map((p) => ({
6075
- name: p.name,
6076
- description: p.description,
6077
- arguments: p.arguments,
6078
- metadata: p.agent ? { agent: p.agent } : void 0
6079
- }));
6080
- const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 50;
6081
- const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
6082
- const offset = decodeCursor(params?.cursor);
6083
- const sliced = allPrompts.slice(offset, offset + limit);
6084
- const nextOffset = offset + sliced.length;
6085
- return {
6086
- prompts: sliced,
6087
- nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
6088
- };
6089
- }
6090
- async function getPrompt(name, args = {}, db, session) {
6091
- const prompt = PROMPTS[name];
6092
- if (!prompt) {
6093
- throw new Error(`Prompt not found: ${name}`);
6094
- }
6095
- const inferredRepo = inferRepoFromSession(session);
6096
- const inferredOwner = inferOwnerFromSession(session);
6097
- const messages = prompt.messages.map((m) => {
6098
- let text = m.content.text;
6099
- for (const [key, value] of Object.entries(args)) {
6100
- text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
6101
- }
6102
- text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
6103
- text = text.replace(/{{current_owner}}/g, inferredOwner || "unknown-owner");
6104
- return {
6105
- ...m,
6106
- content: {
6107
- ...m.content,
6108
- text
6109
- }
6110
- };
6111
- });
6112
- return {
6113
- description: prompt.description,
6114
- messages,
6115
- metadata: prompt.agent ? { agent: prompt.agent } : void 0
6116
- };
6117
- }
6118
6228
  async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
6119
6229
  void name;
6120
6230
  void contextArguments;
@@ -6757,6 +6867,75 @@ var StandardDetailSchema = z6.object({
6757
6867
  message: "Either id or code must be provided"
6758
6868
  });
6759
6869
 
6870
+ // src/mcp/tools/schemas/agent.ts
6871
+ import { z as z7 } from "zod";
6872
+ var AgentContextSchema = z7.object({
6873
+ owner: z7.string().min(1),
6874
+ repo: z7.string().min(1),
6875
+ objective: z7.string().optional(),
6876
+ type_filter: z7.enum(["code_fact", "decision", "mistake", "pattern", "task_archive"]).optional(),
6877
+ limit: z7.number().min(1).max(100).default(5),
6878
+ structured: z7.boolean().default(false)
6879
+ });
6880
+ var DecisionLogSchema = z7.object({
6881
+ summary: z7.string().min(3).max(255, { message: "Summary must be at most 255 characters" }),
6882
+ context: z7.string().min(10, { message: "Context must be at least 10 characters" }),
6883
+ rationale: z7.string().min(10, { message: "Rationale must be at least 10 characters" }),
6884
+ alternatives: z7.array(z7.string()).optional(),
6885
+ tags: z7.array(z7.string()).optional(),
6886
+ owner: z7.string().optional(),
6887
+ repo: z7.string().optional(),
6888
+ structured: z7.boolean().default(false)
6889
+ });
6890
+ var SessionSummarizeSchema = z7.object({
6891
+ summary: z7.string().min(10, { message: "Summary must be at least 10 characters" }),
6892
+ key_decisions: z7.array(z7.string()).optional(),
6893
+ next_steps: z7.array(z7.string()).optional(),
6894
+ tags: z7.array(z7.string()).optional(),
6895
+ owner: z7.string().optional(),
6896
+ repo: z7.string().optional(),
6897
+ structured: z7.boolean().default(false)
6898
+ });
6899
+
6900
+ // src/mcp/tools/schemas/knowledge-graph.ts
6901
+ import { z as z8 } from "zod";
6902
+ var CreateEntitySchema = z8.object({
6903
+ name: z8.string().min(1).max(255),
6904
+ type: z8.string().default("unknown"),
6905
+ description: z8.string().optional(),
6906
+ owner: z8.string().optional(),
6907
+ repo: z8.string().optional(),
6908
+ structured: z8.boolean().default(false)
6909
+ });
6910
+ var DeleteEntitySchema = z8.object({
6911
+ name: z8.string().min(1),
6912
+ owner: z8.string().optional(),
6913
+ repo: z8.string().optional(),
6914
+ structured: z8.boolean().default(false)
6915
+ });
6916
+ var CreateRelationSchema = z8.object({
6917
+ from_entity: z8.string().min(1),
6918
+ to_entity: z8.string().min(1),
6919
+ relation_type: z8.string().min(1),
6920
+ owner: z8.string().optional(),
6921
+ repo: z8.string().optional(),
6922
+ structured: z8.boolean().default(false)
6923
+ });
6924
+ var DeleteRelationSchema = z8.object({
6925
+ from_entity: z8.string().min(1),
6926
+ to_entity: z8.string().min(1),
6927
+ relation_type: z8.string().min(1),
6928
+ owner: z8.string().optional(),
6929
+ repo: z8.string().optional(),
6930
+ structured: z8.boolean().default(false)
6931
+ });
6932
+ var DeleteObservationSchema = z8.object({
6933
+ id: z8.string().min(1),
6934
+ owner: z8.string().optional(),
6935
+ repo: z8.string().optional(),
6936
+ structured: z8.boolean().default(false)
6937
+ });
6938
+
6760
6939
  // src/mcp/tools/handoff.manage.ts
6761
6940
  function buildHandoffListSummary(repo, count, status, fromAgent, toAgent) {
6762
6941
  const parts = [`Found ${count} handoff${count === 1 ? "" : "s"} in repo "${repo}".`];
@@ -7057,37 +7236,27 @@ function buildStandardVectorText(standard) {
7057
7236
  }
7058
7237
 
7059
7238
  export {
7060
- MCP_PROTOCOL_VERSION,
7061
- CAPABILITIES,
7062
7239
  logger,
7063
- setLogLevel,
7064
- getLogLevel,
7065
7240
  addLogSink,
7066
- LOG_LEVEL_VALUES,
7067
7241
  createFileSink,
7068
7242
  parseRepoInput,
7069
7243
  normalizeRepo,
7070
7244
  SQLiteStore,
7071
7245
  RealVectorStore,
7072
7246
  TOOL_DEFINITIONS,
7073
- encodeCursor,
7074
- decodeCursor,
7247
+ rankCompletionValues,
7075
7248
  listResources,
7076
- listResourceTemplates,
7077
7249
  completeResourceArgument,
7078
- readResource,
7079
7250
  createSessionContext,
7080
- updateSessionFromInitialize,
7081
- updateSessionRoots,
7082
- extractRootsFromResult,
7083
7251
  getFilesystemRoots,
7084
7252
  isPathWithinRoots,
7085
7253
  findContainingRoot,
7086
7254
  inferRepoFromSession,
7087
7255
  inferOwnerFromSession,
7256
+ listPromptFiles,
7257
+ loadPromptFromMarkdown,
7258
+ loadServerInstructions,
7088
7259
  PROMPTS,
7089
- listPrompts,
7090
- getPrompt,
7091
7260
  completePromptArgument,
7092
7261
  createMcpResponse,
7093
7262
  getPrimaryTextContent,
@@ -7113,6 +7282,14 @@ export {
7113
7282
  StandardSearchSchema,
7114
7283
  StandardDeleteSchema,
7115
7284
  StandardDetailSchema,
7285
+ AgentContextSchema,
7286
+ DecisionLogSchema,
7287
+ SessionSummarizeSchema,
7288
+ CreateEntitySchema,
7289
+ DeleteEntitySchema,
7290
+ CreateRelationSchema,
7291
+ DeleteRelationSchema,
7292
+ DeleteObservationSchema,
7116
7293
  handleHandoffCreate,
7117
7294
  handleHandoffList,
7118
7295
  handleHandoffUpdate,