@vheins/local-memory-mcp 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.id.md +94 -0
- package/README.md +19 -24
- package/dist/{chunk-UZWV2DYU.js → chunk-GXQCHTXK.js} +623 -76
- package/dist/dashboard/public/assets/index-C1OTQhII.js +87 -0
- package/dist/dashboard/public/assets/index-CUg8rZCA.css +1 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +37 -16
- package/dist/mcp/server.js +197 -424
- package/package.json +3 -2
- package/dist/dashboard/public/assets/index-CbVS6V5d.js +0 -87
- package/dist/dashboard/public/assets/index-d4GwN8c5.css +0 -1
package/dist/mcp/server.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CAPABILITIES,
|
|
4
|
-
ClaimListSchema,
|
|
5
|
-
ClaimReleaseSchema,
|
|
6
|
-
HandoffCreateSchema,
|
|
7
|
-
HandoffListSchema,
|
|
8
|
-
HandoffUpdateSchema,
|
|
9
4
|
LOG_LEVEL_VALUES,
|
|
10
5
|
MCP_PROTOCOL_VERSION,
|
|
11
6
|
MemoryAcknowledgeSchema,
|
|
@@ -25,18 +20,19 @@ import {
|
|
|
25
20
|
StandardStoreSchema,
|
|
26
21
|
StandardUpdateSchema,
|
|
27
22
|
TOOL_DEFINITIONS,
|
|
28
|
-
TaskClaimSchema,
|
|
29
23
|
TaskCreateInteractiveSchema,
|
|
30
24
|
TaskCreateSchema,
|
|
31
25
|
TaskDeleteSchema,
|
|
32
26
|
TaskGetSchema,
|
|
33
27
|
TaskListSchema,
|
|
28
|
+
TaskSearchSchema,
|
|
34
29
|
TaskUpdateSchema,
|
|
35
30
|
addLogSink,
|
|
36
31
|
buildStandardVectorText,
|
|
37
32
|
completePromptArgument,
|
|
38
33
|
completeResourceArgument,
|
|
39
34
|
createFileSink,
|
|
35
|
+
createMcpResponse,
|
|
40
36
|
createSessionContext,
|
|
41
37
|
decodeCursor,
|
|
42
38
|
encodeCursor,
|
|
@@ -44,7 +40,14 @@ import {
|
|
|
44
40
|
findContainingRoot,
|
|
45
41
|
getFilesystemRoots,
|
|
46
42
|
getLogLevel,
|
|
43
|
+
getPrimaryTextContent,
|
|
47
44
|
getPrompt,
|
|
45
|
+
handleClaimList,
|
|
46
|
+
handleClaimRelease,
|
|
47
|
+
handleHandoffCreate,
|
|
48
|
+
handleHandoffList,
|
|
49
|
+
handleHandoffUpdate,
|
|
50
|
+
handleTaskClaim,
|
|
48
51
|
inferRepoFromSession,
|
|
49
52
|
isPathWithinRoots,
|
|
50
53
|
listPrompts,
|
|
@@ -57,7 +60,7 @@ import {
|
|
|
57
60
|
toContextSlug,
|
|
58
61
|
updateSessionFromInitialize,
|
|
59
62
|
updateSessionRoots
|
|
60
|
-
} from "../chunk-
|
|
63
|
+
} from "../chunk-GXQCHTXK.js";
|
|
61
64
|
|
|
62
65
|
// src/mcp/server.ts
|
|
63
66
|
import readline from "readline";
|
|
@@ -186,111 +189,6 @@ function invalidCompletionParams(message) {
|
|
|
186
189
|
|
|
187
190
|
// src/mcp/tools/memory.store.ts
|
|
188
191
|
import { randomUUID } from "crypto";
|
|
189
|
-
|
|
190
|
-
// src/mcp/utils/mcp-response.ts
|
|
191
|
-
import { z } from "zod";
|
|
192
|
-
var McpAnnotationsSchema = z.object({
|
|
193
|
-
audience: z.array(z.enum(["user", "assistant"])).optional(),
|
|
194
|
-
priority: z.number().min(0).max(1).optional(),
|
|
195
|
-
lastModified: z.string().optional()
|
|
196
|
-
}).strict().optional();
|
|
197
|
-
var McpContentSchema = z.discriminatedUnion("type", [
|
|
198
|
-
z.object({
|
|
199
|
-
type: z.literal("text"),
|
|
200
|
-
text: z.string(),
|
|
201
|
-
annotations: McpAnnotationsSchema
|
|
202
|
-
}),
|
|
203
|
-
z.object({
|
|
204
|
-
type: z.literal("image"),
|
|
205
|
-
data: z.string(),
|
|
206
|
-
mimeType: z.string(),
|
|
207
|
-
annotations: McpAnnotationsSchema
|
|
208
|
-
}),
|
|
209
|
-
z.object({
|
|
210
|
-
type: z.literal("resource"),
|
|
211
|
-
resource: z.object({
|
|
212
|
-
uri: z.string(),
|
|
213
|
-
mimeType: z.string().optional(),
|
|
214
|
-
text: z.string().optional(),
|
|
215
|
-
annotations: McpAnnotationsSchema
|
|
216
|
-
})
|
|
217
|
-
})
|
|
218
|
-
]);
|
|
219
|
-
function createMcpResponse(data, summary, options) {
|
|
220
|
-
const { structuredContentPathHint, contentSummary, includeSerializedStructuredContent = false } = options || {};
|
|
221
|
-
void includeSerializedStructuredContent;
|
|
222
|
-
let finalData = data;
|
|
223
|
-
if (data && typeof data === "object") {
|
|
224
|
-
const cloned = JSON.parse(JSON.stringify(data));
|
|
225
|
-
finalData = cloned;
|
|
226
|
-
const arrayKeys = ["results", "tasks", "memories", "items"];
|
|
227
|
-
let foundArray = false;
|
|
228
|
-
for (const key of arrayKeys) {
|
|
229
|
-
const value = cloned[key];
|
|
230
|
-
if (Array.isArray(value)) {
|
|
231
|
-
cloned[key] = value.map(
|
|
232
|
-
(item) => pruneMetadata(item)
|
|
233
|
-
);
|
|
234
|
-
foundArray = true;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (Array.isArray(cloned)) {
|
|
238
|
-
finalData = cloned.map((item) => pruneMetadata(item));
|
|
239
|
-
} else if (!foundArray) {
|
|
240
|
-
finalData = pruneMetadata(cloned);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
const content = [];
|
|
244
|
-
if (contentSummary && contentSummary.trim().length > 0) {
|
|
245
|
-
content.push({
|
|
246
|
-
type: "text",
|
|
247
|
-
text: contentSummary.trim()
|
|
248
|
-
});
|
|
249
|
-
} else if (summary && summary.trim().length > 0) {
|
|
250
|
-
const pointerText = structuredContentPathHint ? `Read structuredContent.${structuredContentPathHint} for details.` : `Read structuredContent for machine-readable results.`;
|
|
251
|
-
content.push({
|
|
252
|
-
type: "text",
|
|
253
|
-
text: `${summary.trim()} ${pointerText}`
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
const response = {
|
|
257
|
-
structuredContent: finalData,
|
|
258
|
-
isError: false
|
|
259
|
-
};
|
|
260
|
-
if (includeSerializedStructuredContent === false) {
|
|
261
|
-
delete response.structuredContent;
|
|
262
|
-
}
|
|
263
|
-
response.content = content;
|
|
264
|
-
return response;
|
|
265
|
-
}
|
|
266
|
-
function pruneMetadata(item) {
|
|
267
|
-
if (!item || typeof item !== "object") return item;
|
|
268
|
-
const pruned = { ...item };
|
|
269
|
-
const toRemove = [
|
|
270
|
-
"hit_count",
|
|
271
|
-
"recall_count",
|
|
272
|
-
"last_used_at",
|
|
273
|
-
"expires_at",
|
|
274
|
-
"agent",
|
|
275
|
-
"role",
|
|
276
|
-
"model",
|
|
277
|
-
"recall_rate",
|
|
278
|
-
"vector_version",
|
|
279
|
-
"similarity"
|
|
280
|
-
// Similarity is useful but adds noise if many results
|
|
281
|
-
];
|
|
282
|
-
for (const field of toRemove) {
|
|
283
|
-
delete pruned[field];
|
|
284
|
-
}
|
|
285
|
-
return pruned;
|
|
286
|
-
}
|
|
287
|
-
function getPrimaryTextContent(response) {
|
|
288
|
-
if (!Array.isArray(response.content)) return "";
|
|
289
|
-
const textItem = response.content.find((item) => item.type === "text");
|
|
290
|
-
return textItem?.type === "text" ? textItem.text : "";
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// src/mcp/tools/memory.store.ts
|
|
294
192
|
function hasMetadataLikeTitle(title) {
|
|
295
193
|
const normalized = title.trim();
|
|
296
194
|
return /^\[[^\]]{0,200}(agent:|role:|model:|\d{4}-\d{2}-\d{2}|source_)[^\]]*\]/i.test(normalized);
|
|
@@ -311,9 +209,10 @@ async function handleMemoryStore(params, db2, vectors2) {
|
|
|
311
209
|
);
|
|
312
210
|
}
|
|
313
211
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
314
|
-
const
|
|
212
|
+
const createdAtTime = new Date(now).getTime();
|
|
213
|
+
const expires_at = validated.ttlDays != null ? new Date(createdAtTime + validated.ttlDays * 864e5).toISOString() : null;
|
|
315
214
|
if (!validated.supersedes && validated.type !== "task_archive") {
|
|
316
|
-
const conflict = await db2.
|
|
215
|
+
const conflict = await db2.memoryVectors.checkConflicts(
|
|
317
216
|
validated.content,
|
|
318
217
|
validated.scope.repo,
|
|
319
218
|
validated.type,
|
|
@@ -416,9 +315,17 @@ function hasMetadataLikeTitle2(title) {
|
|
|
416
315
|
}
|
|
417
316
|
async function handleMemoryUpdate(params, db2, vectors2) {
|
|
418
317
|
const validated = MemoryUpdateSchema.parse(params);
|
|
419
|
-
|
|
318
|
+
let resolvedId = validated.id;
|
|
319
|
+
if (!resolvedId && validated.code) {
|
|
320
|
+
const byCode = db2.memories.getByCode(validated.code);
|
|
321
|
+
if (!byCode) throw new Error(`Memory not found: ${validated.code}`);
|
|
322
|
+
resolvedId = byCode.id;
|
|
323
|
+
} else if (!resolvedId) {
|
|
324
|
+
throw new Error("Either id or code must be provided");
|
|
325
|
+
}
|
|
326
|
+
const existing = db2.memories.getById(resolvedId);
|
|
420
327
|
if (!existing) {
|
|
421
|
-
throw new Error(`Memory not found: ${
|
|
328
|
+
throw new Error(`Memory not found: ${resolvedId}`);
|
|
422
329
|
}
|
|
423
330
|
const repoFilter = params?.repo || params?.scope?.repo;
|
|
424
331
|
if (repoFilter && repoFilter !== existing.scope.repo) {
|
|
@@ -444,20 +351,21 @@ async function handleMemoryUpdate(params, db2, vectors2) {
|
|
|
444
351
|
if (validated.metadata !== void 0) updates.metadata = validated.metadata;
|
|
445
352
|
if (validated.is_global !== void 0) updates.is_global = validated.is_global;
|
|
446
353
|
if (validated.completed_at !== void 0) updates.completed_at = validated.completed_at;
|
|
447
|
-
db2.memories.update(
|
|
354
|
+
db2.memories.update(resolvedId, updates);
|
|
448
355
|
if (validated.content !== void 0) {
|
|
449
|
-
await vectors2.upsert(
|
|
356
|
+
await vectors2.upsert(resolvedId, validated.content);
|
|
450
357
|
}
|
|
451
|
-
db2.actions.logAction("update", existing.scope.repo, { memoryId:
|
|
452
|
-
logger.info("[Tool] memory.update", { repo: existing.scope.repo, id:
|
|
358
|
+
db2.actions.logAction("update", existing.scope.repo, { memoryId: resolvedId, resultCount: 1 });
|
|
359
|
+
logger.info("[Tool] memory.update", { repo: existing.scope.repo, id: resolvedId, fields: Object.keys(updates) });
|
|
453
360
|
return createMcpResponse(
|
|
454
361
|
{
|
|
455
362
|
success: true,
|
|
456
|
-
id:
|
|
363
|
+
id: resolvedId,
|
|
364
|
+
code: existing.code,
|
|
457
365
|
repo: existing.scope.repo,
|
|
458
366
|
updatedFields: Object.keys(updates)
|
|
459
367
|
},
|
|
460
|
-
`Updated memory ${
|
|
368
|
+
`Updated memory ${resolvedId} in repo "${existing.scope.repo}". Fields: ${Object.keys(updates).join(", ") || "none"}.`,
|
|
461
369
|
{
|
|
462
370
|
structuredContentPathHint: "updatedFields",
|
|
463
371
|
includeSerializedStructuredContent: validated.structured
|
|
@@ -499,7 +407,7 @@ async function handleMemorySearch(params, db2, vectors2) {
|
|
|
499
407
|
const validated = MemorySearchSchema.parse(params);
|
|
500
408
|
const searchQuery = expandQuery(validated.query, validated.prompt);
|
|
501
409
|
const fetchLimit = (validated.offset + validated.limit) * 3;
|
|
502
|
-
const similarityResults = db2.
|
|
410
|
+
const similarityResults = db2.memoryVectors.searchBySimilarity(
|
|
503
411
|
searchQuery,
|
|
504
412
|
validated.repo,
|
|
505
413
|
fetchLimit,
|
|
@@ -815,7 +723,7 @@ function deriveTaskStatusTimestamps(status, now, existingTask) {
|
|
|
815
723
|
async function archiveTaskToMemory(taskId, repo, storage, vectors2) {
|
|
816
724
|
const task = storage.tasks.getTaskById(taskId);
|
|
817
725
|
if (!task) return;
|
|
818
|
-
const comments = storage.
|
|
726
|
+
const comments = storage.taskComments.getTaskCommentsByTaskId(taskId);
|
|
819
727
|
let content = `Task: [${task.task_code}] ${task.title}
|
|
820
728
|
`;
|
|
821
729
|
content += `Phase: ${task.phase}
|
|
@@ -931,7 +839,7 @@ async function handleTaskCreate(args, storage) {
|
|
|
931
839
|
const createdTasks = [];
|
|
932
840
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
933
841
|
const codesInRequest = /* @__PURE__ */ new Set();
|
|
934
|
-
const initialStats = storage.
|
|
842
|
+
const initialStats = storage.taskStats.getTaskStats(repo);
|
|
935
843
|
let pendingInRequestCount = 0;
|
|
936
844
|
for (const taskData of bulkTasks) {
|
|
937
845
|
if (codesInRequest.has(taskData.task_code)) {
|
|
@@ -979,6 +887,8 @@ async function handleTaskCreate(args, storage) {
|
|
|
979
887
|
canceled_at: statusTimestamps2.canceled_at,
|
|
980
888
|
est_tokens: taskData.est_tokens ?? 0,
|
|
981
889
|
tags,
|
|
890
|
+
commit_id: null,
|
|
891
|
+
changed_files: [],
|
|
982
892
|
metadata: taskData.metadata || {},
|
|
983
893
|
parent_id: resolveParentId(taskData.parent_id, repo, storage),
|
|
984
894
|
depends_on: taskData.depends_on || null
|
|
@@ -1021,9 +931,11 @@ async function handleTaskCreate(args, storage) {
|
|
|
1021
931
|
throw new Error("New tasks must be created with status 'backlog' or 'pending'.");
|
|
1022
932
|
}
|
|
1023
933
|
if (status === "pending") {
|
|
1024
|
-
const stats = storage.
|
|
934
|
+
const stats = storage.taskStats.getTaskStats(repo);
|
|
1025
935
|
if (stats.todo >= 10) {
|
|
1026
|
-
throw new Error(
|
|
936
|
+
throw new Error(
|
|
937
|
+
`Cannot create task as 'pending'. Maximum of 10 pending tasks reached. Please use status 'backlog' for new tasks instead.`
|
|
938
|
+
);
|
|
1027
939
|
}
|
|
1028
940
|
}
|
|
1029
941
|
const taskId = randomUUID2();
|
|
@@ -1053,6 +965,8 @@ async function handleTaskCreate(args, storage) {
|
|
|
1053
965
|
canceled_at: statusTimestamps.canceled_at,
|
|
1054
966
|
est_tokens: est_tokens ?? 0,
|
|
1055
967
|
tags: finalTags,
|
|
968
|
+
commit_id: null,
|
|
969
|
+
changed_files: [],
|
|
1056
970
|
metadata: metadata || {},
|
|
1057
971
|
parent_id: resolveParentId(parent_id, repo, storage),
|
|
1058
972
|
depends_on: depends_on || null
|
|
@@ -1246,7 +1160,7 @@ async function handleTaskUpdate(args, storage, vectors2) {
|
|
|
1246
1160
|
finalUpdates.in_progress_at = now;
|
|
1247
1161
|
storage.tasks.updateTask(targetId, finalUpdates);
|
|
1248
1162
|
if (comment !== void 0 || isStatusChanging) {
|
|
1249
|
-
storage.
|
|
1163
|
+
storage.taskComments.insertTaskComment({
|
|
1250
1164
|
id: randomUUID2(),
|
|
1251
1165
|
task_id: targetId,
|
|
1252
1166
|
repo,
|
|
@@ -1306,11 +1220,19 @@ async function handleTaskUpdate(args, storage, vectors2) {
|
|
|
1306
1220
|
}
|
|
1307
1221
|
async function handleTaskDelete(args, storage) {
|
|
1308
1222
|
const validated = TaskDeleteSchema.parse(args);
|
|
1309
|
-
const { repo, id, ids } = validated;
|
|
1310
|
-
const
|
|
1311
|
-
if (
|
|
1312
|
-
|
|
1223
|
+
const { repo, id, ids, task_code } = validated;
|
|
1224
|
+
const resolvedIds = [];
|
|
1225
|
+
if (ids) resolvedIds.push(...ids);
|
|
1226
|
+
if (id) resolvedIds.push(id);
|
|
1227
|
+
if (task_code) {
|
|
1228
|
+
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
1229
|
+
if (!task) throw new Error(`Task not found: ${task_code}`);
|
|
1230
|
+
resolvedIds.push(task.id);
|
|
1231
|
+
}
|
|
1232
|
+
if (resolvedIds.length === 0) {
|
|
1233
|
+
throw new Error("Either 'id', 'ids', or 'task_code' must be provided for deletion");
|
|
1313
1234
|
}
|
|
1235
|
+
const targetIds = resolvedIds;
|
|
1314
1236
|
for (const targetId of targetIds) {
|
|
1315
1237
|
storage.tasks.deleteTask(targetId);
|
|
1316
1238
|
}
|
|
@@ -1561,31 +1483,54 @@ async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
|
|
|
1561
1483
|
// src/mcp/tools/memory.delete.ts
|
|
1562
1484
|
async function handleMemoryDelete(params, db2, vectors2, onProgress) {
|
|
1563
1485
|
const validated = MemoryDeleteSchema.parse(params);
|
|
1564
|
-
const { id, ids, repo, structured } = validated;
|
|
1565
|
-
const
|
|
1566
|
-
if (
|
|
1567
|
-
|
|
1568
|
-
|
|
1486
|
+
const { id, ids, code, codes, repo, structured } = validated;
|
|
1487
|
+
const resolvedIds = [];
|
|
1488
|
+
if (ids) resolvedIds.push(...ids);
|
|
1489
|
+
if (id) resolvedIds.push(id);
|
|
1490
|
+
if (code) {
|
|
1491
|
+
const entry = db2.memories.getByCode(code);
|
|
1492
|
+
if (!entry) throw new Error(`Memory not found: ${code}`);
|
|
1493
|
+
resolvedIds.push(entry.id);
|
|
1494
|
+
}
|
|
1495
|
+
if (codes) {
|
|
1496
|
+
for (const c of codes) {
|
|
1497
|
+
const entry = db2.memories.getByCode(c);
|
|
1498
|
+
if (!entry) throw new Error(`Memory not found: ${c}`);
|
|
1499
|
+
resolvedIds.push(entry.id);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (resolvedIds.length === 0) {
|
|
1503
|
+
throw new Error("Either 'id', 'ids', 'code', or 'codes' must be provided for deletion");
|
|
1504
|
+
}
|
|
1505
|
+
const targetIds = resolvedIds;
|
|
1569
1506
|
let deletedCount = 0;
|
|
1570
1507
|
const deletedCodes = [];
|
|
1571
1508
|
let lastRepo = repo || "unknown";
|
|
1572
1509
|
const total = targetIds.length;
|
|
1573
1510
|
let progress = 0;
|
|
1511
|
+
const existingMemories = db2.memories.getByIds(targetIds);
|
|
1512
|
+
const existingMap = new Map(existingMemories.map((m) => [m.id, m]));
|
|
1513
|
+
const validIdsToDelete = [];
|
|
1574
1514
|
for (const targetId of targetIds) {
|
|
1575
|
-
|
|
1576
|
-
onProgress(progress, total);
|
|
1577
|
-
}
|
|
1578
|
-
const existing = db2.memories.getById(targetId);
|
|
1515
|
+
const existing = existingMap.get(targetId);
|
|
1579
1516
|
if (existing) {
|
|
1580
1517
|
lastRepo = existing.scope.repo;
|
|
1581
1518
|
deletedCodes.push(existing.code || existing.id);
|
|
1582
|
-
|
|
1583
|
-
await vectors2.remove(targetId);
|
|
1584
|
-
deletedCount++;
|
|
1519
|
+
validIdsToDelete.push(targetId);
|
|
1585
1520
|
} else if (id) {
|
|
1586
1521
|
throw new Error(`Memory not found: ${targetId}`);
|
|
1587
1522
|
}
|
|
1588
|
-
|
|
1523
|
+
}
|
|
1524
|
+
if (validIdsToDelete.length > 0) {
|
|
1525
|
+
db2.memoryArchives.bulkDeleteMemories(validIdsToDelete);
|
|
1526
|
+
for (const validId of validIdsToDelete) {
|
|
1527
|
+
if (onProgress) {
|
|
1528
|
+
onProgress(progress, total);
|
|
1529
|
+
}
|
|
1530
|
+
await vectors2.remove(validId);
|
|
1531
|
+
progress++;
|
|
1532
|
+
}
|
|
1533
|
+
deletedCount = validIdsToDelete.length;
|
|
1589
1534
|
}
|
|
1590
1535
|
if (onProgress) {
|
|
1591
1536
|
onProgress(progress, total);
|
|
@@ -1611,9 +1556,17 @@ async function handleMemoryDelete(params, db2, vectors2, onProgress) {
|
|
|
1611
1556
|
// src/mcp/tools/memory.acknowledge.ts
|
|
1612
1557
|
async function handleMemoryAcknowledge(params, db2) {
|
|
1613
1558
|
const validated = MemoryAcknowledgeSchema.parse(params);
|
|
1614
|
-
|
|
1559
|
+
let memoryId = validated.memory_id;
|
|
1560
|
+
if (!memoryId && validated.code) {
|
|
1561
|
+
const byCode = db2.memories.getByCode(validated.code);
|
|
1562
|
+
if (!byCode) throw new Error(`Memory not found: ${validated.code}`);
|
|
1563
|
+
memoryId = byCode.id;
|
|
1564
|
+
} else if (!memoryId) {
|
|
1565
|
+
throw new Error("Either memory_id or code must be provided");
|
|
1566
|
+
}
|
|
1567
|
+
const memory = db2.memories.getById(memoryId);
|
|
1615
1568
|
if (!memory) {
|
|
1616
|
-
throw new Error(`Memory with ID ${
|
|
1569
|
+
throw new Error(`Memory with ID ${memoryId} not found.`);
|
|
1617
1570
|
}
|
|
1618
1571
|
if (validated.status === "used") {
|
|
1619
1572
|
db2.memories.incrementRecallCount(memory.id);
|
|
@@ -1674,266 +1627,6 @@ async function handleMemoryDetail(args, storage) {
|
|
|
1674
1627
|
});
|
|
1675
1628
|
}
|
|
1676
1629
|
|
|
1677
|
-
// src/mcp/tools/handoff.manage.ts
|
|
1678
|
-
function buildHandoffListSummary(repo, count, status, fromAgent, toAgent) {
|
|
1679
|
-
const parts = [`Found ${count} handoff${count === 1 ? "" : "s"} in repo "${repo}".`];
|
|
1680
|
-
if (status) {
|
|
1681
|
-
parts.push(`Status filter: ${status}.`);
|
|
1682
|
-
}
|
|
1683
|
-
if (fromAgent) {
|
|
1684
|
-
parts.push(`From agent: ${fromAgent}.`);
|
|
1685
|
-
}
|
|
1686
|
-
if (toAgent) {
|
|
1687
|
-
parts.push(`To agent: ${toAgent}.`);
|
|
1688
|
-
}
|
|
1689
|
-
return parts.join("\n");
|
|
1690
|
-
}
|
|
1691
|
-
function buildClaimListSummary(repo, count, agent, activeOnly) {
|
|
1692
|
-
const parts = [`Found ${count} claim${count === 1 ? "" : "s"} in repo "${repo}".`];
|
|
1693
|
-
if (agent) {
|
|
1694
|
-
parts.push(`Agent filter: ${agent}.`);
|
|
1695
|
-
}
|
|
1696
|
-
if (activeOnly) {
|
|
1697
|
-
parts.push("Showing active claims only.");
|
|
1698
|
-
}
|
|
1699
|
-
return parts.join("\n");
|
|
1700
|
-
}
|
|
1701
|
-
async function handleHandoffCreate(args, storage) {
|
|
1702
|
-
const validated = HandoffCreateSchema.parse(args);
|
|
1703
|
-
const { repo, from_agent, to_agent, task_id, task_code, summary, context, expires_at, structured } = validated;
|
|
1704
|
-
let resolvedTaskId = task_id ?? null;
|
|
1705
|
-
if (!resolvedTaskId && task_code) {
|
|
1706
|
-
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
1707
|
-
if (!task) {
|
|
1708
|
-
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
1709
|
-
}
|
|
1710
|
-
resolvedTaskId = task.id;
|
|
1711
|
-
}
|
|
1712
|
-
const handoff = storage.handoffs.createHandoff({
|
|
1713
|
-
repo,
|
|
1714
|
-
from_agent,
|
|
1715
|
-
to_agent,
|
|
1716
|
-
task_id: resolvedTaskId,
|
|
1717
|
-
summary,
|
|
1718
|
-
context,
|
|
1719
|
-
expires_at
|
|
1720
|
-
});
|
|
1721
|
-
const contentSummary = [
|
|
1722
|
-
`Created handoff ${handoff.id}.`,
|
|
1723
|
-
`Repo: ${handoff.repo}`,
|
|
1724
|
-
`From: ${handoff.from_agent}`,
|
|
1725
|
-
`To: ${handoff.to_agent || "unassigned"}`,
|
|
1726
|
-
`Status: ${handoff.status}`,
|
|
1727
|
-
`Task ID: ${handoff.task_id || "-"}`,
|
|
1728
|
-
`Summary: ${handoff.summary}`
|
|
1729
|
-
].join("\n");
|
|
1730
|
-
return createMcpResponse(handoff, contentSummary, {
|
|
1731
|
-
contentSummary,
|
|
1732
|
-
includeSerializedStructuredContent: structured
|
|
1733
|
-
});
|
|
1734
|
-
}
|
|
1735
|
-
async function handleHandoffList(args, storage) {
|
|
1736
|
-
const validated = HandoffListSchema.parse(args);
|
|
1737
|
-
const { repo, status, from_agent, to_agent, limit, offset, structured } = validated;
|
|
1738
|
-
const handoffs = storage.handoffs.listHandoffs({
|
|
1739
|
-
repo,
|
|
1740
|
-
status,
|
|
1741
|
-
from_agent,
|
|
1742
|
-
to_agent,
|
|
1743
|
-
limit,
|
|
1744
|
-
offset
|
|
1745
|
-
});
|
|
1746
|
-
const COLUMNS = [
|
|
1747
|
-
"id",
|
|
1748
|
-
"from_agent",
|
|
1749
|
-
"to_agent",
|
|
1750
|
-
"task_id",
|
|
1751
|
-
"task_code",
|
|
1752
|
-
"status",
|
|
1753
|
-
"created_at",
|
|
1754
|
-
"updated_at",
|
|
1755
|
-
"expires_at",
|
|
1756
|
-
"summary",
|
|
1757
|
-
"context"
|
|
1758
|
-
];
|
|
1759
|
-
const rows = handoffs.map((handoff) => [
|
|
1760
|
-
handoff.id,
|
|
1761
|
-
handoff.from_agent,
|
|
1762
|
-
handoff.to_agent,
|
|
1763
|
-
handoff.task_id,
|
|
1764
|
-
handoff.task_code ?? null,
|
|
1765
|
-
handoff.status,
|
|
1766
|
-
handoff.created_at,
|
|
1767
|
-
handoff.updated_at,
|
|
1768
|
-
handoff.expires_at,
|
|
1769
|
-
handoff.summary,
|
|
1770
|
-
handoff.context
|
|
1771
|
-
]);
|
|
1772
|
-
const structuredData = {
|
|
1773
|
-
schema: "handoff-list",
|
|
1774
|
-
handoffs: {
|
|
1775
|
-
columns: [...COLUMNS],
|
|
1776
|
-
rows
|
|
1777
|
-
},
|
|
1778
|
-
count: rows.length,
|
|
1779
|
-
offset
|
|
1780
|
-
};
|
|
1781
|
-
const contentSummary = buildHandoffListSummary(repo, rows.length, status, from_agent, to_agent);
|
|
1782
|
-
return createMcpResponse(structuredData, contentSummary, {
|
|
1783
|
-
contentSummary,
|
|
1784
|
-
includeSerializedStructuredContent: structured
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1787
|
-
async function handleHandoffUpdate(args, storage) {
|
|
1788
|
-
const validated = HandoffUpdateSchema.parse(args);
|
|
1789
|
-
const { id, status, structured } = validated;
|
|
1790
|
-
const existing = storage.handoffs.getHandoffById(id);
|
|
1791
|
-
if (!existing) {
|
|
1792
|
-
throw new Error(`Handoff not found: ${id}`);
|
|
1793
|
-
}
|
|
1794
|
-
const success = storage.handoffs.updateHandoffStatus(id, status);
|
|
1795
|
-
if (!success) {
|
|
1796
|
-
throw new Error(`Failed to update handoff: ${id}`);
|
|
1797
|
-
}
|
|
1798
|
-
const updated = storage.handoffs.getHandoffById(id);
|
|
1799
|
-
const result = {
|
|
1800
|
-
success,
|
|
1801
|
-
id,
|
|
1802
|
-
status,
|
|
1803
|
-
handoff: updated
|
|
1804
|
-
};
|
|
1805
|
-
const contentSummary = [`Updated handoff ${id}.`, `Status: ${status}`].join("\n");
|
|
1806
|
-
return createMcpResponse(result, contentSummary, {
|
|
1807
|
-
contentSummary,
|
|
1808
|
-
includeSerializedStructuredContent: structured
|
|
1809
|
-
});
|
|
1810
|
-
}
|
|
1811
|
-
async function handleTaskClaim(args, storage) {
|
|
1812
|
-
const validated = TaskClaimSchema.parse(args);
|
|
1813
|
-
const { repo, task_id, task_code, agent, role, metadata, structured } = validated;
|
|
1814
|
-
let taskId = task_id;
|
|
1815
|
-
let resolvedTaskCode;
|
|
1816
|
-
if (taskId) {
|
|
1817
|
-
const task = storage.tasks.getTaskById(taskId);
|
|
1818
|
-
if (!task || task.repo !== repo) {
|
|
1819
|
-
throw new Error(`Task not found: ${taskId} in repo ${repo}`);
|
|
1820
|
-
}
|
|
1821
|
-
resolvedTaskCode = task.task_code;
|
|
1822
|
-
} else if (task_code) {
|
|
1823
|
-
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
1824
|
-
if (!task) {
|
|
1825
|
-
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
1826
|
-
}
|
|
1827
|
-
taskId = task.id;
|
|
1828
|
-
resolvedTaskCode = task.task_code;
|
|
1829
|
-
} else {
|
|
1830
|
-
throw new Error("Either task_id or task_code must be provided");
|
|
1831
|
-
}
|
|
1832
|
-
const claim = storage.handoffs.claimTask({
|
|
1833
|
-
repo,
|
|
1834
|
-
task_id: taskId,
|
|
1835
|
-
agent,
|
|
1836
|
-
role,
|
|
1837
|
-
metadata
|
|
1838
|
-
});
|
|
1839
|
-
const responseData = {
|
|
1840
|
-
...claim,
|
|
1841
|
-
task_code: resolvedTaskCode
|
|
1842
|
-
};
|
|
1843
|
-
const contentSummary = [
|
|
1844
|
-
`Claimed task ${resolvedTaskCode || claim.task_id}.`,
|
|
1845
|
-
`Repo: ${claim.repo}`,
|
|
1846
|
-
`Task ID: ${claim.task_id}`,
|
|
1847
|
-
`Agent: ${claim.agent}`,
|
|
1848
|
-
`Role: ${claim.role}`,
|
|
1849
|
-
`Claimed At: ${claim.claimed_at}`
|
|
1850
|
-
].join("\n");
|
|
1851
|
-
const response = createMcpResponse(responseData, contentSummary, {
|
|
1852
|
-
contentSummary,
|
|
1853
|
-
includeSerializedStructuredContent: structured
|
|
1854
|
-
});
|
|
1855
|
-
if (structured) {
|
|
1856
|
-
response.structuredContent = responseData;
|
|
1857
|
-
}
|
|
1858
|
-
return response;
|
|
1859
|
-
}
|
|
1860
|
-
async function handleClaimList(args, storage) {
|
|
1861
|
-
const validated = ClaimListSchema.parse(args);
|
|
1862
|
-
const { repo, agent, active_only, limit, offset, structured } = validated;
|
|
1863
|
-
const claims = storage.handoffs.listClaims({
|
|
1864
|
-
repo,
|
|
1865
|
-
agent,
|
|
1866
|
-
active_only,
|
|
1867
|
-
limit,
|
|
1868
|
-
offset
|
|
1869
|
-
});
|
|
1870
|
-
const COLUMNS = ["id", "task_id", "task_code", "agent", "role", "claimed_at", "released_at", "metadata"];
|
|
1871
|
-
const rows = claims.map((claim) => [
|
|
1872
|
-
claim.id,
|
|
1873
|
-
claim.task_id,
|
|
1874
|
-
claim.task_code ?? null,
|
|
1875
|
-
claim.agent,
|
|
1876
|
-
claim.role,
|
|
1877
|
-
claim.claimed_at,
|
|
1878
|
-
claim.released_at,
|
|
1879
|
-
claim.metadata
|
|
1880
|
-
]);
|
|
1881
|
-
const structuredData = {
|
|
1882
|
-
schema: "claim-list",
|
|
1883
|
-
claims: {
|
|
1884
|
-
columns: [...COLUMNS],
|
|
1885
|
-
rows
|
|
1886
|
-
},
|
|
1887
|
-
count: rows.length,
|
|
1888
|
-
offset
|
|
1889
|
-
};
|
|
1890
|
-
const contentSummary = buildClaimListSummary(repo, rows.length, agent, active_only);
|
|
1891
|
-
return createMcpResponse(structuredData, contentSummary, {
|
|
1892
|
-
contentSummary,
|
|
1893
|
-
includeSerializedStructuredContent: structured
|
|
1894
|
-
});
|
|
1895
|
-
}
|
|
1896
|
-
async function handleClaimRelease(args, storage) {
|
|
1897
|
-
const validated = ClaimReleaseSchema.parse(args);
|
|
1898
|
-
const { repo, task_id, task_code, agent, structured } = validated;
|
|
1899
|
-
let resolvedTaskId = task_id;
|
|
1900
|
-
let resolvedTaskCode = task_code ?? null;
|
|
1901
|
-
if (resolvedTaskId) {
|
|
1902
|
-
const task = storage.tasks.getTaskById(resolvedTaskId);
|
|
1903
|
-
if (!task || task.repo !== repo) {
|
|
1904
|
-
throw new Error(`Task not found: ${resolvedTaskId} in repo ${repo}`);
|
|
1905
|
-
}
|
|
1906
|
-
resolvedTaskCode = task.task_code;
|
|
1907
|
-
} else if (task_code) {
|
|
1908
|
-
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
1909
|
-
if (!task) {
|
|
1910
|
-
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
1911
|
-
}
|
|
1912
|
-
resolvedTaskId = task.id;
|
|
1913
|
-
resolvedTaskCode = task.task_code;
|
|
1914
|
-
}
|
|
1915
|
-
const success = storage.handoffs.releaseClaim(resolvedTaskId, agent);
|
|
1916
|
-
if (!success) {
|
|
1917
|
-
throw new Error(`No active claim found for task ${resolvedTaskCode || resolvedTaskId}`);
|
|
1918
|
-
}
|
|
1919
|
-
const result = {
|
|
1920
|
-
success,
|
|
1921
|
-
repo,
|
|
1922
|
-
task_id: resolvedTaskId,
|
|
1923
|
-
task_code: resolvedTaskCode,
|
|
1924
|
-
agent: agent ?? null
|
|
1925
|
-
};
|
|
1926
|
-
const contentSummary = [
|
|
1927
|
-
`Released claim for task ${resolvedTaskCode || resolvedTaskId}.`,
|
|
1928
|
-
`Repo: ${repo}`,
|
|
1929
|
-
agent ? `Agent: ${agent}` : "Agent: any active claimant"
|
|
1930
|
-
].join("\n");
|
|
1931
|
-
return createMcpResponse(result, contentSummary, {
|
|
1932
|
-
contentSummary,
|
|
1933
|
-
includeSerializedStructuredContent: structured
|
|
1934
|
-
});
|
|
1935
|
-
}
|
|
1936
|
-
|
|
1937
1630
|
// src/mcp/tools/standard.store.ts
|
|
1938
1631
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1939
1632
|
function generateShortCode2() {
|
|
@@ -2252,9 +1945,17 @@ async function handleStandardSearch(params, db2, vectors2) {
|
|
|
2252
1945
|
// src/mcp/tools/standard.update.ts
|
|
2253
1946
|
async function handleStandardUpdate(params, db2, vectors2) {
|
|
2254
1947
|
const validated = StandardUpdateSchema.parse(params);
|
|
2255
|
-
|
|
1948
|
+
let resolvedId = validated.id;
|
|
1949
|
+
if (!resolvedId && validated.code) {
|
|
1950
|
+
const byCode = db2.standards.getByCode(validated.code);
|
|
1951
|
+
if (!byCode) throw new Error(`Coding standard not found: ${validated.code}`);
|
|
1952
|
+
resolvedId = byCode.id;
|
|
1953
|
+
} else if (!resolvedId) {
|
|
1954
|
+
throw new Error("Either id or code must be provided");
|
|
1955
|
+
}
|
|
1956
|
+
const existing = db2.standards.getById(resolvedId);
|
|
2256
1957
|
if (!existing) {
|
|
2257
|
-
throw new Error(`Coding standard not found: ${
|
|
1958
|
+
throw new Error(`Coding standard not found: ${resolvedId}`);
|
|
2258
1959
|
}
|
|
2259
1960
|
const updates = {};
|
|
2260
1961
|
if (validated.name !== void 0) updates.title = validated.name;
|
|
@@ -2270,26 +1971,27 @@ async function handleStandardUpdate(params, db2, vectors2) {
|
|
|
2270
1971
|
if (validated.metadata !== void 0) updates.metadata = validated.metadata;
|
|
2271
1972
|
if (validated.agent !== void 0) updates.agent = validated.agent;
|
|
2272
1973
|
if (validated.model !== void 0) updates.model = validated.model;
|
|
2273
|
-
db2.standards.update(
|
|
1974
|
+
db2.standards.update(resolvedId, updates);
|
|
2274
1975
|
const merged = {
|
|
2275
1976
|
...existing,
|
|
2276
1977
|
...updates,
|
|
2277
1978
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2278
1979
|
};
|
|
2279
1980
|
if (validated.name !== void 0 || validated.content !== void 0 || validated.context !== void 0 || validated.version !== void 0 || validated.language !== void 0 || validated.stack !== void 0 || validated.tags !== void 0 || validated.metadata !== void 0) {
|
|
2280
|
-
await vectors2.upsert(
|
|
1981
|
+
await vectors2.upsert(resolvedId, buildStandardVectorText(merged), "standard");
|
|
2281
1982
|
}
|
|
2282
1983
|
logger.info("[Tool] standard.update - updated coding standard", {
|
|
2283
|
-
standardId:
|
|
1984
|
+
standardId: resolvedId,
|
|
2284
1985
|
fields: Object.keys(updates)
|
|
2285
1986
|
});
|
|
2286
1987
|
return createMcpResponse(
|
|
2287
1988
|
{
|
|
2288
1989
|
success: true,
|
|
2289
|
-
id:
|
|
1990
|
+
id: resolvedId,
|
|
1991
|
+
code: existing.code,
|
|
2290
1992
|
updatedFields: Object.keys(updates)
|
|
2291
1993
|
},
|
|
2292
|
-
`Updated coding standard ${
|
|
1994
|
+
`Updated coding standard ${resolvedId}. Fields: ${Object.keys(updates).join(", ") || "none"}.`,
|
|
2293
1995
|
{
|
|
2294
1996
|
structuredContentPathHint: "updatedFields",
|
|
2295
1997
|
includeSerializedStructuredContent: true
|
|
@@ -2334,11 +2036,26 @@ async function handleStandardDetail(args, storage) {
|
|
|
2334
2036
|
// src/mcp/tools/standard.delete.ts
|
|
2335
2037
|
async function handleStandardDelete(params, db2, vectors2) {
|
|
2336
2038
|
const validated = StandardDeleteSchema.parse(params);
|
|
2337
|
-
const { id, ids, repo, structured } = validated;
|
|
2338
|
-
const
|
|
2339
|
-
if (
|
|
2340
|
-
|
|
2341
|
-
|
|
2039
|
+
const { id, ids, code, codes, repo, structured } = validated;
|
|
2040
|
+
const resolvedIds = [];
|
|
2041
|
+
if (ids) resolvedIds.push(...ids);
|
|
2042
|
+
if (id) resolvedIds.push(id);
|
|
2043
|
+
if (code) {
|
|
2044
|
+
const entry = db2.standards.getByCode(code);
|
|
2045
|
+
if (!entry) throw new Error(`Coding standard not found: ${code}`);
|
|
2046
|
+
resolvedIds.push(entry.id);
|
|
2047
|
+
}
|
|
2048
|
+
if (codes) {
|
|
2049
|
+
for (const c of codes) {
|
|
2050
|
+
const entry = db2.standards.getByCode(c);
|
|
2051
|
+
if (!entry) throw new Error(`Coding standard not found: ${c}`);
|
|
2052
|
+
resolvedIds.push(entry.id);
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
if (resolvedIds.length === 0) {
|
|
2056
|
+
throw new Error("Either 'id', 'ids', 'code', or 'codes' must be provided for deletion");
|
|
2057
|
+
}
|
|
2058
|
+
const targetIds = resolvedIds;
|
|
2342
2059
|
let deletedCount = 0;
|
|
2343
2060
|
const deletedTitles = [];
|
|
2344
2061
|
let lastRepo = repo || "unknown";
|
|
@@ -2387,7 +2104,7 @@ async function handleTaskGet(args, storage) {
|
|
|
2387
2104
|
if (!task) {
|
|
2388
2105
|
throw new Error(`Task not found: ${id || task_code} in repo ${repo}`);
|
|
2389
2106
|
}
|
|
2390
|
-
const comments = storage.
|
|
2107
|
+
const comments = storage.taskComments.getTaskCommentsByTaskId(task.id);
|
|
2391
2108
|
let contentSummary;
|
|
2392
2109
|
if (!isStructuredRequest) {
|
|
2393
2110
|
const lines = [
|
|
@@ -2424,6 +2141,62 @@ async function handleTaskGet(args, storage) {
|
|
|
2424
2141
|
});
|
|
2425
2142
|
}
|
|
2426
2143
|
|
|
2144
|
+
// src/mcp/tools/task.search.ts
|
|
2145
|
+
async function handleTaskSearch(args, storage) {
|
|
2146
|
+
const validated = TaskSearchSchema.parse(args);
|
|
2147
|
+
const { repo, query, status, limit, offset, structured: isStructuredRequest = false, phase, priority } = validated;
|
|
2148
|
+
let tasks;
|
|
2149
|
+
if (status) {
|
|
2150
|
+
const statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2151
|
+
if (statuses.length > 1) {
|
|
2152
|
+
tasks = storage.tasks.getTasksByMultipleStatuses(repo, statuses, void 0, void 0, query);
|
|
2153
|
+
} else {
|
|
2154
|
+
tasks = storage.tasks.getTasksByRepo(repo, status, void 0, void 0, query);
|
|
2155
|
+
}
|
|
2156
|
+
} else {
|
|
2157
|
+
tasks = storage.tasks.getTasksByRepo(repo, void 0, void 0, void 0, query);
|
|
2158
|
+
}
|
|
2159
|
+
if (phase) {
|
|
2160
|
+
const phaseLower = phase.toLowerCase();
|
|
2161
|
+
tasks = tasks.filter((t) => t.phase && t.phase.toLowerCase() === phaseLower);
|
|
2162
|
+
}
|
|
2163
|
+
if (priority !== void 0) {
|
|
2164
|
+
tasks = tasks.filter((t) => t.priority === priority);
|
|
2165
|
+
}
|
|
2166
|
+
const total = tasks.length;
|
|
2167
|
+
const paginated = tasks.slice(offset, offset + limit);
|
|
2168
|
+
const COLUMNS = ["id", "task_code", "title", "status", "priority", "updated_at", "phase"];
|
|
2169
|
+
const rows = paginated.map((t) => [t.id, t.task_code, t.title, t.status, t.priority, t.updated_at, t.phase]);
|
|
2170
|
+
const structuredData = {
|
|
2171
|
+
schema: "task-search",
|
|
2172
|
+
query,
|
|
2173
|
+
count: paginated.length,
|
|
2174
|
+
total,
|
|
2175
|
+
offset,
|
|
2176
|
+
limit,
|
|
2177
|
+
results: {
|
|
2178
|
+
columns: [...COLUMNS],
|
|
2179
|
+
rows
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
let contentSummary;
|
|
2183
|
+
if (!isStructuredRequest) {
|
|
2184
|
+
contentSummary = paginated.length > 0 ? `Found ${total} tasks matching "${query}" in repo "${repo}". Use task-detail to fetch full task content.` : `No tasks found for "${query}" in repo "${repo}".`;
|
|
2185
|
+
}
|
|
2186
|
+
logger.info("[Tool] task.search", {
|
|
2187
|
+
repo,
|
|
2188
|
+
query,
|
|
2189
|
+
total,
|
|
2190
|
+
offset,
|
|
2191
|
+
returned: paginated.length
|
|
2192
|
+
});
|
|
2193
|
+
return createMcpResponse(structuredData, contentSummary || `Found ${total} tasks for "${query}".`, {
|
|
2194
|
+
contentSummary,
|
|
2195
|
+
structuredContentPathHint: "results",
|
|
2196
|
+
includeSerializedStructuredContent: isStructuredRequest
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2427
2200
|
// src/mcp/router.ts
|
|
2428
2201
|
function createRouter(db2, vectors2, options) {
|
|
2429
2202
|
const getSessionContext = options?.getSessionContext;
|
|
@@ -2575,6 +2348,8 @@ function createRouter(db2, vectors2, options) {
|
|
|
2575
2348
|
return await handleTaskDelete(args, db2);
|
|
2576
2349
|
case "task-list":
|
|
2577
2350
|
return await handleTaskList(args, db2);
|
|
2351
|
+
case "task-search":
|
|
2352
|
+
return await handleTaskSearch(args, db2);
|
|
2578
2353
|
case "task-detail":
|
|
2579
2354
|
return await handleTaskGet(args, db2);
|
|
2580
2355
|
default:
|
|
@@ -2749,8 +2524,8 @@ logger.info("[Server] startup", { pid: process.pid, version: CAPABILITIES.server
|
|
|
2749
2524
|
vectors.initialize().catch((err) => {
|
|
2750
2525
|
logger.warn("[Server] Initial vector model loading failed. Will retry on first use.", { error: String(err) });
|
|
2751
2526
|
});
|
|
2752
|
-
var expiredArchived = db.
|
|
2753
|
-
var lowScoreArchived = db.
|
|
2527
|
+
var expiredArchived = db.memoryArchives.archiveExpiredMemories();
|
|
2528
|
+
var lowScoreArchived = db.memoryArchives.archiveLowScoreMemories();
|
|
2754
2529
|
var totalArchived = (expiredArchived || 0) + (lowScoreArchived || 0);
|
|
2755
2530
|
if (totalArchived > 0) {
|
|
2756
2531
|
logger.info(
|
|
@@ -2771,9 +2546,7 @@ var logNotificationsEnabled = false;
|
|
|
2771
2546
|
var handleMethod = createRouter(db, vectors, {
|
|
2772
2547
|
getSessionContext: () => session,
|
|
2773
2548
|
sampleMessage: (params) => requestClient("sampling/createMessage", params),
|
|
2774
|
-
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
2775
2549
|
elicit: (params) => requestClient("elicitation/create", params),
|
|
2776
|
-
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
2777
2550
|
onResourcesMutated: (uris) => notifyUpdatedResources(uris)
|
|
2778
2551
|
});
|
|
2779
2552
|
addLogSink((payload) => {
|