@vheins/local-memory-mcp 0.10.10 → 0.10.12

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.10.10") {
85
- pkgVersion = "0.10.10";
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,
@@ -245,11 +119,11 @@ function addLogSink(sink) {
245
119
  }
246
120
  var LOG_LEVEL_VALUES = Object.keys(LEVELS);
247
121
  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();
122
+ fs.mkdirSync(logDir, { recursive: true });
123
+ const existing = fs.readdirSync(logDir).filter((f) => f.startsWith("mcp-") && f.endsWith(".log")).sort();
250
124
  while (existing.length >= maxFiles) {
251
125
  try {
252
- fs2.unlinkSync(`${logDir}/${existing.shift()}`);
126
+ fs.unlinkSync(`${logDir}/${existing.shift()}`);
253
127
  } catch {
254
128
  }
255
129
  }
@@ -259,16 +133,118 @@ function createFileSink(logDir, maxFiles = 5) {
259
133
  const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${payload.level.toUpperCase()}] [pid:${process.pid}] ${JSON.stringify(payload.data)}
260
134
  `;
261
135
  try {
262
- fs2.appendFileSync(logFile, line);
136
+ fs.appendFileSync(logFile, line);
263
137
  } catch {
264
138
  }
265
139
  };
266
140
  }
267
141
 
142
+ // src/mcp/session.ts
143
+ import path from "path";
144
+ import { fileURLToPath } from "url";
145
+ function createSessionContext() {
146
+ return {
147
+ roots: [],
148
+ supportsRoots: false,
149
+ supportsSampling: false,
150
+ supportsSamplingTools: false,
151
+ supportsElicitation: false,
152
+ supportsElicitationForm: false,
153
+ supportsElicitationUrl: false
154
+ };
155
+ }
156
+ function updateSessionFromInitialize(session, params) {
157
+ const capabilities = params?.capabilities || {};
158
+ session.clientInfo = params?.clientInfo;
159
+ session.clientCapabilities = capabilities;
160
+ session.supportsRoots = Boolean(capabilities.roots);
161
+ session.supportsSampling = Boolean(capabilities.sampling);
162
+ const sampling = capabilities.sampling;
163
+ session.supportsSamplingTools = Boolean(sampling?.tools);
164
+ session.supportsElicitation = Boolean(capabilities.elicitation);
165
+ session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
166
+ session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
167
+ }
168
+ function supportsElicitationMode(capability, mode) {
169
+ if (!capability || typeof capability !== "object") {
170
+ return false;
171
+ }
172
+ const cap = capability;
173
+ if (mode === "form") {
174
+ return Object.keys(cap).length === 0 || typeof cap.form === "object";
175
+ }
176
+ return typeof cap.url === "object";
177
+ }
178
+ function updateSessionRoots(session, roots) {
179
+ const normalized = normalizeRoots(roots);
180
+ const previous = JSON.stringify(session.roots);
181
+ const next = JSON.stringify(normalized);
182
+ session.roots = normalized;
183
+ return previous !== next;
184
+ }
185
+ function normalizeRoots(roots) {
186
+ if (!Array.isArray(roots)) return [];
187
+ const seen = /* @__PURE__ */ new Set();
188
+ const normalized = [];
189
+ for (const root of roots) {
190
+ if (!root || typeof root !== "object") continue;
191
+ const r = root;
192
+ const uri = typeof r.uri === "string" ? r.uri : void 0;
193
+ const name = typeof r.name === "string" ? r.name : void 0;
194
+ if (!uri || seen.has(uri)) continue;
195
+ seen.add(uri);
196
+ normalized.push({ uri, name });
197
+ }
198
+ return normalized;
199
+ }
200
+ function extractRootsFromResult(result) {
201
+ return normalizeRoots(result?.roots);
202
+ }
203
+ function getFilesystemRoots(session) {
204
+ if (!session) return [];
205
+ const resolved = [];
206
+ for (const root of session.roots) {
207
+ if (!root.uri.startsWith("file://")) continue;
208
+ try {
209
+ resolved.push(path.resolve(fileURLToPath(root.uri)));
210
+ } catch {
211
+ }
212
+ }
213
+ return resolved;
214
+ }
215
+ function isPathWithinRoots(targetPath, session) {
216
+ const roots = getFilesystemRoots(session);
217
+ if (roots.length === 0) return true;
218
+ const normalizedTarget = path.resolve(targetPath);
219
+ return roots.some((rootPath) => {
220
+ const relative = path.relative(rootPath, normalizedTarget);
221
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
222
+ });
223
+ }
224
+ function findContainingRoot(targetPath, session) {
225
+ const roots = getFilesystemRoots(session);
226
+ if (roots.length === 0) return null;
227
+ const normalizedTarget = path.resolve(targetPath);
228
+ for (const rootPath of roots) {
229
+ const relative = path.relative(rootPath, normalizedTarget);
230
+ if (relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative)) {
231
+ return rootPath;
232
+ }
233
+ }
234
+ return null;
235
+ }
236
+ function inferRepoFromSession(session) {
237
+ const roots = getFilesystemRoots(session);
238
+ if (roots.length === 1) {
239
+ return path.basename(roots[0]);
240
+ }
241
+ return void 0;
242
+ }
243
+
268
244
  // src/mcp/storage/sqlite.ts
269
245
  import Database from "better-sqlite3";
270
- import path4 from "path";
271
- import fs4 from "fs";
246
+ import path3 from "path";
247
+ import fs3 from "fs";
272
248
  import os from "os";
273
249
 
274
250
  // src/mcp/storage/migrations.ts
@@ -2760,8 +2736,8 @@ var HandoffEntity = class extends BaseEntity {
2760
2736
 
2761
2737
  // src/mcp/storage/write-lock.ts
2762
2738
  import lockfile from "proper-lockfile";
2763
- import path3 from "path";
2764
- import fs3 from "fs";
2739
+ import path2 from "path";
2740
+ import fs2 from "fs";
2765
2741
  var LOCK_STALE_MS = 3e4;
2766
2742
  var LOCK_RETRY_DELAY_MS = 200;
2767
2743
  var LOCK_RETRY_COUNT = 250;
@@ -2770,9 +2746,9 @@ var WriteLock = class {
2770
2746
  locked = false;
2771
2747
  constructor(dbPath) {
2772
2748
  this.lockTarget = dbPath;
2773
- if (!fs3.existsSync(dbPath)) {
2774
- fs3.mkdirSync(path3.dirname(dbPath), { recursive: true });
2775
- fs3.writeFileSync(dbPath, "");
2749
+ if (!fs2.existsSync(dbPath)) {
2750
+ fs2.mkdirSync(path2.dirname(dbPath), { recursive: true });
2751
+ fs2.writeFileSync(dbPath, "");
2776
2752
  }
2777
2753
  }
2778
2754
  /**
@@ -2824,13 +2800,13 @@ var WriteLock = class {
2824
2800
  // src/mcp/storage/sqlite.ts
2825
2801
  function resolveDbPath() {
2826
2802
  if (process.env.MEMORY_DB_PATH) return process.env.MEMORY_DB_PATH;
2827
- 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");
2828
- const standardPath = path4.join(standardConfigDir, "memory.db");
2829
- if (fs4.existsSync(standardPath)) return standardPath;
2830
- const legacyPath = path4.join(os.homedir(), ".config", "local-memory-mcp", "memory.db");
2831
- if (fs4.existsSync(legacyPath)) return legacyPath;
2832
- const localCwdFile = path4.join(process.cwd(), "storage", "memory.db");
2833
- if (fs4.existsSync(localCwdFile)) return localCwdFile;
2803
+ const standardConfigDir = process.platform === "win32" ? path3.join(os.homedir(), ".local-memory-mcp") : process.platform === "darwin" ? path3.join(os.homedir(), "Library", "Application Support", "local-memory-mcp") : path3.join(os.homedir(), ".config", "local-memory-mcp");
2804
+ const standardPath = path3.join(standardConfigDir, "memory.db");
2805
+ if (fs3.existsSync(standardPath)) return standardPath;
2806
+ const legacyPath = path3.join(os.homedir(), ".config", "local-memory-mcp", "memory.db");
2807
+ if (fs3.existsSync(legacyPath)) return legacyPath;
2808
+ const localCwdFile = path3.join(process.cwd(), "storage", "memory.db");
2809
+ if (fs3.existsSync(localCwdFile)) return localCwdFile;
2834
2810
  return standardPath;
2835
2811
  }
2836
2812
  var DB_PATH = resolveDbPath();
@@ -2849,9 +2825,9 @@ var SQLiteStore = class _SQLiteStore {
2849
2825
  const finalPath = dbPath ?? DB_PATH;
2850
2826
  this.dbPathInstance = finalPath;
2851
2827
  if (finalPath !== ":memory:") {
2852
- const dbDir = path4.dirname(finalPath);
2853
- if (!fs4.existsSync(dbDir)) {
2854
- fs4.mkdirSync(dbDir, { recursive: true });
2828
+ const dbDir = path3.dirname(finalPath);
2829
+ if (!fs3.existsSync(dbDir)) {
2830
+ fs3.mkdirSync(dbDir, { recursive: true });
2855
2831
  }
2856
2832
  }
2857
2833
  this.db = new Database(finalPath);
@@ -2906,12 +2882,12 @@ var SQLiteStore = class _SQLiteStore {
2906
2882
  */
2907
2883
  _attemptRecovery(dbPath) {
2908
2884
  const backupPath = dbPath + ".backup";
2909
- if (fs4.existsSync(backupPath)) {
2885
+ if (fs3.existsSync(backupPath)) {
2910
2886
  logger.warn("[SQLiteStore] Attempting recovery from backup", { backupPath });
2911
2887
  try {
2912
2888
  const corruptPath = `${dbPath}.corrupt_${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 15)}`;
2913
- fs4.copyFileSync(dbPath, corruptPath);
2914
- fs4.copyFileSync(backupPath, dbPath);
2889
+ fs3.copyFileSync(dbPath, corruptPath);
2890
+ fs3.copyFileSync(backupPath, dbPath);
2915
2891
  logger.warn("[SQLiteStore] Recovery successful. Corrupt file saved to", { corruptPath });
2916
2892
  } catch (err) {
2917
2893
  logger.error("[SQLiteStore] Recovery failed", { error: String(err) });
@@ -2929,7 +2905,7 @@ var SQLiteStore = class _SQLiteStore {
2929
2905
  try {
2930
2906
  this.db.pragma("wal_checkpoint(PASSIVE)");
2931
2907
  const backupPath = this.dbPathInstance + ".backup";
2932
- fs4.copyFileSync(this.dbPathInstance, backupPath);
2908
+ fs3.copyFileSync(this.dbPathInstance, backupPath);
2933
2909
  } catch (err) {
2934
2910
  logger.warn("[SQLiteStore] Backup failed", { error: String(err) });
2935
2911
  }
@@ -3051,1128 +3027,1243 @@ var RealVectorStore = class {
3051
3027
  }
3052
3028
  };
3053
3029
 
3054
- // src/mcp/session.ts
3055
- import path5 from "path";
3030
+ // src/mcp/capabilities.ts
3056
3031
  import { fileURLToPath as fileURLToPath3 } from "url";
3057
- function createSessionContext() {
3032
+ import path5 from "path";
3033
+
3034
+ // src/mcp/prompts/loader.ts
3035
+ import fs4 from "fs";
3036
+ import path4 from "path";
3037
+ import { fileURLToPath as fileURLToPath2 } from "url";
3038
+ import matter from "gray-matter";
3039
+ var __filename = fileURLToPath2(import.meta.url);
3040
+ var __dirname = path4.dirname(__filename);
3041
+ function findPromptDir() {
3042
+ const candidates = [
3043
+ // Production if chunked into dist/
3044
+ "./prompts",
3045
+ // Production if inlined into dist/mcp/
3046
+ "../prompts",
3047
+ // Dev: /src/mcp/prompts/definitions (next to loader.ts)
3048
+ "./definitions"
3049
+ ].map((relPath) => path4.resolve(__dirname, relPath));
3050
+ for (const dir of candidates) {
3051
+ if (fs4.existsSync(dir)) {
3052
+ const files = fs4.readdirSync(dir);
3053
+ if (files.some((f) => f.endsWith(".md"))) {
3054
+ return dir;
3055
+ }
3056
+ }
3057
+ }
3058
+ return path4.resolve(__dirname, "./definitions");
3059
+ }
3060
+ var PROMPT_DIR = findPromptDir();
3061
+ function listPromptFiles() {
3062
+ if (!fs4.existsSync(PROMPT_DIR)) return [];
3063
+ return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
3064
+ }
3065
+ function loadPromptFromMarkdown(name) {
3066
+ const filePath = path4.join(PROMPT_DIR, `${name}.md`);
3067
+ if (!fs4.existsSync(filePath)) {
3068
+ throw new Error(`Prompt file not found: ${filePath}`);
3069
+ }
3070
+ const fileContent = fs4.readFileSync(filePath, "utf-8");
3071
+ const { data, content } = matter(fileContent);
3058
3072
  return {
3059
- roots: [],
3060
- supportsRoots: false,
3061
- supportsSampling: false,
3062
- supportsSamplingTools: false,
3063
- supportsElicitation: false,
3064
- supportsElicitationForm: false,
3065
- supportsElicitationUrl: false
3073
+ name: data.name || name,
3074
+ description: data.description || "",
3075
+ arguments: data.arguments || [],
3076
+ agent: data.agent,
3077
+ content: content.trim()
3066
3078
  };
3067
3079
  }
3068
- function updateSessionFromInitialize(session, params) {
3069
- const capabilities = params?.capabilities || {};
3070
- session.clientInfo = params?.clientInfo;
3071
- session.clientCapabilities = capabilities;
3072
- session.supportsRoots = Boolean(capabilities.roots);
3073
- session.supportsSampling = Boolean(capabilities.sampling);
3074
- const sampling = capabilities.sampling;
3075
- session.supportsSamplingTools = Boolean(sampling?.tools);
3076
- session.supportsElicitation = Boolean(capabilities.elicitation);
3077
- session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
3078
- session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
3079
- }
3080
- function supportsElicitationMode(capability, mode) {
3081
- if (!capability || typeof capability !== "object") {
3082
- return false;
3083
- }
3084
- const cap = capability;
3085
- if (mode === "form") {
3086
- return Object.keys(cap).length === 0 || typeof cap.form === "object";
3080
+ function findServerInstructionsDir() {
3081
+ const candidates = [
3082
+ // Production if chunked into dist/
3083
+ "./prompts/server",
3084
+ // Production if inlined into dist/mcp/
3085
+ "../prompts/server",
3086
+ // Dev: /src/mcp/prompts/server (next to loader.ts)
3087
+ "./server"
3088
+ ].map((relPath) => path4.resolve(__dirname, relPath));
3089
+ for (const dir of candidates) {
3090
+ if (fs4.existsSync(dir)) {
3091
+ const filePath = path4.join(dir, "instructions.md");
3092
+ if (fs4.existsSync(filePath)) {
3093
+ return dir;
3094
+ }
3095
+ }
3087
3096
  }
3088
- return typeof cap.url === "object";
3089
- }
3090
- function updateSessionRoots(session, roots) {
3091
- const normalized = normalizeRoots(roots);
3092
- const previous = JSON.stringify(session.roots);
3093
- const next = JSON.stringify(normalized);
3094
- session.roots = normalized;
3095
- return previous !== next;
3097
+ return path4.resolve(__dirname, "./server");
3096
3098
  }
3097
- function normalizeRoots(roots) {
3098
- if (!Array.isArray(roots)) return [];
3099
- const seen = /* @__PURE__ */ new Set();
3100
- const normalized = [];
3101
- for (const root of roots) {
3102
- if (!root || typeof root !== "object") continue;
3103
- const r = root;
3104
- const uri = typeof r.uri === "string" ? r.uri : void 0;
3105
- const name = typeof r.name === "string" ? r.name : void 0;
3106
- if (!uri || seen.has(uri)) continue;
3107
- seen.add(uri);
3108
- normalized.push({ uri, name });
3099
+ var SERVER_DIR = findServerInstructionsDir();
3100
+ function loadServerInstructions() {
3101
+ const filePath = path4.join(SERVER_DIR, "instructions.md");
3102
+ if (!fs4.existsSync(filePath)) {
3103
+ throw new Error(`Server instructions file not found: ${filePath}`);
3109
3104
  }
3110
- return normalized;
3111
- }
3112
- function extractRootsFromResult(result) {
3113
- return normalizeRoots(result?.roots);
3105
+ const fileContent = fs4.readFileSync(filePath, "utf-8");
3106
+ const { content } = matter(fileContent);
3107
+ return content.trim();
3114
3108
  }
3115
- function getFilesystemRoots(session) {
3116
- if (!session) return [];
3117
- const resolved = [];
3118
- for (const root of session.roots) {
3119
- if (!root.uri.startsWith("file://")) continue;
3109
+
3110
+ // src/mcp/capabilities.ts
3111
+ var __dirname2 = path5.dirname(fileURLToPath3(import.meta.url));
3112
+ var pkgVersion = "0.1.0";
3113
+ if ("0.10.12") {
3114
+ pkgVersion = "0.10.12";
3115
+ } else {
3116
+ let searchDir = __dirname2;
3117
+ for (let i = 0; i < 5; i++) {
3118
+ const candidate = path5.join(searchDir, "package.json");
3120
3119
  try {
3121
- resolved.push(path5.resolve(fileURLToPath3(root.uri)));
3120
+ if (fs.existsSync(candidate)) {
3121
+ const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
3122
+ if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
3123
+ pkgVersion = pkg.version;
3124
+ break;
3125
+ }
3126
+ }
3122
3127
  } catch {
3123
3128
  }
3129
+ searchDir = path5.dirname(searchDir);
3124
3130
  }
3125
- return resolved;
3126
- }
3127
- function isPathWithinRoots(targetPath, session) {
3128
- const roots = getFilesystemRoots(session);
3129
- if (roots.length === 0) return true;
3130
- const normalizedTarget = path5.resolve(targetPath);
3131
- return roots.some((rootPath) => {
3132
- const relative = path5.relative(rootPath, normalizedTarget);
3133
- return relative === "" || !relative.startsWith("..") && !path5.isAbsolute(relative);
3134
- });
3135
3131
  }
3136
- function findContainingRoot(targetPath, session) {
3137
- const roots = getFilesystemRoots(session);
3138
- if (roots.length === 0) return null;
3139
- const normalizedTarget = path5.resolve(targetPath);
3140
- for (const rootPath of roots) {
3141
- const relative = path5.relative(rootPath, normalizedTarget);
3142
- if (relative === "" || !relative.startsWith("..") && !path5.isAbsolute(relative)) {
3143
- return rootPath;
3132
+ var MCP_PROTOCOL_VERSION = "2025-03-26";
3133
+ var SERVER_INSTRUCTIONS = loadServerInstructions();
3134
+ var CAPABILITIES = {
3135
+ serverInfo: {
3136
+ name: "local-memory-mcp",
3137
+ version: pkgVersion,
3138
+ instructions: SERVER_INSTRUCTIONS
3139
+ },
3140
+ capabilities: {
3141
+ completions: {},
3142
+ logging: {},
3143
+ resources: {
3144
+ subscribe: true,
3145
+ listChanged: true
3146
+ },
3147
+ tools: {
3148
+ listChanged: false
3149
+ },
3150
+ prompts: {
3151
+ listChanged: true
3144
3152
  }
3145
3153
  }
3146
- return null;
3154
+ };
3155
+
3156
+ // src/mcp/utils/pagination.ts
3157
+ function encodeCursor(offset) {
3158
+ return Buffer.from(String(offset), "utf8").toString("base64");
3147
3159
  }
3148
- function inferRepoFromSession(session) {
3149
- const roots = getFilesystemRoots(session);
3150
- if (roots.length === 1) {
3151
- return path5.basename(roots[0]);
3160
+ function decodeCursor(cursor) {
3161
+ if (cursor === void 0 || cursor === null || cursor === "") {
3162
+ return 0;
3152
3163
  }
3153
- return void 0;
3164
+ if (typeof cursor !== "string" || cursor.trim() === "") {
3165
+ throw invalidPaginationParams("Invalid cursor");
3166
+ }
3167
+ let decoded;
3168
+ try {
3169
+ decoded = Buffer.from(cursor, "base64").toString("utf8");
3170
+ } catch {
3171
+ throw invalidPaginationParams("Invalid cursor");
3172
+ }
3173
+ if (!/^\d+$/.test(decoded)) {
3174
+ throw invalidPaginationParams("Invalid cursor");
3175
+ }
3176
+ const offset = Number.parseInt(decoded, 10);
3177
+ if (!Number.isFinite(offset) || offset < 0) {
3178
+ throw invalidPaginationParams("Invalid cursor");
3179
+ }
3180
+ return offset;
3181
+ }
3182
+ function invalidPaginationParams(message) {
3183
+ const error = new Error(message);
3184
+ error.code = -32602;
3185
+ return error;
3154
3186
  }
3155
3187
 
3156
- // src/mcp/tools/schemas.ts
3157
- import { z } from "zod";
3158
- var MemoryScopeSchema = z.object({
3159
- repo: z.string().min(1).transform(normalizeRepo),
3160
- branch: z.string().optional(),
3161
- folder: z.string().optional(),
3162
- language: z.string().optional()
3163
- });
3164
- var MemoryTypeSchema = z.enum(["code_fact", "decision", "mistake", "pattern", "task_archive"]);
3165
- var MemoryStoreSchema = z.object({
3166
- code: z.string().max(20).optional(),
3167
- type: MemoryTypeSchema,
3168
- title: z.string().min(3).max(255),
3169
- content: z.string().min(10),
3170
- importance: z.number().min(1).max(5),
3171
- agent: z.string().min(1),
3172
- role: z.string().optional().default("unknown"),
3173
- model: z.string().min(1),
3174
- scope: MemoryScopeSchema,
3175
- ttlDays: z.number().min(1).optional(),
3176
- supersedes: z.string().uuid().optional(),
3177
- tags: z.array(z.string()).optional(),
3178
- metadata: z.record(z.string(), z.any()).optional(),
3179
- is_global: z.boolean().default(false),
3180
- structured: z.boolean().default(false)
3181
- });
3182
- var MemoryUpdateSchema = z.object({
3183
- id: z.string().uuid(),
3184
- type: MemoryTypeSchema.optional(),
3185
- title: z.string().min(3).max(255).optional(),
3186
- content: z.string().min(10).optional(),
3187
- importance: z.number().min(1).max(5).optional(),
3188
- agent: z.string().optional(),
3189
- role: z.string().optional(),
3190
- status: z.enum(["active", "archived"]).optional(),
3191
- supersedes: z.string().uuid().optional(),
3192
- tags: z.array(z.string()).optional(),
3193
- metadata: z.record(z.string(), z.any()).optional(),
3194
- is_global: z.boolean().optional(),
3195
- completed_at: z.string().optional(),
3196
- structured: z.boolean().default(false)
3197
- }).refine(
3198
- (data) => data.type !== void 0 || data.content !== void 0 || data.title !== void 0 || data.importance !== void 0 || data.status !== void 0 || data.supersedes !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.is_global !== void 0 || data.agent !== void 0 || data.role !== void 0 || data.completed_at !== void 0,
3199
- { message: "At least one field must be provided for update" }
3200
- );
3201
- var MemorySearchSchema = z.object({
3202
- query: z.string().min(3),
3203
- prompt: z.string().optional(),
3204
- repo: z.string().min(1).transform(normalizeRepo),
3205
- types: z.array(MemoryTypeSchema).optional(),
3206
- minImportance: z.number().min(1).max(5).optional(),
3207
- limit: z.number().min(1).max(100).default(5),
3208
- offset: z.number().min(0).default(0),
3209
- includeRecap: z.boolean().default(false),
3210
- current_file_path: z.string().optional(),
3211
- include_archived: z.boolean().default(false),
3212
- current_tags: z.array(z.string()).optional(),
3213
- scope: MemoryScopeSchema.partial().optional(),
3214
- structured: z.boolean().default(false)
3215
- });
3216
- var MemoryAcknowledgeSchema = z.object({
3217
- memory_id: z.string().uuid(),
3218
- status: z.enum(["used", "irrelevant", "contradictory"]),
3219
- application_context: z.string().min(10).optional(),
3220
- structured: z.boolean().default(false)
3221
- });
3222
- var MemoryRecapSchema = z.object({
3223
- repo: z.string().min(1).transform(normalizeRepo),
3224
- limit: z.number().min(1).max(50).default(20),
3225
- offset: z.number().min(0).default(0),
3226
- structured: z.boolean().default(false)
3227
- });
3228
- var MemoryDeleteSchema = z.object({
3229
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3230
- id: z.string().uuid().optional(),
3231
- ids: z.array(z.string().uuid()).min(1).optional(),
3232
- structured: z.boolean().default(false)
3233
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3234
- message: "Either 'id' or 'ids' must be provided for deletion"
3235
- });
3236
- var MemorySummarizeSchema = z.object({
3237
- repo: z.string().min(1).transform(normalizeRepo),
3238
- signals: z.array(z.string().max(200)).min(1),
3239
- structured: z.boolean().default(false)
3240
- });
3241
- var MemorySynthesizeSchema = z.object({
3242
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3243
- objective: z.string().min(5),
3244
- current_file_path: z.string().optional(),
3245
- include_summary: z.boolean().default(true),
3246
- include_tasks: z.boolean().default(true),
3247
- use_tools: z.boolean().default(true),
3248
- max_iterations: z.number().int().min(1).max(5).default(3),
3249
- max_tokens: z.number().int().min(128).max(4e3).default(1200),
3250
- structured: z.boolean().default(false)
3251
- });
3252
- var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
3253
- var TaskPrioritySchema = z.number().min(1).max(5);
3254
- var SingleTaskCreateSchema = z.object({
3255
- task_code: z.string().min(1),
3256
- phase: z.string().min(1),
3257
- title: z.string().min(3).max(100),
3258
- description: z.string().min(1),
3259
- status: TaskStatusSchema.default("backlog"),
3260
- priority: TaskPrioritySchema.default(3),
3261
- agent: z.string().optional(),
3262
- role: z.string().optional(),
3263
- doc_path: z.string().optional(),
3264
- tags: z.array(z.string()).optional(),
3265
- metadata: z.record(z.string(), z.any()).optional(),
3266
- parent_id: z.string().optional(),
3267
- depends_on: z.string().uuid().optional(),
3268
- est_tokens: z.number().int().min(0).optional()
3269
- });
3270
- var TaskCreateSchema = z.object({
3271
- repo: z.string().min(1).transform(normalizeRepo),
3272
- // Allow single task fields at top level (backward compatibility & single use)
3273
- task_code: z.string().min(1).optional(),
3274
- phase: z.string().min(1).optional(),
3275
- title: z.string().min(3).max(100).optional(),
3276
- description: z.string().min(1).optional(),
3277
- status: TaskStatusSchema.optional(),
3278
- priority: TaskPrioritySchema.optional(),
3279
- agent: z.string().optional(),
3280
- role: z.string().optional(),
3281
- doc_path: z.string().optional(),
3282
- tags: z.array(z.string()).optional(),
3283
- metadata: z.record(z.string(), z.any()).optional(),
3284
- parent_id: z.string().optional(),
3285
- depends_on: z.string().uuid().optional(),
3286
- est_tokens: z.number().int().min(0).optional(),
3287
- // Allow bulk tasks
3288
- tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
3289
- structured: z.boolean().default(false)
3290
- }).refine(
3291
- (data) => {
3292
- if (data.tasks) return true;
3293
- return !!(data.task_code && data.phase && data.title && data.description);
3294
- },
3295
- { message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
3296
- );
3297
- var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
3298
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3299
- structured: z.boolean().default(false)
3300
- });
3301
- var TaskUpdateSchema = z.object({
3302
- repo: z.string().min(1).transform(normalizeRepo),
3303
- id: z.string().uuid().optional(),
3304
- ids: z.array(z.string().uuid()).min(1).optional(),
3305
- task_code: z.string().optional(),
3306
- phase: z.string().optional(),
3307
- title: z.string().min(3).max(100).optional(),
3308
- description: z.string().optional(),
3309
- status: TaskStatusSchema.optional(),
3310
- priority: TaskPrioritySchema.optional(),
3311
- agent: z.string().min(1, "agent name is required").optional(),
3312
- role: z.string().min(1, "agent role is required").optional(),
3313
- model: z.string().optional(),
3314
- comment: z.string().min(1).optional(),
3315
- doc_path: z.string().optional(),
3316
- tags: z.array(z.string()).optional(),
3317
- metadata: z.record(z.string(), z.any()).optional(),
3318
- parent_id: z.string().optional(),
3319
- depends_on: z.string().uuid().optional(),
3320
- est_tokens: z.number().int().min(0).optional(),
3321
- force: z.boolean().optional(),
3322
- structured: z.boolean().default(false)
3323
- }).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
3324
- message: "Either 'id', 'ids', or 'task_code' must be provided for update"
3325
- }).refine((data) => Object.keys(data).length > 2, {
3326
- message: "At least one field besides repo and id/ids must be provided for update"
3327
- });
3328
- var TaskListSchema = z.object({
3329
- repo: z.string().min(1).transform(normalizeRepo),
3330
- status: z.string().optional(),
3331
- phase: z.string().optional(),
3332
- query: z.string().optional(),
3333
- limit: z.number().min(1).max(100).default(15),
3334
- offset: z.number().min(0).default(0),
3335
- structured: z.boolean().default(false)
3336
- });
3337
- var TaskSearchSchema = z.object({
3338
- repo: z.string().min(1).transform(normalizeRepo),
3339
- query: z.string().min(1),
3340
- status: z.string().optional(),
3341
- limit: z.number().min(1).max(100).default(10),
3342
- offset: z.number().min(0).default(0),
3343
- structured: z.boolean().default(false)
3344
- });
3345
- var TaskDeleteSchema = z.object({
3346
- repo: z.string().min(1).transform(normalizeRepo),
3347
- id: z.string().uuid().optional(),
3348
- ids: z.array(z.string().uuid()).min(1).optional(),
3349
- structured: z.boolean().default(false)
3350
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3351
- message: "Either 'id' or 'ids' must be provided for deletion"
3352
- });
3353
- var MemoryDetailSchema = z.object({
3354
- id: z.string().uuid().optional(),
3355
- code: z.string().max(20).optional(),
3356
- structured: z.boolean().default(false)
3357
- }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3358
- message: "Either id or code must be provided"
3359
- });
3360
- var StandardDetailSchema = z.object({
3361
- id: z.string().uuid().optional(),
3362
- code: z.string().max(20).optional(),
3363
- structured: z.boolean().default(false)
3364
- }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3365
- message: "Either id or code must be provided"
3366
- });
3367
- var StandardDeleteSchema = z.object({
3368
- repo: z.string().min(1).transform(normalizeRepo).optional(),
3369
- id: z.string().uuid().optional(),
3370
- ids: z.array(z.string().uuid()).min(1).optional(),
3371
- structured: z.boolean().default(false)
3372
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3373
- message: "Either 'id' or 'ids' must be provided for deletion"
3374
- });
3375
- var TaskGetSchema = z.object({
3376
- repo: z.string().min(1).transform(normalizeRepo),
3377
- id: z.string().uuid().optional(),
3378
- task_code: z.string().optional(),
3379
- structured: z.boolean().default(false)
3380
- }).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
3381
- message: "Either id or task_code must be provided"
3382
- });
3383
- var HandoffStatusSchema = z.enum(["pending", "accepted", "rejected", "expired"]);
3384
- var HandoffCreateSchema = z.object({
3385
- repo: z.string().min(1).transform(normalizeRepo),
3386
- from_agent: z.string().min(1),
3387
- to_agent: z.string().min(1).optional(),
3388
- task_id: z.string().uuid().optional(),
3389
- task_code: z.string().optional(),
3390
- summary: z.string().min(1),
3391
- context: z.record(z.string(), z.any()).optional(),
3392
- expires_at: z.string().optional(),
3393
- structured: z.boolean().default(false)
3394
- }).refine((data) => !(data.task_id && data.task_code), {
3395
- message: "Provide either task_id or task_code, not both"
3396
- }).refine(
3397
- (data) => data.to_agent || data.task_id || data.task_code || data.context?.next_steps || data.context?.blockers || data.context?.remaining_work,
3398
- {
3399
- message: "Handoffs must identify a target agent, linked task, next_steps, blockers, or remaining_work. Do not create pending handoffs for completed-work summaries."
3188
+ // src/mcp/utils/completion.ts
3189
+ var MAX_COMPLETION_VALUES = 100;
3190
+ function rankCompletionValues(candidates, input) {
3191
+ const unique = [...new Set(candidates.filter(Boolean))];
3192
+ const needle = input.trim().toLowerCase();
3193
+ if (!needle) {
3194
+ return unique.slice(0, MAX_COMPLETION_VALUES);
3400
3195
  }
3401
- );
3402
- var HandoffUpdateSchema = z.object({
3403
- id: z.string().uuid(),
3404
- status: HandoffStatusSchema,
3405
- structured: z.boolean().default(false)
3406
- });
3407
- var HandoffListSchema = z.object({
3408
- repo: z.string().min(1).transform(normalizeRepo),
3409
- status: HandoffStatusSchema.optional(),
3410
- from_agent: z.string().min(1).optional(),
3411
- to_agent: z.string().min(1).optional(),
3412
- limit: z.number().min(1).max(100).default(20),
3413
- offset: z.number().min(0).default(0),
3414
- structured: z.boolean().default(false)
3415
- });
3416
- var TaskClaimSchema = z.object({
3417
- repo: z.string().min(1).transform(normalizeRepo),
3418
- task_id: z.string().uuid().optional(),
3419
- task_code: z.string().optional(),
3420
- agent: z.string().min(1),
3421
- role: z.string().optional(),
3422
- metadata: z.record(z.string(), z.any()).optional(),
3423
- structured: z.boolean().default(false)
3424
- }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3425
- message: "Either task_id or task_code must be provided"
3426
- }).refine((data) => !(data.task_id && data.task_code), {
3427
- message: "Provide either task_id or task_code, not both"
3428
- });
3429
- var ClaimListSchema = z.object({
3430
- repo: z.string().min(1).transform(normalizeRepo),
3431
- agent: z.string().min(1).optional(),
3432
- active_only: z.boolean().default(true),
3433
- limit: z.number().min(1).max(100).default(20),
3434
- offset: z.number().min(0).default(0),
3435
- structured: z.boolean().default(false)
3436
- });
3437
- var ClaimReleaseSchema = z.object({
3438
- repo: z.string().min(1).transform(normalizeRepo),
3439
- task_id: z.string().uuid().optional(),
3440
- task_code: z.string().optional(),
3441
- agent: z.string().min(1).optional(),
3442
- structured: z.boolean().default(false)
3443
- }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3444
- message: "Either task_id or task_code must be provided"
3445
- }).refine((data) => !(data.task_id && data.task_code), {
3446
- message: "Provide either task_id or task_code, not both"
3447
- });
3448
- var StandardStoreSchema = z.object({
3449
- name: z.string().min(3).max(255),
3450
- content: z.string().min(10),
3451
- parent_id: z.string().uuid().optional(),
3452
- context: z.string().optional(),
3453
- version: z.string().optional(),
3454
- language: z.string().optional(),
3455
- stack: z.array(z.string()).optional(),
3456
- repo: z.string().transform(normalizeRepo).optional(),
3457
- is_global: z.boolean().optional(),
3458
- tags: z.array(z.string().min(1)).min(1),
3459
- metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, {
3460
- message: "metadata must contain at least one key"
3461
- }),
3462
- agent: z.string().optional(),
3463
- model: z.string().optional(),
3464
- structured: z.boolean().default(false)
3465
- }).refine((data) => data.is_global !== false || !!data.repo, {
3466
- message: "repo is required for repo-specific standards"
3467
- });
3468
- var StandardUpdateSchema = z.object({
3469
- id: z.string().uuid(),
3470
- name: z.string().min(3).max(255).optional(),
3471
- content: z.string().min(10).optional(),
3472
- parent_id: z.string().uuid().nullable().optional(),
3473
- context: z.string().optional(),
3474
- version: z.string().optional(),
3475
- language: z.string().optional(),
3476
- stack: z.array(z.string().min(1)).min(1).optional(),
3477
- repo: z.string().transform(normalizeRepo).optional(),
3478
- is_global: z.boolean().optional(),
3479
- tags: z.array(z.string().min(1)).min(1).optional(),
3480
- metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, { message: "metadata must contain at least one key" }).optional(),
3481
- agent: z.string().optional(),
3482
- model: z.string().optional(),
3483
- structured: z.boolean().default(false)
3484
- }).refine(
3485
- (data) => data.name !== void 0 || data.content !== void 0 || data.parent_id !== void 0 || data.context !== void 0 || data.version !== void 0 || data.language !== void 0 || data.stack !== void 0 || data.repo !== void 0 || data.is_global !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.agent !== void 0 || data.model !== void 0,
3486
- { message: "At least one field must be provided for update" }
3487
- ).refine((data) => data.is_global !== false || !!data.repo, {
3488
- message: "repo is required for repo-specific standards"
3489
- });
3490
- var StandardSearchSchema = z.object({
3491
- query: z.string().optional(),
3492
- stack: z.array(z.string()).optional(),
3493
- tags: z.array(z.string()).optional(),
3494
- language: z.string().optional(),
3495
- context: z.string().optional(),
3496
- version: z.string().optional(),
3497
- repo: z.string().transform(normalizeRepo).optional(),
3498
- is_global: z.boolean().optional(),
3499
- limit: z.number().min(1).max(100).default(20),
3500
- offset: z.number().min(0).default(0),
3501
- structured: z.boolean().default(false)
3502
- });
3503
- var TOOL_DEFINITIONS = [
3504
- {
3505
- name: "memory-synthesize",
3506
- title: "Memory Synthesize",
3507
- description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
3508
- annotations: {
3509
- readOnlyHint: true,
3510
- idempotentHint: true,
3511
- openWorldHint: false
3196
+ 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);
3197
+ }
3198
+ function scoreCompletionValue(value, needle) {
3199
+ const haystack = value.toLowerCase();
3200
+ if (haystack === needle) return 100;
3201
+ if (haystack.startsWith(needle)) return 75;
3202
+ if (haystack.includes(needle)) return 50;
3203
+ const compactNeedle = needle.replace(/[\s_-]+/g, "");
3204
+ const compactHaystack = haystack.replace(/[\s_-]+/g, "");
3205
+ if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
3206
+ return 0;
3207
+ }
3208
+
3209
+ // src/mcp/resources/index.ts
3210
+ var DEFAULT_PAGE_SIZE = 25;
3211
+ var MAX_PAGE_SIZE = 100;
3212
+ function listResources(session, params) {
3213
+ const resources = [
3214
+ {
3215
+ uri: "repository://index",
3216
+ name: "Repository Index",
3217
+ title: "Repository Index",
3218
+ description: "List of all known repositories with memory/task counts and last activity",
3219
+ mimeType: "application/json",
3220
+ annotations: {
3221
+ audience: ["assistant"],
3222
+ priority: 1,
3223
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3224
+ }
3512
3225
  },
3513
- execution: {
3514
- taskSupport: "optional"
3226
+ {
3227
+ uri: "session://roots",
3228
+ name: "Session Roots",
3229
+ title: "Session Roots",
3230
+ description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
3231
+ mimeType: "application/json",
3232
+ size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
3233
+ annotations: {
3234
+ audience: ["assistant"],
3235
+ priority: 0.95,
3236
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3237
+ }
3238
+ }
3239
+ ];
3240
+ return paginateEntries("resources", resources, params);
3241
+ }
3242
+ function listResourceTemplates(params) {
3243
+ const templates = [
3244
+ // ── Memory ──────────────────────────────────────────────────────────────
3245
+ {
3246
+ uriTemplate: "repository://{name}/memories",
3247
+ name: "Repository Memories",
3248
+ title: "Repository Memories",
3249
+ description: "All active memory entries for a specific repository",
3250
+ mimeType: "application/json",
3251
+ annotations: { audience: ["assistant"], priority: 0.85 }
3515
3252
  },
3516
- inputSchema: {
3517
- type: "object",
3518
- properties: {
3519
- repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
3520
- objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
3521
- current_file_path: {
3522
- type: "string",
3523
- description: "Optional absolute file path for workspace-local grounding."
3524
- },
3525
- include_summary: { type: "boolean", default: true },
3526
- include_tasks: { type: "boolean", default: true },
3527
- use_tools: {
3528
- type: "boolean",
3529
- default: true,
3530
- description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
3531
- },
3532
- max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
3533
- max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
3534
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
3535
- },
3536
- required: ["objective"]
3253
+ {
3254
+ uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
3255
+ name: "Filtered Repository Memories",
3256
+ title: "Filtered Repository Memories",
3257
+ description: "Filter or search memories within a repository by keyword, type, or tag",
3258
+ mimeType: "application/json",
3259
+ annotations: { audience: ["assistant"], priority: 0.8 }
3537
3260
  },
3538
- outputSchema: {
3539
- type: "object",
3540
- properties: {
3541
- repo: { type: "string" },
3542
- objective: { type: "string" },
3543
- answer: { type: "string" },
3544
- model: { type: "string" },
3545
- stopReason: { type: "string" },
3546
- iterations: { type: "number" },
3547
- toolCalls: { type: "number" }
3548
- },
3549
- required: ["repo", "objective", "answer", "iterations", "toolCalls"]
3550
- }
3551
- },
3552
- {
3553
- name: "task-create-interactive",
3554
- title: "Interactive Task Create",
3555
- description: "Create a task with MCP elicitation fallback for any missing required fields. Best when an agent knows a task is needed but still needs user confirmation for repo, title, or phase.",
3556
- annotations: {
3557
- readOnlyHint: false,
3558
- idempotentHint: false,
3559
- destructiveHint: false,
3560
- openWorldHint: false
3261
+ {
3262
+ uriTemplate: "memory://{id}",
3263
+ name: "Memory Detail",
3264
+ title: "Memory Detail",
3265
+ description: "Full content and statistics for a specific memory UUID",
3266
+ mimeType: "application/json",
3267
+ annotations: { audience: ["assistant"], priority: 0.75 }
3268
+ },
3269
+ // ── Tasks ────────────────────────────────────────────────────────────────
3270
+ {
3271
+ uriTemplate: "repository://{name}/tasks",
3272
+ name: "Repository Tasks",
3273
+ title: "Repository Tasks",
3274
+ description: "All active tasks for a specific repository",
3275
+ mimeType: "application/json",
3276
+ annotations: { audience: ["assistant"], priority: 0.9 }
3277
+ },
3278
+ {
3279
+ uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
3280
+ name: "Filtered Repository Tasks",
3281
+ title: "Filtered Repository Tasks",
3282
+ description: "Filter tasks within a repository by status or priority level",
3283
+ mimeType: "application/json",
3284
+ annotations: { audience: ["assistant"], priority: 0.85 }
3561
3285
  },
3562
- inputSchema: {
3563
- type: "object",
3564
- properties: {
3565
- repo: {
3566
- type: "string",
3567
- description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
3568
- },
3569
- task_code: { type: "string" },
3570
- phase: { type: "string" },
3571
- title: { type: "string", minLength: 3, maxLength: 100 },
3572
- description: { type: "string", minLength: 1 },
3573
- status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3574
- priority: {
3575
- type: "number",
3576
- minimum: 1,
3577
- maximum: 5,
3578
- default: 3,
3579
- description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
3580
- },
3581
- agent: { type: "string" },
3582
- role: { type: "string" },
3583
- doc_path: { type: "string" },
3584
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3585
- }
3286
+ {
3287
+ uriTemplate: "task://{id}",
3288
+ name: "Task Detail",
3289
+ title: "Task Detail",
3290
+ description: "Full content and comments for a specific task UUID",
3291
+ mimeType: "application/json",
3292
+ annotations: { audience: ["assistant"], priority: 0.8 }
3586
3293
  },
3587
- outputSchema: {
3588
- type: "object",
3589
- properties: {
3590
- repo: { type: "string" },
3591
- task_code: { type: "string" },
3592
- phase: { type: "string" },
3593
- title: { type: "string" },
3594
- status: { type: "string" },
3595
- priority: { type: "number" }
3596
- },
3597
- required: ["repo", "task_code", "phase", "title", "status", "priority"]
3294
+ // ── Repository extras ────────────────────────────────────────────────────
3295
+ {
3296
+ uriTemplate: "repository://{name}/summary",
3297
+ name: "Repository Summary",
3298
+ title: "Repository Summary",
3299
+ description: "High-level architectural summary for a repository",
3300
+ mimeType: "text/plain",
3301
+ annotations: { audience: ["assistant"], priority: 0.95 }
3302
+ },
3303
+ {
3304
+ uriTemplate: "repository://{name}/actions",
3305
+ name: "Repository Actions",
3306
+ title: "Repository Actions",
3307
+ description: "Audit log of agent tool actions scoped to a repository",
3308
+ mimeType: "application/json",
3309
+ annotations: { audience: ["assistant"], priority: 0.6 }
3310
+ },
3311
+ // ── Action detail ────────────────────────────────────────────────────────
3312
+ {
3313
+ uriTemplate: "action://{id}",
3314
+ name: "Action Detail",
3315
+ title: "Action Detail",
3316
+ description: "Full details of a specific audit log entry by integer ID",
3317
+ mimeType: "application/json",
3318
+ annotations: { audience: ["assistant"], priority: 0.55 }
3598
3319
  }
3599
- },
3600
- {
3601
- name: "memory-detail",
3602
- title: "Memory Detail",
3603
- description: "Fetch full details of a specific memory by ID or short code. Use after memory-recap or memory-search when a pointer row is relevant and full content is needed.",
3604
- inputSchema: {
3605
- type: "object",
3606
- properties: {
3607
- id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
3608
- code: { type: "string", description: "Short memory code. Optional if id is provided." },
3609
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3610
- }
3320
+ ];
3321
+ return paginateEntries("resourceTemplates", templates, params);
3322
+ }
3323
+ function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
3324
+ 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") {
3325
+ if (argumentName === "name") {
3326
+ return rankCompletionValues(dataSources.repos, argumentValue);
3611
3327
  }
3612
- },
3613
- {
3614
- name: "standard-detail",
3615
- title: "Standard Detail",
3616
- description: "Fetch full details of a specific coding standard by ID or short code. Use after standard-search when a result is relevant and full guidance is needed.",
3617
- inputSchema: {
3618
- type: "object",
3619
- properties: {
3620
- id: { type: "string", format: "uuid", description: "Coding standard ID. Optional if code is provided." },
3621
- code: { type: "string", description: "Short standard code (e.g. 'A3KPQ2'). Optional if id is provided." },
3622
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3623
- }
3328
+ }
3329
+ if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
3330
+ if (argumentName === "tag") {
3331
+ return rankCompletionValues(dataSources.tags, argumentValue);
3624
3332
  }
3625
- },
3626
- {
3627
- name: "task-detail",
3628
- title: "Task Detail",
3629
- description: "Fetch full details of a specific task by ID or task code. Use this when you have a task ID or code and need to read the full description and comments.",
3630
- inputSchema: {
3631
- type: "object",
3632
- properties: {
3633
- repo: { type: "string", description: "Repository name" },
3634
- id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
3635
- task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
3636
- structured: {
3637
- type: "boolean",
3638
- default: false,
3639
- description: "If true, returns structured JSON without the text content details."
3333
+ }
3334
+ throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
3335
+ }
3336
+ function readResource(uri, db, session) {
3337
+ logger.info("[Tool] resource.read", { uri });
3338
+ if (uri === "repository://index") {
3339
+ const repos = db.system.listRepoNavigation();
3340
+ const payload = JSON.stringify(repos, null, 2);
3341
+ return {
3342
+ contents: [
3343
+ {
3344
+ uri,
3345
+ mimeType: "application/json",
3346
+ text: payload,
3347
+ size: Buffer.byteLength(payload, "utf8"),
3348
+ annotations: {
3349
+ audience: ["assistant"],
3350
+ priority: 1,
3351
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3352
+ }
3640
3353
  }
3641
- },
3642
- required: ["repo"]
3643
- }
3644
- },
3645
- {
3646
- name: "memory-store",
3647
- title: "Memory Store",
3648
- description: "Store a new durable knowledge entry. Do not store coordination state here: task claims, file claims, agent registration, and handoffs belong to task-claim, task-update, and handoff-* tools. Keep 'title' concise and human-readable; put auxiliary context into 'metadata'.",
3649
- annotations: {
3650
- readOnlyHint: false,
3651
- idempotentHint: false,
3652
- destructiveHint: false,
3653
- openWorldHint: false
3654
- },
3655
- inputSchema: {
3656
- type: "object",
3657
- properties: {
3658
- type: {
3659
- type: "string",
3660
- enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"],
3661
- description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
3662
- },
3663
- title: {
3664
- type: "string",
3665
- minLength: 3,
3666
- maxLength: 100,
3667
- description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
3668
- },
3669
- content: {
3670
- type: "string",
3671
- minLength: 10,
3672
- description: "The memory content"
3673
- },
3674
- importance: {
3675
- type: "number",
3676
- minimum: 1,
3677
- maximum: 5,
3678
- description: "Importance score (1-5)"
3679
- },
3680
- agent: {
3681
- type: "string",
3682
- description: "Name of the agent creating this memory"
3683
- },
3684
- role: {
3685
- type: "string",
3686
- description: "Role of the agent creating this memory"
3687
- },
3688
- model: {
3689
- type: "string",
3690
- description: "AI model used by the agent"
3691
- },
3692
- scope: {
3693
- type: "object",
3694
- properties: {
3695
- repo: { type: "string", description: "Repository name" },
3696
- branch: { type: "string" },
3697
- folder: { type: "string" },
3698
- language: { type: "string" }
3699
- },
3700
- required: ["repo"]
3701
- },
3702
- tags: {
3703
- type: "array",
3704
- items: { type: "string" },
3705
- description: "Technology stack tags (e.g., ['filament', 'laravel'])"
3706
- },
3707
- metadata: {
3708
- type: "object",
3709
- description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
3710
- },
3711
- is_global: {
3712
- type: "boolean",
3713
- description: "If true, this memory is shared across all repositories"
3714
- },
3715
- ttlDays: { type: "number", minimum: 1 },
3716
- supersedes: { type: "string", format: "uuid" },
3717
- structured: {
3718
- type: "boolean",
3719
- default: false,
3720
- description: "If true, returns structured JSON of the stored memory."
3354
+ ]
3355
+ };
3356
+ }
3357
+ if (uri === "session://roots") {
3358
+ const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
3359
+ return {
3360
+ contents: [
3361
+ {
3362
+ uri,
3363
+ mimeType: "application/json",
3364
+ text: payload,
3365
+ size: Buffer.byteLength(payload, "utf8"),
3366
+ annotations: {
3367
+ audience: ["assistant"],
3368
+ priority: 0.95,
3369
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
3370
+ }
3371
+ }
3372
+ ]
3373
+ };
3374
+ }
3375
+ const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
3376
+ if (memoryIdMatch) {
3377
+ const id = memoryIdMatch[1];
3378
+ const entry = db.memories.getByIdWithStats(id);
3379
+ if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
3380
+ const payload = JSON.stringify(entry, null, 2);
3381
+ return {
3382
+ contents: [
3383
+ {
3384
+ uri,
3385
+ mimeType: "application/json",
3386
+ text: payload,
3387
+ size: Buffer.byteLength(payload, "utf8"),
3388
+ annotations: {
3389
+ audience: ["assistant"],
3390
+ priority: 0.75,
3391
+ lastModified: entry.updated_at || entry.created_at
3392
+ }
3721
3393
  }
3722
- },
3723
- required: ["type", "title", "content", "importance", "scope", "agent", "model"]
3724
- },
3725
- outputSchema: {
3726
- type: "object",
3727
- properties: {
3728
- success: { type: "boolean" },
3729
- id: { type: "string" },
3730
- code: { type: "string" },
3731
- repo: { type: "string" },
3732
- type: { type: "string" },
3733
- title: { type: "string" },
3734
- error: { type: "string" },
3735
- message: { type: "string" }
3736
- },
3737
- required: ["success"]
3394
+ ]
3395
+ };
3396
+ }
3397
+ const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
3398
+ if (taskIdMatch) {
3399
+ const id = taskIdMatch[1];
3400
+ const task = db.tasks.getTaskById(id);
3401
+ if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
3402
+ const payload = JSON.stringify(task, null, 2);
3403
+ return {
3404
+ contents: [
3405
+ {
3406
+ uri,
3407
+ mimeType: "application/json",
3408
+ text: payload,
3409
+ size: Buffer.byteLength(payload, "utf8"),
3410
+ annotations: {
3411
+ audience: ["assistant"],
3412
+ priority: 0.8,
3413
+ lastModified: task.updated_at || task.created_at
3414
+ }
3415
+ }
3416
+ ]
3417
+ };
3418
+ }
3419
+ const repoBase = parseRepoUri(uri);
3420
+ if (repoBase) {
3421
+ const { name, path: repoPath, query } = repoBase;
3422
+ if (repoPath === "summary") {
3423
+ const summary = db.summaries.getSummary(name);
3424
+ const text = summary?.summary || `No summary available for repository: ${name}`;
3425
+ return {
3426
+ contents: [
3427
+ {
3428
+ uri,
3429
+ mimeType: "text/plain",
3430
+ text,
3431
+ size: Buffer.byteLength(text, "utf8"),
3432
+ annotations: {
3433
+ audience: ["assistant"],
3434
+ priority: 0.95,
3435
+ lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
3436
+ }
3437
+ }
3438
+ ]
3439
+ };
3738
3440
  }
3739
- },
3740
- {
3741
- name: "memory-acknowledge",
3742
- title: "Memory Acknowledge",
3743
- description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
3744
- annotations: {
3745
- readOnlyHint: false,
3746
- idempotentHint: false,
3747
- openWorldHint: false
3748
- },
3749
- inputSchema: {
3750
- type: "object",
3751
- properties: {
3752
- memory_id: { type: "string", format: "uuid" },
3753
- status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
3754
- application_context: { type: "string", minLength: 10 },
3755
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3756
- },
3757
- required: ["memory_id", "status"]
3758
- },
3759
- outputSchema: {
3760
- type: "object",
3761
- properties: {
3762
- success: { type: "boolean" },
3763
- id: { type: "string" },
3764
- status: { type: "string" }
3765
- },
3766
- required: ["success", "id", "status"]
3441
+ if (repoPath === "memories") {
3442
+ const search = query.get("search") || "";
3443
+ const type = query.get("type");
3444
+ const tag = query.get("tag");
3445
+ const result = db.memories.listMemoriesForDashboard({
3446
+ repo: name,
3447
+ type: type || void 0,
3448
+ tag: tag || void 0,
3449
+ search: search || void 0,
3450
+ limit: 50
3451
+ });
3452
+ const entries = result.items;
3453
+ const payload = JSON.stringify(entries, null, 2);
3454
+ return {
3455
+ contents: [
3456
+ {
3457
+ uri,
3458
+ mimeType: "application/json",
3459
+ text: payload,
3460
+ size: Buffer.byteLength(payload, "utf8"),
3461
+ annotations: {
3462
+ audience: ["assistant"],
3463
+ priority: 0.85,
3464
+ lastModified: deriveLastModifiedFromCollection(
3465
+ entries.map((e) => e.updated_at || e.created_at)
3466
+ )
3467
+ }
3468
+ }
3469
+ ]
3470
+ };
3767
3471
  }
3768
- },
3769
- {
3770
- name: "memory-update",
3771
- title: "Memory Update",
3772
- description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
3773
- annotations: {
3774
- readOnlyHint: false,
3775
- idempotentHint: false,
3776
- destructiveHint: false,
3777
- openWorldHint: false
3778
- },
3779
- inputSchema: {
3780
- type: "object",
3781
- properties: {
3782
- id: { type: "string", format: "uuid" },
3783
- type: {
3784
- type: "string",
3785
- enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"]
3786
- },
3787
- title: { type: "string", minLength: 3, maxLength: 100 },
3788
- content: { type: "string", minLength: 10 },
3789
- importance: { type: "number", minimum: 1, maximum: 5 },
3790
- agent: { type: "string" },
3791
- role: { type: "string" },
3792
- status: { type: "string", enum: ["active", "archived"] },
3793
- supersedes: { type: "string", format: "uuid" },
3794
- tags: { type: "array", items: { type: "string" } },
3795
- metadata: { type: "object" },
3796
- is_global: { type: "boolean" },
3797
- completed_at: { type: "string" },
3798
- structured: {
3799
- type: "boolean",
3800
- default: false,
3801
- description: "If true, returns structured JSON of the updated memory."
3802
- }
3803
- },
3804
- required: ["id"]
3805
- },
3806
- outputSchema: {
3807
- type: "object",
3808
- properties: {
3809
- success: { type: "boolean" },
3810
- id: { type: "string" },
3811
- repo: { type: "string" },
3812
- updatedFields: {
3813
- type: "array",
3814
- items: { type: "string" }
3472
+ if (repoPath === "tasks") {
3473
+ const status = query.get("status");
3474
+ const priority = query.get("priority");
3475
+ let tasks;
3476
+ if (status && status !== "all") {
3477
+ const statuses = status.split(",").map((s) => s.trim());
3478
+ tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
3479
+ } else {
3480
+ tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
3481
+ }
3482
+ if (priority) {
3483
+ const p = Number(priority);
3484
+ if (!isNaN(p)) {
3485
+ tasks = tasks.filter((t) => t.priority === p);
3815
3486
  }
3816
- },
3817
- required: ["success", "id", "repo", "updatedFields"]
3487
+ }
3488
+ const payload = JSON.stringify(tasks, null, 2);
3489
+ return {
3490
+ contents: [
3491
+ {
3492
+ uri,
3493
+ mimeType: "application/json",
3494
+ text: payload,
3495
+ size: Buffer.byteLength(payload, "utf8"),
3496
+ annotations: {
3497
+ audience: ["assistant"],
3498
+ priority: 0.9,
3499
+ lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
3500
+ }
3501
+ }
3502
+ ]
3503
+ };
3818
3504
  }
3819
- },
3820
- {
3821
- name: "memory-search",
3822
- title: "Memory Search",
3823
- description: "NAVIGATION LAYER: Returns a pointer table of matching memory IDs only. Returns columns [id, title, type, importance] \u2014 NO content. Retrieve full memory via memory-detail. Use 'current_tags' to find tech-stack specific knowledge from other projects.",
3824
- annotations: {
3825
- readOnlyHint: true,
3826
- idempotentHint: true,
3827
- openWorldHint: false
3828
- },
3829
- inputSchema: {
3830
- type: "object",
3831
- properties: {
3832
- query: { type: "string", minLength: 3 },
3833
- prompt: { type: "string" },
3834
- repo: { type: "string" },
3835
- current_tags: {
3836
- type: "array",
3837
- items: { type: "string" },
3838
- description: "Active tech stack tags (e.g., ['filament', 'react'])"
3839
- },
3840
- types: {
3841
- type: "array",
3842
- items: {
3843
- type: "string",
3844
- enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"]
3505
+ if (repoPath === "actions") {
3506
+ const actions = db.actions.getRecentActions(name, 100);
3507
+ const payload = JSON.stringify(actions, null, 2);
3508
+ return {
3509
+ contents: [
3510
+ {
3511
+ uri,
3512
+ mimeType: "application/json",
3513
+ text: payload,
3514
+ size: Buffer.byteLength(payload, "utf8"),
3515
+ annotations: {
3516
+ audience: ["assistant"],
3517
+ priority: 0.6,
3518
+ lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
3519
+ }
3845
3520
  }
3846
- },
3847
- minImportance: { type: "number", minimum: 1, maximum: 5 },
3848
- limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
3849
- offset: { type: "number", minimum: 0, default: 0 },
3850
- includeRecap: { type: "boolean", default: false },
3851
- current_file_path: { type: "string" },
3852
- include_archived: { type: "boolean", default: false },
3853
- scope: {
3854
- type: "object",
3855
- properties: {
3856
- repo: { type: "string" },
3857
- branch: { type: "string" },
3858
- folder: { type: "string" },
3859
- language: { type: "string" }
3521
+ ]
3522
+ };
3523
+ }
3524
+ }
3525
+ const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
3526
+ if (actionIdMatch) {
3527
+ const id = Number(actionIdMatch[1]);
3528
+ const action = db.actions.getActionById(id);
3529
+ if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
3530
+ const payload = JSON.stringify(action, null, 2);
3531
+ return {
3532
+ contents: [
3533
+ {
3534
+ uri,
3535
+ mimeType: "application/json",
3536
+ text: payload,
3537
+ size: Buffer.byteLength(payload, "utf8"),
3538
+ annotations: {
3539
+ audience: ["assistant"],
3540
+ priority: 0.55,
3541
+ lastModified: action.created_at
3860
3542
  }
3861
- },
3862
- structured: {
3863
- type: "boolean",
3864
- default: false,
3865
- description: "If true, returns structured JSON without the text content summary."
3866
3543
  }
3867
- },
3868
- required: ["query", "repo"]
3869
- },
3870
- outputSchema: {
3871
- type: "object",
3872
- properties: {
3873
- schema: { type: "string", enum: ["memory-search"] },
3874
- query: { type: "string" },
3875
- count: { type: "number", description: "Number of rows returned" },
3876
- total: { type: "number", description: "Total matching memories" },
3877
- offset: { type: "number" },
3878
- limit: { type: "number" },
3879
- results: {
3880
- type: "object",
3881
- properties: {
3882
- columns: {
3883
- type: "array",
3884
- items: { type: "string" },
3885
- description: "Column names: [id, title, type, importance]"
3886
- },
3887
- rows: {
3888
- type: "array",
3889
- items: { type: "array" },
3890
- description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
3891
- }
3892
- },
3893
- required: ["columns", "rows"]
3544
+ ]
3545
+ };
3546
+ }
3547
+ throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
3548
+ }
3549
+ function parseRepoUri(uri) {
3550
+ const prefix = "repository://";
3551
+ if (!uri.startsWith(prefix)) return null;
3552
+ const rest = uri.slice(prefix.length);
3553
+ const queryStart = rest.indexOf("?");
3554
+ const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
3555
+ const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
3556
+ const slashIdx = withoutQuery.indexOf("/");
3557
+ if (slashIdx === -1) return null;
3558
+ const name = withoutQuery.slice(0, slashIdx);
3559
+ const path6 = withoutQuery.slice(slashIdx + 1);
3560
+ if (!name || !path6) return null;
3561
+ return { name, path: path6, query: new URLSearchParams(queryString) };
3562
+ }
3563
+ function paginateEntries(key, entries, params) {
3564
+ const limit = normalizeLimit(params?.limit);
3565
+ const offset = decodeCursor(params?.cursor);
3566
+ const sliced = entries.slice(offset, offset + limit);
3567
+ const nextOffset = offset + sliced.length;
3568
+ return {
3569
+ [key]: sliced,
3570
+ nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
3571
+ };
3572
+ }
3573
+ function normalizeLimit(limit) {
3574
+ if (typeof limit !== "number" || !Number.isFinite(limit)) {
3575
+ return DEFAULT_PAGE_SIZE;
3576
+ }
3577
+ return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
3578
+ }
3579
+ function deriveLastModifiedFromCollection(values) {
3580
+ const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
3581
+ return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
3582
+ }
3583
+ function resourceNotFound(message, uri) {
3584
+ const error = new Error(message);
3585
+ error.code = -32002;
3586
+ error.data = { uri };
3587
+ return error;
3588
+ }
3589
+ function invalidCompletionParams(message) {
3590
+ const error = new Error(message);
3591
+ error.code = -32602;
3592
+ return error;
3593
+ }
3594
+
3595
+ // src/mcp/prompts/registry.ts
3596
+ function createPromptDefinition(loaded) {
3597
+ return {
3598
+ name: loaded.name,
3599
+ description: loaded.description,
3600
+ arguments: loaded.arguments,
3601
+ agent: loaded.agent,
3602
+ messages: [
3603
+ {
3604
+ role: "user",
3605
+ content: {
3606
+ type: "text",
3607
+ text: loaded.content
3894
3608
  }
3895
- },
3896
- required: ["schema", "query", "count", "total", "offset", "limit", "results"]
3609
+ }
3610
+ ]
3611
+ };
3612
+ }
3613
+ var PROMPTS = {};
3614
+ var promptFiles = listPromptFiles();
3615
+ for (const name of promptFiles) {
3616
+ try {
3617
+ PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
3618
+ } catch (e) {
3619
+ logger.warn(`Failed to load prompt ${name}: ${e}`);
3620
+ }
3621
+ }
3622
+ async function listPrompts(db, session, params) {
3623
+ const allPrompts = Object.values(PROMPTS).map((p) => ({
3624
+ name: p.name,
3625
+ description: p.description,
3626
+ arguments: p.arguments,
3627
+ metadata: p.agent ? { agent: p.agent } : void 0
3628
+ }));
3629
+ const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
3630
+ const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
3631
+ const offset = decodeCursor(params?.cursor);
3632
+ const sliced = allPrompts.slice(offset, offset + limit);
3633
+ const nextOffset = offset + sliced.length;
3634
+ return {
3635
+ prompts: sliced,
3636
+ nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
3637
+ };
3638
+ }
3639
+ async function getPrompt(name, args = {}, db, session) {
3640
+ const prompt = PROMPTS[name];
3641
+ if (!prompt) {
3642
+ throw new Error(`Prompt not found: ${name}`);
3643
+ }
3644
+ const inferredRepo = inferRepoFromSession(session);
3645
+ const messages = prompt.messages.map((m) => {
3646
+ let text = m.content.text;
3647
+ for (const [key, value] of Object.entries(args)) {
3648
+ text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
3897
3649
  }
3650
+ text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
3651
+ return {
3652
+ ...m,
3653
+ content: {
3654
+ ...m.content,
3655
+ text
3656
+ }
3657
+ };
3658
+ });
3659
+ return {
3660
+ description: prompt.description,
3661
+ messages,
3662
+ metadata: prompt.agent ? { agent: prompt.agent } : void 0
3663
+ };
3664
+ }
3665
+ async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
3666
+ void name;
3667
+ void contextArguments;
3668
+ if (argName === "task_id") {
3669
+ const values = dataSources.tasks.map((t) => t.id);
3670
+ return rankCompletionValues(values, value);
3671
+ }
3672
+ return [];
3673
+ }
3674
+
3675
+ // src/mcp/tools/schemas.ts
3676
+ import { z } from "zod";
3677
+ var MemoryScopeSchema = z.object({
3678
+ repo: z.string().min(1).transform(normalizeRepo),
3679
+ branch: z.string().optional(),
3680
+ folder: z.string().optional(),
3681
+ language: z.string().optional()
3682
+ });
3683
+ var MemoryTypeSchema = z.enum(["code_fact", "decision", "mistake", "pattern", "task_archive"]);
3684
+ var MemoryStoreSchema = z.object({
3685
+ code: z.string().max(20).optional(),
3686
+ type: MemoryTypeSchema,
3687
+ title: z.string().min(3).max(255),
3688
+ content: z.string().min(10),
3689
+ importance: z.number().min(1).max(5),
3690
+ agent: z.string().min(1),
3691
+ role: z.string().optional().default("unknown"),
3692
+ model: z.string().min(1),
3693
+ scope: MemoryScopeSchema,
3694
+ ttlDays: z.number().min(1).optional(),
3695
+ supersedes: z.string().uuid().optional(),
3696
+ tags: z.array(z.string()).optional(),
3697
+ metadata: z.record(z.string(), z.any()).optional(),
3698
+ is_global: z.boolean().default(false),
3699
+ structured: z.boolean().default(false)
3700
+ });
3701
+ var MemoryUpdateSchema = z.object({
3702
+ id: z.string().uuid(),
3703
+ type: MemoryTypeSchema.optional(),
3704
+ title: z.string().min(3).max(255).optional(),
3705
+ content: z.string().min(10).optional(),
3706
+ importance: z.number().min(1).max(5).optional(),
3707
+ agent: z.string().optional(),
3708
+ role: z.string().optional(),
3709
+ status: z.enum(["active", "archived"]).optional(),
3710
+ supersedes: z.string().uuid().optional(),
3711
+ tags: z.array(z.string()).optional(),
3712
+ metadata: z.record(z.string(), z.any()).optional(),
3713
+ is_global: z.boolean().optional(),
3714
+ completed_at: z.string().optional(),
3715
+ structured: z.boolean().default(false)
3716
+ }).refine(
3717
+ (data) => data.type !== void 0 || data.content !== void 0 || data.title !== void 0 || data.importance !== void 0 || data.status !== void 0 || data.supersedes !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.is_global !== void 0 || data.agent !== void 0 || data.role !== void 0 || data.completed_at !== void 0,
3718
+ { message: "At least one field must be provided for update" }
3719
+ );
3720
+ var MemorySearchSchema = z.object({
3721
+ query: z.string().min(3),
3722
+ prompt: z.string().optional(),
3723
+ repo: z.string().min(1).transform(normalizeRepo),
3724
+ types: z.array(MemoryTypeSchema).optional(),
3725
+ minImportance: z.number().min(1).max(5).optional(),
3726
+ limit: z.number().min(1).max(100).default(5),
3727
+ offset: z.number().min(0).default(0),
3728
+ includeRecap: z.boolean().default(false),
3729
+ current_file_path: z.string().optional(),
3730
+ include_archived: z.boolean().default(false),
3731
+ current_tags: z.array(z.string()).optional(),
3732
+ scope: MemoryScopeSchema.partial().optional(),
3733
+ structured: z.boolean().default(false)
3734
+ });
3735
+ var MemoryAcknowledgeSchema = z.object({
3736
+ memory_id: z.string().uuid(),
3737
+ status: z.enum(["used", "irrelevant", "contradictory"]),
3738
+ application_context: z.string().min(10).optional(),
3739
+ structured: z.boolean().default(false)
3740
+ });
3741
+ var MemoryRecapSchema = z.object({
3742
+ repo: z.string().min(1).transform(normalizeRepo),
3743
+ limit: z.number().min(1).max(50).default(20),
3744
+ offset: z.number().min(0).default(0),
3745
+ structured: z.boolean().default(false)
3746
+ });
3747
+ var MemoryDeleteSchema = z.object({
3748
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3749
+ id: z.string().uuid().optional(),
3750
+ ids: z.array(z.string().uuid()).min(1).optional(),
3751
+ structured: z.boolean().default(false)
3752
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3753
+ message: "Either 'id' or 'ids' must be provided for deletion"
3754
+ });
3755
+ var MemorySummarizeSchema = z.object({
3756
+ repo: z.string().min(1).transform(normalizeRepo),
3757
+ signals: z.array(z.string().max(200)).min(1),
3758
+ structured: z.boolean().default(false)
3759
+ });
3760
+ var MemorySynthesizeSchema = z.object({
3761
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3762
+ objective: z.string().min(5),
3763
+ current_file_path: z.string().optional(),
3764
+ include_summary: z.boolean().default(true),
3765
+ include_tasks: z.boolean().default(true),
3766
+ use_tools: z.boolean().default(true),
3767
+ max_iterations: z.number().int().min(1).max(5).default(3),
3768
+ max_tokens: z.number().int().min(128).max(4e3).default(1200),
3769
+ structured: z.boolean().default(false)
3770
+ });
3771
+ var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
3772
+ var TaskPrioritySchema = z.number().min(1).max(5);
3773
+ var SingleTaskCreateSchema = z.object({
3774
+ task_code: z.string().min(1),
3775
+ phase: z.string().min(1),
3776
+ title: z.string().min(3).max(100),
3777
+ description: z.string().min(1),
3778
+ status: TaskStatusSchema.default("backlog"),
3779
+ priority: TaskPrioritySchema.default(3),
3780
+ agent: z.string().optional(),
3781
+ role: z.string().optional(),
3782
+ doc_path: z.string().optional(),
3783
+ tags: z.array(z.string()).optional(),
3784
+ metadata: z.record(z.string(), z.any()).optional(),
3785
+ parent_id: z.string().optional(),
3786
+ depends_on: z.string().uuid().optional(),
3787
+ est_tokens: z.number().int().min(0).optional()
3788
+ });
3789
+ var TaskCreateSchema = z.object({
3790
+ repo: z.string().min(1).transform(normalizeRepo),
3791
+ // Allow single task fields at top level (backward compatibility & single use)
3792
+ task_code: z.string().min(1).optional(),
3793
+ phase: z.string().min(1).optional(),
3794
+ title: z.string().min(3).max(100).optional(),
3795
+ description: z.string().min(1).optional(),
3796
+ status: TaskStatusSchema.optional(),
3797
+ priority: TaskPrioritySchema.optional(),
3798
+ agent: z.string().optional(),
3799
+ role: z.string().optional(),
3800
+ doc_path: z.string().optional(),
3801
+ tags: z.array(z.string()).optional(),
3802
+ metadata: z.record(z.string(), z.any()).optional(),
3803
+ parent_id: z.string().optional(),
3804
+ depends_on: z.string().uuid().optional(),
3805
+ est_tokens: z.number().int().min(0).optional(),
3806
+ // Allow bulk tasks
3807
+ tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
3808
+ structured: z.boolean().default(false)
3809
+ }).refine(
3810
+ (data) => {
3811
+ if (data.tasks) return true;
3812
+ return !!(data.task_code && data.phase && data.title && data.description);
3898
3813
  },
3814
+ { message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
3815
+ );
3816
+ var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
3817
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3818
+ structured: z.boolean().default(false)
3819
+ });
3820
+ var TaskUpdateSchema = z.object({
3821
+ repo: z.string().min(1).transform(normalizeRepo),
3822
+ id: z.string().uuid().optional(),
3823
+ ids: z.array(z.string().uuid()).min(1).optional(),
3824
+ task_code: z.string().optional(),
3825
+ phase: z.string().optional(),
3826
+ title: z.string().min(3).max(100).optional(),
3827
+ description: z.string().optional(),
3828
+ status: TaskStatusSchema.optional(),
3829
+ priority: TaskPrioritySchema.optional(),
3830
+ agent: z.string().min(1, "agent name is required").optional(),
3831
+ role: z.string().min(1, "agent role is required").optional(),
3832
+ model: z.string().optional(),
3833
+ comment: z.string().min(1).optional(),
3834
+ doc_path: z.string().optional(),
3835
+ tags: z.array(z.string()).optional(),
3836
+ metadata: z.record(z.string(), z.any()).optional(),
3837
+ parent_id: z.string().optional(),
3838
+ depends_on: z.string().uuid().optional(),
3839
+ est_tokens: z.number().int().min(0).optional(),
3840
+ force: z.boolean().optional(),
3841
+ structured: z.boolean().default(false)
3842
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
3843
+ message: "Either 'id', 'ids', or 'task_code' must be provided for update"
3844
+ }).refine((data) => Object.keys(data).length > 2, {
3845
+ message: "At least one field besides repo and id/ids must be provided for update"
3846
+ });
3847
+ var TaskListSchema = z.object({
3848
+ repo: z.string().min(1).transform(normalizeRepo),
3849
+ status: z.string().optional(),
3850
+ phase: z.string().optional(),
3851
+ query: z.string().optional(),
3852
+ limit: z.number().min(1).max(100).default(15),
3853
+ offset: z.number().min(0).default(0),
3854
+ structured: z.boolean().default(false)
3855
+ });
3856
+ var TaskSearchSchema = z.object({
3857
+ repo: z.string().min(1).transform(normalizeRepo),
3858
+ query: z.string().min(1),
3859
+ status: z.string().optional(),
3860
+ limit: z.number().min(1).max(100).default(10),
3861
+ offset: z.number().min(0).default(0),
3862
+ structured: z.boolean().default(false)
3863
+ });
3864
+ var TaskDeleteSchema = z.object({
3865
+ repo: z.string().min(1).transform(normalizeRepo),
3866
+ id: z.string().uuid().optional(),
3867
+ ids: z.array(z.string().uuid()).min(1).optional(),
3868
+ structured: z.boolean().default(false)
3869
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3870
+ message: "Either 'id' or 'ids' must be provided for deletion"
3871
+ });
3872
+ var MemoryDetailSchema = z.object({
3873
+ id: z.string().uuid().optional(),
3874
+ code: z.string().max(20).optional(),
3875
+ structured: z.boolean().default(false)
3876
+ }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3877
+ message: "Either id or code must be provided"
3878
+ });
3879
+ var StandardDetailSchema = z.object({
3880
+ id: z.string().uuid().optional(),
3881
+ code: z.string().max(20).optional(),
3882
+ structured: z.boolean().default(false)
3883
+ }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3884
+ message: "Either id or code must be provided"
3885
+ });
3886
+ var StandardDeleteSchema = z.object({
3887
+ repo: z.string().min(1).transform(normalizeRepo).optional(),
3888
+ id: z.string().uuid().optional(),
3889
+ ids: z.array(z.string().uuid()).min(1).optional(),
3890
+ structured: z.boolean().default(false)
3891
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3892
+ message: "Either 'id' or 'ids' must be provided for deletion"
3893
+ });
3894
+ var TaskGetSchema = z.object({
3895
+ repo: z.string().min(1).transform(normalizeRepo),
3896
+ id: z.string().uuid().optional(),
3897
+ task_code: z.string().optional(),
3898
+ structured: z.boolean().default(false)
3899
+ }).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
3900
+ message: "Either id or task_code must be provided"
3901
+ });
3902
+ var HandoffStatusSchema = z.enum(["pending", "accepted", "rejected", "expired"]);
3903
+ var HandoffCreateSchema = z.object({
3904
+ repo: z.string().min(1).transform(normalizeRepo),
3905
+ from_agent: z.string().min(1),
3906
+ to_agent: z.string().min(1).optional(),
3907
+ task_id: z.string().uuid().optional(),
3908
+ task_code: z.string().optional(),
3909
+ summary: z.string().min(1),
3910
+ context: z.record(z.string(), z.any()).optional(),
3911
+ expires_at: z.string().optional(),
3912
+ structured: z.boolean().default(false)
3913
+ }).refine((data) => !(data.task_id && data.task_code), {
3914
+ message: "Provide either task_id or task_code, not both"
3915
+ }).refine(
3916
+ (data) => data.to_agent || data.task_id || data.task_code || data.context?.next_steps || data.context?.blockers || data.context?.remaining_work,
3917
+ {
3918
+ message: "Handoffs must identify a target agent, linked task, next_steps, blockers, or remaining_work. Do not create pending handoffs for completed-work summaries."
3919
+ }
3920
+ );
3921
+ var HandoffUpdateSchema = z.object({
3922
+ id: z.string().uuid(),
3923
+ status: HandoffStatusSchema,
3924
+ structured: z.boolean().default(false)
3925
+ });
3926
+ var HandoffListSchema = z.object({
3927
+ repo: z.string().min(1).transform(normalizeRepo),
3928
+ status: HandoffStatusSchema.optional(),
3929
+ from_agent: z.string().min(1).optional(),
3930
+ to_agent: z.string().min(1).optional(),
3931
+ limit: z.number().min(1).max(100).default(20),
3932
+ offset: z.number().min(0).default(0),
3933
+ structured: z.boolean().default(false)
3934
+ });
3935
+ var TaskClaimSchema = z.object({
3936
+ repo: z.string().min(1).transform(normalizeRepo),
3937
+ task_id: z.string().uuid().optional(),
3938
+ task_code: z.string().optional(),
3939
+ agent: z.string().min(1),
3940
+ role: z.string().optional(),
3941
+ metadata: z.record(z.string(), z.any()).optional(),
3942
+ structured: z.boolean().default(false)
3943
+ }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3944
+ message: "Either task_id or task_code must be provided"
3945
+ }).refine((data) => !(data.task_id && data.task_code), {
3946
+ message: "Provide either task_id or task_code, not both"
3947
+ });
3948
+ var ClaimListSchema = z.object({
3949
+ repo: z.string().min(1).transform(normalizeRepo),
3950
+ agent: z.string().min(1).optional(),
3951
+ active_only: z.boolean().default(true),
3952
+ limit: z.number().min(1).max(100).default(20),
3953
+ offset: z.number().min(0).default(0),
3954
+ structured: z.boolean().default(false)
3955
+ });
3956
+ var ClaimReleaseSchema = z.object({
3957
+ repo: z.string().min(1).transform(normalizeRepo),
3958
+ task_id: z.string().uuid().optional(),
3959
+ task_code: z.string().optional(),
3960
+ agent: z.string().min(1).optional(),
3961
+ structured: z.boolean().default(false)
3962
+ }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3963
+ message: "Either task_id or task_code must be provided"
3964
+ }).refine((data) => !(data.task_id && data.task_code), {
3965
+ message: "Provide either task_id or task_code, not both"
3966
+ });
3967
+ var StandardStoreSchema = z.object({
3968
+ name: z.string().min(3).max(255),
3969
+ content: z.string().min(10),
3970
+ parent_id: z.string().uuid().optional(),
3971
+ context: z.string().optional(),
3972
+ version: z.string().optional(),
3973
+ language: z.string().optional(),
3974
+ stack: z.array(z.string()).optional(),
3975
+ repo: z.string().transform(normalizeRepo).optional(),
3976
+ is_global: z.boolean().optional(),
3977
+ tags: z.array(z.string().min(1)).min(1),
3978
+ metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, {
3979
+ message: "metadata must contain at least one key"
3980
+ }),
3981
+ agent: z.string().optional(),
3982
+ model: z.string().optional(),
3983
+ structured: z.boolean().default(false)
3984
+ }).refine((data) => data.is_global !== false || !!data.repo, {
3985
+ message: "repo is required for repo-specific standards"
3986
+ });
3987
+ var StandardUpdateSchema = z.object({
3988
+ id: z.string().uuid(),
3989
+ name: z.string().min(3).max(255).optional(),
3990
+ content: z.string().min(10).optional(),
3991
+ parent_id: z.string().uuid().nullable().optional(),
3992
+ context: z.string().optional(),
3993
+ version: z.string().optional(),
3994
+ language: z.string().optional(),
3995
+ stack: z.array(z.string().min(1)).min(1).optional(),
3996
+ repo: z.string().transform(normalizeRepo).optional(),
3997
+ is_global: z.boolean().optional(),
3998
+ tags: z.array(z.string().min(1)).min(1).optional(),
3999
+ metadata: z.record(z.string(), z.any()).refine((value) => Object.keys(value).length > 0, { message: "metadata must contain at least one key" }).optional(),
4000
+ agent: z.string().optional(),
4001
+ model: z.string().optional(),
4002
+ structured: z.boolean().default(false)
4003
+ }).refine(
4004
+ (data) => data.name !== void 0 || data.content !== void 0 || data.parent_id !== void 0 || data.context !== void 0 || data.version !== void 0 || data.language !== void 0 || data.stack !== void 0 || data.repo !== void 0 || data.is_global !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.agent !== void 0 || data.model !== void 0,
4005
+ { message: "At least one field must be provided for update" }
4006
+ ).refine((data) => data.is_global !== false || !!data.repo, {
4007
+ message: "repo is required for repo-specific standards"
4008
+ });
4009
+ var StandardSearchSchema = z.object({
4010
+ query: z.string().optional(),
4011
+ stack: z.array(z.string()).optional(),
4012
+ tags: z.array(z.string()).optional(),
4013
+ language: z.string().optional(),
4014
+ context: z.string().optional(),
4015
+ version: z.string().optional(),
4016
+ repo: z.string().transform(normalizeRepo).optional(),
4017
+ is_global: z.boolean().optional(),
4018
+ limit: z.number().min(1).max(100).default(20),
4019
+ offset: z.number().min(0).default(0),
4020
+ structured: z.boolean().default(false)
4021
+ });
4022
+ var TOOL_DEFINITIONS = [
3899
4023
  {
3900
- name: "memory-summarize",
3901
- title: "Memory Summarize",
3902
- description: "Update the summary for a repository",
4024
+ name: "memory-synthesize",
4025
+ title: "Memory Synthesize",
4026
+ description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
3903
4027
  annotations: {
3904
- readOnlyHint: false,
3905
- idempotentHint: false,
4028
+ readOnlyHint: true,
4029
+ idempotentHint: true,
3906
4030
  openWorldHint: false
3907
4031
  },
4032
+ execution: {
4033
+ taskSupport: "optional"
4034
+ },
3908
4035
  inputSchema: {
3909
4036
  type: "object",
3910
4037
  properties: {
3911
- repo: { type: "string", description: "Repository name" },
3912
- signals: {
3913
- type: "array",
3914
- items: { type: "string", maxLength: 200 },
3915
- minItems: 1,
3916
- description: "High-level signals to include in summary"
4038
+ repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
4039
+ objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
4040
+ current_file_path: {
4041
+ type: "string",
4042
+ description: "Optional absolute file path for workspace-local grounding."
3917
4043
  },
3918
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
4044
+ include_summary: { type: "boolean", default: true },
4045
+ include_tasks: { type: "boolean", default: true },
4046
+ use_tools: {
4047
+ type: "boolean",
4048
+ default: true,
4049
+ description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
4050
+ },
4051
+ max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
4052
+ max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
4053
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
3919
4054
  },
3920
- required: ["repo", "signals"]
4055
+ required: ["objective"]
3921
4056
  },
3922
4057
  outputSchema: {
3923
4058
  type: "object",
3924
4059
  properties: {
3925
- success: { type: "boolean" },
3926
4060
  repo: { type: "string" },
3927
- summary: { type: "string" },
3928
- signalCount: { type: "number" }
4061
+ objective: { type: "string" },
4062
+ answer: { type: "string" },
4063
+ model: { type: "string" },
4064
+ stopReason: { type: "string" },
4065
+ iterations: { type: "number" },
4066
+ toolCalls: { type: "number" }
3929
4067
  },
3930
- required: ["success", "repo", "summary", "signalCount"]
4068
+ required: ["repo", "objective", "answer", "iterations", "toolCalls"]
3931
4069
  }
3932
4070
  },
3933
4071
  {
3934
- name: "memory-delete",
3935
- title: "Memory Delete",
3936
- description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
4072
+ name: "task-create-interactive",
4073
+ title: "Interactive Task Create",
4074
+ description: "Create a task with MCP elicitation fallback for any missing required fields. Best when an agent knows a task is needed but still needs user confirmation for repo, title, or phase.",
3937
4075
  annotations: {
3938
4076
  readOnlyHint: false,
3939
4077
  idempotentHint: false,
3940
- destructiveHint: true,
4078
+ destructiveHint: false,
3941
4079
  openWorldHint: false
3942
4080
  },
3943
4081
  inputSchema: {
3944
4082
  type: "object",
3945
4083
  properties: {
3946
- repo: { type: "string", description: "Repository name (optional for single id)" },
3947
- id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
3948
- ids: {
3949
- type: "array",
3950
- items: { type: "string", format: "uuid" },
3951
- minItems: 1,
3952
- description: "Array of memory IDs to delete"
4084
+ repo: {
4085
+ type: "string",
4086
+ description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
4087
+ },
4088
+ task_code: { type: "string" },
4089
+ phase: { type: "string" },
4090
+ title: { type: "string", minLength: 3, maxLength: 100 },
4091
+ description: {
4092
+ type: "string",
4093
+ minLength: 1,
4094
+ description: "Detailed description. MUST follow format: 1. Context & Analysis, 2. Step & Implementation, 3. Acceptance & Verification"
4095
+ },
4096
+ status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
4097
+ priority: {
4098
+ type: "number",
4099
+ minimum: 1,
4100
+ maximum: 5,
4101
+ default: 3,
4102
+ description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
3953
4103
  },
4104
+ agent: { type: "string" },
4105
+ role: { type: "string" },
4106
+ doc_path: { type: "string" },
3954
4107
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3955
4108
  }
3956
4109
  },
3957
4110
  outputSchema: {
3958
4111
  type: "object",
3959
4112
  properties: {
3960
- success: { type: "boolean" },
3961
- id: { type: "string" },
3962
- ids: { type: "array", items: { type: "string" } },
3963
4113
  repo: { type: "string" },
3964
- deletedCount: { type: "number" }
4114
+ task_code: { type: "string" },
4115
+ phase: { type: "string" },
4116
+ title: { type: "string" },
4117
+ status: { type: "string" },
4118
+ priority: { type: "number" }
3965
4119
  },
3966
- required: ["success"]
4120
+ required: ["repo", "task_code", "phase", "title", "status", "priority"]
3967
4121
  }
3968
4122
  },
3969
4123
  {
3970
- name: "standard-delete",
3971
- title: "Standard Delete",
3972
- description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
3973
- annotations: {
3974
- readOnlyHint: false,
3975
- idempotentHint: false,
3976
- destructiveHint: true,
3977
- openWorldHint: false
3978
- },
4124
+ name: "memory-detail",
4125
+ title: "Memory Detail",
4126
+ description: "Fetch full details of a specific memory by ID or short code. Use after memory-recap or memory-search when a pointer row is relevant and full content is needed.",
3979
4127
  inputSchema: {
3980
4128
  type: "object",
3981
4129
  properties: {
3982
- repo: { type: "string", description: "Repository name (optional for single id)" },
3983
- id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
3984
- ids: {
3985
- type: "array",
3986
- items: { type: "string", format: "uuid" },
3987
- minItems: 1,
3988
- description: "Array of coding standard IDs to delete"
3989
- },
3990
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4130
+ id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
4131
+ code: { type: "string", description: "Short memory code. Optional if id is provided." },
4132
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
3991
4133
  }
3992
- },
3993
- outputSchema: {
4134
+ }
4135
+ },
4136
+ {
4137
+ name: "standard-detail",
4138
+ title: "Standard Detail",
4139
+ description: "Fetch full details of a specific coding standard by ID or short code. Use after standard-search when a result is relevant and full guidance is needed.",
4140
+ inputSchema: {
3994
4141
  type: "object",
3995
4142
  properties: {
3996
- success: { type: "boolean" },
3997
- id: { type: "string" },
3998
- ids: { type: "array", items: { type: "string" } },
3999
- repo: { type: "string" },
4000
- deletedCount: { type: "number" }
4001
- },
4002
- required: ["success"]
4143
+ id: { type: "string", format: "uuid", description: "Coding standard ID. Optional if code is provided." },
4144
+ code: { type: "string", description: "Short standard code (e.g. 'A3KPQ2'). Optional if id is provided." },
4145
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
4146
+ }
4003
4147
  }
4004
4148
  },
4005
4149
  {
4006
- name: "memory-recap",
4007
- title: "Memory Recap",
4008
- description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, code, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
4009
- annotations: {
4010
- readOnlyHint: true,
4011
- idempotentHint: true,
4012
- openWorldHint: false
4013
- },
4150
+ name: "task-detail",
4151
+ title: "Task Detail",
4152
+ description: "Fetch full details of a specific task by ID or task code. Use this when you have a task ID or code and need to read the full description and comments.",
4014
4153
  inputSchema: {
4015
4154
  type: "object",
4016
4155
  properties: {
4017
- repo: { type: "string", description: "Repository name (required)" },
4018
- limit: {
4019
- type: "number",
4020
- minimum: 1,
4021
- maximum: 50,
4022
- default: 20,
4023
- description: "Maximum number of top memories to return in the pointer table"
4024
- },
4025
- offset: {
4026
- type: "number",
4027
- minimum: 0,
4028
- default: 0,
4029
- description: "Number of memories to skip for pagination (optional, default 0)"
4030
- },
4156
+ repo: { type: "string", description: "Repository name" },
4157
+ id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
4158
+ task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
4031
4159
  structured: {
4032
4160
  type: "boolean",
4033
4161
  default: false,
4034
- description: "If true, returns structured JSON without the text content summary."
4162
+ description: "If true, returns structured JSON without the text content details."
4035
4163
  }
4036
4164
  },
4037
4165
  required: ["repo"]
4038
- },
4039
- outputSchema: {
4040
- type: "object",
4041
- properties: {
4042
- schema: { type: "string", enum: ["memory-recap"] },
4043
- repo: { type: "string" },
4044
- count: { type: "number", description: "Number of rows in the top pointer table" },
4045
- total: { type: "number", description: "Total active memories in repo" },
4046
- offset: { type: "number" },
4047
- limit: { type: "number" },
4048
- stats: {
4049
- type: "object",
4050
- properties: {
4051
- byType: {
4052
- type: "object",
4053
- description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
4054
- }
4055
- },
4056
- required: ["byType"]
4057
- },
4058
- top: {
4059
- type: "object",
4060
- properties: {
4061
- columns: {
4062
- type: "array",
4063
- items: { type: "string" },
4064
- description: "Column names: [id, code, title, type, importance]"
4065
- },
4066
- rows: {
4067
- type: "array",
4068
- items: { type: "array" },
4069
- description: "Each row: [id, code, title, type, importance]. Fetch full content via memory-detail"
4070
- }
4071
- },
4072
- required: ["columns", "rows"]
4073
- }
4074
- },
4075
- required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
4076
4166
  }
4077
4167
  },
4078
4168
  {
4079
- name: "task-create",
4080
- title: "Task Create",
4081
- description: "Register one or more new tasks in a repository. task_code must be unique within the repository. Supports single task object or an array of tasks for bulk creation.",
4169
+ name: "memory-store",
4170
+ title: "Memory Store",
4171
+ description: "Store a new durable knowledge entry. Do not store coordination state here: task claims, file claims, agent registration, and handoffs belong to task-claim, task-update, and handoff-* tools. Keep 'title' concise and human-readable; put auxiliary context into 'metadata'.",
4082
4172
  annotations: {
4083
4173
  readOnlyHint: false,
4084
4174
  idempotentHint: false,
4175
+ destructiveHint: false,
4085
4176
  openWorldHint: false
4086
4177
  },
4087
4178
  inputSchema: {
4088
4179
  type: "object",
4089
4180
  properties: {
4090
- repo: { type: "string", description: "Repository name" },
4091
- task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
4092
- phase: { type: "string", description: "Project phase (Required for single task)" },
4181
+ type: {
4182
+ type: "string",
4183
+ enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"],
4184
+ description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
4185
+ },
4093
4186
  title: {
4094
4187
  type: "string",
4095
4188
  minLength: 3,
4096
4189
  maxLength: 100,
4097
- description: "Task objective (Required for single task)"
4190
+ description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
4191
+ },
4192
+ content: {
4193
+ type: "string",
4194
+ minLength: 10,
4195
+ description: "The memory content"
4196
+ },
4197
+ importance: {
4198
+ type: "number",
4199
+ minimum: 1,
4200
+ maximum: 5,
4201
+ description: "Importance score (1-5)"
4202
+ },
4203
+ agent: {
4204
+ type: "string",
4205
+ description: "Name of the agent creating this memory"
4206
+ },
4207
+ role: {
4208
+ type: "string",
4209
+ description: "Role of the agent creating this memory"
4098
4210
  },
4099
- description: { type: "string", description: "Detailed description (Required for single task)" },
4100
- status: {
4211
+ model: {
4101
4212
  type: "string",
4102
- enum: ["backlog", "pending"],
4103
- default: "backlog",
4104
- description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
4213
+ description: "AI model used by the agent"
4105
4214
  },
4106
- priority: {
4107
- type: "number",
4108
- minimum: 1,
4109
- maximum: 5,
4110
- default: 3,
4111
- description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4215
+ scope: {
4216
+ type: "object",
4217
+ properties: {
4218
+ repo: { type: "string", description: "Repository name" },
4219
+ branch: { type: "string" },
4220
+ folder: { type: "string" },
4221
+ language: { type: "string" }
4222
+ },
4223
+ required: ["repo"]
4112
4224
  },
4113
- agent: { type: "string" },
4114
- role: { type: "string" },
4115
- doc_path: { type: "string" },
4116
- tags: { type: "array", items: { type: "string" } },
4117
- metadata: { type: "object" },
4118
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4119
- depends_on: { type: "string", format: "uuid" },
4120
- est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
4121
- tasks: {
4225
+ tags: {
4122
4226
  type: "array",
4123
- items: {
4124
- type: "object",
4125
- properties: {
4126
- task_code: { type: "string" },
4127
- phase: { type: "string" },
4128
- title: { type: "string", minLength: 3, maxLength: 100 },
4129
- description: { type: "string" },
4130
- status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
4131
- priority: {
4132
- type: "number",
4133
- minimum: 1,
4134
- maximum: 5,
4135
- default: 3,
4136
- description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4137
- },
4138
- agent: { type: "string" },
4139
- role: { type: "string" },
4140
- doc_path: { type: "string" },
4141
- tags: { type: "array", items: { type: "string" } },
4142
- metadata: { type: "object" },
4143
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4144
- depends_on: { type: "string", format: "uuid" },
4145
- est_tokens: { type: "number", minimum: 0 }
4146
- },
4147
- required: ["task_code", "phase", "title", "description"]
4148
- },
4149
- description: "Array of tasks for bulk creation"
4227
+ items: { type: "string" },
4228
+ description: "Technology stack tags (e.g., ['filament', 'laravel'])"
4150
4229
  },
4151
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4230
+ metadata: {
4231
+ type: "object",
4232
+ description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
4233
+ },
4234
+ is_global: {
4235
+ type: "boolean",
4236
+ description: "If true, this memory is shared across all repositories"
4237
+ },
4238
+ ttlDays: { type: "number", minimum: 1 },
4239
+ supersedes: { type: "string", format: "uuid" },
4240
+ structured: {
4241
+ type: "boolean",
4242
+ default: false,
4243
+ description: "If true, returns structured JSON of the stored memory."
4244
+ }
4152
4245
  },
4153
- required: ["repo"]
4246
+ required: ["type", "title", "content", "importance", "scope", "agent", "model"]
4154
4247
  },
4155
4248
  outputSchema: {
4156
4249
  type: "object",
4157
4250
  properties: {
4158
4251
  success: { type: "boolean" },
4159
4252
  id: { type: "string" },
4160
- task_code: { type: "string" },
4253
+ code: { type: "string" },
4161
4254
  repo: { type: "string" },
4162
- phase: { type: "string" },
4255
+ type: { type: "string" },
4163
4256
  title: { type: "string" },
4164
- status: { type: "string" },
4165
- priority: { type: "number" },
4166
- createdCount: { type: "number" },
4167
- taskCodes: { type: "array", items: { type: "string" } }
4257
+ error: { type: "string" },
4258
+ message: { type: "string" }
4168
4259
  },
4169
- required: ["success", "repo"]
4260
+ required: ["success"]
4170
4261
  }
4171
4262
  },
4172
4263
  {
4173
- name: "task-update",
4174
- title: "Task Update",
4175
- description: "Update one or more tasks. Supports single update via 'id' or bulk update via 'ids'. Provide only the fields that need to be changed. MANDATORY WORKFLOW: You cannot move a task from 'pending' or 'blocked' directly to 'completed'. You MUST move it to 'in_progress' first. When changing status to 'completed', include 'est_tokens' with the estimated total tokens actually used for the task.",
4264
+ name: "memory-acknowledge",
4265
+ title: "Memory Acknowledge",
4266
+ description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
4176
4267
  annotations: {
4177
4268
  readOnlyHint: false,
4178
4269
  idempotentHint: false,
@@ -4181,103 +4272,78 @@ var TOOL_DEFINITIONS = [
4181
4272
  inputSchema: {
4182
4273
  type: "object",
4183
4274
  properties: {
4184
- repo: { type: "string", description: "Repository name" },
4185
- id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
4186
- ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
4187
- task_code: { type: "string" },
4188
- phase: { type: "string" },
4189
- title: { type: "string", minLength: 3, maxLength: 100 },
4190
- description: { type: "string" },
4191
- status: {
4192
- type: "string",
4193
- enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
4194
- description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
4195
- },
4196
- priority: {
4197
- type: "number",
4198
- minimum: 1,
4199
- maximum: 5,
4200
- description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4201
- },
4202
- agent: { type: "string" },
4203
- role: { type: "string" },
4204
- model: { type: "string" },
4205
- comment: {
4206
- type: "string",
4207
- description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
4208
- },
4209
- doc_path: { type: "string" },
4210
- tags: { type: "array", items: { type: "string" } },
4211
- metadata: { type: "object" },
4212
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4213
- depends_on: { type: "string", format: "uuid" },
4214
- est_tokens: {
4215
- type: "number",
4216
- minimum: 0,
4217
- description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
4218
- },
4219
- force: {
4220
- type: "boolean",
4221
- description: "If true, bypasses status transition validation (e.g. pending -> completed)."
4222
- },
4275
+ memory_id: { type: "string", format: "uuid" },
4276
+ status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
4277
+ application_context: { type: "string", minLength: 10 },
4223
4278
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4224
4279
  },
4225
- required: ["repo"]
4280
+ required: ["memory_id", "status"]
4226
4281
  },
4227
4282
  outputSchema: {
4228
4283
  type: "object",
4229
4284
  properties: {
4230
4285
  success: { type: "boolean" },
4231
4286
  id: { type: "string" },
4232
- ids: { type: "array", items: { type: "string" } },
4233
- repo: { type: "string" },
4234
- status: { type: "string" },
4235
- archivedToMemory: { type: "boolean" },
4236
- updatedFields: {
4237
- type: "array",
4238
- items: { type: "string" }
4239
- },
4240
- updatedCount: { type: "number" }
4287
+ status: { type: "string" }
4241
4288
  },
4242
- required: ["success", "repo"]
4289
+ required: ["success", "id", "status"]
4243
4290
  }
4244
4291
  },
4245
4292
  {
4246
- name: "task-delete",
4247
- title: "Task Delete",
4248
- description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
4293
+ name: "memory-update",
4294
+ title: "Memory Update",
4295
+ description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
4249
4296
  annotations: {
4250
4297
  readOnlyHint: false,
4251
4298
  idempotentHint: false,
4252
- destructiveHint: true,
4299
+ destructiveHint: false,
4253
4300
  openWorldHint: false
4254
4301
  },
4255
4302
  inputSchema: {
4256
4303
  type: "object",
4257
4304
  properties: {
4258
- repo: { type: "string", description: "Repository name" },
4259
- id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
4260
- ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
4261
- structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4305
+ id: { type: "string", format: "uuid" },
4306
+ type: {
4307
+ type: "string",
4308
+ enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"]
4309
+ },
4310
+ title: { type: "string", minLength: 3, maxLength: 100 },
4311
+ content: { type: "string", minLength: 10 },
4312
+ importance: { type: "number", minimum: 1, maximum: 5 },
4313
+ agent: { type: "string" },
4314
+ role: { type: "string" },
4315
+ status: { type: "string", enum: ["active", "archived"] },
4316
+ supersedes: { type: "string", format: "uuid" },
4317
+ tags: { type: "array", items: { type: "string" } },
4318
+ metadata: { type: "object" },
4319
+ is_global: { type: "boolean" },
4320
+ completed_at: { type: "string" },
4321
+ structured: {
4322
+ type: "boolean",
4323
+ default: false,
4324
+ description: "If true, returns structured JSON of the updated memory."
4325
+ }
4262
4326
  },
4263
- required: ["repo"]
4327
+ required: ["id"]
4264
4328
  },
4265
4329
  outputSchema: {
4266
4330
  type: "object",
4267
4331
  properties: {
4268
4332
  success: { type: "boolean" },
4269
4333
  id: { type: "string" },
4270
- ids: { type: "array", items: { type: "string" } },
4271
4334
  repo: { type: "string" },
4272
- deletedCount: { type: "number" }
4335
+ updatedFields: {
4336
+ type: "array",
4337
+ items: { type: "string" }
4338
+ }
4273
4339
  },
4274
- required: ["success", "repo"]
4340
+ required: ["success", "id", "repo", "updatedFields"]
4275
4341
  }
4276
4342
  },
4277
4343
  {
4278
- name: "task-list",
4279
- title: "Task List",
4280
- description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority, updated_at, comments_count). Defaults to in_progress and pending tasks. Use 'query' to filter by code, title, or description. Use 'status' (comma-separated) for specific filters. AGENTS: call this once at start, pick ONE task, then call task-detail.",
4344
+ name: "memory-search",
4345
+ title: "Memory Search",
4346
+ description: "NAVIGATION LAYER: Returns a pointer table of matching memory IDs only. Returns columns [id, title, type, importance] \u2014 NO content. Retrieve full memory via memory-detail. Use 'current_tags' to find tech-stack specific knowledge from other projects.",
4281
4347
  annotations: {
4282
4348
  readOnlyHint: true,
4283
4349
  idempotentHint: true,
@@ -4286,35 +4352,35 @@ var TOOL_DEFINITIONS = [
4286
4352
  inputSchema: {
4287
4353
  type: "object",
4288
4354
  properties: {
4289
- repo: {
4290
- type: "string",
4291
- description: "Repository name (required)"
4292
- },
4293
- status: {
4294
- type: "string",
4295
- default: "in_progress,pending",
4296
- description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
4297
- },
4298
- phase: {
4299
- type: "string",
4300
- description: "Filter by phase (e.g., 'research', 'implementation')"
4301
- },
4302
- query: {
4303
- type: "string",
4304
- description: "Search keyword matching task code, title, or description"
4355
+ query: { type: "string", minLength: 3 },
4356
+ prompt: { type: "string" },
4357
+ repo: { type: "string" },
4358
+ current_tags: {
4359
+ type: "array",
4360
+ items: { type: "string" },
4361
+ description: "Active tech stack tags (e.g., ['filament', 'react'])"
4305
4362
  },
4306
- limit: {
4307
- type: "number",
4308
- minimum: 1,
4309
- maximum: 100,
4310
- default: 5,
4311
- description: "Maximum rows to return (default 5)"
4363
+ types: {
4364
+ type: "array",
4365
+ items: {
4366
+ type: "string",
4367
+ enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"]
4368
+ }
4312
4369
  },
4313
- offset: {
4314
- type: "number",
4315
- minimum: 0,
4316
- default: 0,
4317
- description: "Offset for pagination"
4370
+ minImportance: { type: "number", minimum: 1, maximum: 5 },
4371
+ limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
4372
+ offset: { type: "number", minimum: 0, default: 0 },
4373
+ includeRecap: { type: "boolean", default: false },
4374
+ current_file_path: { type: "string" },
4375
+ include_archived: { type: "boolean", default: false },
4376
+ scope: {
4377
+ type: "object",
4378
+ properties: {
4379
+ repo: { type: "string" },
4380
+ branch: { type: "string" },
4381
+ folder: { type: "string" },
4382
+ language: { type: "string" }
4383
+ }
4318
4384
  },
4319
4385
  structured: {
4320
4386
  type: "boolean",
@@ -4322,113 +4388,147 @@ var TOOL_DEFINITIONS = [
4322
4388
  description: "If true, returns structured JSON without the text content summary."
4323
4389
  }
4324
4390
  },
4325
- required: ["repo"]
4391
+ required: ["query", "repo"]
4326
4392
  },
4327
4393
  outputSchema: {
4328
4394
  type: "object",
4329
4395
  properties: {
4330
- schema: { type: "string", enum: ["task-list"] },
4331
- tasks: {
4396
+ schema: { type: "string", enum: ["memory-search"] },
4397
+ query: { type: "string" },
4398
+ count: { type: "number", description: "Number of rows returned" },
4399
+ total: { type: "number", description: "Total matching memories" },
4400
+ offset: { type: "number" },
4401
+ limit: { type: "number" },
4402
+ results: {
4332
4403
  type: "object",
4333
4404
  properties: {
4334
4405
  columns: {
4335
4406
  type: "array",
4336
4407
  items: { type: "string" },
4337
- description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
4408
+ description: "Column names: [id, title, type, importance]"
4338
4409
  },
4339
4410
  rows: {
4340
4411
  type: "array",
4341
4412
  items: { type: "array" },
4342
- description: "Each row: [id, task_code, title, status, priority, updated_at, comments_count]. Use task-detail to fetch full task."
4413
+ description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
4343
4414
  }
4344
4415
  },
4345
4416
  required: ["columns", "rows"]
4346
- },
4347
- count: { type: "number" },
4348
- offset: { type: "number" }
4417
+ }
4349
4418
  },
4350
- required: ["schema", "tasks", "count"]
4419
+ required: ["schema", "query", "count", "total", "offset", "limit", "results"]
4351
4420
  }
4352
4421
  },
4353
4422
  {
4354
- name: "handoff-create",
4355
- title: "Handoff Create",
4356
- description: "Create a pending handoff only when unfinished work needs context transfer between agents. Do not use this for completed-work summaries, release notes, validation notes, or archives; put those on task-update/task comments or durable memory.",
4423
+ name: "memory-summarize",
4424
+ title: "Memory Summarize",
4425
+ description: "Update the summary for a repository",
4357
4426
  annotations: {
4358
4427
  readOnlyHint: false,
4359
4428
  idempotentHint: false,
4360
- destructiveHint: false,
4361
4429
  openWorldHint: false
4362
4430
  },
4363
4431
  inputSchema: {
4364
4432
  type: "object",
4365
4433
  properties: {
4366
4434
  repo: { type: "string", description: "Repository name" },
4367
- from_agent: { type: "string", description: "Agent creating the handoff" },
4368
- to_agent: { type: "string", description: "Optional target agent" },
4369
- task_id: { type: "string", format: "uuid", description: "Optional task id to associate" },
4370
- task_code: { type: "string", description: "Optional task code to associate" },
4371
- summary: { type: "string", minLength: 1, description: "Concise human-readable transfer summary" },
4372
- context: {
4373
- type: "object",
4374
- description: "Structured handoff context. Include next_steps, blockers, or remaining_work unless a target agent or task is provided."
4435
+ signals: {
4436
+ type: "array",
4437
+ items: { type: "string", maxLength: 200 },
4438
+ minItems: 1,
4439
+ description: "High-level signals to include in summary"
4375
4440
  },
4376
- expires_at: { type: "string", description: "Optional expiration timestamp" },
4377
- structured: { type: "boolean", default: false }
4441
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
4378
4442
  },
4379
- required: ["repo", "from_agent", "summary"]
4443
+ required: ["repo", "signals"]
4380
4444
  },
4381
4445
  outputSchema: {
4382
4446
  type: "object",
4383
4447
  properties: {
4384
- id: { type: "string" },
4448
+ success: { type: "boolean" },
4385
4449
  repo: { type: "string" },
4386
- from_agent: { type: "string" },
4387
- to_agent: { type: "string", nullable: true },
4388
- task_id: { type: "string", nullable: true },
4389
4450
  summary: { type: "string" },
4390
- context: { type: "object" },
4391
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4392
- created_at: { type: "string" },
4393
- updated_at: { type: "string" },
4394
- expires_at: { type: "string", nullable: true }
4451
+ signalCount: { type: "number" }
4395
4452
  },
4396
- required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
4453
+ required: ["success", "repo", "summary", "signalCount"]
4397
4454
  }
4398
4455
  },
4399
4456
  {
4400
- name: "handoff-update",
4401
- title: "Handoff Update",
4402
- description: "Close or reclassify a handoff after it has been consumed or found stale. Use accepted when transfer context was consumed, rejected when intentionally declined, and expired when the handoff is obsolete or only described completed work.",
4457
+ name: "memory-delete",
4458
+ title: "Memory Delete",
4459
+ description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
4403
4460
  annotations: {
4404
4461
  readOnlyHint: false,
4405
4462
  idempotentHint: false,
4406
- destructiveHint: false,
4463
+ destructiveHint: true,
4407
4464
  openWorldHint: false
4408
4465
  },
4409
4466
  inputSchema: {
4410
4467
  type: "object",
4411
4468
  properties: {
4412
- id: { type: "string", format: "uuid", description: "Handoff ID" },
4413
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4414
- structured: { type: "boolean", default: false }
4469
+ repo: { type: "string", description: "Repository name (optional for single id)" },
4470
+ id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
4471
+ ids: {
4472
+ type: "array",
4473
+ items: { type: "string", format: "uuid" },
4474
+ minItems: 1,
4475
+ description: "Array of memory IDs to delete"
4476
+ },
4477
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4478
+ }
4479
+ },
4480
+ outputSchema: {
4481
+ type: "object",
4482
+ properties: {
4483
+ success: { type: "boolean" },
4484
+ id: { type: "string" },
4485
+ ids: { type: "array", items: { type: "string" } },
4486
+ repo: { type: "string" },
4487
+ deletedCount: { type: "number" }
4415
4488
  },
4416
- required: ["id", "status"]
4489
+ required: ["success"]
4490
+ }
4491
+ },
4492
+ {
4493
+ name: "standard-delete",
4494
+ title: "Standard Delete",
4495
+ description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
4496
+ annotations: {
4497
+ readOnlyHint: false,
4498
+ idempotentHint: false,
4499
+ destructiveHint: true,
4500
+ openWorldHint: false
4501
+ },
4502
+ inputSchema: {
4503
+ type: "object",
4504
+ properties: {
4505
+ repo: { type: "string", description: "Repository name (optional for single id)" },
4506
+ id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
4507
+ ids: {
4508
+ type: "array",
4509
+ items: { type: "string", format: "uuid" },
4510
+ minItems: 1,
4511
+ description: "Array of coding standard IDs to delete"
4512
+ },
4513
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4514
+ }
4417
4515
  },
4418
4516
  outputSchema: {
4419
4517
  type: "object",
4420
4518
  properties: {
4421
4519
  success: { type: "boolean" },
4422
4520
  id: { type: "string" },
4423
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] }
4521
+ ids: { type: "array", items: { type: "string" } },
4522
+ repo: { type: "string" },
4523
+ deletedCount: { type: "number" }
4424
4524
  },
4425
- required: ["success", "id", "status"]
4525
+ required: ["success"]
4426
4526
  }
4427
4527
  },
4428
4528
  {
4429
- name: "handoff-list",
4430
- title: "Handoff List",
4431
- description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
4529
+ name: "memory-recap",
4530
+ title: "Memory Recap",
4531
+ description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, code, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
4432
4532
  annotations: {
4433
4533
  readOnlyHint: true,
4434
4534
  idempotentHint: true,
@@ -4437,155 +4537,260 @@ var TOOL_DEFINITIONS = [
4437
4537
  inputSchema: {
4438
4538
  type: "object",
4439
4539
  properties: {
4440
- repo: { type: "string", description: "Repository name" },
4441
- status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4442
- from_agent: { type: "string" },
4443
- to_agent: { type: "string" },
4444
- limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4445
- offset: { type: "number", minimum: 0, default: 0 },
4446
- structured: { type: "boolean", default: false }
4540
+ repo: { type: "string", description: "Repository name (required)" },
4541
+ limit: {
4542
+ type: "number",
4543
+ minimum: 1,
4544
+ maximum: 50,
4545
+ default: 20,
4546
+ description: "Maximum number of top memories to return in the pointer table"
4547
+ },
4548
+ offset: {
4549
+ type: "number",
4550
+ minimum: 0,
4551
+ default: 0,
4552
+ description: "Number of memories to skip for pagination (optional, default 0)"
4553
+ },
4554
+ structured: {
4555
+ type: "boolean",
4556
+ default: false,
4557
+ description: "If true, returns structured JSON without the text content summary."
4558
+ }
4447
4559
  },
4448
4560
  required: ["repo"]
4449
4561
  },
4450
4562
  outputSchema: {
4451
4563
  type: "object",
4452
4564
  properties: {
4453
- schema: { type: "string", enum: ["handoff-list"] },
4454
- handoffs: {
4565
+ schema: { type: "string", enum: ["memory-recap"] },
4566
+ repo: { type: "string" },
4567
+ count: { type: "number", description: "Number of rows in the top pointer table" },
4568
+ total: { type: "number", description: "Total active memories in repo" },
4569
+ offset: { type: "number" },
4570
+ limit: { type: "number" },
4571
+ stats: {
4572
+ type: "object",
4573
+ properties: {
4574
+ byType: {
4575
+ type: "object",
4576
+ description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
4577
+ }
4578
+ },
4579
+ required: ["byType"]
4580
+ },
4581
+ top: {
4455
4582
  type: "object",
4456
4583
  properties: {
4457
4584
  columns: {
4458
4585
  type: "array",
4459
4586
  items: { type: "string" },
4460
- description: "Column names: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
4587
+ description: "Column names: [id, code, title, type, importance]"
4461
4588
  },
4462
4589
  rows: {
4463
4590
  type: "array",
4464
4591
  items: { type: "array" },
4465
- description: "Each row: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
4592
+ description: "Each row: [id, code, title, type, importance]. Fetch full content via memory-detail"
4466
4593
  }
4467
4594
  },
4468
4595
  required: ["columns", "rows"]
4469
- },
4470
- count: { type: "number" },
4471
- offset: { type: "number" }
4596
+ }
4472
4597
  },
4473
- required: ["schema", "handoffs", "count", "offset"]
4598
+ required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
4474
4599
  }
4475
4600
  },
4476
4601
  {
4477
- name: "task-claim",
4478
- title: "Task Claim",
4479
- description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
4602
+ name: "task-create",
4603
+ title: "Task Create",
4604
+ description: "Register one or more new tasks in a repository. task_code must be unique within the repository. Supports single task object or an array of tasks for bulk creation.",
4480
4605
  annotations: {
4481
4606
  readOnlyHint: false,
4482
4607
  idempotentHint: false,
4483
- destructiveHint: false,
4484
4608
  openWorldHint: false
4485
4609
  },
4486
4610
  inputSchema: {
4487
4611
  type: "object",
4488
4612
  properties: {
4489
4613
  repo: { type: "string", description: "Repository name" },
4490
- task_id: {
4614
+ task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
4615
+ phase: { type: "string", description: "Project phase (Required for single task)" },
4616
+ title: {
4491
4617
  type: "string",
4492
- format: "uuid",
4493
- description: "Task id to claim. Optional if task_code is provided."
4618
+ minLength: 3,
4619
+ maxLength: 100,
4620
+ description: "Task objective (Required for single task)"
4494
4621
  },
4495
- task_code: { type: "string", description: "Task code to claim. Optional if task_id is provided." },
4496
- agent: { type: "string", description: "Claiming agent name" },
4497
- role: { type: "string", description: "Claiming agent role" },
4498
- metadata: { type: "object", description: "Optional claim metadata" },
4499
- structured: { type: "boolean", default: false }
4622
+ description: {
4623
+ type: "string",
4624
+ description: "Detailed description. MUST follow format: 1. Context & Analysis, 2. Step & Implementation, 3. Acceptance & Verification"
4625
+ },
4626
+ status: {
4627
+ type: "string",
4628
+ enum: ["backlog", "pending"],
4629
+ default: "backlog",
4630
+ description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
4631
+ },
4632
+ priority: {
4633
+ type: "number",
4634
+ minimum: 1,
4635
+ maximum: 5,
4636
+ default: 3,
4637
+ description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4638
+ },
4639
+ agent: { type: "string" },
4640
+ role: { type: "string" },
4641
+ doc_path: { type: "string" },
4642
+ tags: { type: "array", items: { type: "string" } },
4643
+ metadata: { type: "object" },
4644
+ parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4645
+ depends_on: { type: "string", format: "uuid" },
4646
+ est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
4647
+ tasks: {
4648
+ type: "array",
4649
+ items: {
4650
+ type: "object",
4651
+ properties: {
4652
+ task_code: { type: "string" },
4653
+ phase: { type: "string" },
4654
+ title: { type: "string", minLength: 3, maxLength: 100 },
4655
+ description: {
4656
+ type: "string",
4657
+ description: "Detailed description. MUST follow format: 1. Context & Analysis, 2. Step & Implementation, 3. Acceptance & Verification"
4658
+ },
4659
+ status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
4660
+ priority: {
4661
+ type: "number",
4662
+ minimum: 1,
4663
+ maximum: 5,
4664
+ default: 3,
4665
+ description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4666
+ },
4667
+ agent: { type: "string" },
4668
+ role: { type: "string" },
4669
+ doc_path: { type: "string" },
4670
+ tags: { type: "array", items: { type: "string" } },
4671
+ metadata: { type: "object" },
4672
+ parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4673
+ depends_on: { type: "string", format: "uuid" },
4674
+ est_tokens: { type: "number", minimum: 0 }
4675
+ },
4676
+ required: ["task_code", "phase", "title", "description"]
4677
+ },
4678
+ description: "Array of tasks for bulk creation"
4679
+ },
4680
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4500
4681
  },
4501
- required: ["repo", "agent"]
4682
+ required: ["repo"]
4502
4683
  },
4503
4684
  outputSchema: {
4504
4685
  type: "object",
4505
4686
  properties: {
4687
+ success: { type: "boolean" },
4506
4688
  id: { type: "string" },
4689
+ task_code: { type: "string" },
4507
4690
  repo: { type: "string" },
4508
- task_id: { type: "string" },
4509
- task_code: { type: "string", nullable: true },
4510
- agent: { type: "string" },
4511
- role: { type: "string" },
4512
- claimed_at: { type: "string" },
4513
- released_at: { type: "string", nullable: true },
4514
- metadata: { type: "object" }
4691
+ phase: { type: "string" },
4692
+ title: { type: "string" },
4693
+ status: { type: "string" },
4694
+ priority: { type: "number" },
4695
+ createdCount: { type: "number" },
4696
+ taskCodes: { type: "array", items: { type: "string" } }
4515
4697
  },
4516
- required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
4698
+ required: ["success", "repo"]
4517
4699
  }
4518
4700
  },
4519
4701
  {
4520
- name: "claim-list",
4521
- title: "Claim List",
4522
- description: "List task claims in a repository. Use this to inspect active ownership, optionally filtered by agent.",
4702
+ name: "task-update",
4703
+ title: "Task Update",
4704
+ description: "Update one or more tasks. Supports single update via 'id' or bulk update via 'ids'. Provide only the fields that need to be changed. MANDATORY WORKFLOW: You cannot move a task from 'pending' or 'blocked' directly to 'completed'. You MUST move it to 'in_progress' first. When changing status to 'completed', include 'est_tokens' with the estimated total tokens actually used for the task.",
4523
4705
  annotations: {
4524
- readOnlyHint: true,
4525
- idempotentHint: true,
4526
- destructiveHint: false,
4706
+ readOnlyHint: false,
4707
+ idempotentHint: false,
4527
4708
  openWorldHint: false
4528
4709
  },
4529
4710
  inputSchema: {
4530
4711
  type: "object",
4531
4712
  properties: {
4532
4713
  repo: { type: "string", description: "Repository name" },
4533
- agent: { type: "string", description: "Optional agent filter" },
4534
- active_only: { type: "boolean", description: "When true, return only unreleased claims" },
4535
- limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4536
- offset: { type: "number", minimum: 0, default: 0 },
4537
- structured: { type: "boolean", default: false }
4714
+ id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
4715
+ ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
4716
+ task_code: { type: "string" },
4717
+ phase: { type: "string" },
4718
+ title: { type: "string", minLength: 3, maxLength: 100 },
4719
+ description: {
4720
+ type: "string",
4721
+ description: "Detailed description. MUST follow format: 1. Context & Analysis, 2. Step & Implementation, 3. Acceptance & Verification"
4722
+ },
4723
+ status: {
4724
+ type: "string",
4725
+ enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
4726
+ description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
4727
+ },
4728
+ priority: {
4729
+ type: "number",
4730
+ minimum: 1,
4731
+ maximum: 5,
4732
+ description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical."
4733
+ },
4734
+ agent: { type: "string" },
4735
+ role: { type: "string" },
4736
+ model: { type: "string" },
4737
+ comment: {
4738
+ type: "string",
4739
+ description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
4740
+ },
4741
+ doc_path: { type: "string" },
4742
+ tags: { type: "array", items: { type: "string" } },
4743
+ metadata: { type: "object" },
4744
+ parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
4745
+ depends_on: { type: "string", format: "uuid" },
4746
+ est_tokens: {
4747
+ type: "number",
4748
+ minimum: 0,
4749
+ description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
4750
+ },
4751
+ force: {
4752
+ type: "boolean",
4753
+ description: "If true, bypasses status transition validation (e.g. pending -> completed)."
4754
+ },
4755
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4538
4756
  },
4539
4757
  required: ["repo"]
4540
4758
  },
4541
4759
  outputSchema: {
4542
4760
  type: "object",
4543
4761
  properties: {
4544
- schema: { type: "string", enum: ["claim-list"] },
4545
- claims: {
4546
- type: "object",
4547
- properties: {
4548
- columns: {
4549
- type: "array",
4550
- items: { type: "string" },
4551
- description: "Column names: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
4552
- },
4553
- rows: {
4554
- type: "array",
4555
- items: { type: "array" },
4556
- description: "Each row: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
4557
- }
4558
- },
4559
- required: ["columns", "rows"]
4762
+ success: { type: "boolean" },
4763
+ id: { type: "string" },
4764
+ ids: { type: "array", items: { type: "string" } },
4765
+ repo: { type: "string" },
4766
+ status: { type: "string" },
4767
+ archivedToMemory: { type: "boolean" },
4768
+ updatedFields: {
4769
+ type: "array",
4770
+ items: { type: "string" }
4560
4771
  },
4561
- count: { type: "number" },
4562
- offset: { type: "number" }
4772
+ updatedCount: { type: "number" }
4563
4773
  },
4564
- required: ["schema", "claims", "count", "offset"]
4774
+ required: ["success", "repo"]
4565
4775
  }
4566
4776
  },
4567
4777
  {
4568
- name: "claim-release",
4569
- title: "Claim Release",
4570
- description: "Release an active claim for a task. Optionally restrict the release to a specific agent.",
4778
+ name: "task-delete",
4779
+ title: "Task Delete",
4780
+ description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
4571
4781
  annotations: {
4572
4782
  readOnlyHint: false,
4573
4783
  idempotentHint: false,
4574
- destructiveHint: false,
4784
+ destructiveHint: true,
4575
4785
  openWorldHint: false
4576
4786
  },
4577
4787
  inputSchema: {
4578
4788
  type: "object",
4579
4789
  properties: {
4580
4790
  repo: { type: "string", description: "Repository name" },
4581
- task_id: {
4582
- type: "string",
4583
- format: "uuid",
4584
- description: "Task id to release. Optional if task_code is provided."
4585
- },
4586
- task_code: { type: "string", description: "Task code to release. Optional if task_id is provided." },
4587
- agent: { type: "string", description: "Optional agent name to release only that claim" },
4588
- structured: { type: "boolean", default: false }
4791
+ id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
4792
+ ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
4793
+ structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4589
4794
  },
4590
4795
  required: ["repo"]
4591
4796
  },
@@ -4593,116 +4798,94 @@ var TOOL_DEFINITIONS = [
4593
4798
  type: "object",
4594
4799
  properties: {
4595
4800
  success: { type: "boolean" },
4801
+ id: { type: "string" },
4802
+ ids: { type: "array", items: { type: "string" } },
4596
4803
  repo: { type: "string" },
4597
- task_id: { type: "string" },
4598
- task_code: { type: "string", nullable: true },
4599
- agent: { type: "string", nullable: true }
4804
+ deletedCount: { type: "number" }
4600
4805
  },
4601
- required: ["success", "repo", "task_id"]
4806
+ required: ["success", "repo"]
4602
4807
  }
4603
4808
  },
4604
4809
  {
4605
- name: "standard-store",
4606
- title: "Standard Store",
4607
- description: "Store one atomic coding standard. Use for durable implementation rules with explicit context, stack/language filters, and repo/global scope.",
4810
+ name: "task-list",
4811
+ title: "Task List",
4812
+ description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority, updated_at, comments_count). Defaults to in_progress and pending tasks. Use 'query' to filter by code, title, or description. Use 'status' (comma-separated) for specific filters. AGENTS: call this once at start, pick ONE task, then call task-detail.",
4608
4813
  annotations: {
4609
- readOnlyHint: false,
4610
- idempotentHint: false,
4611
- destructiveHint: false,
4814
+ readOnlyHint: true,
4815
+ idempotentHint: true,
4612
4816
  openWorldHint: false
4613
4817
  },
4614
4818
  inputSchema: {
4615
4819
  type: "object",
4616
4820
  properties: {
4617
- name: { type: "string", minLength: 3, maxLength: 255, description: "Human-readable standard name" },
4618
- content: {
4821
+ repo: {
4619
4822
  type: "string",
4620
- minLength: 10,
4621
- description: "One atomic, actionable standard written as concise Markdown"
4823
+ description: "Repository name (required)"
4622
4824
  },
4623
- parent_id: {
4825
+ status: {
4624
4826
  type: "string",
4625
- format: "uuid",
4626
- description: "Optional parent standard ID when this rule is a child/specialization."
4827
+ default: "in_progress,pending",
4828
+ description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
4627
4829
  },
4628
- context: { type: "string", description: "Context or category (e.g., 'error-handling', 'security')" },
4629
- version: { type: "string", description: "Version of the standard (e.g., '1.0.0')" },
4630
- language: { type: "string", description: "Programming language (e.g., 'typescript', 'python')" },
4631
- stack: {
4632
- type: "array",
4633
- items: { type: "string" },
4634
- description: "Technology stack (e.g., ['react', 'nextjs'])"
4830
+ phase: {
4831
+ type: "string",
4832
+ description: "Filter by phase (e.g., 'research', 'implementation')"
4635
4833
  },
4636
- repo: {
4834
+ query: {
4637
4835
  type: "string",
4638
- description: "Repository name for repo-specific standards. Omit only for global standards."
4836
+ description: "Search keyword matching task code, title, or description"
4639
4837
  },
4640
- is_global: { type: "boolean", description: "Whether standard applies globally or repo-specific" },
4641
- tags: {
4642
- type: "array",
4643
- items: { type: "string" },
4644
- description: "Tags for categorization"
4838
+ limit: {
4839
+ type: "number",
4840
+ minimum: 1,
4841
+ maximum: 100,
4842
+ default: 5,
4843
+ description: "Maximum rows to return (default 5)"
4645
4844
  },
4646
- metadata: {
4647
- type: "object",
4648
- description: "Additional metadata"
4845
+ offset: {
4846
+ type: "number",
4847
+ minimum: 0,
4848
+ default: 0,
4849
+ description: "Offset for pagination"
4649
4850
  },
4650
- agent: { type: "string", description: "Agent creating the standard" },
4651
- model: { type: "string", description: "AI model used" },
4652
- structured: { type: "boolean", default: false }
4851
+ structured: {
4852
+ type: "boolean",
4853
+ default: false,
4854
+ description: "If true, returns structured JSON without the text content summary."
4855
+ }
4653
4856
  },
4654
- required: ["name", "content", "tags", "metadata"]
4857
+ required: ["repo"]
4655
4858
  },
4656
4859
  outputSchema: {
4657
4860
  type: "object",
4658
4861
  properties: {
4659
- success: { type: "boolean" },
4660
- standard: {
4862
+ schema: { type: "string", enum: ["task-list"] },
4863
+ tasks: {
4661
4864
  type: "object",
4662
4865
  properties: {
4663
- id: { type: "string" },
4664
- title: { type: "string" },
4665
- content: { type: "string" },
4666
- parent_id: { type: "string", nullable: true },
4667
- context: { type: "string" },
4668
- version: { type: "string" },
4669
- language: { type: "string", nullable: true },
4670
- stack: { type: "array", items: { type: "string" } },
4671
- is_global: { type: "boolean" },
4672
- repo: { type: "string", nullable: true },
4673
- tags: { type: "array", items: { type: "string" } },
4674
- metadata: { type: "object" },
4675
- created_at: { type: "string" },
4676
- updated_at: { type: "string" },
4677
- agent: { type: "string" },
4678
- model: { type: "string" }
4866
+ columns: {
4867
+ type: "array",
4868
+ items: { type: "string" },
4869
+ description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
4870
+ },
4871
+ rows: {
4872
+ type: "array",
4873
+ items: { type: "array" },
4874
+ description: "Each row: [id, task_code, title, status, priority, updated_at, comments_count]. Use task-detail to fetch full task."
4875
+ }
4679
4876
  },
4680
- required: [
4681
- "id",
4682
- "title",
4683
- "content",
4684
- "parent_id",
4685
- "context",
4686
- "version",
4687
- "stack",
4688
- "is_global",
4689
- "tags",
4690
- "metadata",
4691
- "created_at",
4692
- "updated_at",
4693
- "agent",
4694
- "model"
4695
- ]
4877
+ required: ["columns", "rows"]
4696
4878
  },
4697
- message: { type: "string" }
4879
+ count: { type: "number" },
4880
+ offset: { type: "number" }
4698
4881
  },
4699
- required: ["success", "standard", "message"]
4882
+ required: ["schema", "tasks", "count"]
4700
4883
  }
4701
4884
  },
4702
- {
4703
- name: "standard-update",
4704
- title: "Standard Update",
4705
- description: "Update an existing coding standard. Use this when the rule changes, expands scope, or metadata/tags need correction.",
4885
+ {
4886
+ name: "handoff-create",
4887
+ title: "Handoff Create",
4888
+ description: "Create a pending handoff only when unfinished work needs context transfer between agents. Do not use this for completed-work summaries, release notes, validation notes, or archives; put those on task-update/task comments or durable memory.",
4706
4889
  annotations: {
4707
4890
  readOnlyHint: false,
4708
4891
  idempotentHint: false,
@@ -4712,616 +4895,446 @@ var TOOL_DEFINITIONS = [
4712
4895
  inputSchema: {
4713
4896
  type: "object",
4714
4897
  properties: {
4715
- id: { type: "string", description: "Standard ID to update" },
4716
- name: { type: "string", minLength: 3, maxLength: 255 },
4717
- content: { type: "string", minLength: 10 },
4718
- parent_id: { type: "string", format: "uuid", nullable: true },
4719
- context: { type: "string" },
4720
- version: { type: "string" },
4721
- language: { type: "string" },
4722
- stack: { type: "array", items: { type: "string" } },
4723
- repo: { type: "string" },
4724
- is_global: { type: "boolean" },
4725
- tags: { type: "array", items: { type: "string" } },
4726
- metadata: { type: "object" },
4727
- agent: { type: "string" },
4728
- model: { type: "string" },
4898
+ repo: { type: "string", description: "Repository name" },
4899
+ from_agent: { type: "string", description: "Agent creating the handoff" },
4900
+ to_agent: { type: "string", description: "Optional target agent" },
4901
+ task_id: { type: "string", format: "uuid", description: "Optional task id to associate" },
4902
+ task_code: { type: "string", description: "Optional task code to associate" },
4903
+ summary: { type: "string", minLength: 1, description: "Concise human-readable transfer summary" },
4904
+ context: {
4905
+ type: "object",
4906
+ description: "Structured handoff context. Include next_steps, blockers, or remaining_work unless a target agent or task is provided."
4907
+ },
4908
+ expires_at: { type: "string", description: "Optional expiration timestamp" },
4729
4909
  structured: { type: "boolean", default: false }
4730
4910
  },
4731
- required: ["id"]
4911
+ required: ["repo", "from_agent", "summary"]
4732
4912
  },
4733
4913
  outputSchema: {
4734
4914
  type: "object",
4735
4915
  properties: {
4736
- success: { type: "boolean" },
4737
4916
  id: { type: "string" },
4738
- updatedFields: { type: "array", items: { type: "string" } }
4917
+ repo: { type: "string" },
4918
+ from_agent: { type: "string" },
4919
+ to_agent: { type: "string", nullable: true },
4920
+ task_id: { type: "string", nullable: true },
4921
+ summary: { type: "string" },
4922
+ context: { type: "object" },
4923
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4924
+ created_at: { type: "string" },
4925
+ updated_at: { type: "string" },
4926
+ expires_at: { type: "string", nullable: true }
4739
4927
  },
4740
- required: ["success", "id", "updatedFields"]
4928
+ required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
4741
4929
  }
4742
4930
  },
4743
4931
  {
4744
- name: "standard-search",
4745
- title: "Standard Search",
4746
- description: "MANDATORY PRE-IMPLEMENTATION CHECK: Call before any code edit, test edit, refactor, migration, or implementation decision to find applicable coding standards. Returns a compact pointer table; use `standard-detail` for relevant results. If no relevant standards are returned, continue and state that no applicable standards were found.",
4932
+ name: "handoff-update",
4933
+ title: "Handoff Update",
4934
+ description: "Close or reclassify a handoff after it has been consumed or found stale. Use accepted when transfer context was consumed, rejected when intentionally declined, and expired when the handoff is obsolete or only described completed work.",
4747
4935
  annotations: {
4748
- readOnlyHint: true,
4749
- idempotentHint: true,
4936
+ readOnlyHint: false,
4937
+ idempotentHint: false,
4938
+ destructiveHint: false,
4750
4939
  openWorldHint: false
4751
4940
  },
4752
4941
  inputSchema: {
4753
4942
  type: "object",
4754
4943
  properties: {
4755
- query: { type: "string", description: "Search query (optional, searches title/content)" },
4756
- stack: {
4757
- type: "array",
4758
- items: { type: "string" },
4759
- description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
4760
- },
4761
- tags: {
4762
- type: "array",
4763
- items: { type: "string" },
4764
- description: "Tag filter"
4765
- },
4766
- language: { type: "string", description: "Programming language filter" },
4767
- context: { type: "string", description: "Context/category filter" },
4768
- version: { type: "string", description: "Version filter" },
4769
- repo: { type: "string", description: "Repository filter (optional)" },
4770
- is_global: { type: "boolean", description: "Filter by global/repo-specific" },
4771
- limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4772
- offset: { type: "number", minimum: 0, default: 0 },
4944
+ id: { type: "string", format: "uuid", description: "Handoff ID" },
4945
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4773
4946
  structured: { type: "boolean", default: false }
4774
4947
  },
4775
- required: []
4948
+ required: ["id", "status"]
4776
4949
  },
4777
4950
  outputSchema: {
4778
4951
  type: "object",
4779
4952
  properties: {
4780
- schema: { type: "string", enum: ["standard-search"] },
4781
- query: { type: "string" },
4782
- count: { type: "number", description: "Number of rows returned" },
4783
- total: { type: "number", description: "Total number of matches before pagination" },
4784
- offset: { type: "number" },
4785
- limit: { type: "number" },
4786
- results: {
4787
- type: "object",
4788
- properties: {
4789
- columns: {
4790
- type: "array",
4791
- items: { type: "string" }
4792
- },
4793
- rows: {
4794
- type: "array",
4795
- items: { type: "array" },
4796
- description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
4797
- }
4798
- },
4799
- required: ["columns", "rows"]
4800
- }
4953
+ success: { type: "boolean" },
4954
+ id: { type: "string" },
4955
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] }
4801
4956
  },
4802
- required: ["schema", "query", "count", "total", "offset", "limit", "results"]
4803
- }
4804
- }
4805
- ];
4806
-
4807
- // src/mcp/utils/pagination.ts
4808
- function encodeCursor(offset) {
4809
- return Buffer.from(String(offset), "utf8").toString("base64");
4810
- }
4811
- function decodeCursor(cursor) {
4812
- if (cursor === void 0 || cursor === null || cursor === "") {
4813
- return 0;
4814
- }
4815
- if (typeof cursor !== "string" || cursor.trim() === "") {
4816
- throw invalidPaginationParams("Invalid cursor");
4817
- }
4818
- let decoded;
4819
- try {
4820
- decoded = Buffer.from(cursor, "base64").toString("utf8");
4821
- } catch {
4822
- throw invalidPaginationParams("Invalid cursor");
4823
- }
4824
- if (!/^\d+$/.test(decoded)) {
4825
- throw invalidPaginationParams("Invalid cursor");
4826
- }
4827
- const offset = Number.parseInt(decoded, 10);
4828
- if (!Number.isFinite(offset) || offset < 0) {
4829
- throw invalidPaginationParams("Invalid cursor");
4830
- }
4831
- return offset;
4832
- }
4833
- function invalidPaginationParams(message) {
4834
- const error = new Error(message);
4835
- error.code = -32602;
4836
- return error;
4837
- }
4838
-
4839
- // src/mcp/utils/completion.ts
4840
- var MAX_COMPLETION_VALUES = 100;
4841
- function rankCompletionValues(candidates, input) {
4842
- const unique = [...new Set(candidates.filter(Boolean))];
4843
- const needle = input.trim().toLowerCase();
4844
- if (!needle) {
4845
- return unique.slice(0, MAX_COMPLETION_VALUES);
4846
- }
4847
- 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);
4848
- }
4849
- function scoreCompletionValue(value, needle) {
4850
- const haystack = value.toLowerCase();
4851
- if (haystack === needle) return 100;
4852
- if (haystack.startsWith(needle)) return 75;
4853
- if (haystack.includes(needle)) return 50;
4854
- const compactNeedle = needle.replace(/[\s_-]+/g, "");
4855
- const compactHaystack = haystack.replace(/[\s_-]+/g, "");
4856
- if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
4857
- return 0;
4858
- }
4859
-
4860
- // src/mcp/resources/index.ts
4861
- var DEFAULT_PAGE_SIZE = 25;
4862
- var MAX_PAGE_SIZE = 100;
4863
- function listResources(session, params) {
4864
- const resources = [
4865
- {
4866
- uri: "repository://index",
4867
- name: "Repository Index",
4868
- title: "Repository Index",
4869
- description: "List of all known repositories with memory/task counts and last activity",
4870
- mimeType: "application/json",
4871
- annotations: {
4872
- audience: ["assistant"],
4873
- priority: 1,
4874
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4875
- }
4876
- },
4877
- {
4878
- uri: "session://roots",
4879
- name: "Session Roots",
4880
- title: "Session Roots",
4881
- description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
4882
- mimeType: "application/json",
4883
- size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
4884
- annotations: {
4885
- audience: ["assistant"],
4886
- priority: 0.95,
4887
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
4888
- }
4957
+ required: ["success", "id", "status"]
4889
4958
  }
4890
- ];
4891
- return paginateEntries("resources", resources, params);
4892
- }
4893
- function listResourceTemplates(params) {
4894
- const templates = [
4895
- // ── Memory ──────────────────────────────────────────────────────────────
4896
- {
4897
- uriTemplate: "repository://{name}/memories",
4898
- name: "Repository Memories",
4899
- title: "Repository Memories",
4900
- description: "All active memory entries for a specific repository",
4901
- mimeType: "application/json",
4902
- annotations: { audience: ["assistant"], priority: 0.85 }
4903
- },
4904
- {
4905
- uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
4906
- name: "Filtered Repository Memories",
4907
- title: "Filtered Repository Memories",
4908
- description: "Filter or search memories within a repository by keyword, type, or tag",
4909
- mimeType: "application/json",
4910
- annotations: { audience: ["assistant"], priority: 0.8 }
4911
- },
4912
- {
4913
- uriTemplate: "memory://{id}",
4914
- name: "Memory Detail",
4915
- title: "Memory Detail",
4916
- description: "Full content and statistics for a specific memory UUID",
4917
- mimeType: "application/json",
4918
- annotations: { audience: ["assistant"], priority: 0.75 }
4919
- },
4920
- // ── Tasks ────────────────────────────────────────────────────────────────
4921
- {
4922
- uriTemplate: "repository://{name}/tasks",
4923
- name: "Repository Tasks",
4924
- title: "Repository Tasks",
4925
- description: "All active tasks for a specific repository",
4926
- mimeType: "application/json",
4927
- annotations: { audience: ["assistant"], priority: 0.9 }
4928
- },
4929
- {
4930
- uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
4931
- name: "Filtered Repository Tasks",
4932
- title: "Filtered Repository Tasks",
4933
- description: "Filter tasks within a repository by status or priority level",
4934
- mimeType: "application/json",
4935
- annotations: { audience: ["assistant"], priority: 0.85 }
4936
- },
4937
- {
4938
- uriTemplate: "task://{id}",
4939
- name: "Task Detail",
4940
- title: "Task Detail",
4941
- description: "Full content and comments for a specific task UUID",
4942
- mimeType: "application/json",
4943
- annotations: { audience: ["assistant"], priority: 0.8 }
4944
- },
4945
- // ── Repository extras ────────────────────────────────────────────────────
4946
- {
4947
- uriTemplate: "repository://{name}/summary",
4948
- name: "Repository Summary",
4949
- title: "Repository Summary",
4950
- description: "High-level architectural summary for a repository",
4951
- mimeType: "text/plain",
4952
- annotations: { audience: ["assistant"], priority: 0.95 }
4959
+ },
4960
+ {
4961
+ name: "handoff-list",
4962
+ title: "Handoff List",
4963
+ description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
4964
+ annotations: {
4965
+ readOnlyHint: true,
4966
+ idempotentHint: true,
4967
+ openWorldHint: false
4953
4968
  },
4954
- {
4955
- uriTemplate: "repository://{name}/actions",
4956
- name: "Repository Actions",
4957
- title: "Repository Actions",
4958
- description: "Audit log of agent tool actions scoped to a repository",
4959
- mimeType: "application/json",
4960
- annotations: { audience: ["assistant"], priority: 0.6 }
4969
+ inputSchema: {
4970
+ type: "object",
4971
+ properties: {
4972
+ repo: { type: "string", description: "Repository name" },
4973
+ status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
4974
+ from_agent: { type: "string" },
4975
+ to_agent: { type: "string" },
4976
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4977
+ offset: { type: "number", minimum: 0, default: 0 },
4978
+ structured: { type: "boolean", default: false }
4979
+ },
4980
+ required: ["repo"]
4961
4981
  },
4962
- // ── Action detail ────────────────────────────────────────────────────────
4963
- {
4964
- uriTemplate: "action://{id}",
4965
- name: "Action Detail",
4966
- title: "Action Detail",
4967
- description: "Full details of a specific audit log entry by integer ID",
4968
- mimeType: "application/json",
4969
- annotations: { audience: ["assistant"], priority: 0.55 }
4970
- }
4971
- ];
4972
- return paginateEntries("resourceTemplates", templates, params);
4973
- }
4974
- function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
4975
- 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") {
4976
- if (argumentName === "name") {
4977
- return rankCompletionValues(dataSources.repos, argumentValue);
4978
- }
4979
- }
4980
- if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
4981
- if (argumentName === "tag") {
4982
- return rankCompletionValues(dataSources.tags, argumentValue);
4983
- }
4984
- }
4985
- throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
4986
- }
4987
- function readResource(uri, db, session) {
4988
- logger.info("[Tool] resource.read", { uri });
4989
- if (uri === "repository://index") {
4990
- const repos = db.system.listRepoNavigation();
4991
- const payload = JSON.stringify(repos, null, 2);
4992
- return {
4993
- contents: [
4994
- {
4995
- uri,
4996
- mimeType: "application/json",
4997
- text: payload,
4998
- size: Buffer.byteLength(payload, "utf8"),
4999
- annotations: {
5000
- audience: ["assistant"],
5001
- priority: 1,
5002
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5003
- }
5004
- }
5005
- ]
5006
- };
5007
- }
5008
- if (uri === "session://roots") {
5009
- const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
5010
- return {
5011
- contents: [
5012
- {
5013
- uri,
5014
- mimeType: "application/json",
5015
- text: payload,
5016
- size: Buffer.byteLength(payload, "utf8"),
5017
- annotations: {
5018
- audience: ["assistant"],
5019
- priority: 0.95,
5020
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
5021
- }
5022
- }
5023
- ]
5024
- };
5025
- }
5026
- const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
5027
- if (memoryIdMatch) {
5028
- const id = memoryIdMatch[1];
5029
- const entry = db.memories.getByIdWithStats(id);
5030
- if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
5031
- const payload = JSON.stringify(entry, null, 2);
5032
- return {
5033
- contents: [
5034
- {
5035
- uri,
5036
- mimeType: "application/json",
5037
- text: payload,
5038
- size: Buffer.byteLength(payload, "utf8"),
5039
- annotations: {
5040
- audience: ["assistant"],
5041
- priority: 0.75,
5042
- lastModified: entry.updated_at || entry.created_at
5043
- }
5044
- }
5045
- ]
5046
- };
5047
- }
5048
- const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
5049
- if (taskIdMatch) {
5050
- const id = taskIdMatch[1];
5051
- const task = db.tasks.getTaskById(id);
5052
- if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
5053
- const payload = JSON.stringify(task, null, 2);
5054
- return {
5055
- contents: [
5056
- {
5057
- uri,
5058
- mimeType: "application/json",
5059
- text: payload,
5060
- size: Buffer.byteLength(payload, "utf8"),
5061
- annotations: {
5062
- audience: ["assistant"],
5063
- priority: 0.8,
5064
- lastModified: task.updated_at || task.created_at
5065
- }
5066
- }
5067
- ]
5068
- };
5069
- }
5070
- const repoBase = parseRepoUri(uri);
5071
- if (repoBase) {
5072
- const { name, path: repoPath, query } = repoBase;
5073
- if (repoPath === "summary") {
5074
- const summary = db.summaries.getSummary(name);
5075
- const text = summary?.summary || `No summary available for repository: ${name}`;
5076
- return {
5077
- contents: [
5078
- {
5079
- uri,
5080
- mimeType: "text/plain",
5081
- text,
5082
- size: Buffer.byteLength(text, "utf8"),
5083
- annotations: {
5084
- audience: ["assistant"],
5085
- priority: 0.95,
5086
- lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
4982
+ outputSchema: {
4983
+ type: "object",
4984
+ properties: {
4985
+ schema: { type: "string", enum: ["handoff-list"] },
4986
+ handoffs: {
4987
+ type: "object",
4988
+ properties: {
4989
+ columns: {
4990
+ type: "array",
4991
+ items: { type: "string" },
4992
+ description: "Column names: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
4993
+ },
4994
+ rows: {
4995
+ type: "array",
4996
+ items: { type: "array" },
4997
+ description: "Each row: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
5087
4998
  }
5088
- }
5089
- ]
5090
- };
4999
+ },
5000
+ required: ["columns", "rows"]
5001
+ },
5002
+ count: { type: "number" },
5003
+ offset: { type: "number" }
5004
+ },
5005
+ required: ["schema", "handoffs", "count", "offset"]
5091
5006
  }
5092
- if (repoPath === "memories") {
5093
- const search = query.get("search") || "";
5094
- const type = query.get("type");
5095
- const tag = query.get("tag");
5096
- const result = db.memories.listMemoriesForDashboard({
5097
- repo: name,
5098
- type: type || void 0,
5099
- tag: tag || void 0,
5100
- search: search || void 0,
5101
- limit: 50
5102
- });
5103
- const entries = result.items;
5104
- const payload = JSON.stringify(entries, null, 2);
5105
- return {
5106
- contents: [
5107
- {
5108
- uri,
5109
- mimeType: "application/json",
5110
- text: payload,
5111
- size: Buffer.byteLength(payload, "utf8"),
5112
- annotations: {
5113
- audience: ["assistant"],
5114
- priority: 0.85,
5115
- lastModified: deriveLastModifiedFromCollection(
5116
- entries.map((e) => e.updated_at || e.created_at)
5117
- )
5007
+ },
5008
+ {
5009
+ name: "task-claim",
5010
+ title: "Task Claim",
5011
+ description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
5012
+ annotations: {
5013
+ readOnlyHint: false,
5014
+ idempotentHint: false,
5015
+ destructiveHint: false,
5016
+ openWorldHint: false
5017
+ },
5018
+ inputSchema: {
5019
+ type: "object",
5020
+ properties: {
5021
+ repo: { type: "string", description: "Repository name" },
5022
+ task_id: {
5023
+ type: "string",
5024
+ format: "uuid",
5025
+ description: "Task id to claim. Optional if task_code is provided."
5026
+ },
5027
+ task_code: { type: "string", description: "Task code to claim. Optional if task_id is provided." },
5028
+ agent: { type: "string", description: "Claiming agent name" },
5029
+ role: { type: "string", description: "Claiming agent role" },
5030
+ metadata: { type: "object", description: "Optional claim metadata" },
5031
+ structured: { type: "boolean", default: false }
5032
+ },
5033
+ required: ["repo", "agent"]
5034
+ },
5035
+ outputSchema: {
5036
+ type: "object",
5037
+ properties: {
5038
+ id: { type: "string" },
5039
+ repo: { type: "string" },
5040
+ task_id: { type: "string" },
5041
+ task_code: { type: "string", nullable: true },
5042
+ agent: { type: "string" },
5043
+ role: { type: "string" },
5044
+ claimed_at: { type: "string" },
5045
+ released_at: { type: "string", nullable: true },
5046
+ metadata: { type: "object" }
5047
+ },
5048
+ required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
5049
+ }
5050
+ },
5051
+ {
5052
+ name: "claim-list",
5053
+ title: "Claim List",
5054
+ description: "List task claims in a repository. Use this to inspect active ownership, optionally filtered by agent.",
5055
+ annotations: {
5056
+ readOnlyHint: true,
5057
+ idempotentHint: true,
5058
+ destructiveHint: false,
5059
+ openWorldHint: false
5060
+ },
5061
+ inputSchema: {
5062
+ type: "object",
5063
+ properties: {
5064
+ repo: { type: "string", description: "Repository name" },
5065
+ agent: { type: "string", description: "Optional agent filter" },
5066
+ active_only: { type: "boolean", description: "When true, return only unreleased claims" },
5067
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
5068
+ offset: { type: "number", minimum: 0, default: 0 },
5069
+ structured: { type: "boolean", default: false }
5070
+ },
5071
+ required: ["repo"]
5072
+ },
5073
+ outputSchema: {
5074
+ type: "object",
5075
+ properties: {
5076
+ schema: { type: "string", enum: ["claim-list"] },
5077
+ claims: {
5078
+ type: "object",
5079
+ properties: {
5080
+ columns: {
5081
+ type: "array",
5082
+ items: { type: "string" },
5083
+ description: "Column names: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
5084
+ },
5085
+ rows: {
5086
+ type: "array",
5087
+ items: { type: "array" },
5088
+ description: "Each row: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
5118
5089
  }
5119
- }
5120
- ]
5121
- };
5090
+ },
5091
+ required: ["columns", "rows"]
5092
+ },
5093
+ count: { type: "number" },
5094
+ offset: { type: "number" }
5095
+ },
5096
+ required: ["schema", "claims", "count", "offset"]
5122
5097
  }
5123
- if (repoPath === "tasks") {
5124
- const status = query.get("status");
5125
- const priority = query.get("priority");
5126
- let tasks;
5127
- if (status && status !== "all") {
5128
- const statuses = status.split(",").map((s) => s.trim());
5129
- tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
5130
- } else {
5131
- tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
5132
- }
5133
- if (priority) {
5134
- const p = Number(priority);
5135
- if (!isNaN(p)) {
5136
- tasks = tasks.filter((t) => t.priority === p);
5137
- }
5138
- }
5139
- const payload = JSON.stringify(tasks, null, 2);
5140
- return {
5141
- contents: [
5142
- {
5143
- uri,
5144
- mimeType: "application/json",
5145
- text: payload,
5146
- size: Buffer.byteLength(payload, "utf8"),
5147
- annotations: {
5148
- audience: ["assistant"],
5149
- priority: 0.9,
5150
- lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
5151
- }
5152
- }
5153
- ]
5154
- };
5098
+ },
5099
+ {
5100
+ name: "claim-release",
5101
+ title: "Claim Release",
5102
+ description: "Release an active claim for a task. Optionally restrict the release to a specific agent.",
5103
+ annotations: {
5104
+ readOnlyHint: false,
5105
+ idempotentHint: false,
5106
+ destructiveHint: false,
5107
+ openWorldHint: false
5108
+ },
5109
+ inputSchema: {
5110
+ type: "object",
5111
+ properties: {
5112
+ repo: { type: "string", description: "Repository name" },
5113
+ task_id: {
5114
+ type: "string",
5115
+ format: "uuid",
5116
+ description: "Task id to release. Optional if task_code is provided."
5117
+ },
5118
+ task_code: { type: "string", description: "Task code to release. Optional if task_id is provided." },
5119
+ agent: { type: "string", description: "Optional agent name to release only that claim" },
5120
+ structured: { type: "boolean", default: false }
5121
+ },
5122
+ required: ["repo"]
5123
+ },
5124
+ outputSchema: {
5125
+ type: "object",
5126
+ properties: {
5127
+ success: { type: "boolean" },
5128
+ repo: { type: "string" },
5129
+ task_id: { type: "string" },
5130
+ task_code: { type: "string", nullable: true },
5131
+ agent: { type: "string", nullable: true }
5132
+ },
5133
+ required: ["success", "repo", "task_id"]
5155
5134
  }
5156
- if (repoPath === "actions") {
5157
- const actions = db.actions.getRecentActions(name, 100);
5158
- const payload = JSON.stringify(actions, null, 2);
5159
- return {
5160
- contents: [
5161
- {
5162
- uri,
5163
- mimeType: "application/json",
5164
- text: payload,
5165
- size: Buffer.byteLength(payload, "utf8"),
5166
- annotations: {
5167
- audience: ["assistant"],
5168
- priority: 0.6,
5169
- lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
5170
- }
5171
- }
5172
- ]
5173
- };
5135
+ },
5136
+ {
5137
+ name: "standard-store",
5138
+ title: "Standard Store",
5139
+ description: "Store one atomic coding standard. Use for durable implementation rules with explicit context, stack/language filters, and repo/global scope.",
5140
+ annotations: {
5141
+ readOnlyHint: false,
5142
+ idempotentHint: false,
5143
+ destructiveHint: false,
5144
+ openWorldHint: false
5145
+ },
5146
+ inputSchema: {
5147
+ type: "object",
5148
+ properties: {
5149
+ name: { type: "string", minLength: 3, maxLength: 255, description: "Human-readable standard name" },
5150
+ content: {
5151
+ type: "string",
5152
+ minLength: 10,
5153
+ description: "One atomic, actionable standard written as concise Markdown"
5154
+ },
5155
+ parent_id: {
5156
+ type: "string",
5157
+ format: "uuid",
5158
+ description: "Optional parent standard ID when this rule is a child/specialization."
5159
+ },
5160
+ context: { type: "string", description: "Context or category (e.g., 'error-handling', 'security')" },
5161
+ version: { type: "string", description: "Version of the standard (e.g., '1.0.0')" },
5162
+ language: { type: "string", description: "Programming language (e.g., 'typescript', 'python')" },
5163
+ stack: {
5164
+ type: "array",
5165
+ items: { type: "string" },
5166
+ description: "Technology stack (e.g., ['react', 'nextjs'])"
5167
+ },
5168
+ repo: {
5169
+ type: "string",
5170
+ description: "Repository name for repo-specific standards. Omit only for global standards."
5171
+ },
5172
+ is_global: { type: "boolean", description: "Whether standard applies globally or repo-specific" },
5173
+ tags: {
5174
+ type: "array",
5175
+ items: { type: "string" },
5176
+ description: "Tags for categorization"
5177
+ },
5178
+ metadata: {
5179
+ type: "object",
5180
+ description: "Additional metadata"
5181
+ },
5182
+ agent: { type: "string", description: "Agent creating the standard" },
5183
+ model: { type: "string", description: "AI model used" },
5184
+ structured: { type: "boolean", default: false }
5185
+ },
5186
+ required: ["name", "content", "tags", "metadata"]
5187
+ },
5188
+ outputSchema: {
5189
+ type: "object",
5190
+ properties: {
5191
+ success: { type: "boolean" },
5192
+ standard: {
5193
+ type: "object",
5194
+ properties: {
5195
+ id: { type: "string" },
5196
+ title: { type: "string" },
5197
+ content: { type: "string" },
5198
+ parent_id: { type: "string", nullable: true },
5199
+ context: { type: "string" },
5200
+ version: { type: "string" },
5201
+ language: { type: "string", nullable: true },
5202
+ stack: { type: "array", items: { type: "string" } },
5203
+ is_global: { type: "boolean" },
5204
+ repo: { type: "string", nullable: true },
5205
+ tags: { type: "array", items: { type: "string" } },
5206
+ metadata: { type: "object" },
5207
+ created_at: { type: "string" },
5208
+ updated_at: { type: "string" },
5209
+ agent: { type: "string" },
5210
+ model: { type: "string" }
5211
+ },
5212
+ required: [
5213
+ "id",
5214
+ "title",
5215
+ "content",
5216
+ "parent_id",
5217
+ "context",
5218
+ "version",
5219
+ "stack",
5220
+ "is_global",
5221
+ "tags",
5222
+ "metadata",
5223
+ "created_at",
5224
+ "updated_at",
5225
+ "agent",
5226
+ "model"
5227
+ ]
5228
+ },
5229
+ message: { type: "string" }
5230
+ },
5231
+ required: ["success", "standard", "message"]
5232
+ }
5233
+ },
5234
+ {
5235
+ name: "standard-update",
5236
+ title: "Standard Update",
5237
+ description: "Update an existing coding standard. Use this when the rule changes, expands scope, or metadata/tags need correction.",
5238
+ annotations: {
5239
+ readOnlyHint: false,
5240
+ idempotentHint: false,
5241
+ destructiveHint: false,
5242
+ openWorldHint: false
5243
+ },
5244
+ inputSchema: {
5245
+ type: "object",
5246
+ properties: {
5247
+ id: { type: "string", description: "Standard ID to update" },
5248
+ name: { type: "string", minLength: 3, maxLength: 255 },
5249
+ content: { type: "string", minLength: 10 },
5250
+ parent_id: { type: "string", format: "uuid", nullable: true },
5251
+ context: { type: "string" },
5252
+ version: { type: "string" },
5253
+ language: { type: "string" },
5254
+ stack: { type: "array", items: { type: "string" } },
5255
+ repo: { type: "string" },
5256
+ is_global: { type: "boolean" },
5257
+ tags: { type: "array", items: { type: "string" } },
5258
+ metadata: { type: "object" },
5259
+ agent: { type: "string" },
5260
+ model: { type: "string" },
5261
+ structured: { type: "boolean", default: false }
5262
+ },
5263
+ required: ["id"]
5264
+ },
5265
+ outputSchema: {
5266
+ type: "object",
5267
+ properties: {
5268
+ success: { type: "boolean" },
5269
+ id: { type: "string" },
5270
+ updatedFields: { type: "array", items: { type: "string" } }
5271
+ },
5272
+ required: ["success", "id", "updatedFields"]
5174
5273
  }
5175
- }
5176
- const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
5177
- if (actionIdMatch) {
5178
- const id = Number(actionIdMatch[1]);
5179
- const action = db.actions.getActionById(id);
5180
- if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
5181
- const payload = JSON.stringify(action, null, 2);
5182
- return {
5183
- contents: [
5184
- {
5185
- uri,
5186
- mimeType: "application/json",
5187
- text: payload,
5188
- size: Buffer.byteLength(payload, "utf8"),
5189
- annotations: {
5190
- audience: ["assistant"],
5191
- priority: 0.55,
5192
- lastModified: action.created_at
5193
- }
5194
- }
5195
- ]
5196
- };
5197
- }
5198
- throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
5199
- }
5200
- function parseRepoUri(uri) {
5201
- const prefix = "repository://";
5202
- if (!uri.startsWith(prefix)) return null;
5203
- const rest = uri.slice(prefix.length);
5204
- const queryStart = rest.indexOf("?");
5205
- const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
5206
- const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
5207
- const slashIdx = withoutQuery.indexOf("/");
5208
- if (slashIdx === -1) return null;
5209
- const name = withoutQuery.slice(0, slashIdx);
5210
- const path6 = withoutQuery.slice(slashIdx + 1);
5211
- if (!name || !path6) return null;
5212
- return { name, path: path6, query: new URLSearchParams(queryString) };
5213
- }
5214
- function paginateEntries(key, entries, params) {
5215
- const limit = normalizeLimit(params?.limit);
5216
- const offset = decodeCursor(params?.cursor);
5217
- const sliced = entries.slice(offset, offset + limit);
5218
- const nextOffset = offset + sliced.length;
5219
- return {
5220
- [key]: sliced,
5221
- nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
5222
- };
5223
- }
5224
- function normalizeLimit(limit) {
5225
- if (typeof limit !== "number" || !Number.isFinite(limit)) {
5226
- return DEFAULT_PAGE_SIZE;
5227
- }
5228
- return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
5229
- }
5230
- function deriveLastModifiedFromCollection(values) {
5231
- const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
5232
- return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
5233
- }
5234
- function resourceNotFound(message, uri) {
5235
- const error = new Error(message);
5236
- error.code = -32002;
5237
- error.data = { uri };
5238
- return error;
5239
- }
5240
- function invalidCompletionParams(message) {
5241
- const error = new Error(message);
5242
- error.code = -32602;
5243
- return error;
5244
- }
5245
-
5246
- // src/mcp/prompts/registry.ts
5247
- function createPromptDefinition(loaded) {
5248
- return {
5249
- name: loaded.name,
5250
- description: loaded.description,
5251
- arguments: loaded.arguments,
5252
- agent: loaded.agent,
5253
- messages: [
5254
- {
5255
- role: "user",
5256
- content: {
5257
- type: "text",
5258
- text: loaded.content
5274
+ },
5275
+ {
5276
+ name: "standard-search",
5277
+ title: "Standard Search",
5278
+ description: "MANDATORY PRE-IMPLEMENTATION CHECK: Call before any code edit, test edit, refactor, migration, or implementation decision to find applicable coding standards. Returns a compact pointer table; use `standard-detail` for relevant results. If no relevant standards are returned, continue and state that no applicable standards were found.",
5279
+ annotations: {
5280
+ readOnlyHint: true,
5281
+ idempotentHint: true,
5282
+ openWorldHint: false
5283
+ },
5284
+ inputSchema: {
5285
+ type: "object",
5286
+ properties: {
5287
+ query: { type: "string", description: "Search query (optional, searches title/content)" },
5288
+ stack: {
5289
+ type: "array",
5290
+ items: { type: "string" },
5291
+ description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
5292
+ },
5293
+ tags: {
5294
+ type: "array",
5295
+ items: { type: "string" },
5296
+ description: "Tag filter"
5297
+ },
5298
+ language: { type: "string", description: "Programming language filter" },
5299
+ context: { type: "string", description: "Context/category filter" },
5300
+ version: { type: "string", description: "Version filter" },
5301
+ repo: { type: "string", description: "Repository filter (optional)" },
5302
+ is_global: { type: "boolean", description: "Filter by global/repo-specific" },
5303
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
5304
+ offset: { type: "number", minimum: 0, default: 0 },
5305
+ structured: { type: "boolean", default: false }
5306
+ },
5307
+ required: []
5308
+ },
5309
+ outputSchema: {
5310
+ type: "object",
5311
+ properties: {
5312
+ schema: { type: "string", enum: ["standard-search"] },
5313
+ query: { type: "string" },
5314
+ count: { type: "number", description: "Number of rows returned" },
5315
+ total: { type: "number", description: "Total number of matches before pagination" },
5316
+ offset: { type: "number" },
5317
+ limit: { type: "number" },
5318
+ results: {
5319
+ type: "object",
5320
+ properties: {
5321
+ columns: {
5322
+ type: "array",
5323
+ items: { type: "string" }
5324
+ },
5325
+ rows: {
5326
+ type: "array",
5327
+ items: { type: "array" },
5328
+ description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
5329
+ }
5330
+ },
5331
+ required: ["columns", "rows"]
5259
5332
  }
5260
- }
5261
- ]
5262
- };
5263
- }
5264
- var PROMPTS = {};
5265
- var promptFiles = listPromptFiles();
5266
- for (const name of promptFiles) {
5267
- try {
5268
- PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
5269
- } catch (e) {
5270
- logger.warn(`Failed to load prompt ${name}: ${e}`);
5271
- }
5272
- }
5273
- async function listPrompts(db, session, params) {
5274
- const allPrompts = Object.values(PROMPTS).map((p) => ({
5275
- name: p.name,
5276
- description: p.description,
5277
- arguments: p.arguments,
5278
- metadata: p.agent ? { agent: p.agent } : void 0
5279
- }));
5280
- const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
5281
- const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
5282
- const offset = decodeCursor(params?.cursor);
5283
- const sliced = allPrompts.slice(offset, offset + limit);
5284
- const nextOffset = offset + sliced.length;
5285
- return {
5286
- prompts: sliced,
5287
- nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
5288
- };
5289
- }
5290
- async function getPrompt(name, args = {}, db, session) {
5291
- const prompt = PROMPTS[name];
5292
- if (!prompt) {
5293
- throw new Error(`Prompt not found: ${name}`);
5294
- }
5295
- const inferredRepo = inferRepoFromSession(session);
5296
- const messages = prompt.messages.map((m) => {
5297
- let text = m.content.text;
5298
- for (const [key, value] of Object.entries(args)) {
5299
- text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
5333
+ },
5334
+ required: ["schema", "query", "count", "total", "offset", "limit", "results"]
5300
5335
  }
5301
- text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
5302
- return {
5303
- ...m,
5304
- content: {
5305
- ...m.content,
5306
- text
5307
- }
5308
- };
5309
- });
5310
- return {
5311
- description: prompt.description,
5312
- messages,
5313
- metadata: prompt.agent ? { agent: prompt.agent } : void 0
5314
- };
5315
- }
5316
- async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
5317
- void name;
5318
- void contextArguments;
5319
- if (argName === "task_id") {
5320
- const values = dataSources.tasks.map((t) => t.id);
5321
- return rankCompletionValues(values, value);
5322
5336
  }
5323
- return [];
5324
- }
5337
+ ];
5325
5338
 
5326
5339
  // src/mcp/tools/standard.shared.ts
5327
5340
  function toContextSlug(value) {
@@ -5341,17 +5354,31 @@ function buildStandardVectorText(standard) {
5341
5354
  }
5342
5355
 
5343
5356
  export {
5344
- MCP_PROTOCOL_VERSION,
5345
- CAPABILITIES,
5346
5357
  logger,
5347
5358
  setLogLevel,
5348
5359
  getLogLevel,
5349
5360
  addLogSink,
5350
5361
  LOG_LEVEL_VALUES,
5351
5362
  createFileSink,
5363
+ encodeCursor,
5364
+ decodeCursor,
5365
+ listResources,
5366
+ listResourceTemplates,
5367
+ completeResourceArgument,
5368
+ readResource,
5369
+ createSessionContext,
5370
+ updateSessionFromInitialize,
5371
+ updateSessionRoots,
5372
+ extractRootsFromResult,
5373
+ getFilesystemRoots,
5374
+ isPathWithinRoots,
5375
+ findContainingRoot,
5376
+ inferRepoFromSession,
5377
+ PROMPTS,
5378
+ listPrompts,
5379
+ getPrompt,
5380
+ completePromptArgument,
5352
5381
  normalizeRepo,
5353
- SQLiteStore,
5354
- RealVectorStore,
5355
5382
  MemoryStoreSchema,
5356
5383
  MemoryUpdateSchema,
5357
5384
  MemorySearchSchema,
@@ -5379,24 +5406,10 @@ export {
5379
5406
  StandardUpdateSchema,
5380
5407
  StandardSearchSchema,
5381
5408
  TOOL_DEFINITIONS,
5382
- encodeCursor,
5383
- decodeCursor,
5384
- listResources,
5385
- listResourceTemplates,
5386
- completeResourceArgument,
5387
- readResource,
5388
- createSessionContext,
5389
- updateSessionFromInitialize,
5390
- updateSessionRoots,
5391
- extractRootsFromResult,
5392
- getFilesystemRoots,
5393
- isPathWithinRoots,
5394
- findContainingRoot,
5395
- inferRepoFromSession,
5396
- PROMPTS,
5397
- listPrompts,
5398
- getPrompt,
5399
- completePromptArgument,
5400
5409
  toContextSlug,
5401
- buildStandardVectorText
5410
+ buildStandardVectorText,
5411
+ SQLiteStore,
5412
+ RealVectorStore,
5413
+ MCP_PROTOCOL_VERSION,
5414
+ CAPABILITIES
5402
5415
  };