@vheins/local-memory-mcp 0.9.4 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,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.9.6") {
|
|
7
|
+
pkgVersion = "0.9.6";
|
|
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-03-26";
|
|
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";
|
|
@@ -690,6 +634,15 @@ var MigrationManager = class {
|
|
|
690
634
|
this.run("CREATE INDEX IF NOT EXISTS idx_memories_repo_code ON memories(repo, code)");
|
|
691
635
|
}
|
|
692
636
|
}
|
|
637
|
+
addStandardCodeColumn() {
|
|
638
|
+
const tableInfo = this.all("PRAGMA table_info(coding_standards)");
|
|
639
|
+
const hasCode = tableInfo.some((col) => col.name === "code");
|
|
640
|
+
if (!hasCode) {
|
|
641
|
+
this.run("ALTER TABLE coding_standards ADD COLUMN code TEXT");
|
|
642
|
+
this.run("CREATE INDEX IF NOT EXISTS idx_coding_standards_code ON coding_standards(code)");
|
|
643
|
+
this.run("CREATE INDEX IF NOT EXISTS idx_coding_standards_repo_code ON coding_standards(repo, code)");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
693
646
|
};
|
|
694
647
|
|
|
695
648
|
// src/mcp/utils/stopwords.ts
|
|
@@ -2171,11 +2124,12 @@ var StandardEntity = class extends BaseEntity {
|
|
|
2171
2124
|
insert(entry) {
|
|
2172
2125
|
this.run(
|
|
2173
2126
|
`INSERT INTO coding_standards (
|
|
2174
|
-
id, title, content, parent_id, context, version, language, stack,
|
|
2127
|
+
id, code, title, content, parent_id, context, version, language, stack,
|
|
2175
2128
|
is_global, repo, tags, metadata, created_at, updated_at, hit_count, last_used_at, agent, model
|
|
2176
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2129
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2177
2130
|
[
|
|
2178
2131
|
entry.id,
|
|
2132
|
+
entry.code ?? null,
|
|
2179
2133
|
entry.title,
|
|
2180
2134
|
entry.content,
|
|
2181
2135
|
entry.parent_id,
|
|
@@ -2200,6 +2154,10 @@ var StandardEntity = class extends BaseEntity {
|
|
|
2200
2154
|
const row = this.get("SELECT * FROM coding_standards WHERE id = ?", [id]);
|
|
2201
2155
|
return row ? this.rowToEntry(row) : null;
|
|
2202
2156
|
}
|
|
2157
|
+
getByCode(code) {
|
|
2158
|
+
const row = this.get("SELECT * FROM coding_standards WHERE code = ?", [code]);
|
|
2159
|
+
return row ? this.rowToEntry(row) : null;
|
|
2160
|
+
}
|
|
2203
2161
|
search(options) {
|
|
2204
2162
|
const { query, context, version, language, stack, tag, repo, is_global, limit = 20, offset = 0 } = options;
|
|
2205
2163
|
const where = [];
|
|
@@ -2270,6 +2228,38 @@ var StandardEntity = class extends BaseEntity {
|
|
|
2270
2228
|
return { ...standard, similarity };
|
|
2271
2229
|
}).sort((a, b) => b.similarity - a.similarity);
|
|
2272
2230
|
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Check if a new coding standard's content conflicts with an existing one.
|
|
2233
|
+
*
|
|
2234
|
+
* Returns the first conflicting entry whose cosine similarity exceeds `threshold`.
|
|
2235
|
+
* A conflict is SKIPPED (returns null) when the incoming version differs from
|
|
2236
|
+
* the conflicting entry's version — this allows intentional version bumps.
|
|
2237
|
+
*
|
|
2238
|
+
* @param content Raw content of the new standard to check.
|
|
2239
|
+
* @param incomingVersion Version of the new standard (e.g. "2.0.0").
|
|
2240
|
+
* @param repo Repo filter; pass undefined for global standards.
|
|
2241
|
+
* @param threshold Cosine-similarity cutoff (default 0.82 — stricter than memory).
|
|
2242
|
+
*/
|
|
2243
|
+
checkConflicts(content, incomingVersion, repo, incomingLanguage, incomingStack, threshold = 0.82) {
|
|
2244
|
+
const candidates = this.search({ repo, limit: 80, offset: 0 });
|
|
2245
|
+
if (candidates.length === 0) return null;
|
|
2246
|
+
const queryVector = this.computeVector(content);
|
|
2247
|
+
for (const standard of candidates) {
|
|
2248
|
+
const similarity = this.cosineSimilarity(queryVector, this.computeVector(standard.content));
|
|
2249
|
+
if (similarity < threshold) continue;
|
|
2250
|
+
if (incomingVersion && standard.version && incomingVersion !== standard.version) {
|
|
2251
|
+
continue;
|
|
2252
|
+
}
|
|
2253
|
+
if (incomingLanguage && standard.language && incomingLanguage !== standard.language) {
|
|
2254
|
+
continue;
|
|
2255
|
+
}
|
|
2256
|
+
if (incomingStack.length > 0 && standard.stack.length > 0 && !incomingStack.some((s) => standard.stack.includes(s))) {
|
|
2257
|
+
continue;
|
|
2258
|
+
}
|
|
2259
|
+
return { ...standard, similarity };
|
|
2260
|
+
}
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2273
2263
|
getByIds(ids) {
|
|
2274
2264
|
if (ids.length === 0) return [];
|
|
2275
2265
|
const placeholders = ids.map(() => "?").join(",");
|
|
@@ -2346,6 +2336,7 @@ var StandardEntity = class extends BaseEntity {
|
|
|
2346
2336
|
rowToEntry(row) {
|
|
2347
2337
|
return {
|
|
2348
2338
|
id: row.id,
|
|
2339
|
+
code: row.code ?? void 0,
|
|
2349
2340
|
title: row.title,
|
|
2350
2341
|
content: row.content,
|
|
2351
2342
|
parent_id: row.parent_id ?? null,
|
|
@@ -2638,6 +2629,7 @@ var SQLiteStore = class _SQLiteStore {
|
|
|
2638
2629
|
const migrator = new MigrationManager(this.db);
|
|
2639
2630
|
migrator.migrate();
|
|
2640
2631
|
migrator.addMemoryCodeColumn();
|
|
2632
|
+
migrator.addStandardCodeColumn();
|
|
2641
2633
|
this.memories = new MemoryEntity(this.db);
|
|
2642
2634
|
this.tasks = new TaskEntity(this.db);
|
|
2643
2635
|
this.actions = new ActionEntity(this.db);
|
|
@@ -2797,7 +2789,8 @@ var RealVectorStore = class {
|
|
|
2797
2789
|
throw error;
|
|
2798
2790
|
}
|
|
2799
2791
|
}
|
|
2800
|
-
async remove(id,
|
|
2792
|
+
async remove(id, kind = "memory") {
|
|
2793
|
+
void kind;
|
|
2801
2794
|
if (!id) return;
|
|
2802
2795
|
}
|
|
2803
2796
|
async search(query, limit, repo, kind = "memory") {
|
|
@@ -2821,616 +2814,106 @@ var RealVectorStore = class {
|
|
|
2821
2814
|
}
|
|
2822
2815
|
};
|
|
2823
2816
|
|
|
2824
|
-
// src/mcp/
|
|
2825
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2817
|
+
// src/mcp/session.ts
|
|
2826
2818
|
import path4 from "path";
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
if (pkg.name === "@vheins/local-memory-mcp" && pkg.version) {
|
|
2839
|
-
pkgVersion = pkg.version;
|
|
2840
|
-
break;
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2843
|
-
} catch {
|
|
2844
|
-
}
|
|
2845
|
-
searchDir = path4.dirname(searchDir);
|
|
2846
|
-
}
|
|
2819
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2820
|
+
function createSessionContext() {
|
|
2821
|
+
return {
|
|
2822
|
+
roots: [],
|
|
2823
|
+
supportsRoots: false,
|
|
2824
|
+
supportsSampling: false,
|
|
2825
|
+
supportsSamplingTools: false,
|
|
2826
|
+
supportsElicitation: false,
|
|
2827
|
+
supportsElicitationForm: false,
|
|
2828
|
+
supportsElicitationUrl: false
|
|
2829
|
+
};
|
|
2847
2830
|
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
capabilities
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
listChanged: true
|
|
2860
|
-
},
|
|
2861
|
-
tools: {
|
|
2862
|
-
listChanged: false
|
|
2863
|
-
},
|
|
2864
|
-
prompts: {
|
|
2865
|
-
listChanged: true
|
|
2866
|
-
}
|
|
2867
|
-
}
|
|
2868
|
-
};
|
|
2869
|
-
|
|
2870
|
-
// src/mcp/utils/pagination.ts
|
|
2871
|
-
function encodeCursor(offset) {
|
|
2872
|
-
return Buffer.from(String(offset), "utf8").toString("base64");
|
|
2831
|
+
function updateSessionFromInitialize(session, params) {
|
|
2832
|
+
const capabilities = params?.capabilities || {};
|
|
2833
|
+
session.clientInfo = params?.clientInfo;
|
|
2834
|
+
session.clientCapabilities = capabilities;
|
|
2835
|
+
session.supportsRoots = Boolean(capabilities.roots);
|
|
2836
|
+
session.supportsSampling = Boolean(capabilities.sampling);
|
|
2837
|
+
const sampling = capabilities.sampling;
|
|
2838
|
+
session.supportsSamplingTools = Boolean(sampling?.tools);
|
|
2839
|
+
session.supportsElicitation = Boolean(capabilities.elicitation);
|
|
2840
|
+
session.supportsElicitationForm = supportsElicitationMode(capabilities.elicitation, "form");
|
|
2841
|
+
session.supportsElicitationUrl = supportsElicitationMode(capabilities.elicitation, "url");
|
|
2873
2842
|
}
|
|
2874
|
-
function
|
|
2875
|
-
if (
|
|
2876
|
-
return
|
|
2877
|
-
}
|
|
2878
|
-
if (typeof cursor !== "string" || cursor.trim() === "") {
|
|
2879
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2880
|
-
}
|
|
2881
|
-
let decoded;
|
|
2882
|
-
try {
|
|
2883
|
-
decoded = Buffer.from(cursor, "base64").toString("utf8");
|
|
2884
|
-
} catch {
|
|
2885
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2886
|
-
}
|
|
2887
|
-
if (!/^\d+$/.test(decoded)) {
|
|
2888
|
-
throw invalidPaginationParams("Invalid cursor");
|
|
2843
|
+
function supportsElicitationMode(capability, mode) {
|
|
2844
|
+
if (!capability || typeof capability !== "object") {
|
|
2845
|
+
return false;
|
|
2889
2846
|
}
|
|
2890
|
-
const
|
|
2891
|
-
if (
|
|
2892
|
-
|
|
2847
|
+
const cap = capability;
|
|
2848
|
+
if (mode === "form") {
|
|
2849
|
+
return Object.keys(cap).length === 0 || typeof cap.form === "object";
|
|
2893
2850
|
}
|
|
2894
|
-
return
|
|
2851
|
+
return typeof cap.url === "object";
|
|
2895
2852
|
}
|
|
2896
|
-
function
|
|
2897
|
-
const
|
|
2898
|
-
|
|
2899
|
-
|
|
2853
|
+
function updateSessionRoots(session, roots) {
|
|
2854
|
+
const normalized = normalizeRoots(roots);
|
|
2855
|
+
const previous = JSON.stringify(session.roots);
|
|
2856
|
+
const next = JSON.stringify(normalized);
|
|
2857
|
+
session.roots = normalized;
|
|
2858
|
+
return previous !== next;
|
|
2900
2859
|
}
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
const
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2860
|
+
function normalizeRoots(roots) {
|
|
2861
|
+
if (!Array.isArray(roots)) return [];
|
|
2862
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2863
|
+
const normalized = [];
|
|
2864
|
+
for (const root of roots) {
|
|
2865
|
+
if (!root || typeof root !== "object") continue;
|
|
2866
|
+
const r = root;
|
|
2867
|
+
const uri = typeof r.uri === "string" ? r.uri : void 0;
|
|
2868
|
+
const name = typeof r.name === "string" ? r.name : void 0;
|
|
2869
|
+
if (!uri || seen.has(uri)) continue;
|
|
2870
|
+
seen.add(uri);
|
|
2871
|
+
normalized.push({ uri, name });
|
|
2909
2872
|
}
|
|
2910
|
-
return
|
|
2873
|
+
return normalized;
|
|
2911
2874
|
}
|
|
2912
|
-
function
|
|
2913
|
-
|
|
2914
|
-
if (haystack === needle) return 100;
|
|
2915
|
-
if (haystack.startsWith(needle)) return 75;
|
|
2916
|
-
if (haystack.includes(needle)) return 50;
|
|
2917
|
-
const compactNeedle = needle.replace(/[\s_-]+/g, "");
|
|
2918
|
-
const compactHaystack = haystack.replace(/[\s_-]+/g, "");
|
|
2919
|
-
if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
|
|
2920
|
-
return 0;
|
|
2875
|
+
function extractRootsFromResult(result) {
|
|
2876
|
+
return normalizeRoots(result?.roots);
|
|
2921
2877
|
}
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
name: "Repository Index",
|
|
2931
|
-
title: "Repository Index",
|
|
2932
|
-
description: "List of all known repositories with memory/task counts and last activity",
|
|
2933
|
-
mimeType: "application/json",
|
|
2934
|
-
annotations: {
|
|
2935
|
-
audience: ["assistant"],
|
|
2936
|
-
priority: 1,
|
|
2937
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
2938
|
-
}
|
|
2939
|
-
},
|
|
2940
|
-
{
|
|
2941
|
-
uri: "session://roots",
|
|
2942
|
-
name: "Session Roots",
|
|
2943
|
-
title: "Session Roots",
|
|
2944
|
-
description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
|
|
2945
|
-
mimeType: "application/json",
|
|
2946
|
-
size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
|
|
2947
|
-
annotations: {
|
|
2948
|
-
audience: ["assistant"],
|
|
2949
|
-
priority: 0.95,
|
|
2950
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
2951
|
-
}
|
|
2878
|
+
function getFilesystemRoots(session) {
|
|
2879
|
+
if (!session) return [];
|
|
2880
|
+
const resolved = [];
|
|
2881
|
+
for (const root of session.roots) {
|
|
2882
|
+
if (!root.uri.startsWith("file://")) continue;
|
|
2883
|
+
try {
|
|
2884
|
+
resolved.push(path4.resolve(fileURLToPath2(root.uri)));
|
|
2885
|
+
} catch {
|
|
2952
2886
|
}
|
|
2953
|
-
|
|
2954
|
-
return
|
|
2887
|
+
}
|
|
2888
|
+
return resolved;
|
|
2955
2889
|
}
|
|
2956
|
-
function
|
|
2957
|
-
const
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
mimeType: "application/json",
|
|
2965
|
-
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
2966
|
-
},
|
|
2967
|
-
{
|
|
2968
|
-
uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
|
|
2969
|
-
name: "Filtered Repository Memories",
|
|
2970
|
-
title: "Filtered Repository Memories",
|
|
2971
|
-
description: "Filter or search memories within a repository by keyword, type, or tag",
|
|
2972
|
-
mimeType: "application/json",
|
|
2973
|
-
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
2974
|
-
},
|
|
2975
|
-
{
|
|
2976
|
-
uriTemplate: "memory://{id}",
|
|
2977
|
-
name: "Memory Detail",
|
|
2978
|
-
title: "Memory Detail",
|
|
2979
|
-
description: "Full content and statistics for a specific memory UUID",
|
|
2980
|
-
mimeType: "application/json",
|
|
2981
|
-
annotations: { audience: ["assistant"], priority: 0.75 }
|
|
2982
|
-
},
|
|
2983
|
-
// ── Tasks ────────────────────────────────────────────────────────────────
|
|
2984
|
-
{
|
|
2985
|
-
uriTemplate: "repository://{name}/tasks",
|
|
2986
|
-
name: "Repository Tasks",
|
|
2987
|
-
title: "Repository Tasks",
|
|
2988
|
-
description: "All active tasks for a specific repository",
|
|
2989
|
-
mimeType: "application/json",
|
|
2990
|
-
annotations: { audience: ["assistant"], priority: 0.9 }
|
|
2991
|
-
},
|
|
2992
|
-
{
|
|
2993
|
-
uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
|
|
2994
|
-
name: "Filtered Repository Tasks",
|
|
2995
|
-
title: "Filtered Repository Tasks",
|
|
2996
|
-
description: "Filter tasks within a repository by status or priority level",
|
|
2997
|
-
mimeType: "application/json",
|
|
2998
|
-
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
2999
|
-
},
|
|
3000
|
-
{
|
|
3001
|
-
uriTemplate: "task://{id}",
|
|
3002
|
-
name: "Task Detail",
|
|
3003
|
-
title: "Task Detail",
|
|
3004
|
-
description: "Full content and comments for a specific task UUID",
|
|
3005
|
-
mimeType: "application/json",
|
|
3006
|
-
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
3007
|
-
},
|
|
3008
|
-
// ── Repository extras ────────────────────────────────────────────────────
|
|
3009
|
-
{
|
|
3010
|
-
uriTemplate: "repository://{name}/summary",
|
|
3011
|
-
name: "Repository Summary",
|
|
3012
|
-
title: "Repository Summary",
|
|
3013
|
-
description: "High-level architectural summary for a repository",
|
|
3014
|
-
mimeType: "text/plain",
|
|
3015
|
-
annotations: { audience: ["assistant"], priority: 0.95 }
|
|
3016
|
-
},
|
|
3017
|
-
{
|
|
3018
|
-
uriTemplate: "repository://{name}/actions",
|
|
3019
|
-
name: "Repository Actions",
|
|
3020
|
-
title: "Repository Actions",
|
|
3021
|
-
description: "Audit log of agent tool actions scoped to a repository",
|
|
3022
|
-
mimeType: "application/json",
|
|
3023
|
-
annotations: { audience: ["assistant"], priority: 0.6 }
|
|
3024
|
-
},
|
|
3025
|
-
// ── Action detail ────────────────────────────────────────────────────────
|
|
3026
|
-
{
|
|
3027
|
-
uriTemplate: "action://{id}",
|
|
3028
|
-
name: "Action Detail",
|
|
3029
|
-
title: "Action Detail",
|
|
3030
|
-
description: "Full details of a specific audit log entry by integer ID",
|
|
3031
|
-
mimeType: "application/json",
|
|
3032
|
-
annotations: { audience: ["assistant"], priority: 0.55 }
|
|
3033
|
-
}
|
|
3034
|
-
];
|
|
3035
|
-
return paginateEntries("resourceTemplates", templates, params);
|
|
2890
|
+
function isPathWithinRoots(targetPath, session) {
|
|
2891
|
+
const roots = getFilesystemRoots(session);
|
|
2892
|
+
if (roots.length === 0) return true;
|
|
2893
|
+
const normalizedTarget = path4.resolve(targetPath);
|
|
2894
|
+
return roots.some((rootPath) => {
|
|
2895
|
+
const relative = path4.relative(rootPath, normalizedTarget);
|
|
2896
|
+
return relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative);
|
|
2897
|
+
});
|
|
3036
2898
|
}
|
|
3037
|
-
function
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
return rankCompletionValues(dataSources.tags, argumentValue);
|
|
2899
|
+
function findContainingRoot(targetPath, session) {
|
|
2900
|
+
const roots = getFilesystemRoots(session);
|
|
2901
|
+
if (roots.length === 0) return null;
|
|
2902
|
+
const normalizedTarget = path4.resolve(targetPath);
|
|
2903
|
+
for (const rootPath of roots) {
|
|
2904
|
+
const relative = path4.relative(rootPath, normalizedTarget);
|
|
2905
|
+
if (relative === "" || !relative.startsWith("..") && !path4.isAbsolute(relative)) {
|
|
2906
|
+
return rootPath;
|
|
3046
2907
|
}
|
|
3047
2908
|
}
|
|
3048
|
-
|
|
2909
|
+
return null;
|
|
3049
2910
|
}
|
|
3050
|
-
function
|
|
3051
|
-
|
|
3052
|
-
if (
|
|
3053
|
-
|
|
3054
|
-
const payload = JSON.stringify(repos, null, 2);
|
|
3055
|
-
return {
|
|
3056
|
-
contents: [
|
|
3057
|
-
{
|
|
3058
|
-
uri,
|
|
3059
|
-
mimeType: "application/json",
|
|
3060
|
-
text: payload,
|
|
3061
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3062
|
-
annotations: {
|
|
3063
|
-
audience: ["assistant"],
|
|
3064
|
-
priority: 1,
|
|
3065
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3066
|
-
}
|
|
3067
|
-
}
|
|
3068
|
-
]
|
|
3069
|
-
};
|
|
3070
|
-
}
|
|
3071
|
-
if (uri === "session://roots") {
|
|
3072
|
-
const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
|
|
3073
|
-
return {
|
|
3074
|
-
contents: [
|
|
3075
|
-
{
|
|
3076
|
-
uri,
|
|
3077
|
-
mimeType: "application/json",
|
|
3078
|
-
text: payload,
|
|
3079
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3080
|
-
annotations: {
|
|
3081
|
-
audience: ["assistant"],
|
|
3082
|
-
priority: 0.95,
|
|
3083
|
-
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
3084
|
-
}
|
|
3085
|
-
}
|
|
3086
|
-
]
|
|
3087
|
-
};
|
|
3088
|
-
}
|
|
3089
|
-
const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
|
|
3090
|
-
if (memoryIdMatch) {
|
|
3091
|
-
const id = memoryIdMatch[1];
|
|
3092
|
-
const entry = db.memories.getByIdWithStats(id);
|
|
3093
|
-
if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
|
|
3094
|
-
const payload = JSON.stringify(entry, null, 2);
|
|
3095
|
-
return {
|
|
3096
|
-
contents: [
|
|
3097
|
-
{
|
|
3098
|
-
uri,
|
|
3099
|
-
mimeType: "application/json",
|
|
3100
|
-
text: payload,
|
|
3101
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3102
|
-
annotations: {
|
|
3103
|
-
audience: ["assistant"],
|
|
3104
|
-
priority: 0.75,
|
|
3105
|
-
lastModified: entry.updated_at || entry.created_at
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
]
|
|
3109
|
-
};
|
|
2911
|
+
function inferRepoFromSession(session) {
|
|
2912
|
+
const roots = getFilesystemRoots(session);
|
|
2913
|
+
if (roots.length === 1) {
|
|
2914
|
+
return path4.basename(roots[0]);
|
|
3110
2915
|
}
|
|
3111
|
-
|
|
3112
|
-
if (taskIdMatch) {
|
|
3113
|
-
const id = taskIdMatch[1];
|
|
3114
|
-
const task = db.tasks.getTaskById(id);
|
|
3115
|
-
if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
|
|
3116
|
-
const payload = JSON.stringify(task, null, 2);
|
|
3117
|
-
return {
|
|
3118
|
-
contents: [
|
|
3119
|
-
{
|
|
3120
|
-
uri,
|
|
3121
|
-
mimeType: "application/json",
|
|
3122
|
-
text: payload,
|
|
3123
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3124
|
-
annotations: {
|
|
3125
|
-
audience: ["assistant"],
|
|
3126
|
-
priority: 0.8,
|
|
3127
|
-
lastModified: task.updated_at || task.created_at
|
|
3128
|
-
}
|
|
3129
|
-
}
|
|
3130
|
-
]
|
|
3131
|
-
};
|
|
3132
|
-
}
|
|
3133
|
-
const repoBase = parseRepoUri(uri);
|
|
3134
|
-
if (repoBase) {
|
|
3135
|
-
const { name, path: repoPath, query } = repoBase;
|
|
3136
|
-
if (repoPath === "summary") {
|
|
3137
|
-
const summary = db.summaries.getSummary(name);
|
|
3138
|
-
const text = summary?.summary || `No summary available for repository: ${name}`;
|
|
3139
|
-
return {
|
|
3140
|
-
contents: [
|
|
3141
|
-
{
|
|
3142
|
-
uri,
|
|
3143
|
-
mimeType: "text/plain",
|
|
3144
|
-
text,
|
|
3145
|
-
size: Buffer.byteLength(text, "utf8"),
|
|
3146
|
-
annotations: {
|
|
3147
|
-
audience: ["assistant"],
|
|
3148
|
-
priority: 0.95,
|
|
3149
|
-
lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
3150
|
-
}
|
|
3151
|
-
}
|
|
3152
|
-
]
|
|
3153
|
-
};
|
|
3154
|
-
}
|
|
3155
|
-
if (repoPath === "memories") {
|
|
3156
|
-
const search = query.get("search") || "";
|
|
3157
|
-
const type = query.get("type");
|
|
3158
|
-
const tag = query.get("tag");
|
|
3159
|
-
const result = db.memories.listMemoriesForDashboard({
|
|
3160
|
-
repo: name,
|
|
3161
|
-
type: type || void 0,
|
|
3162
|
-
tag: tag || void 0,
|
|
3163
|
-
search: search || void 0,
|
|
3164
|
-
limit: 50
|
|
3165
|
-
});
|
|
3166
|
-
const entries = result.items;
|
|
3167
|
-
const payload = JSON.stringify(entries, null, 2);
|
|
3168
|
-
return {
|
|
3169
|
-
contents: [
|
|
3170
|
-
{
|
|
3171
|
-
uri,
|
|
3172
|
-
mimeType: "application/json",
|
|
3173
|
-
text: payload,
|
|
3174
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3175
|
-
annotations: {
|
|
3176
|
-
audience: ["assistant"],
|
|
3177
|
-
priority: 0.85,
|
|
3178
|
-
lastModified: deriveLastModifiedFromCollection(
|
|
3179
|
-
entries.map((e) => e.updated_at || e.created_at)
|
|
3180
|
-
)
|
|
3181
|
-
}
|
|
3182
|
-
}
|
|
3183
|
-
]
|
|
3184
|
-
};
|
|
3185
|
-
}
|
|
3186
|
-
if (repoPath === "tasks") {
|
|
3187
|
-
const status = query.get("status");
|
|
3188
|
-
const priority = query.get("priority");
|
|
3189
|
-
let tasks;
|
|
3190
|
-
if (status && status !== "all") {
|
|
3191
|
-
const statuses = status.split(",").map((s) => s.trim());
|
|
3192
|
-
tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
|
|
3193
|
-
} else {
|
|
3194
|
-
tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
|
|
3195
|
-
}
|
|
3196
|
-
if (priority) {
|
|
3197
|
-
const p = Number(priority);
|
|
3198
|
-
if (!isNaN(p)) {
|
|
3199
|
-
tasks = tasks.filter((t) => t.priority === p);
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
const payload = JSON.stringify(tasks, null, 2);
|
|
3203
|
-
return {
|
|
3204
|
-
contents: [
|
|
3205
|
-
{
|
|
3206
|
-
uri,
|
|
3207
|
-
mimeType: "application/json",
|
|
3208
|
-
text: payload,
|
|
3209
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3210
|
-
annotations: {
|
|
3211
|
-
audience: ["assistant"],
|
|
3212
|
-
priority: 0.9,
|
|
3213
|
-
lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
3216
|
-
]
|
|
3217
|
-
};
|
|
3218
|
-
}
|
|
3219
|
-
if (repoPath === "actions") {
|
|
3220
|
-
const actions = db.actions.getRecentActions(name, 100);
|
|
3221
|
-
const payload = JSON.stringify(actions, null, 2);
|
|
3222
|
-
return {
|
|
3223
|
-
contents: [
|
|
3224
|
-
{
|
|
3225
|
-
uri,
|
|
3226
|
-
mimeType: "application/json",
|
|
3227
|
-
text: payload,
|
|
3228
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3229
|
-
annotations: {
|
|
3230
|
-
audience: ["assistant"],
|
|
3231
|
-
priority: 0.6,
|
|
3232
|
-
lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
|
|
3233
|
-
}
|
|
3234
|
-
}
|
|
3235
|
-
]
|
|
3236
|
-
};
|
|
3237
|
-
}
|
|
3238
|
-
}
|
|
3239
|
-
const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
|
|
3240
|
-
if (actionIdMatch) {
|
|
3241
|
-
const id = Number(actionIdMatch[1]);
|
|
3242
|
-
const action = db.actions.getActionById(id);
|
|
3243
|
-
if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
|
|
3244
|
-
const payload = JSON.stringify(action, null, 2);
|
|
3245
|
-
return {
|
|
3246
|
-
contents: [
|
|
3247
|
-
{
|
|
3248
|
-
uri,
|
|
3249
|
-
mimeType: "application/json",
|
|
3250
|
-
text: payload,
|
|
3251
|
-
size: Buffer.byteLength(payload, "utf8"),
|
|
3252
|
-
annotations: {
|
|
3253
|
-
audience: ["assistant"],
|
|
3254
|
-
priority: 0.55,
|
|
3255
|
-
lastModified: action.created_at
|
|
3256
|
-
}
|
|
3257
|
-
}
|
|
3258
|
-
]
|
|
3259
|
-
};
|
|
3260
|
-
}
|
|
3261
|
-
throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
|
|
3262
|
-
}
|
|
3263
|
-
function parseRepoUri(uri) {
|
|
3264
|
-
const prefix = "repository://";
|
|
3265
|
-
if (!uri.startsWith(prefix)) return null;
|
|
3266
|
-
const rest = uri.slice(prefix.length);
|
|
3267
|
-
const queryStart = rest.indexOf("?");
|
|
3268
|
-
const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
|
|
3269
|
-
const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
|
|
3270
|
-
const slashIdx = withoutQuery.indexOf("/");
|
|
3271
|
-
if (slashIdx === -1) return null;
|
|
3272
|
-
const name = withoutQuery.slice(0, slashIdx);
|
|
3273
|
-
const path6 = withoutQuery.slice(slashIdx + 1);
|
|
3274
|
-
if (!name || !path6) return null;
|
|
3275
|
-
return { name, path: path6, query: new URLSearchParams(queryString) };
|
|
3276
|
-
}
|
|
3277
|
-
function paginateEntries(key, entries, params) {
|
|
3278
|
-
const limit = normalizeLimit(params?.limit);
|
|
3279
|
-
const offset = decodeCursor(params?.cursor);
|
|
3280
|
-
const sliced = entries.slice(offset, offset + limit);
|
|
3281
|
-
const nextOffset = offset + sliced.length;
|
|
3282
|
-
return {
|
|
3283
|
-
[key]: sliced,
|
|
3284
|
-
nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
|
|
3285
|
-
};
|
|
3286
|
-
}
|
|
3287
|
-
function normalizeLimit(limit) {
|
|
3288
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
3289
|
-
return DEFAULT_PAGE_SIZE;
|
|
3290
|
-
}
|
|
3291
|
-
return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
|
|
3292
|
-
}
|
|
3293
|
-
function deriveLastModifiedFromCollection(values) {
|
|
3294
|
-
const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
|
|
3295
|
-
return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
3296
|
-
}
|
|
3297
|
-
function resourceNotFound(message, uri) {
|
|
3298
|
-
const error = new Error(message);
|
|
3299
|
-
error.code = -32002;
|
|
3300
|
-
error.data = { uri };
|
|
3301
|
-
return error;
|
|
3302
|
-
}
|
|
3303
|
-
function invalidCompletionParams(message) {
|
|
3304
|
-
const error = new Error(message);
|
|
3305
|
-
error.code = -32602;
|
|
3306
|
-
return error;
|
|
3307
|
-
}
|
|
3308
|
-
|
|
3309
|
-
// src/mcp/prompts/loader.ts
|
|
3310
|
-
import fs4 from "fs";
|
|
3311
|
-
import path5 from "path";
|
|
3312
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3313
|
-
import matter from "gray-matter";
|
|
3314
|
-
var __filename = fileURLToPath3(import.meta.url);
|
|
3315
|
-
var __dirname2 = path5.dirname(__filename);
|
|
3316
|
-
function findPromptDir() {
|
|
3317
|
-
const candidates = [
|
|
3318
|
-
// Production if chunked into dist/
|
|
3319
|
-
"./prompts",
|
|
3320
|
-
// Production if inlined into dist/mcp/
|
|
3321
|
-
"../prompts",
|
|
3322
|
-
// Dev: /src/mcp/prompts/definitions (next to loader.ts)
|
|
3323
|
-
"./definitions"
|
|
3324
|
-
].map((relPath) => path5.resolve(__dirname2, relPath));
|
|
3325
|
-
for (const dir of candidates) {
|
|
3326
|
-
if (fs4.existsSync(dir)) {
|
|
3327
|
-
const files = fs4.readdirSync(dir);
|
|
3328
|
-
if (files.some((f) => f.endsWith(".md"))) {
|
|
3329
|
-
return dir;
|
|
3330
|
-
}
|
|
3331
|
-
}
|
|
3332
|
-
}
|
|
3333
|
-
return path5.resolve(__dirname2, "./definitions");
|
|
3334
|
-
}
|
|
3335
|
-
var PROMPT_DIR = findPromptDir();
|
|
3336
|
-
function listPromptFiles() {
|
|
3337
|
-
if (!fs4.existsSync(PROMPT_DIR)) return [];
|
|
3338
|
-
return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
|
|
3339
|
-
}
|
|
3340
|
-
function loadPromptFromMarkdown(name) {
|
|
3341
|
-
const filePath = path5.join(PROMPT_DIR, `${name}.md`);
|
|
3342
|
-
if (!fs4.existsSync(filePath)) {
|
|
3343
|
-
throw new Error(`Prompt file not found: ${filePath}`);
|
|
3344
|
-
}
|
|
3345
|
-
const fileContent = fs4.readFileSync(filePath, "utf-8");
|
|
3346
|
-
const { data, content } = matter(fileContent);
|
|
3347
|
-
return {
|
|
3348
|
-
name: data.name || name,
|
|
3349
|
-
description: data.description || "",
|
|
3350
|
-
arguments: data.arguments || [],
|
|
3351
|
-
agent: data.agent,
|
|
3352
|
-
content: content.trim()
|
|
3353
|
-
};
|
|
3354
|
-
}
|
|
3355
|
-
|
|
3356
|
-
// src/mcp/prompts/registry.ts
|
|
3357
|
-
function createPromptDefinition(loaded) {
|
|
3358
|
-
return {
|
|
3359
|
-
name: loaded.name,
|
|
3360
|
-
description: loaded.description,
|
|
3361
|
-
arguments: loaded.arguments,
|
|
3362
|
-
agent: loaded.agent,
|
|
3363
|
-
messages: [
|
|
3364
|
-
{
|
|
3365
|
-
role: "user",
|
|
3366
|
-
content: {
|
|
3367
|
-
type: "text",
|
|
3368
|
-
text: loaded.content
|
|
3369
|
-
}
|
|
3370
|
-
}
|
|
3371
|
-
]
|
|
3372
|
-
};
|
|
3373
|
-
}
|
|
3374
|
-
var PROMPTS = {};
|
|
3375
|
-
var promptFiles = listPromptFiles();
|
|
3376
|
-
for (const name of promptFiles) {
|
|
3377
|
-
try {
|
|
3378
|
-
PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
|
|
3379
|
-
} catch (e) {
|
|
3380
|
-
logger.warn(`Failed to load prompt ${name}: ${e}`);
|
|
3381
|
-
}
|
|
3382
|
-
}
|
|
3383
|
-
async function listPrompts(db, session, params) {
|
|
3384
|
-
const allPrompts = Object.values(PROMPTS).map((p) => ({
|
|
3385
|
-
name: p.name,
|
|
3386
|
-
description: p.description,
|
|
3387
|
-
arguments: p.arguments,
|
|
3388
|
-
metadata: p.agent ? { agent: p.agent } : void 0
|
|
3389
|
-
}));
|
|
3390
|
-
const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
|
|
3391
|
-
const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
|
|
3392
|
-
const offset = decodeCursor(params?.cursor);
|
|
3393
|
-
const sliced = allPrompts.slice(offset, offset + limit);
|
|
3394
|
-
const nextOffset = offset + sliced.length;
|
|
3395
|
-
return {
|
|
3396
|
-
prompts: sliced,
|
|
3397
|
-
nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
|
|
3398
|
-
};
|
|
3399
|
-
}
|
|
3400
|
-
async function getPrompt(name, args = {}, db, session) {
|
|
3401
|
-
const prompt = PROMPTS[name];
|
|
3402
|
-
if (!prompt) {
|
|
3403
|
-
throw new Error(`Prompt not found: ${name}`);
|
|
3404
|
-
}
|
|
3405
|
-
const inferredRepo = inferRepoFromSession(session);
|
|
3406
|
-
const messages = prompt.messages.map((m) => {
|
|
3407
|
-
let text = m.content.text;
|
|
3408
|
-
for (const [key, value] of Object.entries(args)) {
|
|
3409
|
-
text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
|
|
3410
|
-
}
|
|
3411
|
-
text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
|
|
3412
|
-
return {
|
|
3413
|
-
...m,
|
|
3414
|
-
content: {
|
|
3415
|
-
...m.content,
|
|
3416
|
-
text
|
|
3417
|
-
}
|
|
3418
|
-
};
|
|
3419
|
-
});
|
|
3420
|
-
return {
|
|
3421
|
-
description: prompt.description,
|
|
3422
|
-
messages,
|
|
3423
|
-
metadata: prompt.agent ? { agent: prompt.agent } : void 0
|
|
3424
|
-
};
|
|
3425
|
-
}
|
|
3426
|
-
async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
|
|
3427
|
-
void name;
|
|
3428
|
-
void contextArguments;
|
|
3429
|
-
if (argName === "task_id") {
|
|
3430
|
-
const values = dataSources.tasks.map((t) => t.id);
|
|
3431
|
-
return rankCompletionValues(values, value);
|
|
3432
|
-
}
|
|
3433
|
-
return [];
|
|
2916
|
+
return void 0;
|
|
3434
2917
|
}
|
|
3435
2918
|
|
|
3436
2919
|
// src/mcp/tools/schemas.ts
|
|
@@ -3643,10 +3126,13 @@ var MemoryDetailSchema = z.object({
|
|
|
3643
3126
|
}).refine((data) => data.id !== void 0 || data.code !== void 0, {
|
|
3644
3127
|
message: "Either id or code must be provided"
|
|
3645
3128
|
});
|
|
3646
|
-
var StandardDetailSchema = z.object({
|
|
3647
|
-
id: z.string().uuid(),
|
|
3648
|
-
|
|
3649
|
-
|
|
3129
|
+
var StandardDetailSchema = z.object({
|
|
3130
|
+
id: z.string().uuid().optional(),
|
|
3131
|
+
code: z.string().max(20).optional(),
|
|
3132
|
+
structured: z.boolean().default(false)
|
|
3133
|
+
}).refine((data) => data.id !== void 0 || data.code !== void 0, {
|
|
3134
|
+
message: "Either id or code must be provided"
|
|
3135
|
+
});
|
|
3650
3136
|
var StandardDeleteSchema = z.object({
|
|
3651
3137
|
repo: z.string().min(1).transform(normalizeRepo).optional(),
|
|
3652
3138
|
id: z.string().uuid().optional(),
|
|
@@ -3763,241 +3249,669 @@ var StandardSearchSchema = z.object({
|
|
|
3763
3249
|
});
|
|
3764
3250
|
var TOOL_DEFINITIONS = [
|
|
3765
3251
|
{
|
|
3766
|
-
name: "memory-synthesize",
|
|
3767
|
-
title: "Memory Synthesize",
|
|
3768
|
-
description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
|
|
3252
|
+
name: "memory-synthesize",
|
|
3253
|
+
title: "Memory Synthesize",
|
|
3254
|
+
description: "Use client sampling to synthesize a grounded answer from local memory and tasks. Best for project briefings, tradeoff summaries, and context-aware answers.",
|
|
3255
|
+
annotations: {
|
|
3256
|
+
readOnlyHint: true,
|
|
3257
|
+
idempotentHint: true,
|
|
3258
|
+
openWorldHint: false
|
|
3259
|
+
},
|
|
3260
|
+
execution: {
|
|
3261
|
+
taskSupport: "optional"
|
|
3262
|
+
},
|
|
3263
|
+
inputSchema: {
|
|
3264
|
+
type: "object",
|
|
3265
|
+
properties: {
|
|
3266
|
+
repo: { type: "string", description: "Repository name. Optional when a single MCP root is active." },
|
|
3267
|
+
objective: { type: "string", minLength: 5, description: "Question or synthesis objective." },
|
|
3268
|
+
current_file_path: {
|
|
3269
|
+
type: "string",
|
|
3270
|
+
description: "Optional absolute file path for workspace-local grounding."
|
|
3271
|
+
},
|
|
3272
|
+
include_summary: { type: "boolean", default: true },
|
|
3273
|
+
include_tasks: { type: "boolean", default: true },
|
|
3274
|
+
use_tools: {
|
|
3275
|
+
type: "boolean",
|
|
3276
|
+
default: true,
|
|
3277
|
+
description: "Allow the sampled model to call local memory/task tools during synthesis when the client supports sampling.tools."
|
|
3278
|
+
},
|
|
3279
|
+
max_iterations: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3280
|
+
max_tokens: { type: "number", minimum: 128, maximum: 4e3, default: 1200 },
|
|
3281
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON results." }
|
|
3282
|
+
},
|
|
3283
|
+
required: ["objective"]
|
|
3284
|
+
},
|
|
3285
|
+
outputSchema: {
|
|
3286
|
+
type: "object",
|
|
3287
|
+
properties: {
|
|
3288
|
+
repo: { type: "string" },
|
|
3289
|
+
objective: { type: "string" },
|
|
3290
|
+
answer: { type: "string" },
|
|
3291
|
+
model: { type: "string" },
|
|
3292
|
+
stopReason: { type: "string" },
|
|
3293
|
+
iterations: { type: "number" },
|
|
3294
|
+
toolCalls: { type: "number" }
|
|
3295
|
+
},
|
|
3296
|
+
required: ["repo", "objective", "answer", "iterations", "toolCalls"]
|
|
3297
|
+
}
|
|
3298
|
+
},
|
|
3299
|
+
{
|
|
3300
|
+
name: "task-create-interactive",
|
|
3301
|
+
title: "Interactive Task Create",
|
|
3302
|
+
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.",
|
|
3303
|
+
annotations: {
|
|
3304
|
+
readOnlyHint: false,
|
|
3305
|
+
idempotentHint: false,
|
|
3306
|
+
destructiveHint: false,
|
|
3307
|
+
openWorldHint: false
|
|
3308
|
+
},
|
|
3309
|
+
inputSchema: {
|
|
3310
|
+
type: "object",
|
|
3311
|
+
properties: {
|
|
3312
|
+
repo: {
|
|
3313
|
+
type: "string",
|
|
3314
|
+
description: "Repository name. Optional when it can be inferred from MCP roots or elicited from the user."
|
|
3315
|
+
},
|
|
3316
|
+
task_code: { type: "string" },
|
|
3317
|
+
phase: { type: "string" },
|
|
3318
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3319
|
+
description: { type: "string", minLength: 1 },
|
|
3320
|
+
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3321
|
+
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3322
|
+
agent: { type: "string" },
|
|
3323
|
+
role: { type: "string" },
|
|
3324
|
+
doc_path: { type: "string" },
|
|
3325
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3326
|
+
}
|
|
3327
|
+
},
|
|
3328
|
+
outputSchema: {
|
|
3329
|
+
type: "object",
|
|
3330
|
+
properties: {
|
|
3331
|
+
repo: { type: "string" },
|
|
3332
|
+
task_code: { type: "string" },
|
|
3333
|
+
phase: { type: "string" },
|
|
3334
|
+
title: { type: "string" },
|
|
3335
|
+
status: { type: "string" },
|
|
3336
|
+
priority: { type: "number" }
|
|
3337
|
+
},
|
|
3338
|
+
required: ["repo", "task_code", "phase", "title", "status", "priority"]
|
|
3339
|
+
}
|
|
3340
|
+
},
|
|
3341
|
+
{
|
|
3342
|
+
name: "memory-detail",
|
|
3343
|
+
title: "Memory Detail",
|
|
3344
|
+
description: "Fetch full details of a specific memory by ID or short code. Use after memory-recap or memory-search when a pointer row is relevant and full content is needed.",
|
|
3345
|
+
inputSchema: {
|
|
3346
|
+
type: "object",
|
|
3347
|
+
properties: {
|
|
3348
|
+
id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
|
|
3349
|
+
code: { type: "string", description: "Short memory code. Optional if id is provided." },
|
|
3350
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
},
|
|
3354
|
+
{
|
|
3355
|
+
name: "standard-detail",
|
|
3356
|
+
title: "Standard Detail",
|
|
3357
|
+
description: "Fetch full details of a specific coding standard by ID or short code. Use after standard-search when a result is relevant and full guidance is needed.",
|
|
3358
|
+
inputSchema: {
|
|
3359
|
+
type: "object",
|
|
3360
|
+
properties: {
|
|
3361
|
+
id: { type: "string", format: "uuid", description: "Coding standard ID. Optional if code is provided." },
|
|
3362
|
+
code: { type: "string", description: "Short standard code (e.g. 'A3KPQ2'). Optional if id is provided." },
|
|
3363
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON details." }
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
},
|
|
3367
|
+
{
|
|
3368
|
+
name: "task-detail",
|
|
3369
|
+
title: "Task Detail",
|
|
3370
|
+
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.",
|
|
3371
|
+
inputSchema: {
|
|
3372
|
+
type: "object",
|
|
3373
|
+
properties: {
|
|
3374
|
+
repo: { type: "string", description: "Repository name" },
|
|
3375
|
+
id: { type: "string", format: "uuid", description: "Task ID (optional if task_code is provided)" },
|
|
3376
|
+
task_code: { type: "string", description: "Task code (e.g. TASK-001) (optional if id is provided)" },
|
|
3377
|
+
structured: {
|
|
3378
|
+
type: "boolean",
|
|
3379
|
+
default: false,
|
|
3380
|
+
description: "If true, returns structured JSON without the text content details."
|
|
3381
|
+
}
|
|
3382
|
+
},
|
|
3383
|
+
required: ["repo"]
|
|
3384
|
+
}
|
|
3385
|
+
},
|
|
3386
|
+
{
|
|
3387
|
+
name: "memory-store",
|
|
3388
|
+
title: "Memory Store",
|
|
3389
|
+
description: "Store a new durable knowledge entry. Do not store coordination state here: task claims, file claims, agent registration, and handoffs belong to task-claim, task-update, and handoff-* tools. Keep 'title' concise and human-readable; put auxiliary context into 'metadata'.",
|
|
3390
|
+
annotations: {
|
|
3391
|
+
readOnlyHint: false,
|
|
3392
|
+
idempotentHint: false,
|
|
3393
|
+
destructiveHint: false,
|
|
3394
|
+
openWorldHint: false
|
|
3395
|
+
},
|
|
3396
|
+
inputSchema: {
|
|
3397
|
+
type: "object",
|
|
3398
|
+
properties: {
|
|
3399
|
+
type: {
|
|
3400
|
+
type: "string",
|
|
3401
|
+
enum: [
|
|
3402
|
+
"code_fact",
|
|
3403
|
+
"decision",
|
|
3404
|
+
"mistake",
|
|
3405
|
+
"pattern",
|
|
3406
|
+
"task_archive"
|
|
3407
|
+
],
|
|
3408
|
+
description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
|
|
3409
|
+
},
|
|
3410
|
+
title: {
|
|
3411
|
+
type: "string",
|
|
3412
|
+
minLength: 3,
|
|
3413
|
+
maxLength: 100,
|
|
3414
|
+
description: "Short human-readable title for the memory. Do not embed bracketed metadata like agent/role/date prefixes here."
|
|
3415
|
+
},
|
|
3416
|
+
content: {
|
|
3417
|
+
type: "string",
|
|
3418
|
+
minLength: 10,
|
|
3419
|
+
description: "The memory content"
|
|
3420
|
+
},
|
|
3421
|
+
importance: {
|
|
3422
|
+
type: "number",
|
|
3423
|
+
minimum: 1,
|
|
3424
|
+
maximum: 5,
|
|
3425
|
+
description: "Importance score (1-5)"
|
|
3426
|
+
},
|
|
3427
|
+
agent: {
|
|
3428
|
+
type: "string",
|
|
3429
|
+
description: "Name of the agent creating this memory"
|
|
3430
|
+
},
|
|
3431
|
+
role: {
|
|
3432
|
+
type: "string",
|
|
3433
|
+
description: "Role of the agent creating this memory"
|
|
3434
|
+
},
|
|
3435
|
+
model: {
|
|
3436
|
+
type: "string",
|
|
3437
|
+
description: "AI model used by the agent"
|
|
3438
|
+
},
|
|
3439
|
+
scope: {
|
|
3440
|
+
type: "object",
|
|
3441
|
+
properties: {
|
|
3442
|
+
repo: { type: "string", description: "Repository name" },
|
|
3443
|
+
branch: { type: "string" },
|
|
3444
|
+
folder: { type: "string" },
|
|
3445
|
+
language: { type: "string" }
|
|
3446
|
+
},
|
|
3447
|
+
required: ["repo"]
|
|
3448
|
+
},
|
|
3449
|
+
tags: {
|
|
3450
|
+
type: "array",
|
|
3451
|
+
items: { type: "string" },
|
|
3452
|
+
description: "Technology stack tags (e.g., ['filament', 'laravel'])"
|
|
3453
|
+
},
|
|
3454
|
+
metadata: {
|
|
3455
|
+
type: "object",
|
|
3456
|
+
description: "Structured metadata for non-title context such as source agent, claim fields, or timestamps"
|
|
3457
|
+
},
|
|
3458
|
+
is_global: {
|
|
3459
|
+
type: "boolean",
|
|
3460
|
+
description: "If true, this memory is shared across all repositories"
|
|
3461
|
+
},
|
|
3462
|
+
ttlDays: { type: "number", minimum: 1 },
|
|
3463
|
+
supersedes: { type: "string", format: "uuid" },
|
|
3464
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
|
|
3465
|
+
},
|
|
3466
|
+
required: ["type", "title", "content", "importance", "scope", "agent", "model"]
|
|
3467
|
+
},
|
|
3468
|
+
outputSchema: {
|
|
3469
|
+
type: "object",
|
|
3470
|
+
properties: {
|
|
3471
|
+
success: { type: "boolean" },
|
|
3472
|
+
id: { type: "string" },
|
|
3473
|
+
code: { type: "string" },
|
|
3474
|
+
repo: { type: "string" },
|
|
3475
|
+
type: { type: "string" },
|
|
3476
|
+
title: { type: "string" },
|
|
3477
|
+
error: { type: "string" },
|
|
3478
|
+
message: { type: "string" }
|
|
3479
|
+
},
|
|
3480
|
+
required: ["success"]
|
|
3481
|
+
}
|
|
3482
|
+
},
|
|
3483
|
+
{
|
|
3484
|
+
name: "memory-acknowledge",
|
|
3485
|
+
title: "Memory Acknowledge",
|
|
3486
|
+
description: "Acknowledge the use of a memory or report its irrelevance/contradiction. Mandatory after using memory to generate code.",
|
|
3487
|
+
annotations: {
|
|
3488
|
+
readOnlyHint: false,
|
|
3489
|
+
idempotentHint: false,
|
|
3490
|
+
openWorldHint: false
|
|
3491
|
+
},
|
|
3492
|
+
inputSchema: {
|
|
3493
|
+
type: "object",
|
|
3494
|
+
properties: {
|
|
3495
|
+
memory_id: { type: "string", format: "uuid" },
|
|
3496
|
+
status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
|
|
3497
|
+
application_context: { type: "string", minLength: 10 },
|
|
3498
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3499
|
+
},
|
|
3500
|
+
required: ["memory_id", "status"]
|
|
3501
|
+
},
|
|
3502
|
+
outputSchema: {
|
|
3503
|
+
type: "object",
|
|
3504
|
+
properties: {
|
|
3505
|
+
success: { type: "boolean" },
|
|
3506
|
+
id: { type: "string" },
|
|
3507
|
+
status: { type: "string" }
|
|
3508
|
+
},
|
|
3509
|
+
required: ["success", "id", "status"]
|
|
3510
|
+
}
|
|
3511
|
+
},
|
|
3512
|
+
{
|
|
3513
|
+
name: "memory-update",
|
|
3514
|
+
title: "Memory Update",
|
|
3515
|
+
description: "Update an existing memory entry. Keep 'title' concise and move agent/role/date or claim context into 'metadata' instead of the title.",
|
|
3516
|
+
annotations: {
|
|
3517
|
+
readOnlyHint: false,
|
|
3518
|
+
idempotentHint: false,
|
|
3519
|
+
destructiveHint: false,
|
|
3520
|
+
openWorldHint: false
|
|
3521
|
+
},
|
|
3522
|
+
inputSchema: {
|
|
3523
|
+
type: "object",
|
|
3524
|
+
properties: {
|
|
3525
|
+
id: { type: "string", format: "uuid" },
|
|
3526
|
+
type: {
|
|
3527
|
+
type: "string",
|
|
3528
|
+
enum: [
|
|
3529
|
+
"code_fact",
|
|
3530
|
+
"decision",
|
|
3531
|
+
"mistake",
|
|
3532
|
+
"pattern",
|
|
3533
|
+
"task_archive"
|
|
3534
|
+
]
|
|
3535
|
+
},
|
|
3536
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3537
|
+
content: { type: "string", minLength: 10 },
|
|
3538
|
+
importance: { type: "number", minimum: 1, maximum: 5 },
|
|
3539
|
+
agent: { type: "string" },
|
|
3540
|
+
role: { type: "string" },
|
|
3541
|
+
status: { type: "string", enum: ["active", "archived"] },
|
|
3542
|
+
supersedes: { type: "string", format: "uuid" },
|
|
3543
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3544
|
+
metadata: { type: "object" },
|
|
3545
|
+
is_global: { type: "boolean" },
|
|
3546
|
+
completed_at: { type: "string" },
|
|
3547
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
|
|
3548
|
+
},
|
|
3549
|
+
required: ["id"]
|
|
3550
|
+
},
|
|
3551
|
+
outputSchema: {
|
|
3552
|
+
type: "object",
|
|
3553
|
+
properties: {
|
|
3554
|
+
success: { type: "boolean" },
|
|
3555
|
+
id: { type: "string" },
|
|
3556
|
+
repo: { type: "string" },
|
|
3557
|
+
updatedFields: {
|
|
3558
|
+
type: "array",
|
|
3559
|
+
items: { type: "string" }
|
|
3560
|
+
}
|
|
3561
|
+
},
|
|
3562
|
+
required: ["success", "id", "repo", "updatedFields"]
|
|
3563
|
+
}
|
|
3564
|
+
},
|
|
3565
|
+
{
|
|
3566
|
+
name: "memory-search",
|
|
3567
|
+
title: "Memory Search",
|
|
3568
|
+
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.",
|
|
3769
3569
|
annotations: {
|
|
3770
3570
|
readOnlyHint: true,
|
|
3771
3571
|
idempotentHint: true,
|
|
3772
3572
|
openWorldHint: false
|
|
3773
3573
|
},
|
|
3774
|
-
execution: {
|
|
3775
|
-
taskSupport: "optional"
|
|
3776
|
-
},
|
|
3777
3574
|
inputSchema: {
|
|
3778
3575
|
type: "object",
|
|
3779
3576
|
properties: {
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3577
|
+
query: { type: "string", minLength: 3 },
|
|
3578
|
+
prompt: { type: "string" },
|
|
3579
|
+
repo: { type: "string" },
|
|
3580
|
+
current_tags: {
|
|
3581
|
+
type: "array",
|
|
3582
|
+
items: { type: "string" },
|
|
3583
|
+
description: "Active tech stack tags (e.g., ['filament', 'react'])"
|
|
3785
3584
|
},
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3585
|
+
types: {
|
|
3586
|
+
type: "array",
|
|
3587
|
+
items: {
|
|
3588
|
+
type: "string",
|
|
3589
|
+
enum: [
|
|
3590
|
+
"code_fact",
|
|
3591
|
+
"decision",
|
|
3592
|
+
"mistake",
|
|
3593
|
+
"pattern",
|
|
3594
|
+
"task_archive"
|
|
3595
|
+
]
|
|
3596
|
+
}
|
|
3792
3597
|
},
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3598
|
+
minImportance: { type: "number", minimum: 1, maximum: 5 },
|
|
3599
|
+
limit: { type: "number", minimum: 1, maximum: 100, default: 5 },
|
|
3600
|
+
offset: { type: "number", minimum: 0, default: 0 },
|
|
3601
|
+
includeRecap: { type: "boolean", default: false },
|
|
3602
|
+
current_file_path: { type: "string" },
|
|
3603
|
+
include_archived: { type: "boolean", default: false },
|
|
3604
|
+
scope: {
|
|
3605
|
+
type: "object",
|
|
3606
|
+
properties: {
|
|
3607
|
+
repo: { type: "string" },
|
|
3608
|
+
branch: { type: "string" },
|
|
3609
|
+
folder: { type: "string" },
|
|
3610
|
+
language: { type: "string" }
|
|
3611
|
+
}
|
|
3612
|
+
},
|
|
3613
|
+
structured: {
|
|
3614
|
+
type: "boolean",
|
|
3615
|
+
default: false,
|
|
3616
|
+
description: "If true, returns structured JSON without the text content summary."
|
|
3617
|
+
}
|
|
3796
3618
|
},
|
|
3797
|
-
required: ["
|
|
3619
|
+
required: ["query", "repo"]
|
|
3798
3620
|
},
|
|
3799
3621
|
outputSchema: {
|
|
3800
3622
|
type: "object",
|
|
3801
3623
|
properties: {
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3624
|
+
schema: { type: "string", enum: ["memory-search"] },
|
|
3625
|
+
query: { type: "string" },
|
|
3626
|
+
count: { type: "number", description: "Number of rows returned" },
|
|
3627
|
+
total: { type: "number", description: "Total matching memories" },
|
|
3628
|
+
offset: { type: "number" },
|
|
3629
|
+
limit: { type: "number" },
|
|
3630
|
+
results: {
|
|
3631
|
+
type: "object",
|
|
3632
|
+
properties: {
|
|
3633
|
+
columns: {
|
|
3634
|
+
type: "array",
|
|
3635
|
+
items: { type: "string" },
|
|
3636
|
+
description: "Column names: [id, title, type, importance]"
|
|
3637
|
+
},
|
|
3638
|
+
rows: {
|
|
3639
|
+
type: "array",
|
|
3640
|
+
items: { type: "array" },
|
|
3641
|
+
description: "Each row: [id, title, type, importance]. Fetch full content via memory-detail"
|
|
3642
|
+
}
|
|
3643
|
+
},
|
|
3644
|
+
required: ["columns", "rows"]
|
|
3645
|
+
}
|
|
3809
3646
|
},
|
|
3810
|
-
required: ["
|
|
3647
|
+
required: ["schema", "query", "count", "total", "offset", "limit", "results"]
|
|
3811
3648
|
}
|
|
3812
3649
|
},
|
|
3813
3650
|
{
|
|
3814
|
-
name: "
|
|
3815
|
-
title: "
|
|
3816
|
-
description: "
|
|
3651
|
+
name: "memory-summarize",
|
|
3652
|
+
title: "Memory Summarize",
|
|
3653
|
+
description: "Update the summary for a repository",
|
|
3817
3654
|
annotations: {
|
|
3818
3655
|
readOnlyHint: false,
|
|
3819
3656
|
idempotentHint: false,
|
|
3820
|
-
destructiveHint: false,
|
|
3821
3657
|
openWorldHint: false
|
|
3822
3658
|
},
|
|
3823
3659
|
inputSchema: {
|
|
3824
3660
|
type: "object",
|
|
3825
3661
|
properties: {
|
|
3826
|
-
repo: {
|
|
3827
|
-
|
|
3828
|
-
|
|
3662
|
+
repo: { type: "string", description: "Repository name" },
|
|
3663
|
+
signals: {
|
|
3664
|
+
type: "array",
|
|
3665
|
+
items: { type: "string", maxLength: 200 },
|
|
3666
|
+
minItems: 1,
|
|
3667
|
+
description: "High-level signals to include in summary"
|
|
3829
3668
|
},
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
description: { type: "string", minLength: 1 },
|
|
3834
|
-
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3835
|
-
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3836
|
-
agent: { type: "string" },
|
|
3837
|
-
role: { type: "string" },
|
|
3838
|
-
doc_path: { type: "string" },
|
|
3839
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3840
|
-
}
|
|
3669
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the summary." }
|
|
3670
|
+
},
|
|
3671
|
+
required: ["repo", "signals"]
|
|
3841
3672
|
},
|
|
3842
3673
|
outputSchema: {
|
|
3843
3674
|
type: "object",
|
|
3844
3675
|
properties: {
|
|
3676
|
+
success: { type: "boolean" },
|
|
3845
3677
|
repo: { type: "string" },
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
title: { type: "string" },
|
|
3849
|
-
status: { type: "string" },
|
|
3850
|
-
priority: { type: "number" }
|
|
3678
|
+
summary: { type: "string" },
|
|
3679
|
+
signalCount: { type: "number" }
|
|
3851
3680
|
},
|
|
3852
|
-
required: ["
|
|
3681
|
+
required: ["success", "repo", "summary", "signalCount"]
|
|
3853
3682
|
}
|
|
3854
3683
|
},
|
|
3855
3684
|
{
|
|
3856
|
-
name: "memory-
|
|
3857
|
-
title: "Memory
|
|
3858
|
-
description: "
|
|
3685
|
+
name: "memory-delete",
|
|
3686
|
+
title: "Memory Delete",
|
|
3687
|
+
description: "Soft-delete one or more memory entries. Supports single 'id' or bulk 'ids'.",
|
|
3688
|
+
annotations: {
|
|
3689
|
+
readOnlyHint: false,
|
|
3690
|
+
idempotentHint: false,
|
|
3691
|
+
destructiveHint: true,
|
|
3692
|
+
openWorldHint: false
|
|
3693
|
+
},
|
|
3859
3694
|
inputSchema: {
|
|
3860
3695
|
type: "object",
|
|
3861
3696
|
properties: {
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3697
|
+
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
3698
|
+
id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
|
|
3699
|
+
ids: {
|
|
3700
|
+
type: "array",
|
|
3701
|
+
items: { type: "string", format: "uuid" },
|
|
3702
|
+
minItems: 1,
|
|
3703
|
+
description: "Array of memory IDs to delete"
|
|
3704
|
+
},
|
|
3705
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3865
3706
|
}
|
|
3707
|
+
},
|
|
3708
|
+
outputSchema: {
|
|
3709
|
+
type: "object",
|
|
3710
|
+
properties: {
|
|
3711
|
+
success: { type: "boolean" },
|
|
3712
|
+
id: { type: "string" },
|
|
3713
|
+
ids: { type: "array", items: { type: "string" } },
|
|
3714
|
+
repo: { type: "string" },
|
|
3715
|
+
deletedCount: { type: "number" }
|
|
3716
|
+
},
|
|
3717
|
+
required: ["success"]
|
|
3866
3718
|
}
|
|
3867
3719
|
},
|
|
3868
3720
|
{
|
|
3869
|
-
name: "standard-
|
|
3870
|
-
title: "Standard
|
|
3871
|
-
description: "
|
|
3721
|
+
name: "standard-delete",
|
|
3722
|
+
title: "Standard Delete",
|
|
3723
|
+
description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
|
|
3724
|
+
annotations: {
|
|
3725
|
+
readOnlyHint: false,
|
|
3726
|
+
idempotentHint: false,
|
|
3727
|
+
destructiveHint: true,
|
|
3728
|
+
openWorldHint: false
|
|
3729
|
+
},
|
|
3872
3730
|
inputSchema: {
|
|
3873
3731
|
type: "object",
|
|
3874
3732
|
properties: {
|
|
3875
|
-
|
|
3876
|
-
|
|
3733
|
+
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
3734
|
+
id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
|
|
3735
|
+
ids: {
|
|
3736
|
+
type: "array",
|
|
3737
|
+
items: { type: "string", format: "uuid" },
|
|
3738
|
+
minItems: 1,
|
|
3739
|
+
description: "Array of coding standard IDs to delete"
|
|
3740
|
+
},
|
|
3741
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3742
|
+
}
|
|
3743
|
+
},
|
|
3744
|
+
outputSchema: {
|
|
3745
|
+
type: "object",
|
|
3746
|
+
properties: {
|
|
3747
|
+
success: { type: "boolean" },
|
|
3748
|
+
id: { type: "string" },
|
|
3749
|
+
ids: { type: "array", items: { type: "string" } },
|
|
3750
|
+
repo: { type: "string" },
|
|
3751
|
+
deletedCount: { type: "number" }
|
|
3877
3752
|
},
|
|
3878
|
-
required: ["
|
|
3753
|
+
required: ["success"]
|
|
3879
3754
|
}
|
|
3880
3755
|
},
|
|
3881
3756
|
{
|
|
3882
|
-
name: "
|
|
3883
|
-
title: "
|
|
3884
|
-
description: "
|
|
3757
|
+
name: "memory-recap",
|
|
3758
|
+
title: "Memory Recap",
|
|
3759
|
+
description: "AGGREGATED OVERVIEW LAYER: Returns stats (counts by type) and a pointer table of top memories [id, code, title, type, importance]. NO content. Use for orientation only \u2014 retrieve full memory via memory-detail.",
|
|
3760
|
+
annotations: {
|
|
3761
|
+
readOnlyHint: true,
|
|
3762
|
+
idempotentHint: true,
|
|
3763
|
+
openWorldHint: false
|
|
3764
|
+
},
|
|
3885
3765
|
inputSchema: {
|
|
3886
3766
|
type: "object",
|
|
3887
3767
|
properties: {
|
|
3888
|
-
repo: { type: "string", description: "Repository name" },
|
|
3889
|
-
|
|
3890
|
-
|
|
3768
|
+
repo: { type: "string", description: "Repository name (required)" },
|
|
3769
|
+
limit: {
|
|
3770
|
+
type: "number",
|
|
3771
|
+
minimum: 1,
|
|
3772
|
+
maximum: 50,
|
|
3773
|
+
default: 20,
|
|
3774
|
+
description: "Maximum number of top memories to return in the pointer table"
|
|
3775
|
+
},
|
|
3776
|
+
offset: {
|
|
3777
|
+
type: "number",
|
|
3778
|
+
minimum: 0,
|
|
3779
|
+
default: 0,
|
|
3780
|
+
description: "Number of memories to skip for pagination (optional, default 0)"
|
|
3781
|
+
},
|
|
3891
3782
|
structured: {
|
|
3892
3783
|
type: "boolean",
|
|
3893
3784
|
default: false,
|
|
3894
|
-
description: "If true, returns structured JSON without the text content
|
|
3785
|
+
description: "If true, returns structured JSON without the text content summary."
|
|
3895
3786
|
}
|
|
3896
3787
|
},
|
|
3897
3788
|
required: ["repo"]
|
|
3789
|
+
},
|
|
3790
|
+
outputSchema: {
|
|
3791
|
+
type: "object",
|
|
3792
|
+
properties: {
|
|
3793
|
+
schema: { type: "string", enum: ["memory-recap"] },
|
|
3794
|
+
repo: { type: "string" },
|
|
3795
|
+
count: { type: "number", description: "Number of rows in the top pointer table" },
|
|
3796
|
+
total: { type: "number", description: "Total active memories in repo" },
|
|
3797
|
+
offset: { type: "number" },
|
|
3798
|
+
limit: { type: "number" },
|
|
3799
|
+
stats: {
|
|
3800
|
+
type: "object",
|
|
3801
|
+
properties: {
|
|
3802
|
+
byType: {
|
|
3803
|
+
type: "object",
|
|
3804
|
+
description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
|
|
3805
|
+
}
|
|
3806
|
+
},
|
|
3807
|
+
required: ["byType"]
|
|
3808
|
+
},
|
|
3809
|
+
top: {
|
|
3810
|
+
type: "object",
|
|
3811
|
+
properties: {
|
|
3812
|
+
columns: {
|
|
3813
|
+
type: "array",
|
|
3814
|
+
items: { type: "string" },
|
|
3815
|
+
description: "Column names: [id, code, title, type, importance]"
|
|
3816
|
+
},
|
|
3817
|
+
rows: {
|
|
3818
|
+
type: "array",
|
|
3819
|
+
items: { type: "array" },
|
|
3820
|
+
description: "Each row: [id, code, title, type, importance]. Fetch full content via memory-detail"
|
|
3821
|
+
}
|
|
3822
|
+
},
|
|
3823
|
+
required: ["columns", "rows"]
|
|
3824
|
+
}
|
|
3825
|
+
},
|
|
3826
|
+
required: ["schema", "repo", "count", "total", "offset", "limit", "stats", "top"]
|
|
3898
3827
|
}
|
|
3899
3828
|
},
|
|
3900
3829
|
{
|
|
3901
|
-
name: "
|
|
3902
|
-
title: "
|
|
3903
|
-
description: "
|
|
3830
|
+
name: "task-create",
|
|
3831
|
+
title: "Task Create",
|
|
3832
|
+
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.",
|
|
3904
3833
|
annotations: {
|
|
3905
3834
|
readOnlyHint: false,
|
|
3906
3835
|
idempotentHint: false,
|
|
3907
|
-
destructiveHint: false,
|
|
3908
3836
|
openWorldHint: false
|
|
3909
3837
|
},
|
|
3910
3838
|
inputSchema: {
|
|
3911
3839
|
type: "object",
|
|
3912
3840
|
properties: {
|
|
3913
|
-
type:
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
"code_fact",
|
|
3917
|
-
"decision",
|
|
3918
|
-
"mistake",
|
|
3919
|
-
"pattern",
|
|
3920
|
-
"task_archive"
|
|
3921
|
-
],
|
|
3922
|
-
description: "Type of durable knowledge being stored. Coordination types such as file_claim are intentionally unsupported."
|
|
3923
|
-
},
|
|
3841
|
+
repo: { type: "string", description: "Repository name" },
|
|
3842
|
+
task_code: { type: "string", description: "Unique task code (e.g. TASK-001) (Required for single task)" },
|
|
3843
|
+
phase: { type: "string", description: "Project phase (Required for single task)" },
|
|
3924
3844
|
title: {
|
|
3925
3845
|
type: "string",
|
|
3926
3846
|
minLength: 3,
|
|
3927
3847
|
maxLength: 100,
|
|
3928
|
-
description: "
|
|
3929
|
-
},
|
|
3930
|
-
content: {
|
|
3931
|
-
type: "string",
|
|
3932
|
-
minLength: 10,
|
|
3933
|
-
description: "The memory content"
|
|
3934
|
-
},
|
|
3935
|
-
importance: {
|
|
3936
|
-
type: "number",
|
|
3937
|
-
minimum: 1,
|
|
3938
|
-
maximum: 5,
|
|
3939
|
-
description: "Importance score (1-5)"
|
|
3940
|
-
},
|
|
3941
|
-
agent: {
|
|
3942
|
-
type: "string",
|
|
3943
|
-
description: "Name of the agent creating this memory"
|
|
3944
|
-
},
|
|
3945
|
-
role: {
|
|
3946
|
-
type: "string",
|
|
3947
|
-
description: "Role of the agent creating this memory"
|
|
3848
|
+
description: "Task objective (Required for single task)"
|
|
3948
3849
|
},
|
|
3949
|
-
|
|
3850
|
+
description: { type: "string", description: "Detailed description (Required for single task)" },
|
|
3851
|
+
status: {
|
|
3950
3852
|
type: "string",
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
type: "object",
|
|
3955
|
-
properties: {
|
|
3956
|
-
repo: { type: "string", description: "Repository name" },
|
|
3957
|
-
branch: { type: "string" },
|
|
3958
|
-
folder: { type: "string" },
|
|
3959
|
-
language: { type: "string" }
|
|
3960
|
-
},
|
|
3961
|
-
required: ["repo"]
|
|
3853
|
+
enum: ["backlog", "pending"],
|
|
3854
|
+
default: "backlog",
|
|
3855
|
+
description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
|
|
3962
3856
|
},
|
|
3963
|
-
|
|
3857
|
+
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3858
|
+
agent: { type: "string" },
|
|
3859
|
+
role: { type: "string" },
|
|
3860
|
+
doc_path: { type: "string" },
|
|
3861
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3862
|
+
metadata: { type: "object" },
|
|
3863
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3864
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3865
|
+
est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
|
|
3866
|
+
tasks: {
|
|
3964
3867
|
type: "array",
|
|
3965
|
-
items: {
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3868
|
+
items: {
|
|
3869
|
+
type: "object",
|
|
3870
|
+
properties: {
|
|
3871
|
+
task_code: { type: "string" },
|
|
3872
|
+
phase: { type: "string" },
|
|
3873
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3874
|
+
description: { type: "string" },
|
|
3875
|
+
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
3876
|
+
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
3877
|
+
agent: { type: "string" },
|
|
3878
|
+
role: { type: "string" },
|
|
3879
|
+
doc_path: { type: "string" },
|
|
3880
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3881
|
+
metadata: { type: "object" },
|
|
3882
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3883
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3884
|
+
est_tokens: { type: "number", minimum: 0 }
|
|
3885
|
+
},
|
|
3886
|
+
required: ["task_code", "phase", "title", "description"]
|
|
3887
|
+
},
|
|
3888
|
+
description: "Array of tasks for bulk creation"
|
|
3975
3889
|
},
|
|
3976
|
-
|
|
3977
|
-
supersedes: { type: "string", format: "uuid" },
|
|
3978
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the stored memory." }
|
|
3890
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
3979
3891
|
},
|
|
3980
|
-
required: ["
|
|
3892
|
+
required: ["repo"]
|
|
3981
3893
|
},
|
|
3982
3894
|
outputSchema: {
|
|
3983
3895
|
type: "object",
|
|
3984
3896
|
properties: {
|
|
3985
3897
|
success: { type: "boolean" },
|
|
3986
3898
|
id: { type: "string" },
|
|
3987
|
-
|
|
3899
|
+
task_code: { type: "string" },
|
|
3988
3900
|
repo: { type: "string" },
|
|
3989
|
-
|
|
3901
|
+
phase: { type: "string" },
|
|
3990
3902
|
title: { type: "string" },
|
|
3991
|
-
|
|
3992
|
-
|
|
3903
|
+
status: { type: "string" },
|
|
3904
|
+
priority: { type: "number" },
|
|
3905
|
+
createdCount: { type: "number" },
|
|
3906
|
+
taskCodes: { type: "array", items: { type: "string" } }
|
|
3993
3907
|
},
|
|
3994
|
-
required: ["success"]
|
|
3908
|
+
required: ["success", "repo"]
|
|
3995
3909
|
}
|
|
3996
3910
|
},
|
|
3997
3911
|
{
|
|
3998
|
-
name: "
|
|
3999
|
-
title: "
|
|
4000
|
-
description: "
|
|
3912
|
+
name: "task-update",
|
|
3913
|
+
title: "Task Update",
|
|
3914
|
+
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.",
|
|
4001
3915
|
annotations: {
|
|
4002
3916
|
readOnlyHint: false,
|
|
4003
3917
|
idempotentHint: false,
|
|
@@ -4006,80 +3920,98 @@ var TOOL_DEFINITIONS = [
|
|
|
4006
3920
|
inputSchema: {
|
|
4007
3921
|
type: "object",
|
|
4008
3922
|
properties: {
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
3923
|
+
repo: { type: "string", description: "Repository name" },
|
|
3924
|
+
id: { type: "string", format: "uuid", description: "Task ID (for single update)" },
|
|
3925
|
+
ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk update)" },
|
|
3926
|
+
task_code: { type: "string" },
|
|
3927
|
+
phase: { type: "string" },
|
|
3928
|
+
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
3929
|
+
description: { type: "string" },
|
|
3930
|
+
status: {
|
|
3931
|
+
type: "string",
|
|
3932
|
+
enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
|
|
3933
|
+
description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
|
|
3934
|
+
},
|
|
3935
|
+
priority: { type: "number", minimum: 1, maximum: 5 },
|
|
3936
|
+
agent: { type: "string" },
|
|
3937
|
+
role: { type: "string" },
|
|
3938
|
+
model: { type: "string" },
|
|
3939
|
+
comment: {
|
|
3940
|
+
type: "string",
|
|
3941
|
+
description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
|
|
3942
|
+
},
|
|
3943
|
+
doc_path: { type: "string" },
|
|
3944
|
+
tags: { type: "array", items: { type: "string" } },
|
|
3945
|
+
metadata: { type: "object" },
|
|
3946
|
+
parent_id: { type: "string", format: "uuid" },
|
|
3947
|
+
depends_on: { type: "string", format: "uuid" },
|
|
3948
|
+
est_tokens: {
|
|
3949
|
+
type: "number",
|
|
3950
|
+
minimum: 0,
|
|
3951
|
+
description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
|
|
3952
|
+
},
|
|
3953
|
+
force: {
|
|
3954
|
+
type: "boolean",
|
|
3955
|
+
description: "If true, bypasses status transition validation (e.g. pending -> completed)."
|
|
3956
|
+
},
|
|
4012
3957
|
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4013
3958
|
},
|
|
4014
|
-
required: ["
|
|
3959
|
+
required: ["repo"]
|
|
4015
3960
|
},
|
|
4016
3961
|
outputSchema: {
|
|
4017
3962
|
type: "object",
|
|
4018
3963
|
properties: {
|
|
4019
3964
|
success: { type: "boolean" },
|
|
4020
3965
|
id: { type: "string" },
|
|
4021
|
-
|
|
3966
|
+
ids: { type: "array", items: { type: "string" } },
|
|
3967
|
+
repo: { type: "string" },
|
|
3968
|
+
status: { type: "string" },
|
|
3969
|
+
archivedToMemory: { type: "boolean" },
|
|
3970
|
+
updatedFields: {
|
|
3971
|
+
type: "array",
|
|
3972
|
+
items: { type: "string" }
|
|
3973
|
+
},
|
|
3974
|
+
updatedCount: { type: "number" }
|
|
4022
3975
|
},
|
|
4023
|
-
required: ["success", "
|
|
3976
|
+
required: ["success", "repo"]
|
|
4024
3977
|
}
|
|
4025
3978
|
},
|
|
4026
3979
|
{
|
|
4027
|
-
name: "
|
|
4028
|
-
title: "
|
|
4029
|
-
description: "
|
|
3980
|
+
name: "task-delete",
|
|
3981
|
+
title: "Task Delete",
|
|
3982
|
+
description: "Delete one or more tasks from a repository. Supports single 'id' or bulk 'ids'.",
|
|
4030
3983
|
annotations: {
|
|
4031
3984
|
readOnlyHint: false,
|
|
4032
3985
|
idempotentHint: false,
|
|
4033
|
-
destructiveHint:
|
|
3986
|
+
destructiveHint: true,
|
|
4034
3987
|
openWorldHint: false
|
|
4035
3988
|
},
|
|
4036
3989
|
inputSchema: {
|
|
4037
3990
|
type: "object",
|
|
4038
3991
|
properties: {
|
|
4039
|
-
|
|
4040
|
-
type:
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
"code_fact",
|
|
4044
|
-
"decision",
|
|
4045
|
-
"mistake",
|
|
4046
|
-
"pattern",
|
|
4047
|
-
"task_archive"
|
|
4048
|
-
]
|
|
4049
|
-
},
|
|
4050
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
4051
|
-
content: { type: "string", minLength: 10 },
|
|
4052
|
-
importance: { type: "number", minimum: 1, maximum: 5 },
|
|
4053
|
-
agent: { type: "string" },
|
|
4054
|
-
role: { type: "string" },
|
|
4055
|
-
status: { type: "string", enum: ["active", "archived"] },
|
|
4056
|
-
supersedes: { type: "string", format: "uuid" },
|
|
4057
|
-
tags: { type: "array", items: { type: "string" } },
|
|
4058
|
-
metadata: { type: "object" },
|
|
4059
|
-
is_global: { type: "boolean" },
|
|
4060
|
-
completed_at: { type: "string" },
|
|
4061
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON of the updated memory." }
|
|
3992
|
+
repo: { type: "string", description: "Repository name" },
|
|
3993
|
+
id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
|
|
3994
|
+
ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
|
|
3995
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4062
3996
|
},
|
|
4063
|
-
required: ["
|
|
3997
|
+
required: ["repo"]
|
|
4064
3998
|
},
|
|
4065
3999
|
outputSchema: {
|
|
4066
4000
|
type: "object",
|
|
4067
4001
|
properties: {
|
|
4068
4002
|
success: { type: "boolean" },
|
|
4069
4003
|
id: { type: "string" },
|
|
4004
|
+
ids: { type: "array", items: { type: "string" } },
|
|
4070
4005
|
repo: { type: "string" },
|
|
4071
|
-
|
|
4072
|
-
type: "array",
|
|
4073
|
-
items: { type: "string" }
|
|
4074
|
-
}
|
|
4006
|
+
deletedCount: { type: "number" }
|
|
4075
4007
|
},
|
|
4076
|
-
required: ["success", "
|
|
4008
|
+
required: ["success", "repo"]
|
|
4077
4009
|
}
|
|
4078
4010
|
},
|
|
4079
4011
|
{
|
|
4080
|
-
name: "
|
|
4081
|
-
title: "
|
|
4082
|
-
description: "
|
|
4012
|
+
name: "task-list",
|
|
4013
|
+
title: "Task List",
|
|
4014
|
+
description: "PRIMARY navigation and search tool for tasks. Returns a compact tabular list of tasks (id, task_code, title, status, priority, updated_at, comments_count). Defaults to in_progress and pending tasks. Use 'query' to filter by code, title, or description. Use 'status' (comma-separated) for specific filters. AGENTS: call this once at start, pick ONE task, then call task-detail.",
|
|
4083
4015
|
annotations: {
|
|
4084
4016
|
readOnlyHint: true,
|
|
4085
4017
|
idempotentHint: true,
|
|
@@ -4088,41 +4020,35 @@ var TOOL_DEFINITIONS = [
|
|
|
4088
4020
|
inputSchema: {
|
|
4089
4021
|
type: "object",
|
|
4090
4022
|
properties: {
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
current_tags: {
|
|
4095
|
-
type: "array",
|
|
4096
|
-
items: { type: "string" },
|
|
4097
|
-
description: "Active tech stack tags (e.g., ['filament', 'react'])"
|
|
4023
|
+
repo: {
|
|
4024
|
+
type: "string",
|
|
4025
|
+
description: "Repository name"
|
|
4098
4026
|
},
|
|
4099
|
-
|
|
4100
|
-
type: "
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
enum: [
|
|
4104
|
-
"code_fact",
|
|
4105
|
-
"decision",
|
|
4106
|
-
"mistake",
|
|
4107
|
-
"pattern",
|
|
4108
|
-
"task_archive"
|
|
4109
|
-
]
|
|
4110
|
-
}
|
|
4027
|
+
status: {
|
|
4028
|
+
type: "string",
|
|
4029
|
+
default: "in_progress,pending",
|
|
4030
|
+
description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
|
|
4111
4031
|
},
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4032
|
+
phase: {
|
|
4033
|
+
type: "string",
|
|
4034
|
+
description: "Filter by phase (e.g., 'research', 'implementation')"
|
|
4035
|
+
},
|
|
4036
|
+
query: {
|
|
4037
|
+
type: "string",
|
|
4038
|
+
description: "Search keyword matching task code, title, or description"
|
|
4039
|
+
},
|
|
4040
|
+
limit: {
|
|
4041
|
+
type: "number",
|
|
4042
|
+
minimum: 1,
|
|
4043
|
+
maximum: 100,
|
|
4044
|
+
default: 5,
|
|
4045
|
+
description: "Maximum rows to return (default 5)"
|
|
4046
|
+
},
|
|
4047
|
+
offset: {
|
|
4048
|
+
type: "number",
|
|
4049
|
+
minimum: 0,
|
|
4050
|
+
default: 0,
|
|
4051
|
+
description: "Offset for pagination"
|
|
4126
4052
|
},
|
|
4127
4053
|
structured: {
|
|
4128
4054
|
type: "boolean",
|
|
@@ -4130,402 +4056,328 @@ var TOOL_DEFINITIONS = [
|
|
|
4130
4056
|
description: "If true, returns structured JSON without the text content summary."
|
|
4131
4057
|
}
|
|
4132
4058
|
},
|
|
4133
|
-
required: ["
|
|
4059
|
+
required: ["repo"]
|
|
4134
4060
|
},
|
|
4135
4061
|
outputSchema: {
|
|
4136
4062
|
type: "object",
|
|
4137
4063
|
properties: {
|
|
4138
|
-
schema: { type: "string", enum: ["
|
|
4139
|
-
|
|
4140
|
-
count: { type: "number", description: "Number of rows returned" },
|
|
4141
|
-
total: { type: "number", description: "Total matching memories" },
|
|
4142
|
-
offset: { type: "number" },
|
|
4143
|
-
limit: { type: "number" },
|
|
4144
|
-
results: {
|
|
4064
|
+
schema: { type: "string", enum: ["task-list"] },
|
|
4065
|
+
tasks: {
|
|
4145
4066
|
type: "object",
|
|
4146
4067
|
properties: {
|
|
4147
4068
|
columns: {
|
|
4148
4069
|
type: "array",
|
|
4149
4070
|
items: { type: "string" },
|
|
4150
|
-
description: "Column names:
|
|
4071
|
+
description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
|
|
4151
4072
|
},
|
|
4152
4073
|
rows: {
|
|
4153
4074
|
type: "array",
|
|
4154
4075
|
items: { type: "array" },
|
|
4155
|
-
description: "Each row: [id, title,
|
|
4076
|
+
description: "Each row: [id, task_code, title, status, priority, updated_at, comments_count]. Use task-detail to fetch full task."
|
|
4156
4077
|
}
|
|
4157
4078
|
},
|
|
4158
4079
|
required: ["columns", "rows"]
|
|
4159
|
-
}
|
|
4080
|
+
},
|
|
4081
|
+
count: { type: "number" },
|
|
4082
|
+
offset: { type: "number" }
|
|
4160
4083
|
},
|
|
4161
|
-
required: ["schema", "
|
|
4084
|
+
required: ["schema", "tasks", "count"]
|
|
4162
4085
|
}
|
|
4163
4086
|
},
|
|
4164
4087
|
{
|
|
4165
|
-
name: "
|
|
4166
|
-
title: "
|
|
4167
|
-
description: "
|
|
4088
|
+
name: "handoff-create",
|
|
4089
|
+
title: "Handoff Create",
|
|
4090
|
+
description: "Create a pending handoff only when unfinished work needs context transfer between agents. Do not use this for completed-work summaries, release notes, validation notes, or archives; put those on task-update/task comments or durable memory.",
|
|
4168
4091
|
annotations: {
|
|
4169
4092
|
readOnlyHint: false,
|
|
4170
4093
|
idempotentHint: false,
|
|
4094
|
+
destructiveHint: false,
|
|
4171
4095
|
openWorldHint: false
|
|
4172
4096
|
},
|
|
4173
4097
|
inputSchema: {
|
|
4174
4098
|
type: "object",
|
|
4175
4099
|
properties: {
|
|
4176
4100
|
repo: { type: "string", description: "Repository name" },
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4101
|
+
from_agent: { type: "string", description: "Agent creating the handoff" },
|
|
4102
|
+
to_agent: { type: "string", description: "Optional target agent" },
|
|
4103
|
+
task_id: { type: "string", format: "uuid", description: "Optional task id to associate" },
|
|
4104
|
+
task_code: { type: "string", description: "Optional task code to associate" },
|
|
4105
|
+
summary: { type: "string", minLength: 1, description: "Concise human-readable transfer summary" },
|
|
4106
|
+
context: {
|
|
4107
|
+
type: "object",
|
|
4108
|
+
description: "Structured handoff context. Include next_steps, blockers, or remaining_work unless a target agent or task is provided."
|
|
4182
4109
|
},
|
|
4183
|
-
|
|
4110
|
+
expires_at: { type: "string", description: "Optional expiration timestamp" },
|
|
4111
|
+
structured: { type: "boolean", default: false }
|
|
4184
4112
|
},
|
|
4185
|
-
required: ["repo", "
|
|
4113
|
+
required: ["repo", "from_agent", "summary"]
|
|
4186
4114
|
},
|
|
4187
4115
|
outputSchema: {
|
|
4188
4116
|
type: "object",
|
|
4189
4117
|
properties: {
|
|
4190
|
-
|
|
4118
|
+
id: { type: "string" },
|
|
4191
4119
|
repo: { type: "string" },
|
|
4120
|
+
from_agent: { type: "string" },
|
|
4121
|
+
to_agent: { type: "string", nullable: true },
|
|
4122
|
+
task_id: { type: "string", nullable: true },
|
|
4192
4123
|
summary: { type: "string" },
|
|
4193
|
-
|
|
4124
|
+
context: { type: "object" },
|
|
4125
|
+
status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
|
|
4126
|
+
created_at: { type: "string" },
|
|
4127
|
+
updated_at: { type: "string" },
|
|
4128
|
+
expires_at: { type: "string", nullable: true }
|
|
4194
4129
|
},
|
|
4195
|
-
required: ["
|
|
4130
|
+
required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
|
|
4196
4131
|
}
|
|
4197
4132
|
},
|
|
4198
4133
|
{
|
|
4199
|
-
name: "
|
|
4200
|
-
title: "
|
|
4201
|
-
description: "
|
|
4134
|
+
name: "handoff-update",
|
|
4135
|
+
title: "Handoff Update",
|
|
4136
|
+
description: "Close or reclassify a handoff after it has been consumed or found stale. Use accepted when transfer context was consumed, rejected when intentionally declined, and expired when the handoff is obsolete or only described completed work.",
|
|
4202
4137
|
annotations: {
|
|
4203
4138
|
readOnlyHint: false,
|
|
4204
4139
|
idempotentHint: false,
|
|
4205
|
-
destructiveHint:
|
|
4140
|
+
destructiveHint: false,
|
|
4206
4141
|
openWorldHint: false
|
|
4207
4142
|
},
|
|
4208
4143
|
inputSchema: {
|
|
4209
4144
|
type: "object",
|
|
4210
4145
|
properties: {
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
type: "array",
|
|
4215
|
-
items: { type: "string", format: "uuid" },
|
|
4216
|
-
minItems: 1,
|
|
4217
|
-
description: "Array of memory IDs to delete"
|
|
4218
|
-
},
|
|
4219
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4220
|
-
}
|
|
4221
|
-
},
|
|
4222
|
-
outputSchema: {
|
|
4223
|
-
type: "object",
|
|
4224
|
-
properties: {
|
|
4225
|
-
success: { type: "boolean" },
|
|
4226
|
-
id: { type: "string" },
|
|
4227
|
-
ids: { type: "array", items: { type: "string" } },
|
|
4228
|
-
repo: { type: "string" },
|
|
4229
|
-
deletedCount: { type: "number" }
|
|
4146
|
+
id: { type: "string", format: "uuid", description: "Handoff ID" },
|
|
4147
|
+
status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
|
|
4148
|
+
structured: { type: "boolean", default: false }
|
|
4230
4149
|
},
|
|
4231
|
-
required: ["
|
|
4232
|
-
}
|
|
4233
|
-
},
|
|
4234
|
-
{
|
|
4235
|
-
name: "standard-delete",
|
|
4236
|
-
title: "Standard Delete",
|
|
4237
|
-
description: "Delete one or more coding standards. Supports single 'id' or bulk 'ids'.",
|
|
4238
|
-
annotations: {
|
|
4239
|
-
readOnlyHint: false,
|
|
4240
|
-
idempotentHint: false,
|
|
4241
|
-
destructiveHint: true,
|
|
4242
|
-
openWorldHint: false
|
|
4243
|
-
},
|
|
4244
|
-
inputSchema: {
|
|
4245
|
-
type: "object",
|
|
4246
|
-
properties: {
|
|
4247
|
-
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
4248
|
-
id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
|
|
4249
|
-
ids: {
|
|
4250
|
-
type: "array",
|
|
4251
|
-
items: { type: "string", format: "uuid" },
|
|
4252
|
-
minItems: 1,
|
|
4253
|
-
description: "Array of coding standard IDs to delete"
|
|
4254
|
-
},
|
|
4255
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4256
|
-
}
|
|
4150
|
+
required: ["id", "status"]
|
|
4257
4151
|
},
|
|
4258
4152
|
outputSchema: {
|
|
4259
4153
|
type: "object",
|
|
4260
4154
|
properties: {
|
|
4261
4155
|
success: { type: "boolean" },
|
|
4262
4156
|
id: { type: "string" },
|
|
4263
|
-
|
|
4264
|
-
repo: { type: "string" },
|
|
4265
|
-
deletedCount: { type: "number" }
|
|
4157
|
+
status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] }
|
|
4266
4158
|
},
|
|
4267
|
-
required: ["success"]
|
|
4159
|
+
required: ["success", "id", "status"]
|
|
4268
4160
|
}
|
|
4269
4161
|
},
|
|
4270
4162
|
{
|
|
4271
|
-
name: "
|
|
4272
|
-
title: "
|
|
4273
|
-
description: "
|
|
4163
|
+
name: "handoff-list",
|
|
4164
|
+
title: "Handoff List",
|
|
4165
|
+
description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
|
|
4274
4166
|
annotations: {
|
|
4275
4167
|
readOnlyHint: true,
|
|
4276
4168
|
idempotentHint: true,
|
|
4277
4169
|
openWorldHint: false
|
|
4278
|
-
},
|
|
4279
|
-
inputSchema: {
|
|
4280
|
-
type: "object",
|
|
4281
|
-
properties: {
|
|
4282
|
-
repo: { type: "string", description: "Repository name
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
},
|
|
4290
|
-
offset: {
|
|
4291
|
-
type: "number",
|
|
4292
|
-
minimum: 0,
|
|
4293
|
-
default: 0,
|
|
4294
|
-
description: "Number of memories to skip for pagination (optional, default 0)"
|
|
4295
|
-
},
|
|
4296
|
-
structured: {
|
|
4297
|
-
type: "boolean",
|
|
4298
|
-
default: false,
|
|
4299
|
-
description: "If true, returns structured JSON without the text content summary."
|
|
4300
|
-
}
|
|
4170
|
+
},
|
|
4171
|
+
inputSchema: {
|
|
4172
|
+
type: "object",
|
|
4173
|
+
properties: {
|
|
4174
|
+
repo: { type: "string", description: "Repository name" },
|
|
4175
|
+
status: { type: "string", enum: ["pending", "accepted", "rejected", "expired"] },
|
|
4176
|
+
from_agent: { type: "string" },
|
|
4177
|
+
to_agent: { type: "string" },
|
|
4178
|
+
limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
|
|
4179
|
+
offset: { type: "number", minimum: 0, default: 0 },
|
|
4180
|
+
structured: { type: "boolean", default: false }
|
|
4301
4181
|
},
|
|
4302
4182
|
required: ["repo"]
|
|
4303
4183
|
},
|
|
4304
4184
|
outputSchema: {
|
|
4305
4185
|
type: "object",
|
|
4306
4186
|
properties: {
|
|
4307
|
-
schema: { type: "string", enum: ["
|
|
4308
|
-
|
|
4309
|
-
count: { type: "number", description: "Number of rows in the top pointer table" },
|
|
4310
|
-
total: { type: "number", description: "Total active memories in repo" },
|
|
4311
|
-
offset: { type: "number" },
|
|
4312
|
-
limit: { type: "number" },
|
|
4313
|
-
stats: {
|
|
4314
|
-
type: "object",
|
|
4315
|
-
properties: {
|
|
4316
|
-
byType: {
|
|
4317
|
-
type: "object",
|
|
4318
|
-
description: "Count of active memories per type (e.g. { decision: 3, code_fact: 7 })"
|
|
4319
|
-
}
|
|
4320
|
-
},
|
|
4321
|
-
required: ["byType"]
|
|
4322
|
-
},
|
|
4323
|
-
top: {
|
|
4187
|
+
schema: { type: "string", enum: ["handoff-list"] },
|
|
4188
|
+
handoffs: {
|
|
4324
4189
|
type: "object",
|
|
4325
4190
|
properties: {
|
|
4326
4191
|
columns: {
|
|
4327
4192
|
type: "array",
|
|
4328
4193
|
items: { type: "string" },
|
|
4329
|
-
description: "Column names: [id,
|
|
4194
|
+
description: "Column names: [id, from_agent, to_agent, task_id, status, created_at, summary]"
|
|
4330
4195
|
},
|
|
4331
4196
|
rows: {
|
|
4332
4197
|
type: "array",
|
|
4333
4198
|
items: { type: "array" },
|
|
4334
|
-
description: "Each row: [id,
|
|
4199
|
+
description: "Each row: [id, from_agent, to_agent, task_id, status, created_at, summary]"
|
|
4335
4200
|
}
|
|
4336
4201
|
},
|
|
4337
4202
|
required: ["columns", "rows"]
|
|
4338
|
-
}
|
|
4203
|
+
},
|
|
4204
|
+
count: { type: "number" },
|
|
4205
|
+
offset: { type: "number" }
|
|
4339
4206
|
},
|
|
4340
|
-
required: ["schema", "
|
|
4207
|
+
required: ["schema", "handoffs", "count", "offset"]
|
|
4341
4208
|
}
|
|
4342
4209
|
},
|
|
4343
4210
|
{
|
|
4344
|
-
name: "task-
|
|
4345
|
-
title: "Task
|
|
4346
|
-
description: "
|
|
4211
|
+
name: "task-claim",
|
|
4212
|
+
title: "Task Claim",
|
|
4213
|
+
description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
|
|
4347
4214
|
annotations: {
|
|
4348
4215
|
readOnlyHint: false,
|
|
4349
4216
|
idempotentHint: false,
|
|
4217
|
+
destructiveHint: false,
|
|
4350
4218
|
openWorldHint: false
|
|
4351
4219
|
},
|
|
4352
4220
|
inputSchema: {
|
|
4353
4221
|
type: "object",
|
|
4354
4222
|
properties: {
|
|
4355
4223
|
repo: { type: "string", description: "Repository name" },
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
description: "Task objective (Required for single task)"
|
|
4363
|
-
},
|
|
4364
|
-
description: { type: "string", description: "Detailed description (Required for single task)" },
|
|
4365
|
-
status: {
|
|
4366
|
-
type: "string",
|
|
4367
|
-
enum: ["backlog", "pending"],
|
|
4368
|
-
default: "backlog",
|
|
4369
|
-
description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
|
|
4370
|
-
},
|
|
4371
|
-
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
4372
|
-
agent: { type: "string" },
|
|
4373
|
-
role: { type: "string" },
|
|
4374
|
-
doc_path: { type: "string" },
|
|
4375
|
-
tags: { type: "array", items: { type: "string" } },
|
|
4376
|
-
metadata: { type: "object" },
|
|
4377
|
-
parent_id: { type: "string", format: "uuid" },
|
|
4378
|
-
depends_on: { type: "string", format: "uuid" },
|
|
4379
|
-
est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
|
|
4380
|
-
tasks: {
|
|
4381
|
-
type: "array",
|
|
4382
|
-
items: {
|
|
4383
|
-
type: "object",
|
|
4384
|
-
properties: {
|
|
4385
|
-
task_code: { type: "string" },
|
|
4386
|
-
phase: { type: "string" },
|
|
4387
|
-
title: { type: "string", minLength: 3, maxLength: 100 },
|
|
4388
|
-
description: { type: "string" },
|
|
4389
|
-
status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
|
|
4390
|
-
priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
|
|
4391
|
-
agent: { type: "string" },
|
|
4392
|
-
role: { type: "string" },
|
|
4393
|
-
doc_path: { type: "string" },
|
|
4394
|
-
tags: { type: "array", items: { type: "string" } },
|
|
4395
|
-
metadata: { type: "object" },
|
|
4396
|
-
parent_id: { type: "string", format: "uuid" },
|
|
4397
|
-
depends_on: { type: "string", format: "uuid" },
|
|
4398
|
-
est_tokens: { type: "number", minimum: 0 }
|
|
4399
|
-
},
|
|
4400
|
-
required: ["task_code", "phase", "title", "description"]
|
|
4401
|
-
},
|
|
4402
|
-
description: "Array of tasks for bulk creation"
|
|
4403
|
-
},
|
|
4404
|
-
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4224
|
+
task_id: { type: "string", format: "uuid", description: "Task id to claim. Optional if task_code is provided." },
|
|
4225
|
+
task_code: { type: "string", description: "Task code to claim. Optional if task_id is provided." },
|
|
4226
|
+
agent: { type: "string", description: "Claiming agent name" },
|
|
4227
|
+
role: { type: "string", description: "Claiming agent role" },
|
|
4228
|
+
metadata: { type: "object", description: "Optional claim metadata" },
|
|
4229
|
+
structured: { type: "boolean", default: false }
|
|
4405
4230
|
},
|
|
4406
|
-
required: ["repo"]
|
|
4231
|
+
required: ["repo", "agent"]
|
|
4407
4232
|
},
|
|
4408
4233
|
outputSchema: {
|
|
4409
4234
|
type: "object",
|
|
4410
4235
|
properties: {
|
|
4411
|
-
success: { type: "boolean" },
|
|
4412
4236
|
id: { type: "string" },
|
|
4413
|
-
task_code: { type: "string" },
|
|
4414
4237
|
repo: { type: "string" },
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4238
|
+
task_id: { type: "string" },
|
|
4239
|
+
task_code: { type: "string", nullable: true },
|
|
4240
|
+
agent: { type: "string" },
|
|
4241
|
+
role: { type: "string" },
|
|
4242
|
+
claimed_at: { type: "string" },
|
|
4243
|
+
released_at: { type: "string", nullable: true },
|
|
4244
|
+
metadata: { type: "object" }
|
|
4421
4245
|
},
|
|
4422
|
-
required: ["
|
|
4246
|
+
required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
|
|
4423
4247
|
}
|
|
4424
4248
|
},
|
|
4425
4249
|
{
|
|
4426
|
-
name: "
|
|
4427
|
-
title: "
|
|
4428
|
-
description: "
|
|
4250
|
+
name: "standard-store",
|
|
4251
|
+
title: "Standard Store",
|
|
4252
|
+
description: "Store one atomic coding standard. Use for durable implementation rules with explicit context, stack/language filters, and repo/global scope.",
|
|
4429
4253
|
annotations: {
|
|
4430
4254
|
readOnlyHint: false,
|
|
4431
4255
|
idempotentHint: false,
|
|
4256
|
+
destructiveHint: false,
|
|
4432
4257
|
openWorldHint: false
|
|
4433
4258
|
},
|
|
4434
4259
|
inputSchema: {
|
|
4435
4260
|
type: "object",
|
|
4436
4261
|
properties: {
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
type: "string",
|
|
4446
|
-
|
|
4447
|
-
description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
|
|
4448
|
-
},
|
|
4449
|
-
priority: { type: "number", minimum: 1, maximum: 5 },
|
|
4450
|
-
agent: { type: "string" },
|
|
4451
|
-
role: { type: "string" },
|
|
4452
|
-
model: { type: "string" },
|
|
4453
|
-
comment: {
|
|
4454
|
-
type: "string",
|
|
4455
|
-
description: "REQUIRED when changing task status. Explain WHY the status is changing (e.g., 'Starting implementation', 'Blocked by missing API docs', 'Verified fix')."
|
|
4262
|
+
name: { type: "string", minLength: 3, maxLength: 255, description: "Human-readable standard name" },
|
|
4263
|
+
content: { type: "string", minLength: 10, description: "One atomic, actionable standard written as concise Markdown" },
|
|
4264
|
+
parent_id: { type: "string", format: "uuid", description: "Optional parent standard ID when this rule is a child/specialization." },
|
|
4265
|
+
context: { type: "string", description: "Context or category (e.g., 'error-handling', 'security')" },
|
|
4266
|
+
version: { type: "string", description: "Version of the standard (e.g., '1.0.0')" },
|
|
4267
|
+
language: { type: "string", description: "Programming language (e.g., 'typescript', 'python')" },
|
|
4268
|
+
stack: {
|
|
4269
|
+
type: "array",
|
|
4270
|
+
items: { type: "string" },
|
|
4271
|
+
description: "Technology stack (e.g., ['react', 'nextjs'])"
|
|
4456
4272
|
},
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
type: "number",
|
|
4464
|
-
minimum: 0,
|
|
4465
|
-
description: "Estimated total tokens actually used for this task. Required when status changes to 'completed'."
|
|
4273
|
+
repo: { type: "string", description: "Repository name for repo-specific standards. Omit only for global standards." },
|
|
4274
|
+
is_global: { type: "boolean", description: "Whether standard applies globally or repo-specific" },
|
|
4275
|
+
tags: {
|
|
4276
|
+
type: "array",
|
|
4277
|
+
items: { type: "string" },
|
|
4278
|
+
description: "Tags for categorization"
|
|
4466
4279
|
},
|
|
4467
|
-
|
|
4468
|
-
type: "
|
|
4469
|
-
description: "
|
|
4280
|
+
metadata: {
|
|
4281
|
+
type: "object",
|
|
4282
|
+
description: "Additional metadata"
|
|
4470
4283
|
},
|
|
4471
|
-
|
|
4284
|
+
agent: { type: "string", description: "Agent creating the standard" },
|
|
4285
|
+
model: { type: "string", description: "AI model used" },
|
|
4286
|
+
structured: { type: "boolean", default: false }
|
|
4472
4287
|
},
|
|
4473
|
-
required: ["
|
|
4288
|
+
required: ["name", "content", "tags", "metadata"]
|
|
4474
4289
|
},
|
|
4475
4290
|
outputSchema: {
|
|
4476
4291
|
type: "object",
|
|
4477
4292
|
properties: {
|
|
4478
4293
|
success: { type: "boolean" },
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4294
|
+
standard: {
|
|
4295
|
+
type: "object",
|
|
4296
|
+
properties: {
|
|
4297
|
+
id: { type: "string" },
|
|
4298
|
+
title: { type: "string" },
|
|
4299
|
+
content: { type: "string" },
|
|
4300
|
+
parent_id: { type: "string", nullable: true },
|
|
4301
|
+
context: { type: "string" },
|
|
4302
|
+
version: { type: "string" },
|
|
4303
|
+
language: { type: "string", nullable: true },
|
|
4304
|
+
stack: { type: "array", items: { type: "string" } },
|
|
4305
|
+
is_global: { type: "boolean" },
|
|
4306
|
+
repo: { type: "string", nullable: true },
|
|
4307
|
+
tags: { type: "array", items: { type: "string" } },
|
|
4308
|
+
metadata: { type: "object" },
|
|
4309
|
+
created_at: { type: "string" },
|
|
4310
|
+
updated_at: { type: "string" },
|
|
4311
|
+
agent: { type: "string" },
|
|
4312
|
+
model: { type: "string" }
|
|
4313
|
+
},
|
|
4314
|
+
required: [
|
|
4315
|
+
"id",
|
|
4316
|
+
"title",
|
|
4317
|
+
"content",
|
|
4318
|
+
"parent_id",
|
|
4319
|
+
"context",
|
|
4320
|
+
"version",
|
|
4321
|
+
"stack",
|
|
4322
|
+
"is_global",
|
|
4323
|
+
"tags",
|
|
4324
|
+
"metadata",
|
|
4325
|
+
"created_at",
|
|
4326
|
+
"updated_at",
|
|
4327
|
+
"agent",
|
|
4328
|
+
"model"
|
|
4329
|
+
]
|
|
4487
4330
|
},
|
|
4488
|
-
|
|
4331
|
+
message: { type: "string" }
|
|
4489
4332
|
},
|
|
4490
|
-
required: ["success", "
|
|
4333
|
+
required: ["success", "standard", "message"]
|
|
4491
4334
|
}
|
|
4492
4335
|
},
|
|
4493
4336
|
{
|
|
4494
|
-
name: "
|
|
4495
|
-
title: "
|
|
4496
|
-
description: "
|
|
4337
|
+
name: "standard-update",
|
|
4338
|
+
title: "Standard Update",
|
|
4339
|
+
description: "Update an existing coding standard. Use this when the rule changes, expands scope, or metadata/tags need correction.",
|
|
4497
4340
|
annotations: {
|
|
4498
4341
|
readOnlyHint: false,
|
|
4499
4342
|
idempotentHint: false,
|
|
4500
|
-
destructiveHint:
|
|
4343
|
+
destructiveHint: false,
|
|
4501
4344
|
openWorldHint: false
|
|
4502
4345
|
},
|
|
4503
4346
|
inputSchema: {
|
|
4504
4347
|
type: "object",
|
|
4505
4348
|
properties: {
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4349
|
+
id: { type: "string", description: "Standard ID to update" },
|
|
4350
|
+
name: { type: "string", minLength: 3, maxLength: 255 },
|
|
4351
|
+
content: { type: "string", minLength: 10 },
|
|
4352
|
+
parent_id: { type: "string", format: "uuid", nullable: true },
|
|
4353
|
+
context: { type: "string" },
|
|
4354
|
+
version: { type: "string" },
|
|
4355
|
+
language: { type: "string" },
|
|
4356
|
+
stack: { type: "array", items: { type: "string" } },
|
|
4357
|
+
repo: { type: "string" },
|
|
4358
|
+
is_global: { type: "boolean" },
|
|
4359
|
+
tags: { type: "array", items: { type: "string" } },
|
|
4360
|
+
metadata: { type: "object" },
|
|
4361
|
+
agent: { type: "string" },
|
|
4362
|
+
model: { type: "string" },
|
|
4363
|
+
structured: { type: "boolean", default: false }
|
|
4510
4364
|
},
|
|
4511
|
-
required: ["
|
|
4365
|
+
required: ["id"]
|
|
4512
4366
|
},
|
|
4513
4367
|
outputSchema: {
|
|
4514
4368
|
type: "object",
|
|
4515
4369
|
properties: {
|
|
4516
4370
|
success: { type: "boolean" },
|
|
4517
4371
|
id: { type: "string" },
|
|
4518
|
-
|
|
4519
|
-
repo: { type: "string" },
|
|
4520
|
-
deletedCount: { type: "number" }
|
|
4372
|
+
updatedFields: { type: "array", items: { type: "string" } }
|
|
4521
4373
|
},
|
|
4522
|
-
required: ["success", "
|
|
4374
|
+
required: ["success", "id", "updatedFields"]
|
|
4523
4375
|
}
|
|
4524
4376
|
},
|
|
4525
4377
|
{
|
|
4526
|
-
name: "
|
|
4527
|
-
title: "
|
|
4528
|
-
description: "
|
|
4378
|
+
name: "standard-search",
|
|
4379
|
+
title: "Standard Search",
|
|
4380
|
+
description: "NAVIGATION LAYER: Returns a compact pointer table of matching coding standards. Use `standard-detail` to fetch full content for a selected result.",
|
|
4529
4381
|
annotations: {
|
|
4530
4382
|
readOnlyHint: true,
|
|
4531
4383
|
idempotentHint: true,
|
|
@@ -4534,425 +4386,628 @@ var TOOL_DEFINITIONS = [
|
|
|
4534
4386
|
inputSchema: {
|
|
4535
4387
|
type: "object",
|
|
4536
4388
|
properties: {
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
type: "string",
|
|
4543
|
-
default: "in_progress,pending",
|
|
4544
|
-
description: "Comma-separated status filter (backlog, pending, in_progress, completed, canceled, blocked). Defaults to 'in_progress,pending'."
|
|
4545
|
-
},
|
|
4546
|
-
phase: {
|
|
4547
|
-
type: "string",
|
|
4548
|
-
description: "Filter by phase (e.g., 'research', 'implementation')"
|
|
4549
|
-
},
|
|
4550
|
-
query: {
|
|
4551
|
-
type: "string",
|
|
4552
|
-
description: "Search keyword matching task code, title, or description"
|
|
4553
|
-
},
|
|
4554
|
-
limit: {
|
|
4555
|
-
type: "number",
|
|
4556
|
-
minimum: 1,
|
|
4557
|
-
maximum: 100,
|
|
4558
|
-
default: 5,
|
|
4559
|
-
description: "Maximum rows to return (default 5)"
|
|
4389
|
+
query: { type: "string", description: "Search query (optional, searches title/content)" },
|
|
4390
|
+
stack: {
|
|
4391
|
+
type: "array",
|
|
4392
|
+
items: { type: "string" },
|
|
4393
|
+
description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
|
|
4560
4394
|
},
|
|
4561
|
-
|
|
4562
|
-
type: "
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
description: "Offset for pagination"
|
|
4395
|
+
tags: {
|
|
4396
|
+
type: "array",
|
|
4397
|
+
items: { type: "string" },
|
|
4398
|
+
description: "Tag filter"
|
|
4566
4399
|
},
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
}
|
|
4400
|
+
language: { type: "string", description: "Programming language filter" },
|
|
4401
|
+
context: { type: "string", description: "Context/category filter" },
|
|
4402
|
+
version: { type: "string", description: "Version filter" },
|
|
4403
|
+
repo: { type: "string", description: "Repository filter (optional)" },
|
|
4404
|
+
is_global: { type: "boolean", description: "Filter by global/repo-specific" },
|
|
4405
|
+
limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
|
|
4406
|
+
offset: { type: "number", minimum: 0, default: 0 },
|
|
4407
|
+
structured: { type: "boolean", default: false }
|
|
4572
4408
|
},
|
|
4573
|
-
required: [
|
|
4409
|
+
required: []
|
|
4574
4410
|
},
|
|
4575
4411
|
outputSchema: {
|
|
4576
4412
|
type: "object",
|
|
4577
4413
|
properties: {
|
|
4578
|
-
schema: { type: "string", enum: ["
|
|
4579
|
-
|
|
4414
|
+
schema: { type: "string", enum: ["standard-search"] },
|
|
4415
|
+
query: { type: "string" },
|
|
4416
|
+
count: { type: "number", description: "Number of rows returned" },
|
|
4417
|
+
total: { type: "number", description: "Total number of matches before pagination" },
|
|
4418
|
+
offset: { type: "number" },
|
|
4419
|
+
limit: { type: "number" },
|
|
4420
|
+
results: {
|
|
4580
4421
|
type: "object",
|
|
4581
4422
|
properties: {
|
|
4582
4423
|
columns: {
|
|
4583
4424
|
type: "array",
|
|
4584
|
-
items: { type: "string" }
|
|
4585
|
-
description: "Column names in order: id, task_code, title, status, priority, updated_at, comments_count"
|
|
4425
|
+
items: { type: "string" }
|
|
4586
4426
|
},
|
|
4587
4427
|
rows: {
|
|
4588
4428
|
type: "array",
|
|
4589
4429
|
items: { type: "array" },
|
|
4590
|
-
description: "Each row
|
|
4430
|
+
description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
|
|
4591
4431
|
}
|
|
4592
4432
|
},
|
|
4593
4433
|
required: ["columns", "rows"]
|
|
4594
|
-
}
|
|
4595
|
-
count: { type: "number" },
|
|
4596
|
-
offset: { type: "number" }
|
|
4434
|
+
}
|
|
4597
4435
|
},
|
|
4598
|
-
required: ["schema", "
|
|
4436
|
+
required: ["schema", "query", "count", "total", "offset", "limit", "results"]
|
|
4599
4437
|
}
|
|
4600
|
-
}
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4438
|
+
}
|
|
4439
|
+
];
|
|
4440
|
+
|
|
4441
|
+
// src/mcp/utils/pagination.ts
|
|
4442
|
+
function encodeCursor(offset) {
|
|
4443
|
+
return Buffer.from(String(offset), "utf8").toString("base64");
|
|
4444
|
+
}
|
|
4445
|
+
function decodeCursor(cursor) {
|
|
4446
|
+
if (cursor === void 0 || cursor === null || cursor === "") {
|
|
4447
|
+
return 0;
|
|
4448
|
+
}
|
|
4449
|
+
if (typeof cursor !== "string" || cursor.trim() === "") {
|
|
4450
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
4451
|
+
}
|
|
4452
|
+
let decoded;
|
|
4453
|
+
try {
|
|
4454
|
+
decoded = Buffer.from(cursor, "base64").toString("utf8");
|
|
4455
|
+
} catch {
|
|
4456
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
4457
|
+
}
|
|
4458
|
+
if (!/^\d+$/.test(decoded)) {
|
|
4459
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
4460
|
+
}
|
|
4461
|
+
const offset = Number.parseInt(decoded, 10);
|
|
4462
|
+
if (!Number.isFinite(offset) || offset < 0) {
|
|
4463
|
+
throw invalidPaginationParams("Invalid cursor");
|
|
4464
|
+
}
|
|
4465
|
+
return offset;
|
|
4466
|
+
}
|
|
4467
|
+
function invalidPaginationParams(message) {
|
|
4468
|
+
const error = new Error(message);
|
|
4469
|
+
error.code = -32602;
|
|
4470
|
+
return error;
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
// src/mcp/utils/completion.ts
|
|
4474
|
+
var MAX_COMPLETION_VALUES = 100;
|
|
4475
|
+
function rankCompletionValues(candidates, input) {
|
|
4476
|
+
const unique = [...new Set(candidates.filter(Boolean))];
|
|
4477
|
+
const needle = input.trim().toLowerCase();
|
|
4478
|
+
if (!needle) {
|
|
4479
|
+
return unique.slice(0, MAX_COMPLETION_VALUES);
|
|
4480
|
+
}
|
|
4481
|
+
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);
|
|
4482
|
+
}
|
|
4483
|
+
function scoreCompletionValue(value, needle) {
|
|
4484
|
+
const haystack = value.toLowerCase();
|
|
4485
|
+
if (haystack === needle) return 100;
|
|
4486
|
+
if (haystack.startsWith(needle)) return 75;
|
|
4487
|
+
if (haystack.includes(needle)) return 50;
|
|
4488
|
+
const compactNeedle = needle.replace(/[\s_-]+/g, "");
|
|
4489
|
+
const compactHaystack = haystack.replace(/[\s_-]+/g, "");
|
|
4490
|
+
if (compactNeedle && compactHaystack.includes(compactNeedle)) return 25;
|
|
4491
|
+
return 0;
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
// src/mcp/resources/index.ts
|
|
4495
|
+
var DEFAULT_PAGE_SIZE = 25;
|
|
4496
|
+
var MAX_PAGE_SIZE = 100;
|
|
4497
|
+
function listResources(session, params) {
|
|
4498
|
+
const resources = [
|
|
4499
|
+
{
|
|
4500
|
+
uri: "repository://index",
|
|
4501
|
+
name: "Repository Index",
|
|
4502
|
+
title: "Repository Index",
|
|
4503
|
+
description: "List of all known repositories with memory/task counts and last activity",
|
|
4504
|
+
mimeType: "application/json",
|
|
4505
|
+
annotations: {
|
|
4506
|
+
audience: ["assistant"],
|
|
4507
|
+
priority: 1,
|
|
4508
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
4509
|
+
}
|
|
4628
4510
|
},
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
updated_at: { type: "string" },
|
|
4642
|
-
expires_at: { type: "string", nullable: true }
|
|
4643
|
-
},
|
|
4644
|
-
required: ["id", "repo", "from_agent", "summary", "context", "status", "created_at", "updated_at"]
|
|
4511
|
+
{
|
|
4512
|
+
uri: "session://roots",
|
|
4513
|
+
name: "Session Roots",
|
|
4514
|
+
title: "Session Roots",
|
|
4515
|
+
description: session?.roots.length ? "Active workspace roots provided by the MCP client" : "No active workspace roots were provided by the MCP client",
|
|
4516
|
+
mimeType: "application/json",
|
|
4517
|
+
size: Buffer.byteLength(JSON.stringify({ roots: session?.roots ?? [] }), "utf8"),
|
|
4518
|
+
annotations: {
|
|
4519
|
+
audience: ["assistant"],
|
|
4520
|
+
priority: 0.95,
|
|
4521
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
4522
|
+
}
|
|
4645
4523
|
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4524
|
+
];
|
|
4525
|
+
return paginateEntries("resources", resources, params);
|
|
4526
|
+
}
|
|
4527
|
+
function listResourceTemplates(params) {
|
|
4528
|
+
const templates = [
|
|
4529
|
+
// ── Memory ──────────────────────────────────────────────────────────────
|
|
4530
|
+
{
|
|
4531
|
+
uriTemplate: "repository://{name}/memories",
|
|
4532
|
+
name: "Repository Memories",
|
|
4533
|
+
title: "Repository Memories",
|
|
4534
|
+
description: "All active memory entries for a specific repository",
|
|
4535
|
+
mimeType: "application/json",
|
|
4536
|
+
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
4537
|
+
},
|
|
4538
|
+
{
|
|
4539
|
+
uriTemplate: "repository://{name}/memories?search={search}&type={type}&tag={tag}",
|
|
4540
|
+
name: "Filtered Repository Memories",
|
|
4541
|
+
title: "Filtered Repository Memories",
|
|
4542
|
+
description: "Filter or search memories within a repository by keyword, type, or tag",
|
|
4543
|
+
mimeType: "application/json",
|
|
4544
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
4545
|
+
},
|
|
4546
|
+
{
|
|
4547
|
+
uriTemplate: "memory://{id}",
|
|
4548
|
+
name: "Memory Detail",
|
|
4549
|
+
title: "Memory Detail",
|
|
4550
|
+
description: "Full content and statistics for a specific memory UUID",
|
|
4551
|
+
mimeType: "application/json",
|
|
4552
|
+
annotations: { audience: ["assistant"], priority: 0.75 }
|
|
4656
4553
|
},
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4554
|
+
// ── Tasks ────────────────────────────────────────────────────────────────
|
|
4555
|
+
{
|
|
4556
|
+
uriTemplate: "repository://{name}/tasks",
|
|
4557
|
+
name: "Repository Tasks",
|
|
4558
|
+
title: "Repository Tasks",
|
|
4559
|
+
description: "All active tasks for a specific repository",
|
|
4560
|
+
mimeType: "application/json",
|
|
4561
|
+
annotations: { audience: ["assistant"], priority: 0.9 }
|
|
4665
4562
|
},
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
}
|
|
4673
|
-
required: ["success", "id", "status"]
|
|
4674
|
-
}
|
|
4675
|
-
},
|
|
4676
|
-
{
|
|
4677
|
-
name: "handoff-list",
|
|
4678
|
-
title: "Handoff List",
|
|
4679
|
-
description: "Navigation layer for handoff queues. List repository handoffs with optional status and agent filters, then inspect selected rows before acting.",
|
|
4680
|
-
annotations: {
|
|
4681
|
-
readOnlyHint: true,
|
|
4682
|
-
idempotentHint: true,
|
|
4683
|
-
openWorldHint: false
|
|
4563
|
+
{
|
|
4564
|
+
uriTemplate: "repository://{name}/tasks?status={status}&priority={priority}",
|
|
4565
|
+
name: "Filtered Repository Tasks",
|
|
4566
|
+
title: "Filtered Repository Tasks",
|
|
4567
|
+
description: "Filter tasks within a repository by status or priority level",
|
|
4568
|
+
mimeType: "application/json",
|
|
4569
|
+
annotations: { audience: ["assistant"], priority: 0.85 }
|
|
4684
4570
|
},
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
|
|
4693
|
-
offset: { type: "number", minimum: 0, default: 0 },
|
|
4694
|
-
structured: { type: "boolean", default: false }
|
|
4695
|
-
},
|
|
4696
|
-
required: ["repo"]
|
|
4571
|
+
{
|
|
4572
|
+
uriTemplate: "task://{id}",
|
|
4573
|
+
name: "Task Detail",
|
|
4574
|
+
title: "Task Detail",
|
|
4575
|
+
description: "Full content and comments for a specific task UUID",
|
|
4576
|
+
mimeType: "application/json",
|
|
4577
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
4697
4578
|
},
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
type: "array",
|
|
4707
|
-
items: { type: "string" },
|
|
4708
|
-
description: "Column names: [id, from_agent, to_agent, task_id, status, created_at, summary]"
|
|
4709
|
-
},
|
|
4710
|
-
rows: {
|
|
4711
|
-
type: "array",
|
|
4712
|
-
items: { type: "array" },
|
|
4713
|
-
description: "Each row: [id, from_agent, to_agent, task_id, status, created_at, summary]"
|
|
4714
|
-
}
|
|
4715
|
-
},
|
|
4716
|
-
required: ["columns", "rows"]
|
|
4717
|
-
},
|
|
4718
|
-
count: { type: "number" },
|
|
4719
|
-
offset: { type: "number" }
|
|
4720
|
-
},
|
|
4721
|
-
required: ["schema", "handoffs", "count", "offset"]
|
|
4722
|
-
}
|
|
4723
|
-
},
|
|
4724
|
-
{
|
|
4725
|
-
name: "task-claim",
|
|
4726
|
-
title: "Task Claim",
|
|
4727
|
-
description: "Claim task ownership for an agent using the dedicated claims table. Use this before taking work from task-list; provide either task_id or task_code.",
|
|
4728
|
-
annotations: {
|
|
4729
|
-
readOnlyHint: false,
|
|
4730
|
-
idempotentHint: false,
|
|
4731
|
-
destructiveHint: false,
|
|
4732
|
-
openWorldHint: false
|
|
4579
|
+
// ── Repository extras ────────────────────────────────────────────────────
|
|
4580
|
+
{
|
|
4581
|
+
uriTemplate: "repository://{name}/summary",
|
|
4582
|
+
name: "Repository Summary",
|
|
4583
|
+
title: "Repository Summary",
|
|
4584
|
+
description: "High-level architectural summary for a repository",
|
|
4585
|
+
mimeType: "text/plain",
|
|
4586
|
+
annotations: { audience: ["assistant"], priority: 0.95 }
|
|
4733
4587
|
},
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
role: { type: "string", description: "Claiming agent role" },
|
|
4742
|
-
metadata: { type: "object", description: "Optional claim metadata" },
|
|
4743
|
-
structured: { type: "boolean", default: false }
|
|
4744
|
-
},
|
|
4745
|
-
required: ["repo", "agent"]
|
|
4588
|
+
{
|
|
4589
|
+
uriTemplate: "repository://{name}/actions",
|
|
4590
|
+
name: "Repository Actions",
|
|
4591
|
+
title: "Repository Actions",
|
|
4592
|
+
description: "Audit log of agent tool actions scoped to a repository",
|
|
4593
|
+
mimeType: "application/json",
|
|
4594
|
+
annotations: { audience: ["assistant"], priority: 0.6 }
|
|
4746
4595
|
},
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4596
|
+
// ── Action detail ────────────────────────────────────────────────────────
|
|
4597
|
+
{
|
|
4598
|
+
uriTemplate: "action://{id}",
|
|
4599
|
+
name: "Action Detail",
|
|
4600
|
+
title: "Action Detail",
|
|
4601
|
+
description: "Full details of a specific audit log entry by integer ID",
|
|
4602
|
+
mimeType: "application/json",
|
|
4603
|
+
annotations: { audience: ["assistant"], priority: 0.55 }
|
|
4604
|
+
}
|
|
4605
|
+
];
|
|
4606
|
+
return paginateEntries("resourceTemplates", templates, params);
|
|
4607
|
+
}
|
|
4608
|
+
function completeResourceArgument(resourceUri, argumentName, argumentValue, _contextArguments, dataSources) {
|
|
4609
|
+
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") {
|
|
4610
|
+
if (argumentName === "name") {
|
|
4611
|
+
return rankCompletionValues(dataSources.repos, argumentValue);
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
if (resourceUri === "repository://{name}/memories?search={search}&type={type}&tag={tag}") {
|
|
4615
|
+
if (argumentName === "tag") {
|
|
4616
|
+
return rankCompletionValues(dataSources.tags, argumentValue);
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
throw invalidCompletionParams(`Unknown resource template or argument: ${resourceUri} (${argumentName})`);
|
|
4620
|
+
}
|
|
4621
|
+
function readResource(uri, db, session) {
|
|
4622
|
+
logger.info("[Tool] resource.read", { uri });
|
|
4623
|
+
if (uri === "repository://index") {
|
|
4624
|
+
const repos = db.system.listRepoNavigation();
|
|
4625
|
+
const payload = JSON.stringify(repos, null, 2);
|
|
4626
|
+
return {
|
|
4627
|
+
contents: [
|
|
4628
|
+
{
|
|
4629
|
+
uri,
|
|
4630
|
+
mimeType: "application/json",
|
|
4631
|
+
text: payload,
|
|
4632
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4633
|
+
annotations: {
|
|
4634
|
+
audience: ["assistant"],
|
|
4635
|
+
priority: 1,
|
|
4636
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
]
|
|
4640
|
+
};
|
|
4641
|
+
}
|
|
4642
|
+
if (uri === "session://roots") {
|
|
4643
|
+
const payload = JSON.stringify({ roots: session?.roots ?? [] }, null, 2);
|
|
4644
|
+
return {
|
|
4645
|
+
contents: [
|
|
4646
|
+
{
|
|
4647
|
+
uri,
|
|
4648
|
+
mimeType: "application/json",
|
|
4649
|
+
text: payload,
|
|
4650
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4651
|
+
annotations: {
|
|
4652
|
+
audience: ["assistant"],
|
|
4653
|
+
priority: 0.95,
|
|
4654
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
]
|
|
4658
|
+
};
|
|
4659
|
+
}
|
|
4660
|
+
const memoryIdMatch = uri.match(/^memory:\/\/([0-9a-f-]{36})$/i);
|
|
4661
|
+
if (memoryIdMatch) {
|
|
4662
|
+
const id = memoryIdMatch[1];
|
|
4663
|
+
const entry = db.memories.getByIdWithStats(id);
|
|
4664
|
+
if (!entry) throw resourceNotFound(`Memory with ID ${id} not found.`, uri);
|
|
4665
|
+
const payload = JSON.stringify(entry, null, 2);
|
|
4666
|
+
return {
|
|
4667
|
+
contents: [
|
|
4668
|
+
{
|
|
4669
|
+
uri,
|
|
4670
|
+
mimeType: "application/json",
|
|
4671
|
+
text: payload,
|
|
4672
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4673
|
+
annotations: {
|
|
4674
|
+
audience: ["assistant"],
|
|
4675
|
+
priority: 0.75,
|
|
4676
|
+
lastModified: entry.updated_at || entry.created_at
|
|
4677
|
+
}
|
|
4678
|
+
}
|
|
4679
|
+
]
|
|
4680
|
+
};
|
|
4681
|
+
}
|
|
4682
|
+
const taskIdMatch = uri.match(/^task:\/\/([0-9a-f-]{36})$/i);
|
|
4683
|
+
if (taskIdMatch) {
|
|
4684
|
+
const id = taskIdMatch[1];
|
|
4685
|
+
const task = db.tasks.getTaskById(id);
|
|
4686
|
+
if (!task) throw resourceNotFound(`Task with ID ${id} not found.`, uri);
|
|
4687
|
+
const payload = JSON.stringify(task, null, 2);
|
|
4688
|
+
return {
|
|
4689
|
+
contents: [
|
|
4690
|
+
{
|
|
4691
|
+
uri,
|
|
4692
|
+
mimeType: "application/json",
|
|
4693
|
+
text: payload,
|
|
4694
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4695
|
+
annotations: {
|
|
4696
|
+
audience: ["assistant"],
|
|
4697
|
+
priority: 0.8,
|
|
4698
|
+
lastModified: task.updated_at || task.created_at
|
|
4699
|
+
}
|
|
4700
|
+
}
|
|
4701
|
+
]
|
|
4702
|
+
};
|
|
4703
|
+
}
|
|
4704
|
+
const repoBase = parseRepoUri(uri);
|
|
4705
|
+
if (repoBase) {
|
|
4706
|
+
const { name, path: repoPath, query } = repoBase;
|
|
4707
|
+
if (repoPath === "summary") {
|
|
4708
|
+
const summary = db.summaries.getSummary(name);
|
|
4709
|
+
const text = summary?.summary || `No summary available for repository: ${name}`;
|
|
4710
|
+
return {
|
|
4711
|
+
contents: [
|
|
4712
|
+
{
|
|
4713
|
+
uri,
|
|
4714
|
+
mimeType: "text/plain",
|
|
4715
|
+
text,
|
|
4716
|
+
size: Buffer.byteLength(text, "utf8"),
|
|
4717
|
+
annotations: {
|
|
4718
|
+
audience: ["assistant"],
|
|
4719
|
+
priority: 0.95,
|
|
4720
|
+
lastModified: summary?.updated_at || (/* @__PURE__ */ new Date()).toISOString()
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
]
|
|
4724
|
+
};
|
|
4761
4725
|
}
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
description: "Tags for categorization"
|
|
4793
|
-
},
|
|
4794
|
-
metadata: {
|
|
4795
|
-
type: "object",
|
|
4796
|
-
description: "Additional metadata"
|
|
4797
|
-
},
|
|
4798
|
-
agent: { type: "string", description: "Agent creating the standard" },
|
|
4799
|
-
model: { type: "string", description: "AI model used" },
|
|
4800
|
-
structured: { type: "boolean", default: false }
|
|
4801
|
-
},
|
|
4802
|
-
required: ["name", "content", "tags", "metadata"]
|
|
4803
|
-
},
|
|
4804
|
-
outputSchema: {
|
|
4805
|
-
type: "object",
|
|
4806
|
-
properties: {
|
|
4807
|
-
success: { type: "boolean" },
|
|
4808
|
-
standard: {
|
|
4809
|
-
type: "object",
|
|
4810
|
-
properties: {
|
|
4811
|
-
id: { type: "string" },
|
|
4812
|
-
title: { type: "string" },
|
|
4813
|
-
content: { type: "string" },
|
|
4814
|
-
parent_id: { type: "string", nullable: true },
|
|
4815
|
-
context: { type: "string" },
|
|
4816
|
-
version: { type: "string" },
|
|
4817
|
-
language: { type: "string", nullable: true },
|
|
4818
|
-
stack: { type: "array", items: { type: "string" } },
|
|
4819
|
-
is_global: { type: "boolean" },
|
|
4820
|
-
repo: { type: "string", nullable: true },
|
|
4821
|
-
tags: { type: "array", items: { type: "string" } },
|
|
4822
|
-
metadata: { type: "object" },
|
|
4823
|
-
created_at: { type: "string" },
|
|
4824
|
-
updated_at: { type: "string" },
|
|
4825
|
-
agent: { type: "string" },
|
|
4826
|
-
model: { type: "string" }
|
|
4827
|
-
},
|
|
4828
|
-
required: [
|
|
4829
|
-
"id",
|
|
4830
|
-
"title",
|
|
4831
|
-
"content",
|
|
4832
|
-
"parent_id",
|
|
4833
|
-
"context",
|
|
4834
|
-
"version",
|
|
4835
|
-
"stack",
|
|
4836
|
-
"is_global",
|
|
4837
|
-
"tags",
|
|
4838
|
-
"metadata",
|
|
4839
|
-
"created_at",
|
|
4840
|
-
"updated_at",
|
|
4841
|
-
"agent",
|
|
4842
|
-
"model"
|
|
4843
|
-
]
|
|
4844
|
-
},
|
|
4845
|
-
message: { type: "string" }
|
|
4846
|
-
},
|
|
4847
|
-
required: ["success", "standard", "message"]
|
|
4726
|
+
if (repoPath === "memories") {
|
|
4727
|
+
const search = query.get("search") || "";
|
|
4728
|
+
const type = query.get("type");
|
|
4729
|
+
const tag = query.get("tag");
|
|
4730
|
+
const result = db.memories.listMemoriesForDashboard({
|
|
4731
|
+
repo: name,
|
|
4732
|
+
type: type || void 0,
|
|
4733
|
+
tag: tag || void 0,
|
|
4734
|
+
search: search || void 0,
|
|
4735
|
+
limit: 50
|
|
4736
|
+
});
|
|
4737
|
+
const entries = result.items;
|
|
4738
|
+
const payload = JSON.stringify(entries, null, 2);
|
|
4739
|
+
return {
|
|
4740
|
+
contents: [
|
|
4741
|
+
{
|
|
4742
|
+
uri,
|
|
4743
|
+
mimeType: "application/json",
|
|
4744
|
+
text: payload,
|
|
4745
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4746
|
+
annotations: {
|
|
4747
|
+
audience: ["assistant"],
|
|
4748
|
+
priority: 0.85,
|
|
4749
|
+
lastModified: deriveLastModifiedFromCollection(
|
|
4750
|
+
entries.map((e) => e.updated_at || e.created_at)
|
|
4751
|
+
)
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
]
|
|
4755
|
+
};
|
|
4848
4756
|
}
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
outputSchema: {
|
|
4882
|
-
type: "object",
|
|
4883
|
-
properties: {
|
|
4884
|
-
success: { type: "boolean" },
|
|
4885
|
-
id: { type: "string" },
|
|
4886
|
-
updatedFields: { type: "array", items: { type: "string" } }
|
|
4887
|
-
},
|
|
4888
|
-
required: ["success", "id", "updatedFields"]
|
|
4757
|
+
if (repoPath === "tasks") {
|
|
4758
|
+
const status = query.get("status");
|
|
4759
|
+
const priority = query.get("priority");
|
|
4760
|
+
let tasks;
|
|
4761
|
+
if (status && status !== "all") {
|
|
4762
|
+
const statuses = status.split(",").map((s) => s.trim());
|
|
4763
|
+
tasks = db.tasks.getTasksByMultipleStatuses(name, statuses);
|
|
4764
|
+
} else {
|
|
4765
|
+
tasks = db.tasks.getTasksByMultipleStatuses(name, ["backlog", "pending", "in_progress", "blocked"]);
|
|
4766
|
+
}
|
|
4767
|
+
if (priority) {
|
|
4768
|
+
const p = Number(priority);
|
|
4769
|
+
if (!isNaN(p)) {
|
|
4770
|
+
tasks = tasks.filter((t) => t.priority === p);
|
|
4771
|
+
}
|
|
4772
|
+
}
|
|
4773
|
+
const payload = JSON.stringify(tasks, null, 2);
|
|
4774
|
+
return {
|
|
4775
|
+
contents: [
|
|
4776
|
+
{
|
|
4777
|
+
uri,
|
|
4778
|
+
mimeType: "application/json",
|
|
4779
|
+
text: payload,
|
|
4780
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4781
|
+
annotations: {
|
|
4782
|
+
audience: ["assistant"],
|
|
4783
|
+
priority: 0.9,
|
|
4784
|
+
lastModified: deriveLastModifiedFromCollection(tasks.map((t) => t.updated_at))
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
]
|
|
4788
|
+
};
|
|
4889
4789
|
}
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
stack: {
|
|
4905
|
-
type: "array",
|
|
4906
|
-
items: { type: "string" },
|
|
4907
|
-
description: "Technology stack to filter by (e.g., ['react', 'nextjs'])"
|
|
4908
|
-
},
|
|
4909
|
-
tags: {
|
|
4910
|
-
type: "array",
|
|
4911
|
-
items: { type: "string" },
|
|
4912
|
-
description: "Tag filter"
|
|
4913
|
-
},
|
|
4914
|
-
language: { type: "string", description: "Programming language filter" },
|
|
4915
|
-
context: { type: "string", description: "Context/category filter" },
|
|
4916
|
-
version: { type: "string", description: "Version filter" },
|
|
4917
|
-
repo: { type: "string", description: "Repository filter (optional)" },
|
|
4918
|
-
is_global: { type: "boolean", description: "Filter by global/repo-specific" },
|
|
4919
|
-
limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
|
|
4920
|
-
offset: { type: "number", minimum: 0, default: 0 },
|
|
4921
|
-
structured: { type: "boolean", default: false }
|
|
4922
|
-
},
|
|
4923
|
-
required: []
|
|
4924
|
-
},
|
|
4925
|
-
outputSchema: {
|
|
4926
|
-
type: "object",
|
|
4927
|
-
properties: {
|
|
4928
|
-
schema: { type: "string", enum: ["standard-search"] },
|
|
4929
|
-
query: { type: "string" },
|
|
4930
|
-
count: { type: "number", description: "Number of rows returned" },
|
|
4931
|
-
total: { type: "number", description: "Total number of matches before pagination" },
|
|
4932
|
-
offset: { type: "number" },
|
|
4933
|
-
limit: { type: "number" },
|
|
4934
|
-
results: {
|
|
4935
|
-
type: "object",
|
|
4936
|
-
properties: {
|
|
4937
|
-
columns: {
|
|
4938
|
-
type: "array",
|
|
4939
|
-
items: { type: "string" }
|
|
4940
|
-
},
|
|
4941
|
-
rows: {
|
|
4942
|
-
type: "array",
|
|
4943
|
-
items: { type: "array" },
|
|
4944
|
-
description: "Each row includes standard id and pointer metadata. Fetch full content via standard-detail."
|
|
4790
|
+
if (repoPath === "actions") {
|
|
4791
|
+
const actions = db.actions.getRecentActions(name, 100);
|
|
4792
|
+
const payload = JSON.stringify(actions, null, 2);
|
|
4793
|
+
return {
|
|
4794
|
+
contents: [
|
|
4795
|
+
{
|
|
4796
|
+
uri,
|
|
4797
|
+
mimeType: "application/json",
|
|
4798
|
+
text: payload,
|
|
4799
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4800
|
+
annotations: {
|
|
4801
|
+
audience: ["assistant"],
|
|
4802
|
+
priority: 0.6,
|
|
4803
|
+
lastModified: deriveLastModifiedFromCollection(actions.map((a) => a.created_at))
|
|
4945
4804
|
}
|
|
4946
|
-
}
|
|
4947
|
-
|
|
4805
|
+
}
|
|
4806
|
+
]
|
|
4807
|
+
};
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
const actionIdMatch = uri.match(/^action:\/\/(\d+)$/);
|
|
4811
|
+
if (actionIdMatch) {
|
|
4812
|
+
const id = Number(actionIdMatch[1]);
|
|
4813
|
+
const action = db.actions.getActionById(id);
|
|
4814
|
+
if (!action) throw resourceNotFound(`Action with ID ${id} not found.`, uri);
|
|
4815
|
+
const payload = JSON.stringify(action, null, 2);
|
|
4816
|
+
return {
|
|
4817
|
+
contents: [
|
|
4818
|
+
{
|
|
4819
|
+
uri,
|
|
4820
|
+
mimeType: "application/json",
|
|
4821
|
+
text: payload,
|
|
4822
|
+
size: Buffer.byteLength(payload, "utf8"),
|
|
4823
|
+
annotations: {
|
|
4824
|
+
audience: ["assistant"],
|
|
4825
|
+
priority: 0.55,
|
|
4826
|
+
lastModified: action.created_at
|
|
4827
|
+
}
|
|
4948
4828
|
}
|
|
4949
|
-
|
|
4950
|
-
|
|
4829
|
+
]
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
throw resourceNotFound(`Unknown resource URI: ${uri}`, uri);
|
|
4833
|
+
}
|
|
4834
|
+
function parseRepoUri(uri) {
|
|
4835
|
+
const prefix = "repository://";
|
|
4836
|
+
if (!uri.startsWith(prefix)) return null;
|
|
4837
|
+
const rest = uri.slice(prefix.length);
|
|
4838
|
+
const queryStart = rest.indexOf("?");
|
|
4839
|
+
const withoutQuery = queryStart === -1 ? rest : rest.slice(0, queryStart);
|
|
4840
|
+
const queryString = queryStart === -1 ? "" : rest.slice(queryStart + 1);
|
|
4841
|
+
const slashIdx = withoutQuery.indexOf("/");
|
|
4842
|
+
if (slashIdx === -1) return null;
|
|
4843
|
+
const name = withoutQuery.slice(0, slashIdx);
|
|
4844
|
+
const path6 = withoutQuery.slice(slashIdx + 1);
|
|
4845
|
+
if (!name || !path6) return null;
|
|
4846
|
+
return { name, path: path6, query: new URLSearchParams(queryString) };
|
|
4847
|
+
}
|
|
4848
|
+
function paginateEntries(key, entries, params) {
|
|
4849
|
+
const limit = normalizeLimit(params?.limit);
|
|
4850
|
+
const offset = decodeCursor(params?.cursor);
|
|
4851
|
+
const sliced = entries.slice(offset, offset + limit);
|
|
4852
|
+
const nextOffset = offset + sliced.length;
|
|
4853
|
+
return {
|
|
4854
|
+
[key]: sliced,
|
|
4855
|
+
nextCursor: nextOffset < entries.length ? encodeCursor(nextOffset) : void 0
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
function normalizeLimit(limit) {
|
|
4859
|
+
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
4860
|
+
return DEFAULT_PAGE_SIZE;
|
|
4861
|
+
}
|
|
4862
|
+
return Math.min(MAX_PAGE_SIZE, Math.max(1, Math.trunc(limit)));
|
|
4863
|
+
}
|
|
4864
|
+
function deriveLastModifiedFromCollection(values) {
|
|
4865
|
+
const normalized = values.filter((value) => typeof value === "string" && value.length > 0);
|
|
4866
|
+
return normalized.sort().at(-1) ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
4867
|
+
}
|
|
4868
|
+
function resourceNotFound(message, uri) {
|
|
4869
|
+
const error = new Error(message);
|
|
4870
|
+
error.code = -32002;
|
|
4871
|
+
error.data = { uri };
|
|
4872
|
+
return error;
|
|
4873
|
+
}
|
|
4874
|
+
function invalidCompletionParams(message) {
|
|
4875
|
+
const error = new Error(message);
|
|
4876
|
+
error.code = -32602;
|
|
4877
|
+
return error;
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
// src/mcp/prompts/loader.ts
|
|
4881
|
+
import fs4 from "fs";
|
|
4882
|
+
import path5 from "path";
|
|
4883
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4884
|
+
import matter from "gray-matter";
|
|
4885
|
+
var __filename = fileURLToPath3(import.meta.url);
|
|
4886
|
+
var __dirname2 = path5.dirname(__filename);
|
|
4887
|
+
function findPromptDir() {
|
|
4888
|
+
const candidates = [
|
|
4889
|
+
// Production if chunked into dist/
|
|
4890
|
+
"./prompts",
|
|
4891
|
+
// Production if inlined into dist/mcp/
|
|
4892
|
+
"../prompts",
|
|
4893
|
+
// Dev: /src/mcp/prompts/definitions (next to loader.ts)
|
|
4894
|
+
"./definitions"
|
|
4895
|
+
].map((relPath) => path5.resolve(__dirname2, relPath));
|
|
4896
|
+
for (const dir of candidates) {
|
|
4897
|
+
if (fs4.existsSync(dir)) {
|
|
4898
|
+
const files = fs4.readdirSync(dir);
|
|
4899
|
+
if (files.some((f) => f.endsWith(".md"))) {
|
|
4900
|
+
return dir;
|
|
4901
|
+
}
|
|
4951
4902
|
}
|
|
4952
4903
|
}
|
|
4953
|
-
|
|
4904
|
+
return path5.resolve(__dirname2, "./definitions");
|
|
4905
|
+
}
|
|
4906
|
+
var PROMPT_DIR = findPromptDir();
|
|
4907
|
+
function listPromptFiles() {
|
|
4908
|
+
if (!fs4.existsSync(PROMPT_DIR)) return [];
|
|
4909
|
+
return fs4.readdirSync(PROMPT_DIR).filter((file) => file.endsWith(".md")).map((file) => file.replace(/\.md$/, "")).sort();
|
|
4910
|
+
}
|
|
4911
|
+
function loadPromptFromMarkdown(name) {
|
|
4912
|
+
const filePath = path5.join(PROMPT_DIR, `${name}.md`);
|
|
4913
|
+
if (!fs4.existsSync(filePath)) {
|
|
4914
|
+
throw new Error(`Prompt file not found: ${filePath}`);
|
|
4915
|
+
}
|
|
4916
|
+
const fileContent = fs4.readFileSync(filePath, "utf-8");
|
|
4917
|
+
const { data, content } = matter(fileContent);
|
|
4918
|
+
return {
|
|
4919
|
+
name: data.name || name,
|
|
4920
|
+
description: data.description || "",
|
|
4921
|
+
arguments: data.arguments || [],
|
|
4922
|
+
agent: data.agent,
|
|
4923
|
+
content: content.trim()
|
|
4924
|
+
};
|
|
4925
|
+
}
|
|
4926
|
+
|
|
4927
|
+
// src/mcp/prompts/registry.ts
|
|
4928
|
+
function createPromptDefinition(loaded) {
|
|
4929
|
+
return {
|
|
4930
|
+
name: loaded.name,
|
|
4931
|
+
description: loaded.description,
|
|
4932
|
+
arguments: loaded.arguments,
|
|
4933
|
+
agent: loaded.agent,
|
|
4934
|
+
messages: [
|
|
4935
|
+
{
|
|
4936
|
+
role: "user",
|
|
4937
|
+
content: {
|
|
4938
|
+
type: "text",
|
|
4939
|
+
text: loaded.content
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
]
|
|
4943
|
+
};
|
|
4944
|
+
}
|
|
4945
|
+
var PROMPTS = {};
|
|
4946
|
+
var promptFiles = listPromptFiles();
|
|
4947
|
+
for (const name of promptFiles) {
|
|
4948
|
+
try {
|
|
4949
|
+
PROMPTS[name] = createPromptDefinition(loadPromptFromMarkdown(name));
|
|
4950
|
+
} catch (e) {
|
|
4951
|
+
logger.warn(`Failed to load prompt ${name}: ${e}`);
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
async function listPrompts(db, session, params) {
|
|
4955
|
+
const allPrompts = Object.values(PROMPTS).map((p) => ({
|
|
4956
|
+
name: p.name,
|
|
4957
|
+
description: p.description,
|
|
4958
|
+
arguments: p.arguments,
|
|
4959
|
+
metadata: p.agent ? { agent: p.agent } : void 0
|
|
4960
|
+
}));
|
|
4961
|
+
const rawLimit = typeof params?.limit === "number" && Number.isInteger(params?.limit) ? params.limit : 25;
|
|
4962
|
+
const limit = Math.max(1, Math.min(100, Math.trunc(rawLimit)));
|
|
4963
|
+
const offset = decodeCursor(params?.cursor);
|
|
4964
|
+
const sliced = allPrompts.slice(offset, offset + limit);
|
|
4965
|
+
const nextOffset = offset + sliced.length;
|
|
4966
|
+
return {
|
|
4967
|
+
prompts: sliced,
|
|
4968
|
+
nextCursor: nextOffset < allPrompts.length ? encodeCursor(nextOffset) : void 0
|
|
4969
|
+
};
|
|
4970
|
+
}
|
|
4971
|
+
async function getPrompt(name, args = {}, db, session) {
|
|
4972
|
+
const prompt = PROMPTS[name];
|
|
4973
|
+
if (!prompt) {
|
|
4974
|
+
throw new Error(`Prompt not found: ${name}`);
|
|
4975
|
+
}
|
|
4976
|
+
const inferredRepo = inferRepoFromSession(session);
|
|
4977
|
+
const messages = prompt.messages.map((m) => {
|
|
4978
|
+
let text = m.content.text;
|
|
4979
|
+
for (const [key, value] of Object.entries(args)) {
|
|
4980
|
+
text = text.replace(new RegExp(`\\{{${key}\\}}`, "g"), value);
|
|
4981
|
+
}
|
|
4982
|
+
text = text.replace(/{{current_repo}}/g, inferredRepo || "unknown-repo");
|
|
4983
|
+
return {
|
|
4984
|
+
...m,
|
|
4985
|
+
content: {
|
|
4986
|
+
...m.content,
|
|
4987
|
+
text
|
|
4988
|
+
}
|
|
4989
|
+
};
|
|
4990
|
+
});
|
|
4991
|
+
return {
|
|
4992
|
+
description: prompt.description,
|
|
4993
|
+
messages,
|
|
4994
|
+
metadata: prompt.agent ? { agent: prompt.agent } : void 0
|
|
4995
|
+
};
|
|
4996
|
+
}
|
|
4997
|
+
async function completePromptArgument(name, argName, value, contextArguments, dataSources) {
|
|
4998
|
+
void name;
|
|
4999
|
+
void contextArguments;
|
|
5000
|
+
if (argName === "task_id") {
|
|
5001
|
+
const values = dataSources.tasks.map((t) => t.id);
|
|
5002
|
+
return rankCompletionValues(values, value);
|
|
5003
|
+
}
|
|
5004
|
+
return [];
|
|
5005
|
+
}
|
|
4954
5006
|
|
|
4955
5007
|
// src/mcp/tools/standard.shared.ts
|
|
5008
|
+
function toContextSlug(value) {
|
|
5009
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
5010
|
+
}
|
|
4956
5011
|
function buildStandardVectorText(standard) {
|
|
4957
5012
|
return [
|
|
4958
5013
|
standard.title,
|
|
@@ -4967,31 +5022,17 @@ function buildStandardVectorText(standard) {
|
|
|
4967
5022
|
}
|
|
4968
5023
|
|
|
4969
5024
|
export {
|
|
5025
|
+
MCP_PROTOCOL_VERSION,
|
|
5026
|
+
CAPABILITIES,
|
|
4970
5027
|
logger,
|
|
4971
5028
|
setLogLevel,
|
|
4972
5029
|
getLogLevel,
|
|
4973
5030
|
addLogSink,
|
|
4974
5031
|
LOG_LEVEL_VALUES,
|
|
4975
5032
|
createFileSink,
|
|
4976
|
-
encodeCursor,
|
|
4977
|
-
decodeCursor,
|
|
4978
|
-
listResources,
|
|
4979
|
-
listResourceTemplates,
|
|
4980
|
-
completeResourceArgument,
|
|
4981
|
-
readResource,
|
|
4982
|
-
createSessionContext,
|
|
4983
|
-
updateSessionFromInitialize,
|
|
4984
|
-
updateSessionRoots,
|
|
4985
|
-
extractRootsFromResult,
|
|
4986
|
-
getFilesystemRoots,
|
|
4987
|
-
isPathWithinRoots,
|
|
4988
|
-
findContainingRoot,
|
|
4989
|
-
inferRepoFromSession,
|
|
4990
|
-
PROMPTS,
|
|
4991
|
-
listPrompts,
|
|
4992
|
-
getPrompt,
|
|
4993
|
-
completePromptArgument,
|
|
4994
5033
|
normalizeRepo,
|
|
5034
|
+
SQLiteStore,
|
|
5035
|
+
RealVectorStore,
|
|
4995
5036
|
MemoryStoreSchema,
|
|
4996
5037
|
MemoryUpdateSchema,
|
|
4997
5038
|
MemorySearchSchema,
|
|
@@ -5017,9 +5058,24 @@ export {
|
|
|
5017
5058
|
StandardUpdateSchema,
|
|
5018
5059
|
StandardSearchSchema,
|
|
5019
5060
|
TOOL_DEFINITIONS,
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5061
|
+
encodeCursor,
|
|
5062
|
+
decodeCursor,
|
|
5063
|
+
listResources,
|
|
5064
|
+
listResourceTemplates,
|
|
5065
|
+
completeResourceArgument,
|
|
5066
|
+
readResource,
|
|
5067
|
+
createSessionContext,
|
|
5068
|
+
updateSessionFromInitialize,
|
|
5069
|
+
updateSessionRoots,
|
|
5070
|
+
extractRootsFromResult,
|
|
5071
|
+
getFilesystemRoots,
|
|
5072
|
+
isPathWithinRoots,
|
|
5073
|
+
findContainingRoot,
|
|
5074
|
+
inferRepoFromSession,
|
|
5075
|
+
PROMPTS,
|
|
5076
|
+
listPrompts,
|
|
5077
|
+
getPrompt,
|
|
5078
|
+
completePromptArgument,
|
|
5079
|
+
toContextSlug,
|
|
5080
|
+
buildStandardVectorText
|
|
5025
5081
|
};
|