@vheins/local-memory-mcp 0.8.24 → 0.8.25
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.
- package/dist/{chunk-M2MVLIYS.js → chunk-BHJLDG4Z.js} +1626 -1626
- package/dist/dashboard/server.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,49 @@
|
|
|
1
|
+
// src/mcp/capabilities.ts
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
var pkgVersion = "0.1.0";
|
|
6
|
+
if ("0.8.25") {
|
|
7
|
+
pkgVersion = "0.8.25";
|
|
8
|
+
} else {
|
|
9
|
+
let searchDir = __dirname;
|
|
10
|
+
for (let i = 0; i < 5; i++) {
|
|
11
|
+
const candidate = path.join(searchDir, "package.json");
|
|
12
|
+
try {
|
|
13
|
+
if (fs.existsSync(candidate)) {
|
|
14
|
+
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
15
|
+
if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
|
|
16
|
+
pkgVersion = pkg.version;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
searchDir = path.dirname(searchDir);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
26
|
+
var CAPABILITIES = {
|
|
27
|
+
serverInfo: {
|
|
28
|
+
name: "mcp-memory-local",
|
|
29
|
+
version: pkgVersion
|
|
30
|
+
},
|
|
31
|
+
capabilities: {
|
|
32
|
+
completions: {},
|
|
33
|
+
logging: {},
|
|
34
|
+
resources: {
|
|
35
|
+
subscribe: true,
|
|
36
|
+
listChanged: true
|
|
37
|
+
},
|
|
38
|
+
tools: {
|
|
39
|
+
listChanged: false
|
|
40
|
+
},
|
|
41
|
+
prompts: {
|
|
42
|
+
listChanged: true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
1
47
|
// src/mcp/utils/logger.ts
|
|
2
48
|
import fs from "fs";
|
|
3
49
|
var LEVELS = {
|
|
@@ -139,108 +185,6 @@ function createFileSink(logDir, maxFiles = 5) {
|
|
|
139
185
|
};
|
|
140
186
|
}
|
|
141
187
|
|
|
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
|
-
|
|
244
188
|
// src/mcp/storage/sqlite.ts
|
|
245
189
|
import Database from "better-sqlite3";
|
|
246
190
|
import path3 from "path";
|
|
@@ -2174,1664 +2118,1705 @@ var SQLiteStore = class _SQLiteStore {
|
|
|
2174
2118
|
}
|
|
2175
2119
|
};
|
|
2176
2120
|
|
|
2177
|
-
// src/mcp/
|
|
2178
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2121
|
+
// src/mcp/session.ts
|
|
2179
2122
|
import path4 from "path";
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2123
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2124
|
+
function createSessionContext() {
|
|
2125
|
+
return {
|
|
2126
|
+
roots: [],
|
|
2127
|
+
supportsRoots: false,
|
|
2128
|
+
supportsSampling: false,
|
|
2129
|
+
supportsSamplingTools: false,
|
|
2130
|
+
supportsElicitation: false,
|
|
2131
|
+
supportsElicitationForm: false,
|
|
2132
|
+
supportsElicitationUrl: false
|
|
2133
|
+
};
|
|
2134
|
+
}
|
|
2135
|
+
function updateSessionFromInitialize(session, params) {
|
|
2136
|
+
const capabilities = params?.capabilities || {};
|
|
2137
|
+
session.clientInfo = params?.clientInfo;
|
|
2138
|
+
session.clientCapabilities = capabilities;
|
|
2139
|
+
session.supportsRoots = Boolean(capabilities.roots);
|
|
2140
|
+
session.supportsSampling = Boolean(capabilities.sampling);
|
|
2141
|
+
const sampling = capabilities.sampling;
|
|
2142
|
+
session.supportsSamplingTools = Boolean(sampling?.tools);
|
|
2143
|
+
session.supportsElicitation = Boolean(capabilities.elicitation);
|
|
2144
|
+
session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
|
|
2145
|
+
session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
|
|
2146
|
+
}
|
|
2147
|
+
function supportsElicitationMode(capability, mode) {
|
|
2148
|
+
if (!capability || typeof capability !== "object") {
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
const cap = capability;
|
|
2152
|
+
if (mode === "form") {
|
|
2153
|
+
return Object.keys(cap).length === 0 || typeof cap.form === "object";
|
|
2154
|
+
}
|
|
2155
|
+
return typeof cap.url === "object";
|
|
2156
|
+
}
|
|
2157
|
+
function updateSessionRoots(session, roots) {
|
|
2158
|
+
const normalized = normalizeRoots(roots);
|
|
2159
|
+
const previous = JSON.stringify(session.roots);
|
|
2160
|
+
const next = JSON.stringify(normalized);
|
|
2161
|
+
session.roots = normalized;
|
|
2162
|
+
return previous !== next;
|
|
2163
|
+
}
|
|
2164
|
+
function normalizeRoots(roots) {
|
|
2165
|
+
if (!Array.isArray(roots)) return [];
|
|
2166
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2167
|
+
const normalized = [];
|
|
2168
|
+
for (const root of roots) {
|
|
2169
|
+
if (!root || typeof root !== "object") continue;
|
|
2170
|
+
const r = root;
|
|
2171
|
+
const uri = typeof r.uri === "string" ? r.uri : void 0;
|
|
2172
|
+
const name = typeof r.name === "string" ? r.name : void 0;
|
|
2173
|
+
if (!uri || seen.has(uri)) continue;
|
|
2174
|
+
seen.add(uri);
|
|
2175
|
+
normalized.push({ uri, name });
|
|
2176
|
+
}
|
|
2177
|
+
return normalized;
|
|
2178
|
+
}
|
|
2179
|
+
function extractRootsFromResult(result) {
|
|
2180
|
+
return normalizeRoots(result?.roots);
|
|
2181
|
+
}
|
|
2182
|
+
function getFilesystemRoots(session) {
|
|
2183
|
+
if (!session) return [];
|
|
2184
|
+
const resolved = [];
|
|
2185
|
+
for (const root of session.roots) {
|
|
2186
|
+
if (!root.uri.startsWith("file://")) continue;
|
|
2188
2187
|
try {
|
|
2189
|
-
|
|
2190
|
-
const pkg = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
2191
|
-
if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
|
|
2192
|
-
pkgVersion = pkg.version;
|
|
2193
|
-
break;
|
|
2194
|
-
}
|
|
2195
|
-
}
|
|
2188
|
+
resolved.push(path4.resolve(fileURLToPath2(root.uri)));
|
|
2196
2189
|
} catch {
|
|
2197
2190
|
}
|
|
2198
|
-
searchDir = path4.dirname(searchDir);
|
|
2199
2191
|
}
|
|
2192
|
+
return resolved;
|
|
2200
2193
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
listChanged: true
|
|
2194
|
+
function isPathWithinRoots(targetPath, session) {
|
|
2195
|
+
const roots = getFilesystemRoots(session);
|
|
2196
|
+
if (roots.length === 0) return true;
|
|
2197
|
+
const normalizedTarget = path4.resolve(targetPath);
|
|
2198
|
+
return roots.some((rootPath) => {
|
|
2199
|
+
const relative = path4.relative(rootPath, normalizedTarget);
|
|
2200
|
+
return relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative);
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
function findContainingRoot(targetPath, session) {
|
|
2204
|
+
const roots = getFilesystemRoots(session);
|
|
2205
|
+
if (roots.length === 0) return null;
|
|
2206
|
+
const normalizedTarget = path4.resolve(targetPath);
|
|
2207
|
+
for (const rootPath of roots) {
|
|
2208
|
+
const relative = path4.relative(rootPath, normalizedTarget);
|
|
2209
|
+
if (relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative)) {
|
|
2210
|
+
return rootPath;
|
|
2219
2211
|
}
|
|
2220
2212
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
// src/mcp/utils/pagination.ts
|
|
2224
|
-
function encodeCursor(offset) {
|
|
2225
|
-
return Buffer.from(String(offset), "utf8").toString("base64");
|
|
2213
|
+
return null;
|
|
2226
2214
|
}
|
|
2227
|
-
function
|
|
2228
|
-
|
|
2229
|
-
|
|
2215
|
+
function inferRepoFromSession(session) {
|
|
2216
|
+
const roots = getFilesystemRoots(session);
|
|
2217
|
+
if (roots.length === 1) {
|
|
2218
|
+
return path4.basename(roots[0]);
|
|
2230
2219
|
}
|
|
2231
|
-
|
|
2232
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2233
|
-
}
|
|
2234
|
-
let decoded;
|
|
2235
|
-
try {
|
|
2236
|
-
decoded = Buffer.from(cursor, "base64").toString("utf8");
|
|
2237
|
-
} catch {
|
|
2238
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2239
|
-
}
|
|
2240
|
-
if (!/^\d+$/.test(decoded)) {
|
|
2241
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2242
|
-
}
|
|
2243
|
-
const offset = Number.parseInt(decoded, 10);
|
|
2244
|
-
if (!Number.isFinite(offset) || offset < 0) {
|
|
2245
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2246
|
-
}
|
|
2247
|
-
return offset;
|
|
2248
|
-
}
|
|
2249
|
-
function invalidPaginationParams(message) {
|
|
2250
|
-
const error = new Error(message);
|
|
2251
|
-
error.code = -32602;
|
|
2252
|
-
return error;
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
// src/mcp/utils/completion.ts
|
|
2256
|
-
var MAX_COMPLETION_VALUES = 100;
|
|
2257
|
-
function rankCompletionValues(candidates, input) {
|
|
2258
|
-
const unique = [...new Set(candidates.filter(Boolean))];
|
|
2259
|
-
const needle = input.trim().toLowerCase();
|
|
2260
|
-
if (!needle) {
|
|
2261
|
-
return unique.slice(0, MAX_COMPLETION_VALUES);
|
|
2262
|
-
}
|
|
2263
|
-
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);
|
|
2264
|
-
}
|
|
2265
|
-
function scoreCompletionValue(value, needle) {
|
|
2266
|
-
const haystack = value.toLowerCase();
|
|
2267
|
-
if (haystack === needle) return 100;
|
|
2268
|
-
if (haystack.startsWith(needle)) return 75;
|
|
2269
|
-
if (haystack.includes(needle)) return 50;
|
|
2270
|
-
const compactNeedle = needle.replace(/[\s_-]+/g, "");
|
|
2271
|
-
const compactHaystack = haystack.replace(/[\s_-]+/g, "");
|
|
2272
|
-
if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
|
|
2273
|
-
return 0;
|
|
2220
|
+
return void 0;
|
|
2274
2221
|
}
|
|
2275
2222
|
|
|
2276
|
-
// src/mcp/
|
|
2277
|
-
|
|
2278
|
-
var
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
}
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
repo: name,
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2223
|
+
// src/mcp/tools/schemas.ts
|
|
2224
|
+
import { z } from "zod";
|
|
2225
|
+
var MemoryScopeSchema = z.object({
|
|
2226
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2227
|
+
branch: z.string().optional(),
|
|
2228
|
+
folder: z.string().optional(),
|
|
2229
|
+
language: z.string().optional()
|
|
2230
|
+
});
|
|
2231
|
+
var MemoryTypeSchema = z.enum([
|
|
2232
|
+
"code_fact",
|
|
2233
|
+
"decision",
|
|
2234
|
+
"mistake",
|
|
2235
|
+
"pattern",
|
|
2236
|
+
"agent_handoff",
|
|
2237
|
+
"agent_registered",
|
|
2238
|
+
"file_claim",
|
|
2239
|
+
"task_archive"
|
|
2240
|
+
]);
|
|
2241
|
+
var MemoryStoreSchema = z.object({
|
|
2242
|
+
code: z.string().max(20).optional(),
|
|
2243
|
+
type: MemoryTypeSchema,
|
|
2244
|
+
title: z.string().min(3).max(255),
|
|
2245
|
+
content: z.string().min(10),
|
|
2246
|
+
importance: z.number().min(1).max(5),
|
|
2247
|
+
agent: z.string().min(1),
|
|
2248
|
+
role: z.string().optional().default("unknown"),
|
|
2249
|
+
model: z.string().min(1),
|
|
2250
|
+
scope: MemoryScopeSchema,
|
|
2251
|
+
ttlDays: z.number().min(1).optional(),
|
|
2252
|
+
supersedes: z.string().uuid().optional(),
|
|
2253
|
+
tags: z.array(z.string()).optional(),
|
|
2254
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
2255
|
+
is_global: z.boolean().default(false),
|
|
2256
|
+
structured: z.boolean().default(false)
|
|
2257
|
+
});
|
|
2258
|
+
var MemoryUpdateSchema = z.object({
|
|
2259
|
+
id: z.string().uuid(),
|
|
2260
|
+
type: MemoryTypeSchema.optional(),
|
|
2261
|
+
title: z.string().min(3).max(255).optional(),
|
|
2262
|
+
content: z.string().min(10).optional(),
|
|
2263
|
+
importance: z.number().min(1).max(5).optional(),
|
|
2264
|
+
agent: z.string().optional(),
|
|
2265
|
+
role: z.string().optional(),
|
|
2266
|
+
status: z.enum(["active", "archived"]).optional(),
|
|
2267
|
+
supersedes: z.string().uuid().optional(),
|
|
2268
|
+
tags: z.array(z.string()).optional(),
|
|
2269
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
2270
|
+
is_global: z.boolean().optional(),
|
|
2271
|
+
completed_at: z.string().optional(),
|
|
2272
|
+
structured: z.boolean().default(false)
|
|
2273
|
+
}).refine(
|
|
2274
|
+
(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,
|
|
2275
|
+
{ message: "At least one field must be provided for update" }
|
|
2276
|
+
);
|
|
2277
|
+
var MemorySearchSchema = z.object({
|
|
2278
|
+
query: z.string().min(3),
|
|
2279
|
+
prompt: z.string().optional(),
|
|
2280
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2281
|
+
types: z.array(MemoryTypeSchema).optional(),
|
|
2282
|
+
minImportance: z.number().min(1).max(5).optional(),
|
|
2283
|
+
limit: z.number().min(1).max(100).default(5),
|
|
2284
|
+
offset: z.number().min(0).default(0),
|
|
2285
|
+
includeRecap: z.boolean().default(false),
|
|
2286
|
+
current_file_path: z.string().optional(),
|
|
2287
|
+
include_archived: z.boolean().default(false),
|
|
2288
|
+
current_tags: z.array(z.string()).optional(),
|
|
2289
|
+
scope: MemoryScopeSchema.partial().optional(),
|
|
2290
|
+
structured: z.boolean().default(false)
|
|
2291
|
+
});
|
|
2292
|
+
var MemoryAcknowledgeSchema = z.object({
|
|
2293
|
+
memory_id: z.string().uuid(),
|
|
2294
|
+
status: z.enum(["used", "irrelevant", "contradictory"]),
|
|
2295
|
+
application_context: z.string().min(10).optional(),
|
|
2296
|
+
structured: z.boolean().default(false)
|
|
2297
|
+
});
|
|
2298
|
+
var MemoryRecapSchema = z.object({
|
|
2299
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2300
|
+
limit: z.number().min(1).max(50).default(20),
|
|
2301
|
+
offset: z.number().min(0).default(0),
|
|
2302
|
+
structured: z.boolean().default(false)
|
|
2303
|
+
});
|
|
2304
|
+
var MemoryDeleteSchema = z.object({
|
|
2305
|
+
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2306
|
+
id: z.string().uuid().optional(),
|
|
2307
|
+
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2308
|
+
structured: z.boolean().default(false)
|
|
2309
|
+
}).refine((data) => data.id !== void 0 || data.ids !== void 0, {
|
|
2310
|
+
message: "Either 'id' or 'ids' must be provided for deletion"
|
|
2311
|
+
});
|
|
2312
|
+
var MemorySummarizeSchema = z.object({
|
|
2313
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2314
|
+
signals: z.array(z.string().max(200)).min(1),
|
|
2315
|
+
structured: z.boolean().default(false)
|
|
2316
|
+
});
|
|
2317
|
+
var MemorySynthesizeSchema = z.object({
|
|
2318
|
+
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2319
|
+
objective: z.string().min(5),
|
|
2320
|
+
current_file_path: z.string().optional(),
|
|
2321
|
+
include_summary: z.boolean().default(true),
|
|
2322
|
+
include_tasks: z.boolean().default(true),
|
|
2323
|
+
use_tools: z.boolean().default(true),
|
|
2324
|
+
max_iterations: z.number().int().min(1).max(5).default(3),
|
|
2325
|
+
max_tokens: z.number().int().min(128).max(4e3).default(1200),
|
|
2326
|
+
structured: z.boolean().default(false)
|
|
2327
|
+
});
|
|
2328
|
+
var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
|
|
2329
|
+
var TaskPrioritySchema = z.number().min(1).max(5);
|
|
2330
|
+
var SingleTaskCreateSchema = z.object({
|
|
2331
|
+
task_code: z.string().min(1),
|
|
2332
|
+
phase: z.string().min(1),
|
|
2333
|
+
title: z.string().min(3).max(100),
|
|
2334
|
+
description: z.string().min(1),
|
|
2335
|
+
status: TaskStatusSchema.default("backlog"),
|
|
2336
|
+
priority: TaskPrioritySchema.default(3),
|
|
2337
|
+
agent: z.string().optional(),
|
|
2338
|
+
role: z.string().optional(),
|
|
2339
|
+
doc_path: z.string().optional(),
|
|
2340
|
+
tags: z.array(z.string()).optional(),
|
|
2341
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
2342
|
+
parent_id: z.string().uuid().optional(),
|
|
2343
|
+
depends_on: z.string().uuid().optional(),
|
|
2344
|
+
est_tokens: z.number().int().min(0).optional()
|
|
2345
|
+
});
|
|
2346
|
+
var TaskCreateSchema = z.object({
|
|
2347
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2348
|
+
// Allow single task fields at top level (backward compatibility & single use)
|
|
2349
|
+
task_code: z.string().min(1).optional(),
|
|
2350
|
+
phase: z.string().min(1).optional(),
|
|
2351
|
+
title: z.string().min(3).max(100).optional(),
|
|
2352
|
+
description: z.string().min(1).optional(),
|
|
2353
|
+
status: TaskStatusSchema.optional(),
|
|
2354
|
+
priority: TaskPrioritySchema.optional(),
|
|
2355
|
+
agent: z.string().optional(),
|
|
2356
|
+
role: z.string().optional(),
|
|
2357
|
+
doc_path: z.string().optional(),
|
|
2358
|
+
tags: z.array(z.string()).optional(),
|
|
2359
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
2360
|
+
parent_id: z.string().uuid().optional(),
|
|
2361
|
+
depends_on: z.string().uuid().optional(),
|
|
2362
|
+
est_tokens: z.number().int().min(0).optional(),
|
|
2363
|
+
// Allow bulk tasks
|
|
2364
|
+
tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
|
|
2365
|
+
structured: z.boolean().default(false)
|
|
2366
|
+
}).refine(
|
|
2367
|
+
(data) => {
|
|
2368
|
+
if (data.tasks) return true;
|
|
2369
|
+
return !!(data.task_code && data.phase && data.title && data.description);
|
|
2370
|
+
},
|
|
2371
|
+
{ message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
|
|
2372
|
+
);
|
|
2373
|
+
var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
|
|
2374
|
+
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2375
|
+
structured: z.boolean().default(false)
|
|
2376
|
+
});
|
|
2377
|
+
var TaskUpdateSchema = z.object({
|
|
2378
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2379
|
+
id: z.string().uuid().optional(),
|
|
2380
|
+
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2381
|
+
task_code: z.string().optional(),
|
|
2382
|
+
phase: z.string().optional(),
|
|
2383
|
+
title: z.string().min(3).max(100).optional(),
|
|
2384
|
+
description: z.string().optional(),
|
|
2385
|
+
status: TaskStatusSchema.optional(),
|
|
2386
|
+
priority: TaskPrioritySchema.optional(),
|
|
2387
|
+
agent: z.string().min(1, "agent name is required").optional(),
|
|
2388
|
+
role: z.string().min(1, "agent role is required").optional(),
|
|
2389
|
+
model: z.string().optional(),
|
|
2390
|
+
comment: z.string().min(1).optional(),
|
|
2391
|
+
doc_path: z.string().optional(),
|
|
2392
|
+
tags: z.array(z.string()).optional(),
|
|
2393
|
+
metadata: z.record(z.string(), z.any()).optional(),
|
|
2394
|
+
parent_id: z.string().uuid().optional(),
|
|
2395
|
+
depends_on: z.string().uuid().optional(),
|
|
2396
|
+
est_tokens: z.number().int().min(0).optional(),
|
|
2397
|
+
force: z.boolean().optional(),
|
|
2398
|
+
structured: z.boolean().default(false)
|
|
2399
|
+
}).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
|
|
2400
|
+
message: "Either 'id', 'ids', or 'task_code' must be provided for update"
|
|
2401
|
+
}).refine((data) => Object.keys(data).length > 2, {
|
|
2402
|
+
message: "At least one field besides repo and id/ids must be provided for update"
|
|
2403
|
+
});
|
|
2404
|
+
var TaskListSchema = z.object({
|
|
2405
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2406
|
+
status: z.string().optional(),
|
|
2407
|
+
phase: z.string().optional(),
|
|
2408
|
+
query: z.string().optional(),
|
|
2409
|
+
limit: z.number().min(1).max(100).default(15),
|
|
2410
|
+
offset: z.number().min(0).default(0),
|
|
2411
|
+
structured: z.boolean().default(false)
|
|
2412
|
+
});
|
|
2413
|
+
var TaskSearchSchema = z.object({
|
|
2414
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2415
|
+
query: z.string().min(1),
|
|
2416
|
+
status: z.string().optional(),
|
|
2417
|
+
limit: z.number().min(1).max(100).default(10),
|
|
2418
|
+
offset: z.number().min(0).default(0),
|
|
2419
|
+
structured: z.boolean().default(false)
|
|
2420
|
+
});
|
|
2421
|
+
var TaskDeleteSchema = z.object({
|
|
2422
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2423
|
+
id: z.string().uuid().optional(),
|
|
2424
|
+
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2425
|
+
structured: z.boolean().default(false)
|
|
2426
|
+
}).refine((data) => data.id !== void 0 || data.ids !== void 0, {
|
|
2427
|
+
message: "Either 'id' or 'ids' must be provided for deletion"
|
|
2428
|
+
});
|
|
2429
|
+
var MemoryDetailSchema = z.object({
|
|
2430
|
+
id: z.string().uuid().optional(),
|
|
2431
|
+
code: z.string().max(20).optional(),
|
|
2432
|
+
structured: z.boolean().default(false)
|
|
2433
|
+
}).refine((data) => data.id !== void 0 || data.code !== void 0, {
|
|
2434
|
+
message: "Either id or code must be provided"
|
|
2435
|
+
});
|
|
2436
|
+
var TaskGetSchema = z.object({
|
|
2437
|
+
repo: z.string().min(1).transform(normalizeRepo),
|
|
2438
|
+
id: z.string().uuid().optional(),
|
|
2439
|
+
task_code: z.string().optional(),
|
|
2440
|
+
structured: z.boolean().default(false)
|
|
2441
|
+
}).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
|
|
2442
|
+
message: "Either id or task_code must be provided"
|
|
2443
|
+
});
|
|
2444
|
+
var TOOL_DEFINITIONS = [
|
|
2445
|
+
{
|
|
2446
|
+
name: "memory-synthesize",
|
|
2447
|
+
title: "Memory Synthesize",
|
|
2448
|
+
description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
|
|
2449
|
+
annotations: {
|
|
2450
|
+
readOnlyHint: true,
|
|
2451
|
+
idempotentHint: true,
|
|
2452
|
+
openWorldHint: false
|
|
2453
|
+
},
|
|
2454
|
+
execution: {
|
|
2455
|
+
taskSupport: "optional"
|
|
2456
|
+
},
|
|
2457
|
+
inputSchema: {
|
|
2458
|
+
type: "object",
|
|
2459
|
+
properties: {
|
|
2460
|
+
repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
|
|
2461
|
+
objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
|
|
2462
|
+
current_file_path: {
|
|
2463
|
+
type: "string",
|
|
2464
|
+
description: "Optional absolute file path for workspace-local grounding."
|
|
2465
|
+
},
|
|
2466
|
+
include_summary: { type: "boolean", default: true },
|
|
2467
|
+
include_tasks: { type: "boolean", default: true },
|
|
2468
|
+
use_tools: {
|
|
2469
|
+
type: "boolean",
|
|
2470
|
+
default: true,
|
|
2471
|
+
description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
|
|
2472
|
+
},
|
|
2473
|
+
max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
2474
|
+
max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
|
|
2475
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
|
|
2476
|
+
},
|
|
2477
|
+
required: ["objective"]
|
|
2478
|
+
},
|
|
2479
|
+
outputSchema: {
|
|
2480
|
+
type: "object",
|
|
2481
|
+
properties: {
|
|
2482
|
+
repo: { type: "string" },
|
|
2483
|
+
objective: { type: "string" },
|
|
2484
|
+
answer: { type: "string" },
|
|
2485
|
+
model: { type: "string" },
|
|
2486
|
+
stopReason: { type: "string" },
|
|
2487
|
+
iterations: { type: "number" },
|
|
2488
|
+
toolCalls: { type: "number" }
|
|
2489
|
+
},
|
|
2490
|
+
required: ["repo", "objective", "answer", "iterations", "toolCalls"]
|
|
2538
2491
|
}
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2492
|
+
},
|
|
2493
|
+
{
|
|
2494
|
+
name: "task-create-interactive",
|
|
2495
|
+
title: "Interactive Task Create",
|
|
2496
|
+
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.",
|
|
2497
|
+
annotations: {
|
|
2498
|
+
readOnlyHint: false,
|
|
2499
|
+
idempotentHint: false,
|
|
2500
|
+
destructiveHint: false,
|
|
2501
|
+
openWorldHint: false
|
|
2502
|
+
},
|
|
2503
|
+
inputSchema: {
|
|
2504
|
+
type: "object",
|
|
2505
|
+
properties: {
|
|
2506
|
+
repo: {
|
|
2507
|
+
type: "string",
|
|
2508
|
+
description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
|
|
2509
|
+
},
|
|
2510
|
+
task_code: { type: "string" },
|
|
2511
|
+
phase: { type: "string" },
|
|
2512
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
2513
|
+
description: { type: "string", minLength: 1 },
|
|
2514
|
+
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
2515
|
+
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
2516
|
+
agent: { type: "string" },
|
|
2517
|
+
role: { type: "string" },
|
|
2518
|
+
doc_path: { type: "string" },
|
|
2519
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
2554
2520
|
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
}
|
|
2568
|
-
}
|
|
2569
|
-
]
|
|
2570
|
-
};
|
|
2571
|
-
}
|
|
2572
|
-
if (repoPath === "actions") {
|
|
2573
|
-
const actions = db.actions.getRecentActions(name, 100);
|
|
2574
|
-
const payload = JSON.stringify(actions, null, 2);
|
|
2575
|
-
return {
|
|
2576
|
-
contents: [
|
|
2577
|
-
{
|
|
2578
|
-
uri,
|
|
2579
|
-
mimeType: "application/json",
|
|
2580
|
-
text: payload,
|
|
2581
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
2582
|
-
annotations: {
|
|
2583
|
-
audience: ["assistant"],
|
|
2584
|
-
priority: 0.6,
|
|
2585
|
-
lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
]
|
|
2589
|
-
};
|
|
2521
|
+
},
|
|
2522
|
+
outputSchema: {
|
|
2523
|
+
type: "object",
|
|
2524
|
+
properties: {
|
|
2525
|
+
repo: { type: "string" },
|
|
2526
|
+
task_code: { type: "string" },
|
|
2527
|
+
phase: { type: "string" },
|
|
2528
|
+
title: { type: "string" },
|
|
2529
|
+
status: { type: "string" },
|
|
2530
|
+
priority: { type: "number" }
|
|
2531
|
+
},
|
|
2532
|
+
required: ["repo", "task_code", "phase", "title", "status", "priority"]
|
|
2590
2533
|
}
|
|
2591
|
-
}
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
{
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2534
|
+
},
|
|
2535
|
+
{
|
|
2536
|
+
name: "memory-detail",
|
|
2537
|
+
title: "Memory Detail",
|
|
2538
|
+
description: "Fetch full details of a specific memory by ID. Use this when you have a memory ID (e.g. from search results) and need to read the full content.",
|
|
2539
|
+
inputSchema: {
|
|
2540
|
+
type: "object",
|
|
2541
|
+
properties: {
|
|
2542
|
+
id: { type: "string", format: "uuid", description: "Memory entry ID" },
|
|
2543
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
|
|
2544
|
+
},
|
|
2545
|
+
required: ["id"]
|
|
2546
|
+
}
|
|
2547
|
+
},
|
|
2548
|
+
{
|
|
2549
|
+
name: "task-detail",
|
|
2550
|
+
title: "Task Detail",
|
|
2551
|
+
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.",
|
|
2552
|
+
inputSchema: {
|
|
2553
|
+
type: "object",
|
|
2554
|
+
properties: {
|
|
2555
|
+
repo: { type: "string", description: "Repository name" },
|
|
2556
|
+
id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
|
|
2557
|
+
task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
|
|
2558
|
+
structured: {
|
|
2559
|
+
type: "boolean",
|
|
2560
|
+
default: false,
|
|
2561
|
+
description: "If true, returns structured JSON without the text content details."
|
|
2610
2562
|
}
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
}
|
|
2614
|
-
throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
|
|
2615
|
-
}
|
|
2616
|
-
function parseRepoUri(uri) {
|
|
2617
|
-
const prefix = "repository://";
|
|
2618
|
-
if (!uri.startsWith(prefix)) return null;
|
|
2619
|
-
const rest = uri.slice(prefix.length);
|
|
2620
|
-
const queryStart = rest.indexOf("?");
|
|
2621
|
-
const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
|
|
2622
|
-
const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
|
|
2623
|
-
const slashIdx = withoutQuery.indexOf("/");
|
|
2624
|
-
if (slashIdx === -1) return null;
|
|
2625
|
-
const name = withoutQuery.slice(0, slashIdx);
|
|
2626
|
-
const path6 = withoutQuery.slice(slashIdx + 1);
|
|
2627
|
-
if (!name || !path6) return null;
|
|
2628
|
-
return { name, path: path6, query: new URLSearchParams(queryString) };
|
|
2629
|
-
}
|
|
2630
|
-
function paginateEntries(key, entries, params) {
|
|
2631
|
-
const limit = normalizeLimit(params?.limit);
|
|
2632
|
-
const offset = decodeCursor(params?.cursor);
|
|
2633
|
-
const sliced = entries.slice(offset, offset + limit);
|
|
2634
|
-
const nextOffset = offset + sliced.length;
|
|
2635
|
-
return {
|
|
2636
|
-
[key]: sliced,
|
|
2637
|
-
nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
|
|
2638
|
-
};
|
|
2639
|
-
}
|
|
2640
|
-
function normalizeLimit(limit) {
|
|
2641
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
2642
|
-
return DEFAULT_PAGE_SIZE;
|
|
2643
|
-
}
|
|
2644
|
-
return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
|
|
2645
|
-
}
|
|
2646
|
-
function deriveLastModifiedFromCollection(values) {
|
|
2647
|
-
const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
|
|
2648
|
-
return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2649
|
-
}
|
|
2650
|
-
function resourceNotFound(message, uri) {
|
|
2651
|
-
const error = new Error(message);
|
|
2652
|
-
error.code = -32002;
|
|
2653
|
-
error.data = { uri };
|
|
2654
|
-
return error;
|
|
2655
|
-
}
|
|
2656
|
-
function invalidCompletionParams(message) {
|
|
2657
|
-
const error = new Error(message);
|
|
2658
|
-
error.code = -32602;
|
|
2659
|
-
return error;
|
|
2660
|
-
}
|
|
2661
|
-
|
|
2662
|
-
// src/mcp/prompts/loader.ts
|
|
2663
|
-
import fs4 from "fs";
|
|
2664
|
-
import path5 from "path";
|
|
2665
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2666
|
-
import matter from "gray-matter";
|
|
2667
|
-
var __filename = fileURLToPath3(import.meta.url);
|
|
2668
|
-
var __dirname2 = path5.dirname(__filename);
|
|
2669
|
-
function findPromptDir() {
|
|
2670
|
-
const candidates = [
|
|
2671
|
-
// Production if chunked into dist/
|
|
2672
|
-
"./prompts",
|
|
2673
|
-
// Production if inlined into dist/mcp/
|
|
2674
|
-
"../prompts",
|
|
2675
|
-
// Dev: /src/mcp/prompts/definitions (next to loader.ts)
|
|
2676
|
-
"./definitions"
|
|
2677
|
-
].map((relPath) => path5.resolve(__dirname2, relPath));
|
|
2678
|
-
for (const dir of candidates) {
|
|
2679
|
-
if (fs4.existsSync(dir)) {
|
|
2680
|
-
const files = fs4.readdirSync(dir);
|
|
2681
|
-
if (files.some((f) => f.endsWith(".md"))) {
|
|
2682
|
-
return dir;
|
|
2683
|
-
}
|
|
2563
|
+
},
|
|
2564
|
+
required: ["repo"]
|
|
2684
2565
|
}
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2566
|
+
},
|
|
2567
|
+
{
|
|
2568
|
+
name: "memory-store",
|
|
2569
|
+
title: "Memory Store",
|
|
2570
|
+
description: "Store a new memory entry. Keep 'title' concise and human-readable; do not embed agent/role/date metadata in the title. Put auxiliary context into 'metadata'. Use 'tags' for tech-stack and 'is_global' for universal rules.",
|
|
2571
|
+
annotations: {
|
|
2572
|
+
readOnlyHint: false,
|
|
2573
|
+
idempotentHint: false,
|
|
2574
|
+
destructiveHint: false,
|
|
2575
|
+
openWorldHint: false
|
|
2576
|
+
},
|
|
2577
|
+
inputSchema: {
|
|
2578
|
+
type: "object",
|
|
2579
|
+
properties: {
|
|
2580
|
+
type: {
|
|
2581
|
+
type: "string",
|
|
2582
|
+
enum: [
|
|
2583
|
+
"code_fact",
|
|
2584
|
+
"decision",
|
|
2585
|
+
"mistake",
|
|
2586
|
+
"pattern",
|
|
2587
|
+
"agent_handoff",
|
|
2588
|
+
"agent_registered",
|
|
2589
|
+
"file_claim",
|
|
2590
|
+
"task_archive"
|
|
2591
|
+
],
|
|
2592
|
+
description: "Type of memory being stored"
|
|
2593
|
+
},
|
|
2594
|
+
title: {
|
|
2595
|
+
type: "string",
|
|
2596
|
+
minLength: 3,
|
|
2597
|
+
maxLength: 100,
|
|
2598
|
+
description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
|
|
2599
|
+
},
|
|
2719
2600
|
content: {
|
|
2720
|
-
type: "
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2601
|
+
type: "string",
|
|
2602
|
+
minLength: 10,
|
|
2603
|
+
description: "The memory content"
|
|
2604
|
+
},
|
|
2605
|
+
importance: {
|
|
2606
|
+
type: "number",
|
|
2607
|
+
minimum: 1,
|
|
2608
|
+
maximum: 5,
|
|
2609
|
+
description: "Importance score (1-5)"
|
|
2610
|
+
},
|
|
2611
|
+
agent: {
|
|
2612
|
+
type: "string",
|
|
2613
|
+
description: "Name of the agent creating this memory"
|
|
2614
|
+
},
|
|
2615
|
+
role: {
|
|
2616
|
+
type: "string",
|
|
2617
|
+
description: "Role of the agent creating this memory"
|
|
2618
|
+
},
|
|
2619
|
+
model: {
|
|
2620
|
+
type: "string",
|
|
2621
|
+
description: "AI model used by the agent"
|
|
2622
|
+
},
|
|
2623
|
+
scope: {
|
|
2624
|
+
type: "object",
|
|
2625
|
+
properties: {
|
|
2626
|
+
repo: { type: "string", description: "Repository name" },
|
|
2627
|
+
branch: { type: "string" },
|
|
2628
|
+
folder: { type: "string" },
|
|
2629
|
+
language: { type: "string" }
|
|
2630
|
+
},
|
|
2631
|
+
required: ["repo"]
|
|
2632
|
+
},
|
|
2633
|
+
tags: {
|
|
2634
|
+
type: "array",
|
|
2635
|
+
items: { type: "string" },
|
|
2636
|
+
description: "Technology stack tags (e.g., ['filament', 'laravel'])"
|
|
2637
|
+
},
|
|
2638
|
+
metadata: {
|
|
2639
|
+
type: "object",
|
|
2640
|
+
description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
|
|
2641
|
+
},
|
|
2642
|
+
is_global: {
|
|
2643
|
+
type: "boolean",
|
|
2644
|
+
description: "If true, this memory is shared across all repositories"
|
|
2645
|
+
},
|
|
2646
|
+
ttlDays: { type: "number", minimum: 1 },
|
|
2647
|
+
supersedes: { type: "string", format: "uuid" },
|
|
2648
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
|
|
2649
|
+
},
|
|
2650
|
+
required: ["type", "title", "content", "importance", "scope", "agent", "model"]
|
|
2651
|
+
},
|
|
2652
|
+
outputSchema: {
|
|
2653
|
+
type: "object",
|
|
2654
|
+
properties: {
|
|
2655
|
+
success: { type: "boolean" },
|
|
2656
|
+
id: { type: "string" },
|
|
2657
|
+
code: { type: "string" },
|
|
2658
|
+
repo: { type: "string" },
|
|
2659
|
+
type: { type: "string" },
|
|
2660
|
+
title: { type: "string" },
|
|
2661
|
+
error: { type: "string" },
|
|
2662
|
+
message: { type: "string" }
|
|
2663
|
+
},
|
|
2664
|
+
required: ["success"]
|
|
2665
|
+
}
|
|
2666
|
+
},
|
|
2667
|
+
{
|
|
2668
|
+
name: "memory-acknowledge",
|
|
2669
|
+
title: "Memory Acknowledge",
|
|
2670
|
+
description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
|
|
2671
|
+
annotations: {
|
|
2672
|
+
readOnlyHint: false,
|
|
2673
|
+
idempotentHint: false,
|
|
2674
|
+
openWorldHint: false
|
|
2675
|
+
},
|
|
2676
|
+
inputSchema: {
|
|
2677
|
+
type: "object",
|
|
2678
|
+
properties: {
|
|
2679
|
+
memory_id: { type: "string", format: "uuid" },
|
|
2680
|
+
status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
|
|
2681
|
+
application_context: { type: "string", minLength: 10 },
|
|
2682
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
2683
|
+
},
|
|
2684
|
+
required: ["memory_id", "status"]
|
|
2685
|
+
},
|
|
2686
|
+
outputSchema: {
|
|
2687
|
+
type: "object",
|
|
2688
|
+
properties: {
|
|
2689
|
+
success: { type: "boolean" },
|
|
2690
|
+
id: { type: "string" },
|
|
2691
|
+
status: { type: "string" }
|
|
2692
|
+
},
|
|
2693
|
+
required: ["success", "id", "status"]
|
|
2694
|
+
}
|
|
2695
|
+
},
|
|
2696
|
+
{
|
|
2697
|
+
name: "memory-update",
|
|
2698
|
+
title: "Memory Update",
|
|
2699
|
+
description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
|
|
2700
|
+
annotations: {
|
|
2701
|
+
readOnlyHint: false,
|
|
2702
|
+
idempotentHint: false,
|
|
2703
|
+
destructiveHint: false,
|
|
2704
|
+
openWorldHint: false
|
|
2705
|
+
},
|
|
2706
|
+
inputSchema: {
|
|
2707
|
+
type: "object",
|
|
2708
|
+
properties: {
|
|
2709
|
+
id: { type: "string", format: "uuid" },
|
|
2710
|
+
type: {
|
|
2711
|
+
type: "string",
|
|
2712
|
+
enum: [
|
|
2713
|
+
"code_fact",
|
|
2714
|
+
"decision",
|
|
2715
|
+
"mistake",
|
|
2716
|
+
"pattern",
|
|
2717
|
+
"agent_handoff",
|
|
2718
|
+
"agent_registered",
|
|
2719
|
+
"file_claim",
|
|
2720
|
+
"task_archive"
|
|
2721
|
+
]
|
|
2722
|
+
},
|
|
2723
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
2724
|
+
content: { type: "string", minLength: 10 },
|
|
2725
|
+
importance: { type: "number", minimum: 1, maximum: 5 },
|
|
2726
|
+
agent: { type: "string" },
|
|
2727
|
+
role: { type: "string" },
|
|
2728
|
+
status: { type: "string", enum: ["active", "archived"] },
|
|
2729
|
+
supersedes: { type: "string", format: "uuid" },
|
|
2730
|
+
tags: { type: "array", items: { type: "string" } },
|
|
2731
|
+
metadata: { type: "object" },
|
|
2732
|
+
is_global: { type: "boolean" },
|
|
2733
|
+
completed_at: { type: "string" },
|
|
2734
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
|
|
2735
|
+
},
|
|
2736
|
+
required: ["id"]
|
|
2737
|
+
},
|
|
2738
|
+
outputSchema: {
|
|
2739
|
+
type: "object",
|
|
2740
|
+
properties: {
|
|
2741
|
+
success: { type: "boolean" },
|
|
2742
|
+
id: { type: "string" },
|
|
2743
|
+
repo: { type: "string" },
|
|
2744
|
+
updatedFields: {
|
|
2745
|
+
type: "array",
|
|
2746
|
+
items: { type: "string" }
|
|
2747
|
+
}
|
|
2748
|
+
},
|
|
2749
|
+
required: ["success", "id", "repo", "updatedFields"]
|
|
2750
|
+
}
|
|
2751
|
+
},
|
|
2752
|
+
{
|
|
2753
|
+
name: "memory-search",
|
|
2754
|
+
title: "Memory Search",
|
|
2755
|
+
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.",
|
|
2756
|
+
annotations: {
|
|
2757
|
+
readOnlyHint: true,
|
|
2758
|
+
idempotentHint: true,
|
|
2759
|
+
openWorldHint: false
|
|
2760
|
+
},
|
|
2761
|
+
inputSchema: {
|
|
2762
|
+
type: "object",
|
|
2763
|
+
properties: {
|
|
2764
|
+
query: { type: "string", minLength: 3 },
|
|
2765
|
+
prompt: { type: "string" },
|
|
2766
|
+
repo: { type: "string" },
|
|
2767
|
+
current_tags: {
|
|
2768
|
+
type: "array",
|
|
2769
|
+
items: { type: "string" },
|
|
2770
|
+
description: "Active tech stack tags (e.g., ['filament', 'react'])"
|
|
2771
|
+
},
|
|
2772
|
+
types: {
|
|
2773
|
+
type: "array",
|
|
2774
|
+
items: {
|
|
2775
|
+
type: "string",
|
|
2776
|
+
enum: [
|
|
2777
|
+
"code_fact",
|
|
2778
|
+
"decision",
|
|
2779
|
+
"mistake",
|
|
2780
|
+
"pattern",
|
|
2781
|
+
"agent_handoff",
|
|
2782
|
+
"agent_registered",
|
|
2783
|
+
"file_claim",
|
|
2784
|
+
"task_archive"
|
|
2785
|
+
]
|
|
2786
|
+
}
|
|
2787
|
+
},
|
|
2788
|
+
minImportance: { type: "number", minimum: 1, maximum: 5 },
|
|
2789
|
+
limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
|
|
2790
|
+
offset: { type: "number", minimum: 0, default: 0 },
|
|
2791
|
+
includeRecap: { type: "boolean", default: false },
|
|
2792
|
+
current_file_path: { type: "string" },
|
|
2793
|
+
include_archived: { type: "boolean", default: false },
|
|
2794
|
+
scope: {
|
|
2795
|
+
type: "object",
|
|
2796
|
+
properties: {
|
|
2797
|
+
repo: { type: "string" },
|
|
2798
|
+
branch: { type: "string" },
|
|
2799
|
+
folder: { type: "string" },
|
|
2800
|
+
language: { type: "string" }
|
|
2801
|
+
}
|
|
2802
|
+
},
|
|
2803
|
+
structured: {
|
|
2804
|
+
type: "boolean",
|
|
2805
|
+
default: false,
|
|
2806
|
+
description: "If true, returns structured JSON without the text content summary."
|
|
2807
|
+
}
|
|
2808
|
+
},
|
|
2809
|
+
required: ["query", "repo"]
|
|
2810
|
+
},
|
|
2811
|
+
outputSchema: {
|
|
2812
|
+
type: "object",
|
|
2813
|
+
properties: {
|
|
2814
|
+
schema: { type: "string", enum: ["memory-search"] },
|
|
2815
|
+
query: { type: "string" },
|
|
2816
|
+
count: { type: "number", description: "Number of rows returned" },
|
|
2817
|
+
total: { type: "number", description: "Total matching memories" },
|
|
2818
|
+
offset: { type: "number" },
|
|
2819
|
+
limit: { type: "number" },
|
|
2820
|
+
results: {
|
|
2821
|
+
type: "object",
|
|
2822
|
+
properties: {
|
|
2823
|
+
columns: {
|
|
2824
|
+
type: "array",
|
|
2825
|
+
items: { type: "string" },
|
|
2826
|
+
description: "Column names: [id, title, type, importance]"
|
|
2827
|
+
},
|
|
2828
|
+
rows: {
|
|
2829
|
+
type: "array",
|
|
2830
|
+
items: { type: "array" },
|
|
2831
|
+
description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
|
|
2832
|
+
}
|
|
2833
|
+
},
|
|
2834
|
+
required: ["columns", "rows"]
|
|
2835
|
+
}
|
|
2836
|
+
},
|
|
2837
|
+
required: ["schema", "query", "count", "total", "offset", "limit", "results"]
|
|
2838
|
+
}
|
|
2839
|
+
},
|
|
2840
|
+
{
|
|
2841
|
+
name: "memory-summarize",
|
|
2842
|
+
title: "Memory Summarize",
|
|
2843
|
+
description: "Update the summary for a repository",
|
|
2844
|
+
annotations: {
|
|
2845
|
+
readOnlyHint: false,
|
|
2846
|
+
idempotentHint: false,
|
|
2847
|
+
openWorldHint: false
|
|
2848
|
+
},
|
|
2849
|
+
inputSchema: {
|
|
2850
|
+
type: "object",
|
|
2851
|
+
properties: {
|
|
2852
|
+
repo: { type: "string", description: "Repository name" },
|
|
2853
|
+
signals: {
|
|
2854
|
+
type: "array",
|
|
2855
|
+
items: { type: "string", maxLength: 200 },
|
|
2856
|
+
minItems: 1,
|
|
2857
|
+
description: "High-level signals to include in summary"
|
|
2858
|
+
},
|
|
2859
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
|
|
2860
|
+
},
|
|
2861
|
+
required: ["repo", "signals"]
|
|
2862
|
+
},
|
|
2863
|
+
outputSchema: {
|
|
2864
|
+
type: "object",
|
|
2865
|
+
properties: {
|
|
2866
|
+
success: { type: "boolean" },
|
|
2867
|
+
repo: { type: "string" },
|
|
2868
|
+
summary: { type: "string" },
|
|
2869
|
+
signalCount: { type: "number" }
|
|
2870
|
+
},
|
|
2871
|
+
required: ["success", "repo", "summary", "signalCount"]
|
|
2872
|
+
}
|
|
2873
|
+
},
|
|
2874
|
+
{
|
|
2875
|
+
name: "memory-delete",
|
|
2876
|
+
title: "Memory Delete",
|
|
2877
|
+
description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
|
|
2878
|
+
annotations: {
|
|
2879
|
+
readOnlyHint: false,
|
|
2880
|
+
idempotentHint: false,
|
|
2881
|
+
destructiveHint: true,
|
|
2882
|
+
openWorldHint: false
|
|
2883
|
+
},
|
|
2884
|
+
inputSchema: {
|
|
2885
|
+
type: "object",
|
|
2886
|
+
properties: {
|
|
2887
|
+
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
2888
|
+
id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
|
|
2889
|
+
ids: {
|
|
2890
|
+
type: "array",
|
|
2891
|
+
items: { type: "string", format: "uuid" },
|
|
2892
|
+
minItems: 1,
|
|
2893
|
+
description: "Array of memory IDs to delete"
|
|
2894
|
+
},
|
|
2895
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
2896
|
+
}
|
|
2897
|
+
},
|
|
2898
|
+
outputSchema: {
|
|
2899
|
+
type: "object",
|
|
2900
|
+
properties: {
|
|
2901
|
+
success: { type: "boolean" },
|
|
2902
|
+
id: { type: "string" },
|
|
2903
|
+
ids: { type: "array", items: { type: "string" } },
|
|
2904
|
+
repo: { type: "string" },
|
|
2905
|
+
deletedCount: { type: "number" }
|
|
2906
|
+
},
|
|
2907
|
+
required: ["success"]
|
|
2763
2908
|
}
|
|
2764
|
-
text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
|
|
2765
|
-
return {
|
|
2766
|
-
...m,
|
|
2767
|
-
content: {
|
|
2768
|
-
...m.content,
|
|
2769
|
-
text
|
|
2770
|
-
}
|
|
2771
|
-
};
|
|
2772
|
-
});
|
|
2773
|
-
return {
|
|
2774
|
-
description: prompt.description,
|
|
2775
|
-
messages,
|
|
2776
|
-
metadata: prompt.agent ? { agent: prompt.agent } : void 0
|
|
2777
|
-
};
|
|
2778
|
-
}
|
|
2779
|
-
async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
|
|
2780
|
-
void name;
|
|
2781
|
-
void contextArguments;
|
|
2782
|
-
if (argName === "task_id") {
|
|
2783
|
-
const values = dataSources.tasks.map((t) => t.id);
|
|
2784
|
-
return rankCompletionValues(values, value);
|
|
2785
|
-
}
|
|
2786
|
-
return [];
|
|
2787
|
-
}
|
|
2788
|
-
|
|
2789
|
-
// src/mcp/tools/schemas.ts
|
|
2790
|
-
import { z } from "zod";
|
|
2791
|
-
var MemoryScopeSchema = z.object({
|
|
2792
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2793
|
-
branch: z.string().optional(),
|
|
2794
|
-
folder: z.string().optional(),
|
|
2795
|
-
language: z.string().optional()
|
|
2796
|
-
});
|
|
2797
|
-
var MemoryTypeSchema = z.enum([
|
|
2798
|
-
"code_fact",
|
|
2799
|
-
"decision",
|
|
2800
|
-
"mistake",
|
|
2801
|
-
"pattern",
|
|
2802
|
-
"agent_handoff",
|
|
2803
|
-
"agent_registered",
|
|
2804
|
-
"file_claim",
|
|
2805
|
-
"task_archive"
|
|
2806
|
-
]);
|
|
2807
|
-
var MemoryStoreSchema = z.object({
|
|
2808
|
-
code: z.string().max(20).optional(),
|
|
2809
|
-
type: MemoryTypeSchema,
|
|
2810
|
-
title: z.string().min(3).max(255),
|
|
2811
|
-
content: z.string().min(10),
|
|
2812
|
-
importance: z.number().min(1).max(5),
|
|
2813
|
-
agent: z.string().min(1),
|
|
2814
|
-
role: z.string().optional().default("unknown"),
|
|
2815
|
-
model: z.string().min(1),
|
|
2816
|
-
scope: MemoryScopeSchema,
|
|
2817
|
-
ttlDays: z.number().min(1).optional(),
|
|
2818
|
-
supersedes: z.string().uuid().optional(),
|
|
2819
|
-
tags: z.array(z.string()).optional(),
|
|
2820
|
-
metadata: z.record(z.string(), z.any()).optional(),
|
|
2821
|
-
is_global: z.boolean().default(false),
|
|
2822
|
-
structured: z.boolean().default(false)
|
|
2823
|
-
});
|
|
2824
|
-
var MemoryUpdateSchema = z.object({
|
|
2825
|
-
id: z.string().uuid(),
|
|
2826
|
-
type: MemoryTypeSchema.optional(),
|
|
2827
|
-
title: z.string().min(3).max(255).optional(),
|
|
2828
|
-
content: z.string().min(10).optional(),
|
|
2829
|
-
importance: z.number().min(1).max(5).optional(),
|
|
2830
|
-
agent: z.string().optional(),
|
|
2831
|
-
role: z.string().optional(),
|
|
2832
|
-
status: z.enum(["active", "archived"]).optional(),
|
|
2833
|
-
supersedes: z.string().uuid().optional(),
|
|
2834
|
-
tags: z.array(z.string()).optional(),
|
|
2835
|
-
metadata: z.record(z.string(), z.any()).optional(),
|
|
2836
|
-
is_global: z.boolean().optional(),
|
|
2837
|
-
completed_at: z.string().optional(),
|
|
2838
|
-
structured: z.boolean().default(false)
|
|
2839
|
-
}).refine(
|
|
2840
|
-
(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,
|
|
2841
|
-
{ message: "At least one field must be provided for update" }
|
|
2842
|
-
);
|
|
2843
|
-
var MemorySearchSchema = z.object({
|
|
2844
|
-
query: z.string().min(3),
|
|
2845
|
-
prompt: z.string().optional(),
|
|
2846
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2847
|
-
types: z.array(MemoryTypeSchema).optional(),
|
|
2848
|
-
minImportance: z.number().min(1).max(5).optional(),
|
|
2849
|
-
limit: z.number().min(1).max(100).default(5),
|
|
2850
|
-
offset: z.number().min(0).default(0),
|
|
2851
|
-
includeRecap: z.boolean().default(false),
|
|
2852
|
-
current_file_path: z.string().optional(),
|
|
2853
|
-
include_archived: z.boolean().default(false),
|
|
2854
|
-
current_tags: z.array(z.string()).optional(),
|
|
2855
|
-
scope: MemoryScopeSchema.partial().optional(),
|
|
2856
|
-
structured: z.boolean().default(false)
|
|
2857
|
-
});
|
|
2858
|
-
var MemoryAcknowledgeSchema = z.object({
|
|
2859
|
-
memory_id: z.string().uuid(),
|
|
2860
|
-
status: z.enum(["used", "irrelevant", "contradictory"]),
|
|
2861
|
-
application_context: z.string().min(10).optional(),
|
|
2862
|
-
structured: z.boolean().default(false)
|
|
2863
|
-
});
|
|
2864
|
-
var MemoryRecapSchema = z.object({
|
|
2865
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2866
|
-
limit: z.number().min(1).max(50).default(20),
|
|
2867
|
-
offset: z.number().min(0).default(0),
|
|
2868
|
-
structured: z.boolean().default(false)
|
|
2869
|
-
});
|
|
2870
|
-
var MemoryDeleteSchema = z.object({
|
|
2871
|
-
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2872
|
-
id: z.string().uuid().optional(),
|
|
2873
|
-
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2874
|
-
structured: z.boolean().default(false)
|
|
2875
|
-
}).refine((data) => data.id !== void 0 || data.ids !== void 0, {
|
|
2876
|
-
message: "Either 'id' or 'ids' must be provided for deletion"
|
|
2877
|
-
});
|
|
2878
|
-
var MemorySummarizeSchema = z.object({
|
|
2879
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2880
|
-
signals: z.array(z.string().max(200)).min(1),
|
|
2881
|
-
structured: z.boolean().default(false)
|
|
2882
|
-
});
|
|
2883
|
-
var MemorySynthesizeSchema = z.object({
|
|
2884
|
-
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2885
|
-
objective: z.string().min(5),
|
|
2886
|
-
current_file_path: z.string().optional(),
|
|
2887
|
-
include_summary: z.boolean().default(true),
|
|
2888
|
-
include_tasks: z.boolean().default(true),
|
|
2889
|
-
use_tools: z.boolean().default(true),
|
|
2890
|
-
max_iterations: z.number().int().min(1).max(5).default(3),
|
|
2891
|
-
max_tokens: z.number().int().min(128).max(4e3).default(1200),
|
|
2892
|
-
structured: z.boolean().default(false)
|
|
2893
|
-
});
|
|
2894
|
-
var TaskStatusSchema = z.enum(["backlog", "pending", "in_progress", "completed", "canceled", "blocked"]);
|
|
2895
|
-
var TaskPrioritySchema = z.number().min(1).max(5);
|
|
2896
|
-
var SingleTaskCreateSchema = z.object({
|
|
2897
|
-
task_code: z.string().min(1),
|
|
2898
|
-
phase: z.string().min(1),
|
|
2899
|
-
title: z.string().min(3).max(100),
|
|
2900
|
-
description: z.string().min(1),
|
|
2901
|
-
status: TaskStatusSchema.default("backlog"),
|
|
2902
|
-
priority: TaskPrioritySchema.default(3),
|
|
2903
|
-
agent: z.string().optional(),
|
|
2904
|
-
role: z.string().optional(),
|
|
2905
|
-
doc_path: z.string().optional(),
|
|
2906
|
-
tags: z.array(z.string()).optional(),
|
|
2907
|
-
metadata: z.record(z.string(), z.any()).optional(),
|
|
2908
|
-
parent_id: z.string().uuid().optional(),
|
|
2909
|
-
depends_on: z.string().uuid().optional(),
|
|
2910
|
-
est_tokens: z.number().int().min(0).optional()
|
|
2911
|
-
});
|
|
2912
|
-
var TaskCreateSchema = z.object({
|
|
2913
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2914
|
-
// Allow single task fields at top level (backward compatibility & single use)
|
|
2915
|
-
task_code: z.string().min(1).optional(),
|
|
2916
|
-
phase: z.string().min(1).optional(),
|
|
2917
|
-
title: z.string().min(3).max(100).optional(),
|
|
2918
|
-
description: z.string().min(1).optional(),
|
|
2919
|
-
status: TaskStatusSchema.optional(),
|
|
2920
|
-
priority: TaskPrioritySchema.optional(),
|
|
2921
|
-
agent: z.string().optional(),
|
|
2922
|
-
role: z.string().optional(),
|
|
2923
|
-
doc_path: z.string().optional(),
|
|
2924
|
-
tags: z.array(z.string()).optional(),
|
|
2925
|
-
metadata: z.record(z.string(), z.any()).optional(),
|
|
2926
|
-
parent_id: z.string().uuid().optional(),
|
|
2927
|
-
depends_on: z.string().uuid().optional(),
|
|
2928
|
-
est_tokens: z.number().int().min(0).optional(),
|
|
2929
|
-
// Allow bulk tasks
|
|
2930
|
-
tasks: z.array(SingleTaskCreateSchema).min(1).optional(),
|
|
2931
|
-
structured: z.boolean().default(false)
|
|
2932
|
-
}).refine(
|
|
2933
|
-
(data) => {
|
|
2934
|
-
if (data.tasks) return true;
|
|
2935
|
-
return !!(data.task_code && data.phase && data.title && data.description);
|
|
2936
2909
|
},
|
|
2937
|
-
{ message: "Either 'tasks' array or single task fields (task_code, phase, title, description) must be provided" }
|
|
2938
|
-
);
|
|
2939
|
-
var TaskCreateInteractiveSchema = SingleTaskCreateSchema.partial().extend({
|
|
2940
|
-
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
2941
|
-
structured: z.boolean().default(false)
|
|
2942
|
-
});
|
|
2943
|
-
var TaskUpdateSchema = z.object({
|
|
2944
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2945
|
-
id: z.string().uuid().optional(),
|
|
2946
|
-
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2947
|
-
task_code: z.string().optional(),
|
|
2948
|
-
phase: z.string().optional(),
|
|
2949
|
-
title: z.string().min(3).max(100).optional(),
|
|
2950
|
-
description: z.string().optional(),
|
|
2951
|
-
status: TaskStatusSchema.optional(),
|
|
2952
|
-
priority: TaskPrioritySchema.optional(),
|
|
2953
|
-
agent: z.string().min(1, "agent name is required").optional(),
|
|
2954
|
-
role: z.string().min(1, "agent role is required").optional(),
|
|
2955
|
-
model: z.string().optional(),
|
|
2956
|
-
comment: z.string().min(1).optional(),
|
|
2957
|
-
doc_path: z.string().optional(),
|
|
2958
|
-
tags: z.array(z.string()).optional(),
|
|
2959
|
-
metadata: z.record(z.string(), z.any()).optional(),
|
|
2960
|
-
parent_id: z.string().uuid().optional(),
|
|
2961
|
-
depends_on: z.string().uuid().optional(),
|
|
2962
|
-
est_tokens: z.number().int().min(0).optional(),
|
|
2963
|
-
force: z.boolean().optional(),
|
|
2964
|
-
structured: z.boolean().default(false)
|
|
2965
|
-
}).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
|
|
2966
|
-
message: "Either 'id', 'ids', or 'task_code' must be provided for update"
|
|
2967
|
-
}).refine((data) => Object.keys(data).length > 2, {
|
|
2968
|
-
message: "At least one field besides repo and id/ids must be provided for update"
|
|
2969
|
-
});
|
|
2970
|
-
var TaskListSchema = z.object({
|
|
2971
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2972
|
-
status: z.string().optional(),
|
|
2973
|
-
phase: z.string().optional(),
|
|
2974
|
-
query: z.string().optional(),
|
|
2975
|
-
limit: z.number().min(1).max(100).default(15),
|
|
2976
|
-
offset: z.number().min(0).default(0),
|
|
2977
|
-
structured: z.boolean().default(false)
|
|
2978
|
-
});
|
|
2979
|
-
var TaskSearchSchema = z.object({
|
|
2980
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2981
|
-
query: z.string().min(1),
|
|
2982
|
-
status: z.string().optional(),
|
|
2983
|
-
limit: z.number().min(1).max(100).default(10),
|
|
2984
|
-
offset: z.number().min(0).default(0),
|
|
2985
|
-
structured: z.boolean().default(false)
|
|
2986
|
-
});
|
|
2987
|
-
var TaskDeleteSchema = z.object({
|
|
2988
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
2989
|
-
id: z.string().uuid().optional(),
|
|
2990
|
-
ids: z.array(z.string().uuid()).min(1).optional(),
|
|
2991
|
-
structured: z.boolean().default(false)
|
|
2992
|
-
}).refine((data) => data.id !== void 0 || data.ids !== void 0, {
|
|
2993
|
-
message: "Either 'id' or 'ids' must be provided for deletion"
|
|
2994
|
-
});
|
|
2995
|
-
var MemoryDetailSchema = z.object({
|
|
2996
|
-
id: z.string().uuid().optional(),
|
|
2997
|
-
code: z.string().max(20).optional(),
|
|
2998
|
-
structured: z.boolean().default(false)
|
|
2999
|
-
}).refine((data) => data.id !== void 0 || data.code !== void 0, {
|
|
3000
|
-
message: "Either id or code must be provided"
|
|
3001
|
-
});
|
|
3002
|
-
var TaskGetSchema = z.object({
|
|
3003
|
-
repo: z.string().min(1).transform(normalizeRepo),
|
|
3004
|
-
id: z.string().uuid().optional(),
|
|
3005
|
-
task_code: z.string().optional(),
|
|
3006
|
-
structured: z.boolean().default(false)
|
|
3007
|
-
}).refine((data) => data.id !== void 0 || data.task_code !== void 0, {
|
|
3008
|
-
message: "Either id or task_code must be provided"
|
|
3009
|
-
});
|
|
3010
|
-
var TOOL_DEFINITIONS = [
|
|
3011
2910
|
{
|
|
3012
|
-
name: "memory-
|
|
3013
|
-
title: "Memory
|
|
3014
|
-
description: "
|
|
2911
|
+
name: "memory-recap",
|
|
2912
|
+
title: "Memory Recap",
|
|
2913
|
+
description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
|
|
3015
2914
|
annotations: {
|
|
3016
2915
|
readOnlyHint: true,
|
|
3017
2916
|
idempotentHint: true,
|
|
3018
2917
|
openWorldHint: false
|
|
3019
2918
|
},
|
|
3020
|
-
execution: {
|
|
3021
|
-
taskSupport: "optional"
|
|
3022
|
-
},
|
|
3023
2919
|
inputSchema: {
|
|
3024
2920
|
type: "object",
|
|
3025
2921
|
properties: {
|
|
3026
|
-
repo: { type: "string", description: "Repository name
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
2922
|
+
repo: { type: "string", description: "Repository name (required)" },
|
|
2923
|
+
limit: {
|
|
2924
|
+
type: "number",
|
|
2925
|
+
minimum: 1,
|
|
2926
|
+
maximum: 50,
|
|
2927
|
+
default: 20,
|
|
2928
|
+
description: "Maximum number of top memories to return in the pointer table"
|
|
3031
2929
|
},
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
|
|
2930
|
+
offset: {
|
|
2931
|
+
type: "number",
|
|
2932
|
+
minimum: 0,
|
|
2933
|
+
default: 0,
|
|
2934
|
+
description: "Number of memories to skip for pagination (optional, default 0)"
|
|
3038
2935
|
},
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
2936
|
+
structured: {
|
|
2937
|
+
type: "boolean",
|
|
2938
|
+
default: false,
|
|
2939
|
+
description: "If true, returns structured JSON without the text content summary."
|
|
2940
|
+
}
|
|
3042
2941
|
},
|
|
3043
|
-
required: ["
|
|
2942
|
+
required: ["repo"]
|
|
3044
2943
|
},
|
|
3045
2944
|
outputSchema: {
|
|
3046
2945
|
type: "object",
|
|
3047
2946
|
properties: {
|
|
2947
|
+
schema: { type: "string", enum: ["memory-recap"] },
|
|
3048
2948
|
repo: { type: "string" },
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
2949
|
+
count: { type: "number", description: "Number of rows in the top pointer table" },
|
|
2950
|
+
total: { type: "number", description: "Total active memories in repo" },
|
|
2951
|
+
offset: { type: "number" },
|
|
2952
|
+
limit: { type: "number" },
|
|
2953
|
+
stats: {
|
|
2954
|
+
type: "object",
|
|
2955
|
+
properties: {
|
|
2956
|
+
by_type: {
|
|
2957
|
+
type: "object",
|
|
2958
|
+
description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
|
|
2959
|
+
}
|
|
2960
|
+
},
|
|
2961
|
+
required: ["by_type"]
|
|
2962
|
+
},
|
|
2963
|
+
top: {
|
|
2964
|
+
type: "object",
|
|
2965
|
+
properties: {
|
|
2966
|
+
columns: {
|
|
2967
|
+
type: "array",
|
|
2968
|
+
items: { type: "string" },
|
|
2969
|
+
description: "Column names: [id, title, type, importance]"
|
|
2970
|
+
},
|
|
2971
|
+
rows: {
|
|
2972
|
+
type: "array",
|
|
2973
|
+
items: { type: "array" },
|
|
2974
|
+
description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
|
|
2975
|
+
}
|
|
2976
|
+
},
|
|
2977
|
+
required: ["columns", "rows"]
|
|
2978
|
+
}
|
|
3055
2979
|
},
|
|
3056
|
-
required: ["repo", "
|
|
2980
|
+
required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
|
|
3057
2981
|
}
|
|
3058
2982
|
},
|
|
3059
2983
|
{
|
|
3060
|
-
name: "task-create
|
|
3061
|
-
title: "
|
|
3062
|
-
description: "
|
|
2984
|
+
name: "task-create",
|
|
2985
|
+
title: "Task Create",
|
|
2986
|
+
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.",
|
|
3063
2987
|
annotations: {
|
|
3064
2988
|
readOnlyHint: false,
|
|
3065
2989
|
idempotentHint: false,
|
|
3066
|
-
destructiveHint: false,
|
|
3067
2990
|
openWorldHint: false
|
|
3068
2991
|
},
|
|
3069
2992
|
inputSchema: {
|
|
3070
2993
|
type: "object",
|
|
3071
2994
|
properties: {
|
|
3072
|
-
repo: {
|
|
2995
|
+
repo: { type: "string", description: "Repository name" },
|
|
2996
|
+
task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
|
|
2997
|
+
phase: { type: "string", description: "Project phase (Required for single task)" },
|
|
2998
|
+
title: {
|
|
3073
2999
|
type: "string",
|
|
3074
|
-
|
|
3000
|
+
minLength: 3,
|
|
3001
|
+
maxLength: 100,
|
|
3002
|
+
description: "Task objective (Required for single task)"
|
|
3003
|
+
},
|
|
3004
|
+
description: { type: "string", description: "Detailed description (Required for single task)" },
|
|
3005
|
+
status: {
|
|
3006
|
+
type: "string",
|
|
3007
|
+
enum: ["backlog", "pending"],
|
|
3008
|
+
default: "backlog",
|
|
3009
|
+
description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
|
|
3075
3010
|
},
|
|
3076
|
-
task_code: { type: "string" },
|
|
3077
|
-
phase: { type: "string" },
|
|
3078
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3079
|
-
description: { type: "string", minLength: 1 },
|
|
3080
|
-
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3081
3011
|
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3082
3012
|
agent: { type: "string" },
|
|
3083
3013
|
role: { type: "string" },
|
|
3084
3014
|
doc_path: { type: "string" },
|
|
3015
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3016
|
+
metadata: { type: "object" },
|
|
3017
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3018
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3019
|
+
est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
|
|
3020
|
+
tasks: {
|
|
3021
|
+
type: "array",
|
|
3022
|
+
items: {
|
|
3023
|
+
type: "object",
|
|
3024
|
+
properties: {
|
|
3025
|
+
task_code: { type: "string" },
|
|
3026
|
+
phase: { type: "string" },
|
|
3027
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3028
|
+
description: { type: "string" },
|
|
3029
|
+
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3030
|
+
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3031
|
+
agent: { type: "string" },
|
|
3032
|
+
role: { type: "string" },
|
|
3033
|
+
doc_path: { type: "string" },
|
|
3034
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3035
|
+
metadata: { type: "object" },
|
|
3036
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3037
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3038
|
+
est_tokens: { type: "number", minimum: 0 }
|
|
3039
|
+
},
|
|
3040
|
+
required: ["task_code", "phase", "title", "description"]
|
|
3041
|
+
},
|
|
3042
|
+
description: "Array of tasks for bulk creation"
|
|
3043
|
+
},
|
|
3085
3044
|
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3086
|
-
}
|
|
3045
|
+
},
|
|
3046
|
+
required: ["repo"]
|
|
3087
3047
|
},
|
|
3088
3048
|
outputSchema: {
|
|
3089
3049
|
type: "object",
|
|
3090
3050
|
properties: {
|
|
3091
|
-
|
|
3051
|
+
success: { type: "boolean" },
|
|
3052
|
+
id: { type: "string" },
|
|
3092
3053
|
task_code: { type: "string" },
|
|
3054
|
+
repo: { type: "string" },
|
|
3093
3055
|
phase: { type: "string" },
|
|
3094
3056
|
title: { type: "string" },
|
|
3095
3057
|
status: { type: "string" },
|
|
3096
|
-
priority: { type: "number" }
|
|
3058
|
+
priority: { type: "number" },
|
|
3059
|
+
createdCount: { type: "number" },
|
|
3060
|
+
taskCodes: { type: "array", items: { type: "string" } }
|
|
3097
3061
|
},
|
|
3098
|
-
required: ["
|
|
3062
|
+
required: ["success", "repo"]
|
|
3099
3063
|
}
|
|
3100
3064
|
},
|
|
3101
3065
|
{
|
|
3102
|
-
name: "
|
|
3103
|
-
title: "
|
|
3104
|
-
description: "
|
|
3066
|
+
name: "task-update",
|
|
3067
|
+
title: "Task Update",
|
|
3068
|
+
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.",
|
|
3069
|
+
annotations: {
|
|
3070
|
+
readOnlyHint: false,
|
|
3071
|
+
idempotentHint: false,
|
|
3072
|
+
openWorldHint: false
|
|
3073
|
+
},
|
|
3105
3074
|
inputSchema: {
|
|
3106
3075
|
type: "object",
|
|
3107
3076
|
properties: {
|
|
3108
|
-
|
|
3109
|
-
|
|
3077
|
+
repo: { type: "string", description: "Repository name" },
|
|
3078
|
+
id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
|
|
3079
|
+
ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
|
|
3080
|
+
task_code: { type: "string" },
|
|
3081
|
+
phase: { type: "string" },
|
|
3082
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3083
|
+
description: { type: "string" },
|
|
3084
|
+
status: {
|
|
3085
|
+
type: "string",
|
|
3086
|
+
enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
|
|
3087
|
+
description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
|
|
3088
|
+
},
|
|
3089
|
+
priority: { type: "number", minimum: 1, maximum: 5 },
|
|
3090
|
+
agent: { type: "string" },
|
|
3091
|
+
role: { type: "string" },
|
|
3092
|
+
model: { type: "string" },
|
|
3093
|
+
comment: {
|
|
3094
|
+
type: "string",
|
|
3095
|
+
description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
|
|
3096
|
+
},
|
|
3097
|
+
doc_path: { type: "string" },
|
|
3098
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3099
|
+
metadata: { type: "object" },
|
|
3100
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3101
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3102
|
+
est_tokens: {
|
|
3103
|
+
type: "number",
|
|
3104
|
+
minimum: 0,
|
|
3105
|
+
description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
|
|
3106
|
+
},
|
|
3107
|
+
force: {
|
|
3108
|
+
type: "boolean",
|
|
3109
|
+
description: "If true, bypasses status transition validation (e.g. pending -> completed)."
|
|
3110
|
+
},
|
|
3111
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3110
3112
|
},
|
|
3111
|
-
required: ["
|
|
3113
|
+
required: ["repo"]
|
|
3114
|
+
},
|
|
3115
|
+
outputSchema: {
|
|
3116
|
+
type: "object",
|
|
3117
|
+
properties: {
|
|
3118
|
+
success: { type: "boolean" },
|
|
3119
|
+
id: { type: "string" },
|
|
3120
|
+
ids: { type: "array", items: { type: "string" } },
|
|
3121
|
+
repo: { type: "string" },
|
|
3122
|
+
status: { type: "string" },
|
|
3123
|
+
archivedToMemory: { type: "boolean" },
|
|
3124
|
+
updatedFields: {
|
|
3125
|
+
type: "array",
|
|
3126
|
+
items: { type: "string" }
|
|
3127
|
+
},
|
|
3128
|
+
updatedCount: { type: "number" }
|
|
3129
|
+
},
|
|
3130
|
+
required: ["success", "repo"]
|
|
3112
3131
|
}
|
|
3113
3132
|
},
|
|
3114
3133
|
{
|
|
3115
|
-
name: "task-
|
|
3116
|
-
title: "Task
|
|
3117
|
-
description: "
|
|
3134
|
+
name: "task-delete",
|
|
3135
|
+
title: "Task Delete",
|
|
3136
|
+
description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
|
|
3137
|
+
annotations: {
|
|
3138
|
+
readOnlyHint: false,
|
|
3139
|
+
idempotentHint: false,
|
|
3140
|
+
destructiveHint: true,
|
|
3141
|
+
openWorldHint: false
|
|
3142
|
+
},
|
|
3118
3143
|
inputSchema: {
|
|
3119
3144
|
type: "object",
|
|
3120
3145
|
properties: {
|
|
3121
3146
|
repo: { type: "string", description: "Repository name" },
|
|
3122
|
-
id: { type: "string", format: "uuid", description: "Task ID (
|
|
3123
|
-
|
|
3124
|
-
structured: {
|
|
3125
|
-
type: "boolean",
|
|
3126
|
-
default: false,
|
|
3127
|
-
description: "If true, returns structured JSON without the text content details."
|
|
3128
|
-
}
|
|
3147
|
+
id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
|
|
3148
|
+
ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
|
|
3149
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3129
3150
|
},
|
|
3130
3151
|
required: ["repo"]
|
|
3152
|
+
},
|
|
3153
|
+
outputSchema: {
|
|
3154
|
+
type: "object",
|
|
3155
|
+
properties: {
|
|
3156
|
+
success: { type: "boolean" },
|
|
3157
|
+
id: { type: "string" },
|
|
3158
|
+
ids: { type: "array", items: { type: "string" } },
|
|
3159
|
+
repo: { type: "string" },
|
|
3160
|
+
deletedCount: { type: "number" }
|
|
3161
|
+
},
|
|
3162
|
+
required: ["success", "repo"]
|
|
3131
3163
|
}
|
|
3132
3164
|
},
|
|
3133
3165
|
{
|
|
3134
|
-
name: "
|
|
3135
|
-
title: "
|
|
3136
|
-
description: "
|
|
3166
|
+
name: "task-list",
|
|
3167
|
+
title: "Task List",
|
|
3168
|
+
description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority). 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.",
|
|
3137
3169
|
annotations: {
|
|
3138
|
-
readOnlyHint:
|
|
3139
|
-
idempotentHint:
|
|
3140
|
-
destructiveHint: false,
|
|
3170
|
+
readOnlyHint: true,
|
|
3171
|
+
idempotentHint: true,
|
|
3141
3172
|
openWorldHint: false
|
|
3142
3173
|
},
|
|
3143
3174
|
inputSchema: {
|
|
3144
3175
|
type: "object",
|
|
3145
3176
|
properties: {
|
|
3146
|
-
|
|
3147
|
-
type: "string",
|
|
3148
|
-
enum: [
|
|
3149
|
-
"code_fact",
|
|
3150
|
-
"decision",
|
|
3151
|
-
"mistake",
|
|
3152
|
-
"pattern",
|
|
3153
|
-
"agent_handoff",
|
|
3154
|
-
"agent_registered",
|
|
3155
|
-
"file_claim",
|
|
3156
|
-
"task_archive"
|
|
3157
|
-
],
|
|
3158
|
-
description: "Type of memory being stored"
|
|
3159
|
-
},
|
|
3160
|
-
title: {
|
|
3161
|
-
type: "string",
|
|
3162
|
-
minLength: 3,
|
|
3163
|
-
maxLength: 100,
|
|
3164
|
-
description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
|
|
3165
|
-
},
|
|
3166
|
-
content: {
|
|
3177
|
+
repo: {
|
|
3167
3178
|
type: "string",
|
|
3168
|
-
|
|
3169
|
-
description: "The memory content"
|
|
3170
|
-
},
|
|
3171
|
-
importance: {
|
|
3172
|
-
type: "number",
|
|
3173
|
-
minimum: 1,
|
|
3174
|
-
maximum: 5,
|
|
3175
|
-
description: "Importance score (1-5)"
|
|
3179
|
+
description: "Repository name"
|
|
3176
3180
|
},
|
|
3177
|
-
|
|
3181
|
+
status: {
|
|
3178
3182
|
type: "string",
|
|
3179
|
-
|
|
3183
|
+
default: "in_progress,pending",
|
|
3184
|
+
description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
|
|
3180
3185
|
},
|
|
3181
|
-
|
|
3186
|
+
phase: {
|
|
3182
3187
|
type: "string",
|
|
3183
|
-
description: "
|
|
3188
|
+
description: "Filter by phase (e.g., 'research', 'implementation')"
|
|
3184
3189
|
},
|
|
3185
|
-
|
|
3190
|
+
query: {
|
|
3186
3191
|
type: "string",
|
|
3187
|
-
description: "
|
|
3188
|
-
},
|
|
3189
|
-
scope: {
|
|
3190
|
-
type: "object",
|
|
3191
|
-
properties: {
|
|
3192
|
-
repo: { type: "string", description: "Repository name" },
|
|
3193
|
-
branch: { type: "string" },
|
|
3194
|
-
folder: { type: "string" },
|
|
3195
|
-
language: { type: "string" }
|
|
3196
|
-
},
|
|
3197
|
-
required: ["repo"]
|
|
3192
|
+
description: "Search keyword matching task code, title, or description"
|
|
3198
3193
|
},
|
|
3199
|
-
|
|
3200
|
-
type: "
|
|
3201
|
-
|
|
3202
|
-
|
|
3194
|
+
limit: {
|
|
3195
|
+
type: "number",
|
|
3196
|
+
minimum: 1,
|
|
3197
|
+
maximum: 100,
|
|
3198
|
+
default: 5,
|
|
3199
|
+
description: "Maximum rows to return (default 5)"
|
|
3203
3200
|
},
|
|
3204
|
-
|
|
3205
|
-
type: "
|
|
3206
|
-
|
|
3201
|
+
offset: {
|
|
3202
|
+
type: "number",
|
|
3203
|
+
minimum: 0,
|
|
3204
|
+
default: 0,
|
|
3205
|
+
description: "Offset for pagination"
|
|
3207
3206
|
},
|
|
3208
|
-
|
|
3207
|
+
structured: {
|
|
3209
3208
|
type: "boolean",
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
supersedes: { type: "string", format: "uuid" },
|
|
3214
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
|
|
3209
|
+
default: false,
|
|
3210
|
+
description: "If true, returns structured JSON without the text content summary."
|
|
3211
|
+
}
|
|
3215
3212
|
},
|
|
3216
|
-
required: ["
|
|
3213
|
+
required: ["repo"]
|
|
3217
3214
|
},
|
|
3218
3215
|
outputSchema: {
|
|
3219
3216
|
type: "object",
|
|
3220
3217
|
properties: {
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3218
|
+
schema: { type: "string", enum: ["task-list"] },
|
|
3219
|
+
tasks: {
|
|
3220
|
+
type: "object",
|
|
3221
|
+
properties: {
|
|
3222
|
+
columns: {
|
|
3223
|
+
type: "array",
|
|
3224
|
+
items: { type: "string" },
|
|
3225
|
+
description: "Column names in order: id, task_code, title, status, priority, comments_count"
|
|
3226
|
+
},
|
|
3227
|
+
rows: {
|
|
3228
|
+
type: "array",
|
|
3229
|
+
items: { type: "array" },
|
|
3230
|
+
description: "Each row: [id, task_code, title, status, priority, comments_count]. Use task-detail to fetch full task."
|
|
3231
|
+
}
|
|
3232
|
+
},
|
|
3233
|
+
required: ["columns", "rows"]
|
|
3234
|
+
},
|
|
3235
|
+
count: { type: "number" },
|
|
3236
|
+
offset: { type: "number" }
|
|
3229
3237
|
},
|
|
3230
|
-
required: ["
|
|
3238
|
+
required: ["schema", "tasks", "count"]
|
|
3231
3239
|
}
|
|
3232
|
-
}
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3240
|
+
}
|
|
3241
|
+
];
|
|
3242
|
+
|
|
3243
|
+
// src/mcp/utils/pagination.ts
|
|
3244
|
+
function encodeCursor(offset) {
|
|
3245
|
+
return Buffer.from(String(offset), "utf8").toString("base64");
|
|
3246
|
+
}
|
|
3247
|
+
function decodeCursor(cursor) {
|
|
3248
|
+
if (cursor === void 0 || cursor === null || cursor === "") {
|
|
3249
|
+
return 0;
|
|
3250
|
+
}
|
|
3251
|
+
if (typeof cursor !== "string" || cursor.trim() === "") {
|
|
3252
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
3253
|
+
}
|
|
3254
|
+
let decoded;
|
|
3255
|
+
try {
|
|
3256
|
+
decoded = Buffer.from(cursor, "base64").toString("utf8");
|
|
3257
|
+
} catch {
|
|
3258
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
3259
|
+
}
|
|
3260
|
+
if (!/^\d+$/.test(decoded)) {
|
|
3261
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
3262
|
+
}
|
|
3263
|
+
const offset = Number.parseInt(decoded, 10);
|
|
3264
|
+
if (!Number.isFinite(offset) || offset < 0) {
|
|
3265
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
3266
|
+
}
|
|
3267
|
+
return offset;
|
|
3268
|
+
}
|
|
3269
|
+
function invalidPaginationParams(message) {
|
|
3270
|
+
const error = new Error(message);
|
|
3271
|
+
error.code = -32602;
|
|
3272
|
+
return error;
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
// src/mcp/utils/completion.ts
|
|
3276
|
+
var MAX_COMPLETION_VALUES = 100;
|
|
3277
|
+
function rankCompletionValues(candidates, input) {
|
|
3278
|
+
const unique = [...new Set(candidates.filter(Boolean))];
|
|
3279
|
+
const needle = input.trim().toLowerCase();
|
|
3280
|
+
if (!needle) {
|
|
3281
|
+
return unique.slice(0, MAX_COMPLETION_VALUES);
|
|
3282
|
+
}
|
|
3283
|
+
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);
|
|
3284
|
+
}
|
|
3285
|
+
function scoreCompletionValue(value, needle) {
|
|
3286
|
+
const haystack = value.toLowerCase();
|
|
3287
|
+
if (haystack === needle) return 100;
|
|
3288
|
+
if (haystack.startsWith(needle)) return 75;
|
|
3289
|
+
if (haystack.includes(needle)) return 50;
|
|
3290
|
+
const compactNeedle = needle.replace(/[\s_-]+/g, "");
|
|
3291
|
+
const compactHaystack = haystack.replace(/[\s_-]+/g, "");
|
|
3292
|
+
if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
|
|
3293
|
+
return 0;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
// src/mcp/resources/index.ts
|
|
3297
|
+
var DEFAULT_PAGE_SIZE = 25;
|
|
3298
|
+
var MAX_PAGE_SIZE = 100;
|
|
3299
|
+
function listResources(session, params) {
|
|
3300
|
+
const resources = [
|
|
3301
|
+
{
|
|
3302
|
+
uri: "repository://index",
|
|
3303
|
+
name: "Repository Index",
|
|
3304
|
+
title: "Repository Index",
|
|
3305
|
+
description: "List of all known repositories with memory/task counts and last activity",
|
|
3306
|
+
mimeType: "application/json",
|
|
3307
|
+
annotations: {
|
|
3308
|
+
audience: ["assistant"],
|
|
3309
|
+
priority: 1,
|
|
3310
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3311
|
+
}
|
|
3312
|
+
},
|
|
3313
|
+
{
|
|
3314
|
+
uri: "session://roots",
|
|
3315
|
+
name: "Session Roots",
|
|
3316
|
+
title: "Session Roots",
|
|
3317
|
+
description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
|
|
3318
|
+
mimeType: "application/json",
|
|
3319
|
+
size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
|
|
3320
|
+
annotations: {
|
|
3321
|
+
audience: ["assistant"],
|
|
3322
|
+
priority: 0.95,
|
|
3323
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
];
|
|
3327
|
+
return paginateEntries("resources", resources, params);
|
|
3328
|
+
}
|
|
3329
|
+
function listResourceTemplates(params) {
|
|
3330
|
+
const templates = [
|
|
3331
|
+
// ── Memory ──────────────────────────────────────────────────────────────
|
|
3332
|
+
{
|
|
3333
|
+
uriTemplate: "repository://{name}/memories",
|
|
3334
|
+
name: "Repository Memories",
|
|
3335
|
+
title: "Repository Memories",
|
|
3336
|
+
description: "All active memory entries for a specific repository",
|
|
3337
|
+
mimeType: "application/json",
|
|
3338
|
+
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
3339
|
+
},
|
|
3340
|
+
{
|
|
3341
|
+
uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
|
|
3342
|
+
name: "Filtered Repository Memories",
|
|
3343
|
+
title: "Filtered Repository Memories",
|
|
3344
|
+
description: "Filter or search memories within a repository by keyword, type, or tag",
|
|
3345
|
+
mimeType: "application/json",
|
|
3346
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
3347
|
+
},
|
|
3348
|
+
{
|
|
3349
|
+
uriTemplate: "memory://{id}",
|
|
3350
|
+
name: "Memory Detail",
|
|
3351
|
+
title: "Memory Detail",
|
|
3352
|
+
description: "Full content and statistics for a specific memory UUID",
|
|
3353
|
+
mimeType: "application/json",
|
|
3354
|
+
annotations: { audience: ["assistant"], priority: 0.75 }
|
|
3241
3355
|
},
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
}
|
|
3250
|
-
required: ["memory_id", "status"]
|
|
3356
|
+
// ── Tasks ────────────────────────────────────────────────────────────────
|
|
3357
|
+
{
|
|
3358
|
+
uriTemplate: "repository://{name}/tasks",
|
|
3359
|
+
name: "Repository Tasks",
|
|
3360
|
+
title: "Repository Tasks",
|
|
3361
|
+
description: "All active tasks for a specific repository",
|
|
3362
|
+
mimeType: "application/json",
|
|
3363
|
+
annotations: { audience: ["assistant"], priority: 0.9 }
|
|
3251
3364
|
},
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
}
|
|
3259
|
-
required: ["success", "id", "status"]
|
|
3260
|
-
}
|
|
3261
|
-
},
|
|
3262
|
-
{
|
|
3263
|
-
name: "memory-update",
|
|
3264
|
-
title: "Memory Update",
|
|
3265
|
-
description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
|
|
3266
|
-
annotations: {
|
|
3267
|
-
readOnlyHint: false,
|
|
3268
|
-
idempotentHint: false,
|
|
3269
|
-
destructiveHint: false,
|
|
3270
|
-
openWorldHint: false
|
|
3365
|
+
{
|
|
3366
|
+
uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
|
|
3367
|
+
name: "Filtered Repository Tasks",
|
|
3368
|
+
title: "Filtered Repository Tasks",
|
|
3369
|
+
description: "Filter tasks within a repository by status or priority level",
|
|
3370
|
+
mimeType: "application/json",
|
|
3371
|
+
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
3271
3372
|
},
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
"code_fact",
|
|
3280
|
-
"decision",
|
|
3281
|
-
"mistake",
|
|
3282
|
-
"pattern",
|
|
3283
|
-
"agent_handoff",
|
|
3284
|
-
"agent_registered",
|
|
3285
|
-
"file_claim",
|
|
3286
|
-
"task_archive"
|
|
3287
|
-
]
|
|
3288
|
-
},
|
|
3289
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3290
|
-
content: { type: "string", minLength: 10 },
|
|
3291
|
-
importance: { type: "number", minimum: 1, maximum: 5 },
|
|
3292
|
-
agent: { type: "string" },
|
|
3293
|
-
role: { type: "string" },
|
|
3294
|
-
status: { type: "string", enum: ["active", "archived"] },
|
|
3295
|
-
supersedes: { type: "string", format: "uuid" },
|
|
3296
|
-
tags: { type: "array", items: { type: "string" } },
|
|
3297
|
-
metadata: { type: "object" },
|
|
3298
|
-
is_global: { type: "boolean" },
|
|
3299
|
-
completed_at: { type: "string" },
|
|
3300
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
|
|
3301
|
-
},
|
|
3302
|
-
required: ["id"]
|
|
3373
|
+
{
|
|
3374
|
+
uriTemplate: "task://{id}",
|
|
3375
|
+
name: "Task Detail",
|
|
3376
|
+
title: "Task Detail",
|
|
3377
|
+
description: "Full content and comments for a specific task UUID",
|
|
3378
|
+
mimeType: "application/json",
|
|
3379
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
3303
3380
|
},
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
items: { type: "string" }
|
|
3313
|
-
}
|
|
3314
|
-
},
|
|
3315
|
-
required: ["success", "id", "repo", "updatedFields"]
|
|
3316
|
-
}
|
|
3317
|
-
},
|
|
3318
|
-
{
|
|
3319
|
-
name: "memory-search",
|
|
3320
|
-
title: "Memory Search",
|
|
3321
|
-
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.",
|
|
3322
|
-
annotations: {
|
|
3323
|
-
readOnlyHint: true,
|
|
3324
|
-
idempotentHint: true,
|
|
3325
|
-
openWorldHint: false
|
|
3381
|
+
// ── Repository extras ────────────────────────────────────────────────────
|
|
3382
|
+
{
|
|
3383
|
+
uriTemplate: "repository://{name}/summary",
|
|
3384
|
+
name: "Repository Summary",
|
|
3385
|
+
title: "Repository Summary",
|
|
3386
|
+
description: "High-level architectural summary for a repository",
|
|
3387
|
+
mimeType: "text/plain",
|
|
3388
|
+
annotations: { audience: ["assistant"], priority: 0.95 }
|
|
3326
3389
|
},
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3390
|
+
{
|
|
3391
|
+
uriTemplate: "repository://{name}/actions",
|
|
3392
|
+
name: "Repository Actions",
|
|
3393
|
+
title: "Repository Actions",
|
|
3394
|
+
description: "Audit log of agent tool actions scoped to a repository",
|
|
3395
|
+
mimeType: "application/json",
|
|
3396
|
+
annotations: { audience: ["assistant"], priority: 0.6 }
|
|
3397
|
+
},
|
|
3398
|
+
// ── Action detail ────────────────────────────────────────────────────────
|
|
3399
|
+
{
|
|
3400
|
+
uriTemplate: "action://{id}",
|
|
3401
|
+
name: "Action Detail",
|
|
3402
|
+
title: "Action Detail",
|
|
3403
|
+
description: "Full details of a specific audit log entry by integer ID",
|
|
3404
|
+
mimeType: "application/json",
|
|
3405
|
+
annotations: { audience: ["assistant"], priority: 0.55 }
|
|
3406
|
+
}
|
|
3407
|
+
];
|
|
3408
|
+
return paginateEntries("resourceTemplates", templates, params);
|
|
3409
|
+
}
|
|
3410
|
+
function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
|
|
3411
|
+
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") {
|
|
3412
|
+
if (argumentName === "name") {
|
|
3413
|
+
return rankCompletionValues(dataSources.repos, argumentValue);
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
|
|
3417
|
+
if (argumentName === "tag") {
|
|
3418
|
+
return rankCompletionValues(dataSources.tags, argumentValue);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
|
|
3422
|
+
}
|
|
3423
|
+
function readResource(uri, db, session) {
|
|
3424
|
+
logger.info("[Tool] resource.read", { uri });
|
|
3425
|
+
if (uri === "repository://index") {
|
|
3426
|
+
const repos = db.system.listRepoNavigation();
|
|
3427
|
+
const payload = JSON.stringify(repos, null, 2);
|
|
3428
|
+
return {
|
|
3429
|
+
contents: [
|
|
3430
|
+
{
|
|
3431
|
+
uri,
|
|
3432
|
+
mimeType: "application/json",
|
|
3433
|
+
text: payload,
|
|
3434
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3435
|
+
annotations: {
|
|
3436
|
+
audience: ["assistant"],
|
|
3437
|
+
priority: 1,
|
|
3438
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3352
3439
|
}
|
|
3353
|
-
}
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3440
|
+
}
|
|
3441
|
+
]
|
|
3442
|
+
};
|
|
3443
|
+
}
|
|
3444
|
+
if (uri === "session://roots") {
|
|
3445
|
+
const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
|
|
3446
|
+
return {
|
|
3447
|
+
contents: [
|
|
3448
|
+
{
|
|
3449
|
+
uri,
|
|
3450
|
+
mimeType: "application/json",
|
|
3451
|
+
text: payload,
|
|
3452
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3453
|
+
annotations: {
|
|
3454
|
+
audience: ["assistant"],
|
|
3455
|
+
priority: 0.95,
|
|
3456
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
]
|
|
3460
|
+
};
|
|
3461
|
+
}
|
|
3462
|
+
const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
|
|
3463
|
+
if (memoryIdMatch) {
|
|
3464
|
+
const id = memoryIdMatch[1];
|
|
3465
|
+
const entry = db.memories.getByIdWithStats(id);
|
|
3466
|
+
if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
|
|
3467
|
+
const payload = JSON.stringify(entry, null, 2);
|
|
3468
|
+
return {
|
|
3469
|
+
contents: [
|
|
3470
|
+
{
|
|
3471
|
+
uri,
|
|
3472
|
+
mimeType: "application/json",
|
|
3473
|
+
text: payload,
|
|
3474
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3475
|
+
annotations: {
|
|
3476
|
+
audience: ["assistant"],
|
|
3477
|
+
priority: 0.75,
|
|
3478
|
+
lastModified: entry.updated_at || entry.created_at
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
]
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
|
|
3485
|
+
if (taskIdMatch) {
|
|
3486
|
+
const id = taskIdMatch[1];
|
|
3487
|
+
const task = db.tasks.getTaskById(id);
|
|
3488
|
+
if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
|
|
3489
|
+
const payload = JSON.stringify(task, null, 2);
|
|
3490
|
+
return {
|
|
3491
|
+
contents: [
|
|
3492
|
+
{
|
|
3493
|
+
uri,
|
|
3494
|
+
mimeType: "application/json",
|
|
3495
|
+
text: payload,
|
|
3496
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3497
|
+
annotations: {
|
|
3498
|
+
audience: ["assistant"],
|
|
3499
|
+
priority: 0.8,
|
|
3500
|
+
lastModified: task.updated_at || task.created_at
|
|
3367
3501
|
}
|
|
3368
|
-
},
|
|
3369
|
-
structured: {
|
|
3370
|
-
type: "boolean",
|
|
3371
|
-
default: false,
|
|
3372
|
-
description: "If true, returns structured JSON without the text content summary."
|
|
3373
3502
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
rows: {
|
|
3395
|
-
type: "array",
|
|
3396
|
-
items: { type: "array" },
|
|
3397
|
-
description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
|
|
3503
|
+
]
|
|
3504
|
+
};
|
|
3505
|
+
}
|
|
3506
|
+
const repoBase = parseRepoUri(uri);
|
|
3507
|
+
if (repoBase) {
|
|
3508
|
+
const { name, path: repoPath, query } = repoBase;
|
|
3509
|
+
if (repoPath === "summary") {
|
|
3510
|
+
const summary = db.summaries.getSummary(name);
|
|
3511
|
+
const text = summary?.summary || `No summary available for repository: ${name}`;
|
|
3512
|
+
return {
|
|
3513
|
+
contents: [
|
|
3514
|
+
{
|
|
3515
|
+
uri,
|
|
3516
|
+
mimeType: "text/plain",
|
|
3517
|
+
text,
|
|
3518
|
+
size: Buffer.byteLength(text, "utf8"),
|
|
3519
|
+
annotations: {
|
|
3520
|
+
audience: ["assistant"],
|
|
3521
|
+
priority: 0.95,
|
|
3522
|
+
lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
3398
3523
|
}
|
|
3399
|
-
}
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
},
|
|
3403
|
-
required: ["schema", "query", "count", "total", "offset", "limit", "results"]
|
|
3524
|
+
}
|
|
3525
|
+
]
|
|
3526
|
+
};
|
|
3404
3527
|
}
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
signalCount: { type: "number" }
|
|
3436
|
-
},
|
|
3437
|
-
required: ["success", "repo", "summary", "signalCount"]
|
|
3528
|
+
if (repoPath === "memories") {
|
|
3529
|
+
const search = query.get("search") || "";
|
|
3530
|
+
const type = query.get("type");
|
|
3531
|
+
const tag = query.get("tag");
|
|
3532
|
+
const result = db.memories.listMemoriesForDashboard({
|
|
3533
|
+
repo: name,
|
|
3534
|
+
type: type || void 0,
|
|
3535
|
+
tag: tag || void 0,
|
|
3536
|
+
search: search || void 0,
|
|
3537
|
+
limit: 50
|
|
3538
|
+
});
|
|
3539
|
+
const entries = result.items;
|
|
3540
|
+
const payload = JSON.stringify(entries, null, 2);
|
|
3541
|
+
return {
|
|
3542
|
+
contents: [
|
|
3543
|
+
{
|
|
3544
|
+
uri,
|
|
3545
|
+
mimeType: "application/json",
|
|
3546
|
+
text: payload,
|
|
3547
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3548
|
+
annotations: {
|
|
3549
|
+
audience: ["assistant"],
|
|
3550
|
+
priority: 0.85,
|
|
3551
|
+
lastModified: deriveLastModifiedFromCollection(
|
|
3552
|
+
entries.map((e) => e.updated_at || e.created_at)
|
|
3553
|
+
)
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
]
|
|
3557
|
+
};
|
|
3438
3558
|
}
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
openWorldHint: false
|
|
3449
|
-
},
|
|
3450
|
-
inputSchema: {
|
|
3451
|
-
type: "object",
|
|
3452
|
-
properties: {
|
|
3453
|
-
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
3454
|
-
id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
|
|
3455
|
-
ids: {
|
|
3456
|
-
type: "array",
|
|
3457
|
-
items: { type: "string", format: "uuid" },
|
|
3458
|
-
minItems: 1,
|
|
3459
|
-
description: "Array of memory IDs to delete"
|
|
3460
|
-
},
|
|
3461
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3559
|
+
if (repoPath === "tasks") {
|
|
3560
|
+
const status = query.get("status");
|
|
3561
|
+
const priority = query.get("priority");
|
|
3562
|
+
let tasks;
|
|
3563
|
+
if (status && status !== "all") {
|
|
3564
|
+
const statuses = status.split(",").map((s) => s.trim());
|
|
3565
|
+
tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
|
|
3566
|
+
} else {
|
|
3567
|
+
tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
|
|
3462
3568
|
}
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
success: { type: "boolean" },
|
|
3468
|
-
id: { type: "string" },
|
|
3469
|
-
ids: { type: "array", items: { type: "string" } },
|
|
3470
|
-
repo: { type: "string" },
|
|
3471
|
-
deletedCount: { type: "number" }
|
|
3472
|
-
},
|
|
3473
|
-
required: ["success"]
|
|
3474
|
-
}
|
|
3475
|
-
},
|
|
3476
|
-
{
|
|
3477
|
-
name: "memory-recap",
|
|
3478
|
-
title: "Memory Recap",
|
|
3479
|
-
description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
|
|
3480
|
-
annotations: {
|
|
3481
|
-
readOnlyHint: true,
|
|
3482
|
-
idempotentHint: true,
|
|
3483
|
-
openWorldHint: false
|
|
3484
|
-
},
|
|
3485
|
-
inputSchema: {
|
|
3486
|
-
type: "object",
|
|
3487
|
-
properties: {
|
|
3488
|
-
repo: { type: "string", description: "Repository name (required)" },
|
|
3489
|
-
limit: {
|
|
3490
|
-
type: "number",
|
|
3491
|
-
minimum: 1,
|
|
3492
|
-
maximum: 50,
|
|
3493
|
-
default: 20,
|
|
3494
|
-
description: "Maximum number of top memories to return in the pointer table"
|
|
3495
|
-
},
|
|
3496
|
-
offset: {
|
|
3497
|
-
type: "number",
|
|
3498
|
-
minimum: 0,
|
|
3499
|
-
default: 0,
|
|
3500
|
-
description: "Number of memories to skip for pagination (optional, default 0)"
|
|
3501
|
-
},
|
|
3502
|
-
structured: {
|
|
3503
|
-
type: "boolean",
|
|
3504
|
-
default: false,
|
|
3505
|
-
description: "If true, returns structured JSON without the text content summary."
|
|
3569
|
+
if (priority) {
|
|
3570
|
+
const p = Number(priority);
|
|
3571
|
+
if (!isNaN(p)) {
|
|
3572
|
+
tasks = tasks.filter((t) => t.priority === p);
|
|
3506
3573
|
}
|
|
3507
|
-
}
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
type: "object",
|
|
3521
|
-
properties: {
|
|
3522
|
-
by_type: {
|
|
3523
|
-
type: "object",
|
|
3524
|
-
description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
|
|
3525
|
-
}
|
|
3526
|
-
},
|
|
3527
|
-
required: ["by_type"]
|
|
3528
|
-
},
|
|
3529
|
-
top: {
|
|
3530
|
-
type: "object",
|
|
3531
|
-
properties: {
|
|
3532
|
-
columns: {
|
|
3533
|
-
type: "array",
|
|
3534
|
-
items: { type: "string" },
|
|
3535
|
-
description: "Column names: [id, title, type, importance]"
|
|
3536
|
-
},
|
|
3537
|
-
rows: {
|
|
3538
|
-
type: "array",
|
|
3539
|
-
items: { type: "array" },
|
|
3540
|
-
description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
|
|
3574
|
+
}
|
|
3575
|
+
const payload = JSON.stringify(tasks, null, 2);
|
|
3576
|
+
return {
|
|
3577
|
+
contents: [
|
|
3578
|
+
{
|
|
3579
|
+
uri,
|
|
3580
|
+
mimeType: "application/json",
|
|
3581
|
+
text: payload,
|
|
3582
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3583
|
+
annotations: {
|
|
3584
|
+
audience: ["assistant"],
|
|
3585
|
+
priority: 0.9,
|
|
3586
|
+
lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
|
|
3541
3587
|
}
|
|
3542
|
-
}
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
},
|
|
3546
|
-
required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
|
|
3547
|
-
}
|
|
3548
|
-
},
|
|
3549
|
-
{
|
|
3550
|
-
name: "task-create",
|
|
3551
|
-
title: "Task Create",
|
|
3552
|
-
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.",
|
|
3553
|
-
annotations: {
|
|
3554
|
-
readOnlyHint: false,
|
|
3555
|
-
idempotentHint: false,
|
|
3556
|
-
openWorldHint: false
|
|
3557
|
-
},
|
|
3558
|
-
inputSchema: {
|
|
3559
|
-
type: "object",
|
|
3560
|
-
properties: {
|
|
3561
|
-
repo: { type: "string", description: "Repository name" },
|
|
3562
|
-
task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
|
|
3563
|
-
phase: { type: "string", description: "Project phase (Required for single task)" },
|
|
3564
|
-
title: {
|
|
3565
|
-
type: "string",
|
|
3566
|
-
minLength: 3,
|
|
3567
|
-
maxLength: 100,
|
|
3568
|
-
description: "Task objective (Required for single task)"
|
|
3569
|
-
},
|
|
3570
|
-
description: { type: "string", description: "Detailed description (Required for single task)" },
|
|
3571
|
-
status: {
|
|
3572
|
-
type: "string",
|
|
3573
|
-
enum: ["backlog", "pending"],
|
|
3574
|
-
default: "backlog",
|
|
3575
|
-
description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
|
|
3576
|
-
},
|
|
3577
|
-
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3578
|
-
agent: { type: "string" },
|
|
3579
|
-
role: { type: "string" },
|
|
3580
|
-
doc_path: { type: "string" },
|
|
3581
|
-
tags: { type: "array", items: { type: "string" } },
|
|
3582
|
-
metadata: { type: "object" },
|
|
3583
|
-
parent_id: { type: "string", format: "uuid" },
|
|
3584
|
-
depends_on: { type: "string", format: "uuid" },
|
|
3585
|
-
est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
|
|
3586
|
-
tasks: {
|
|
3587
|
-
type: "array",
|
|
3588
|
-
items: {
|
|
3589
|
-
type: "object",
|
|
3590
|
-
properties: {
|
|
3591
|
-
task_code: { type: "string" },
|
|
3592
|
-
phase: { type: "string" },
|
|
3593
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3594
|
-
description: { type: "string" },
|
|
3595
|
-
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3596
|
-
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3597
|
-
agent: { type: "string" },
|
|
3598
|
-
role: { type: "string" },
|
|
3599
|
-
doc_path: { type: "string" },
|
|
3600
|
-
tags: { type: "array", items: { type: "string" } },
|
|
3601
|
-
metadata: { type: "object" },
|
|
3602
|
-
parent_id: { type: "string", format: "uuid" },
|
|
3603
|
-
depends_on: { type: "string", format: "uuid" },
|
|
3604
|
-
est_tokens: { type: "number", minimum: 0 }
|
|
3605
|
-
},
|
|
3606
|
-
required: ["task_code", "phase", "title", "description"]
|
|
3607
|
-
},
|
|
3608
|
-
description: "Array of tasks for bulk creation"
|
|
3609
|
-
},
|
|
3610
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3611
|
-
},
|
|
3612
|
-
required: ["repo"]
|
|
3613
|
-
},
|
|
3614
|
-
outputSchema: {
|
|
3615
|
-
type: "object",
|
|
3616
|
-
properties: {
|
|
3617
|
-
success: { type: "boolean" },
|
|
3618
|
-
id: { type: "string" },
|
|
3619
|
-
task_code: { type: "string" },
|
|
3620
|
-
repo: { type: "string" },
|
|
3621
|
-
phase: { type: "string" },
|
|
3622
|
-
title: { type: "string" },
|
|
3623
|
-
status: { type: "string" },
|
|
3624
|
-
priority: { type: "number" },
|
|
3625
|
-
createdCount: { type: "number" },
|
|
3626
|
-
taskCodes: { type: "array", items: { type: "string" } }
|
|
3627
|
-
},
|
|
3628
|
-
required: ["success", "repo"]
|
|
3588
|
+
}
|
|
3589
|
+
]
|
|
3590
|
+
};
|
|
3629
3591
|
}
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3649
|
-
description: { type: "string" },
|
|
3650
|
-
status: {
|
|
3651
|
-
type: "string",
|
|
3652
|
-
enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
|
|
3653
|
-
description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
|
|
3654
|
-
},
|
|
3655
|
-
priority: { type: "number", minimum: 1, maximum: 5 },
|
|
3656
|
-
agent: { type: "string" },
|
|
3657
|
-
role: { type: "string" },
|
|
3658
|
-
model: { type: "string" },
|
|
3659
|
-
comment: {
|
|
3660
|
-
type: "string",
|
|
3661
|
-
description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
|
|
3662
|
-
},
|
|
3663
|
-
doc_path: { type: "string" },
|
|
3664
|
-
tags: { type: "array", items: { type: "string" } },
|
|
3665
|
-
metadata: { type: "object" },
|
|
3666
|
-
parent_id: { type: "string", format: "uuid" },
|
|
3667
|
-
depends_on: { type: "string", format: "uuid" },
|
|
3668
|
-
est_tokens: {
|
|
3669
|
-
type: "number",
|
|
3670
|
-
minimum: 0,
|
|
3671
|
-
description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
|
|
3672
|
-
},
|
|
3673
|
-
force: {
|
|
3674
|
-
type: "boolean",
|
|
3675
|
-
description: "If true, bypasses status transition validation (e.g. pending -> completed)."
|
|
3676
|
-
},
|
|
3677
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3678
|
-
},
|
|
3679
|
-
required: ["repo"]
|
|
3680
|
-
},
|
|
3681
|
-
outputSchema: {
|
|
3682
|
-
type: "object",
|
|
3683
|
-
properties: {
|
|
3684
|
-
success: { type: "boolean" },
|
|
3685
|
-
id: { type: "string" },
|
|
3686
|
-
ids: { type: "array", items: { type: "string" } },
|
|
3687
|
-
repo: { type: "string" },
|
|
3688
|
-
status: { type: "string" },
|
|
3689
|
-
archivedToMemory: { type: "boolean" },
|
|
3690
|
-
updatedFields: {
|
|
3691
|
-
type: "array",
|
|
3692
|
-
items: { type: "string" }
|
|
3693
|
-
},
|
|
3694
|
-
updatedCount: { type: "number" }
|
|
3695
|
-
},
|
|
3696
|
-
required: ["success", "repo"]
|
|
3592
|
+
if (repoPath === "actions") {
|
|
3593
|
+
const actions = db.actions.getRecentActions(name, 100);
|
|
3594
|
+
const payload = JSON.stringify(actions, null, 2);
|
|
3595
|
+
return {
|
|
3596
|
+
contents: [
|
|
3597
|
+
{
|
|
3598
|
+
uri,
|
|
3599
|
+
mimeType: "application/json",
|
|
3600
|
+
text: payload,
|
|
3601
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3602
|
+
annotations: {
|
|
3603
|
+
audience: ["assistant"],
|
|
3604
|
+
priority: 0.6,
|
|
3605
|
+
lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
]
|
|
3609
|
+
};
|
|
3697
3610
|
}
|
|
3698
|
-
}
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3611
|
+
}
|
|
3612
|
+
const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
|
|
3613
|
+
if (actionIdMatch) {
|
|
3614
|
+
const id = Number(actionIdMatch[1]);
|
|
3615
|
+
const action = db.actions.getActionById(id);
|
|
3616
|
+
if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
|
|
3617
|
+
const payload = JSON.stringify(action, null, 2);
|
|
3618
|
+
return {
|
|
3619
|
+
contents: [
|
|
3620
|
+
{
|
|
3621
|
+
uri,
|
|
3622
|
+
mimeType: "application/json",
|
|
3623
|
+
text: payload,
|
|
3624
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
3625
|
+
annotations: {
|
|
3626
|
+
audience: ["assistant"],
|
|
3627
|
+
priority: 0.55,
|
|
3628
|
+
lastModified: action.created_at
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
]
|
|
3632
|
+
};
|
|
3633
|
+
}
|
|
3634
|
+
throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
|
|
3635
|
+
}
|
|
3636
|
+
function parseRepoUri(uri) {
|
|
3637
|
+
const prefix = "repository://";
|
|
3638
|
+
if (!uri.startsWith(prefix)) return null;
|
|
3639
|
+
const rest = uri.slice(prefix.length);
|
|
3640
|
+
const queryStart = rest.indexOf("?");
|
|
3641
|
+
const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
|
|
3642
|
+
const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
|
|
3643
|
+
const slashIdx = withoutQuery.indexOf("/");
|
|
3644
|
+
if (slashIdx === -1) return null;
|
|
3645
|
+
const name = withoutQuery.slice(0, slashIdx);
|
|
3646
|
+
const path6 = withoutQuery.slice(slashIdx + 1);
|
|
3647
|
+
if (!name || !path6) return null;
|
|
3648
|
+
return { name, path: path6, query: new URLSearchParams(queryString) };
|
|
3649
|
+
}
|
|
3650
|
+
function paginateEntries(key, entries, params) {
|
|
3651
|
+
const limit = normalizeLimit(params?.limit);
|
|
3652
|
+
const offset = decodeCursor(params?.cursor);
|
|
3653
|
+
const sliced = entries.slice(offset, offset + limit);
|
|
3654
|
+
const nextOffset = offset + sliced.length;
|
|
3655
|
+
return {
|
|
3656
|
+
[key]: sliced,
|
|
3657
|
+
nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
|
|
3658
|
+
};
|
|
3659
|
+
}
|
|
3660
|
+
function normalizeLimit(limit) {
|
|
3661
|
+
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
3662
|
+
return DEFAULT_PAGE_SIZE;
|
|
3663
|
+
}
|
|
3664
|
+
return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
|
|
3665
|
+
}
|
|
3666
|
+
function deriveLastModifiedFromCollection(values) {
|
|
3667
|
+
const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
|
|
3668
|
+
return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3669
|
+
}
|
|
3670
|
+
function resourceNotFound(message, uri) {
|
|
3671
|
+
const error = new Error(message);
|
|
3672
|
+
error.code = -32002;
|
|
3673
|
+
error.data = { uri };
|
|
3674
|
+
return error;
|
|
3675
|
+
}
|
|
3676
|
+
function invalidCompletionParams(message) {
|
|
3677
|
+
const error = new Error(message);
|
|
3678
|
+
error.code = -32602;
|
|
3679
|
+
return error;
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
// src/mcp/prompts/loader.ts
|
|
3683
|
+
import fs4 from "fs";
|
|
3684
|
+
import path5 from "path";
|
|
3685
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3686
|
+
import matter from "gray-matter";
|
|
3687
|
+
var __filename = fileURLToPath3(import.meta.url);
|
|
3688
|
+
var __dirname2 = path5.dirname(__filename);
|
|
3689
|
+
function findPromptDir() {
|
|
3690
|
+
const candidates = [
|
|
3691
|
+
// Production if chunked into dist/
|
|
3692
|
+
"./prompts",
|
|
3693
|
+
// Production if inlined into dist/mcp/
|
|
3694
|
+
"../prompts",
|
|
3695
|
+
// Dev: /src/mcp/prompts/definitions (next to loader.ts)
|
|
3696
|
+
"./definitions"
|
|
3697
|
+
].map((relPath) => path5.resolve(__dirname2, relPath));
|
|
3698
|
+
for (const dir of candidates) {
|
|
3699
|
+
if (fs4.existsSync(dir)) {
|
|
3700
|
+
const files = fs4.readdirSync(dir);
|
|
3701
|
+
if (files.some((f) => f.endsWith(".md"))) {
|
|
3702
|
+
return dir;
|
|
3703
|
+
}
|
|
3729
3704
|
}
|
|
3730
|
-
}
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
offset: {
|
|
3768
|
-
type: "number",
|
|
3769
|
-
minimum: 0,
|
|
3770
|
-
default: 0,
|
|
3771
|
-
description: "Offset for pagination"
|
|
3772
|
-
},
|
|
3773
|
-
structured: {
|
|
3774
|
-
type: "boolean",
|
|
3775
|
-
default: false,
|
|
3776
|
-
description: "If true, returns structured JSON without the text content summary."
|
|
3705
|
+
}
|
|
3706
|
+
return path5.resolve(__dirname2, "./definitions");
|
|
3707
|
+
}
|
|
3708
|
+
var PROMPT_DIR = findPromptDir();
|
|
3709
|
+
function listPromptFiles() {
|
|
3710
|
+
if (!fs4.existsSync(PROMPT_DIR)) return [];
|
|
3711
|
+
return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
|
|
3712
|
+
}
|
|
3713
|
+
function loadPromptFromMarkdown(name) {
|
|
3714
|
+
const filePath = path5.join(PROMPT_DIR, `${name}.md`);
|
|
3715
|
+
if (!fs4.existsSync(filePath)) {
|
|
3716
|
+
throw new Error(`Prompt file not found: ${filePath}`);
|
|
3717
|
+
}
|
|
3718
|
+
const fileContent = fs4.readFileSync(filePath, "utf-8");
|
|
3719
|
+
const { data, content } = matter(fileContent);
|
|
3720
|
+
return {
|
|
3721
|
+
name: data.name || name,
|
|
3722
|
+
description: data.description || "",
|
|
3723
|
+
arguments: data.arguments || [],
|
|
3724
|
+
agent: data.agent,
|
|
3725
|
+
content: content.trim()
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3729
|
+
// src/mcp/prompts/registry.ts
|
|
3730
|
+
function createPromptDefinition(loaded) {
|
|
3731
|
+
return {
|
|
3732
|
+
name: loaded.name,
|
|
3733
|
+
description: loaded.description,
|
|
3734
|
+
arguments: loaded.arguments,
|
|
3735
|
+
agent: loaded.agent,
|
|
3736
|
+
messages: [
|
|
3737
|
+
{
|
|
3738
|
+
role: "user",
|
|
3739
|
+
content: {
|
|
3740
|
+
type: "text",
|
|
3741
|
+
text: loaded.content
|
|
3777
3742
|
}
|
|
3778
|
-
}
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3743
|
+
}
|
|
3744
|
+
]
|
|
3745
|
+
};
|
|
3746
|
+
}
|
|
3747
|
+
var PROMPTS = {};
|
|
3748
|
+
var promptFiles = listPromptFiles();
|
|
3749
|
+
for (const name of promptFiles) {
|
|
3750
|
+
try {
|
|
3751
|
+
PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
|
|
3752
|
+
} catch (e) {
|
|
3753
|
+
logger.warn(`Failed to load prompt ${name}: ${e}`);
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
async function listPrompts(db, session, params) {
|
|
3757
|
+
const allPrompts = Object.values(PROMPTS).map((p) => ({
|
|
3758
|
+
name: p.name,
|
|
3759
|
+
description: p.description,
|
|
3760
|
+
arguments: p.arguments,
|
|
3761
|
+
metadata: p.agent ? { agent: p.agent } : void 0
|
|
3762
|
+
}));
|
|
3763
|
+
const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
|
|
3764
|
+
const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
|
|
3765
|
+
const offset = decodeCursor(params?.cursor);
|
|
3766
|
+
const sliced = allPrompts.slice(offset, offset + limit);
|
|
3767
|
+
const nextOffset = offset + sliced.length;
|
|
3768
|
+
return {
|
|
3769
|
+
prompts: sliced,
|
|
3770
|
+
nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
|
|
3771
|
+
};
|
|
3772
|
+
}
|
|
3773
|
+
async function getPrompt(name, args = {}, db, session) {
|
|
3774
|
+
const prompt = PROMPTS[name];
|
|
3775
|
+
if (!prompt) {
|
|
3776
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
3777
|
+
}
|
|
3778
|
+
const inferredRepo = inferRepoFromSession(session);
|
|
3779
|
+
const messages = prompt.messages.map((m) => {
|
|
3780
|
+
let text = m.content.text;
|
|
3781
|
+
for (const [key, value] of Object.entries(args)) {
|
|
3782
|
+
text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
|
|
3805
3783
|
}
|
|
3784
|
+
text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
|
|
3785
|
+
return {
|
|
3786
|
+
...m,
|
|
3787
|
+
content: {
|
|
3788
|
+
...m.content,
|
|
3789
|
+
text
|
|
3790
|
+
}
|
|
3791
|
+
};
|
|
3792
|
+
});
|
|
3793
|
+
return {
|
|
3794
|
+
description: prompt.description,
|
|
3795
|
+
messages,
|
|
3796
|
+
metadata: prompt.agent ? { agent: prompt.agent } : void 0
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
|
|
3800
|
+
void name;
|
|
3801
|
+
void contextArguments;
|
|
3802
|
+
if (argName === "task_id") {
|
|
3803
|
+
const values = dataSources.tasks.map((t) => t.id);
|
|
3804
|
+
return rankCompletionValues(values, value);
|
|
3806
3805
|
}
|
|
3807
|
-
];
|
|
3806
|
+
return [];
|
|
3807
|
+
}
|
|
3808
3808
|
|
|
3809
3809
|
export {
|
|
3810
|
+
MCP_PROTOCOL_VERSION,
|
|
3811
|
+
CAPABILITIES,
|
|
3810
3812
|
logger,
|
|
3811
3813
|
setLogLevel,
|
|
3812
3814
|
getLogLevel,
|
|
3813
3815
|
addLogSink,
|
|
3814
3816
|
LOG_LEVEL_VALUES,
|
|
3815
3817
|
createFileSink,
|
|
3816
|
-
encodeCursor,
|
|
3817
|
-
decodeCursor,
|
|
3818
|
-
listResources,
|
|
3819
|
-
listResourceTemplates,
|
|
3820
|
-
completeResourceArgument,
|
|
3821
|
-
readResource,
|
|
3822
|
-
createSessionContext,
|
|
3823
|
-
updateSessionFromInitialize,
|
|
3824
|
-
updateSessionRoots,
|
|
3825
|
-
extractRootsFromResult,
|
|
3826
|
-
getFilesystemRoots,
|
|
3827
|
-
isPathWithinRoots,
|
|
3828
|
-
findContainingRoot,
|
|
3829
|
-
inferRepoFromSession,
|
|
3830
|
-
PROMPTS,
|
|
3831
|
-
listPrompts,
|
|
3832
|
-
getPrompt,
|
|
3833
|
-
completePromptArgument,
|
|
3834
3818
|
normalizeRepo,
|
|
3819
|
+
SQLiteStore,
|
|
3835
3820
|
MemoryStoreSchema,
|
|
3836
3821
|
MemoryUpdateSchema,
|
|
3837
3822
|
MemorySearchSchema,
|
|
@@ -3848,7 +3833,22 @@ export {
|
|
|
3848
3833
|
MemoryDetailSchema,
|
|
3849
3834
|
TaskGetSchema,
|
|
3850
3835
|
TOOL_DEFINITIONS,
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3836
|
+
encodeCursor,
|
|
3837
|
+
decodeCursor,
|
|
3838
|
+
listResources,
|
|
3839
|
+
listResourceTemplates,
|
|
3840
|
+
completeResourceArgument,
|
|
3841
|
+
readResource,
|
|
3842
|
+
createSessionContext,
|
|
3843
|
+
updateSessionFromInitialize,
|
|
3844
|
+
updateSessionRoots,
|
|
3845
|
+
extractRootsFromResult,
|
|
3846
|
+
getFilesystemRoots,
|
|
3847
|
+
isPathWithinRoots,
|
|
3848
|
+
findContainingRoot,
|
|
3849
|
+
inferRepoFromSession,
|
|
3850
|
+
PROMPTS,
|
|
3851
|
+
listPrompts,
|
|
3852
|
+
getPrompt,
|
|
3853
|
+
completePromptArgument
|
|
3854
3854
|
};
|