@vheins/local-memory-mcp 0.16.3 → 0.17.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/dist/{chunk-MSP4MIT7.js → chunk-SITVJ6EA.js} +396 -181
- package/dist/dashboard/server.js +61 -35
- package/dist/mcp/server.js +104 -60
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
toContextSlug,
|
|
61
61
|
updateSessionFromInitialize,
|
|
62
62
|
updateSessionRoots
|
|
63
|
-
} from "../chunk-
|
|
63
|
+
} from "../chunk-SITVJ6EA.js";
|
|
64
64
|
|
|
65
65
|
// src/mcp/server.ts
|
|
66
66
|
import readline from "readline";
|
|
@@ -133,7 +133,7 @@ function getSuggestedRepos(db2, session2) {
|
|
|
133
133
|
}
|
|
134
134
|
function getSuggestedTags(db2) {
|
|
135
135
|
const values = /* @__PURE__ */ new Set();
|
|
136
|
-
const memories = db2.memories.getRecentMemories("", 1e3);
|
|
136
|
+
const memories = db2.memories.getRecentMemories("", "", 1e3);
|
|
137
137
|
for (const memory of memories) {
|
|
138
138
|
for (const tag of memory.tags || []) {
|
|
139
139
|
if (typeof tag === "string" && tag.trim()) {
|
|
@@ -146,7 +146,7 @@ function getSuggestedTags(db2) {
|
|
|
146
146
|
function getSuggestedTasks(db2, session2, contextArguments) {
|
|
147
147
|
const repo = typeof contextArguments.repo === "string" && contextArguments.repo.trim() ? contextArguments.repo.trim() : inferRepoFromSession(session2);
|
|
148
148
|
if (!repo) return [];
|
|
149
|
-
return db2.tasks.getTasksByRepo(repo, void 0, 100).map((task) => ({
|
|
149
|
+
return db2.tasks.getTasksByRepo("", repo, void 0, 100).map((task) => ({
|
|
150
150
|
id: task.id,
|
|
151
151
|
task_code: task.task_code,
|
|
152
152
|
title: task.title
|
|
@@ -196,7 +196,7 @@ var ENTITY_CONFIG = {
|
|
|
196
196
|
memory: { prefix: "MEM", table: "memories", column: "code" },
|
|
197
197
|
standard: { prefix: "STD", table: "coding_standards", column: "code" }
|
|
198
198
|
};
|
|
199
|
-
function generateNextCode(repo, entityType, storage, batchCodes) {
|
|
199
|
+
function generateNextCode(owner, repo, entityType, storage, batchCodes) {
|
|
200
200
|
const config = ENTITY_CONFIG[entityType];
|
|
201
201
|
const pattern = `${config.prefix}-%`;
|
|
202
202
|
const offset = config.prefix.length + 2;
|
|
@@ -204,9 +204,9 @@ function generateNextCode(repo, entityType, storage, batchCodes) {
|
|
|
204
204
|
`
|
|
205
205
|
SELECT MAX(CAST(SUBSTR(${config.column}, ?) AS INTEGER)) as max_seq
|
|
206
206
|
FROM ${config.table}
|
|
207
|
-
WHERE repo = ? AND ${config.column} LIKE ?
|
|
207
|
+
WHERE owner = ? AND repo = ? AND ${config.column} LIKE ?
|
|
208
208
|
`
|
|
209
|
-
).get(offset, repo, pattern);
|
|
209
|
+
).get(offset, owner, repo, pattern);
|
|
210
210
|
let nextSeq = (row?.max_seq ?? 0) + 1;
|
|
211
211
|
if (batchCodes) {
|
|
212
212
|
for (const code of batchCodes) {
|
|
@@ -247,6 +247,7 @@ async function storeSingleMemory(params, db2, vectors2) {
|
|
|
247
247
|
if (!resolvedSupersedes && params.type !== "task_archive") {
|
|
248
248
|
const conflict = await db2.memoryVectors.checkConflicts(
|
|
249
249
|
params.content,
|
|
250
|
+
params.scope.owner,
|
|
250
251
|
params.scope.repo,
|
|
251
252
|
params.type,
|
|
252
253
|
vectors2,
|
|
@@ -277,7 +278,7 @@ async function storeSingleMemory(params, db2, vectors2) {
|
|
|
277
278
|
}
|
|
278
279
|
const entry = {
|
|
279
280
|
id: randomUUID(),
|
|
280
|
-
code: params.code || generateNextCode(params.scope.repo, "memory", db2),
|
|
281
|
+
code: params.code || generateNextCode(params.scope.owner ?? "", params.scope.repo, "memory", db2),
|
|
281
282
|
type: params.type,
|
|
282
283
|
title: params.title,
|
|
283
284
|
content: params.content,
|
|
@@ -285,7 +286,7 @@ async function storeSingleMemory(params, db2, vectors2) {
|
|
|
285
286
|
agent: params.agent,
|
|
286
287
|
role: params.role,
|
|
287
288
|
model: params.model,
|
|
288
|
-
scope: params.scope,
|
|
289
|
+
scope: { ...params.scope, owner: params.scope.owner },
|
|
289
290
|
created_at: now,
|
|
290
291
|
updated_at: now,
|
|
291
292
|
completed_at: null,
|
|
@@ -339,7 +340,14 @@ async function handleMemoryStore(params, db2, vectors2) {
|
|
|
339
340
|
const expires_at = mem.ttlDays != null ? new Date(createdAtTime + mem.ttlDays * 864e5).toISOString() : null;
|
|
340
341
|
const resolvedSupersedes = resolveMemorySupersedes(mem.supersedes, db2);
|
|
341
342
|
if (!resolvedSupersedes && mem.type !== "task_archive") {
|
|
342
|
-
const conflict = await db2.memoryVectors.checkConflicts(
|
|
343
|
+
const conflict = await db2.memoryVectors.checkConflicts(
|
|
344
|
+
mem.content,
|
|
345
|
+
mem.scope.owner,
|
|
346
|
+
mem.scope.repo,
|
|
347
|
+
mem.type,
|
|
348
|
+
vectors2,
|
|
349
|
+
0.55
|
|
350
|
+
);
|
|
343
351
|
if (conflict) {
|
|
344
352
|
return createMcpResponse(
|
|
345
353
|
{
|
|
@@ -363,7 +371,7 @@ async function handleMemoryStore(params, db2, vectors2) {
|
|
|
363
371
|
if (mem.scope.language && !tags.includes(mem.scope.language.toLowerCase())) {
|
|
364
372
|
tags.push(mem.scope.language.toLowerCase());
|
|
365
373
|
}
|
|
366
|
-
const code = mem.code || generateNextCode(mem.scope.repo, "memory", db2, batchCodes);
|
|
374
|
+
const code = mem.code || generateNextCode(mem.scope.owner ?? "", mem.scope.repo, "memory", db2, batchCodes);
|
|
367
375
|
batchCodes.add(code);
|
|
368
376
|
entries.push({
|
|
369
377
|
id: randomUUID(),
|
|
@@ -375,7 +383,7 @@ async function handleMemoryStore(params, db2, vectors2) {
|
|
|
375
383
|
agent: mem.agent,
|
|
376
384
|
role: mem.role,
|
|
377
385
|
model: mem.model,
|
|
378
|
-
scope: mem.scope,
|
|
386
|
+
scope: { ...mem.scope, owner: mem.scope.owner },
|
|
379
387
|
created_at: now,
|
|
380
388
|
updated_at: now,
|
|
381
389
|
completed_at: null,
|
|
@@ -489,7 +497,7 @@ async function handleMemoryUpdate(params, db2, vectors2) {
|
|
|
489
497
|
if (validated.content !== void 0) {
|
|
490
498
|
await vectors2.upsert(resolvedId, validated.content);
|
|
491
499
|
}
|
|
492
|
-
db2.actions.logAction("update", existing.scope.repo, { memoryId: resolvedId, resultCount: 1 });
|
|
500
|
+
db2.actions.logAction("update", existing.scope.owner, existing.scope.repo, { memoryId: resolvedId, resultCount: 1 });
|
|
493
501
|
logger.info("[Tool] memory.update", { repo: existing.scope.repo, id: resolvedId, fields: Object.keys(updates) });
|
|
494
502
|
return createMcpResponse(
|
|
495
503
|
{
|
|
@@ -543,6 +551,7 @@ async function handleMemorySearch(params, db2, vectors2) {
|
|
|
543
551
|
const fetchLimit = (validated.offset + validated.limit) * 3;
|
|
544
552
|
const similarityResults = db2.memoryVectors.searchBySimilarity(
|
|
545
553
|
searchQuery,
|
|
554
|
+
validated.owner,
|
|
546
555
|
validated.repo,
|
|
547
556
|
fetchLimit,
|
|
548
557
|
validated.include_archived,
|
|
@@ -672,7 +681,7 @@ async function handleMemorySummarize(params, db2) {
|
|
|
672
681
|
const summary = validated.signals.join("\n- ");
|
|
673
682
|
const fullSummary = `Project summary:
|
|
674
683
|
- ${summary}`;
|
|
675
|
-
db2.summaries.upsertSummary(validated.repo, fullSummary);
|
|
684
|
+
db2.summaries.upsertSummary(validated.owner, validated.repo, fullSummary);
|
|
676
685
|
const content = `Updated summary for repo "${validated.repo}" with ${validated.signals.length} signals:
|
|
677
686
|
|
|
678
687
|
${fullSummary}`;
|
|
@@ -713,11 +722,16 @@ function extractAcceptedElicitationContent(result) {
|
|
|
713
722
|
async function handleMemoryRecap(params, db2) {
|
|
714
723
|
const validated = MemoryRecapSchema.parse(params);
|
|
715
724
|
logger.info("[Tool] memory.recap", { repo: validated.repo, limit: validated.limit, offset: validated.offset });
|
|
716
|
-
const stats = db2.memories.getStats(validated.repo);
|
|
717
|
-
const total = db2.memories.getTotalCount(validated.repo, false, ["task_archive"]);
|
|
718
|
-
const rows = db2.memories.getRecentMemories(
|
|
719
|
-
|
|
720
|
-
|
|
725
|
+
const stats = db2.memories.getStats(validated.owner, validated.repo);
|
|
726
|
+
const total = db2.memories.getTotalCount(validated.owner, validated.repo, false, ["task_archive"]);
|
|
727
|
+
const rows = db2.memories.getRecentMemories(
|
|
728
|
+
validated.owner,
|
|
729
|
+
validated.repo,
|
|
730
|
+
validated.limit,
|
|
731
|
+
validated.offset,
|
|
732
|
+
false,
|
|
733
|
+
["task_archive"]
|
|
734
|
+
);
|
|
721
735
|
const COLUMNS = ["id", "code", "title", "type", "importance"];
|
|
722
736
|
const topRows = rows.map((row) => [row.id, row.code || "-", row.title ?? "Untitled", row.type, row.importance]);
|
|
723
737
|
const byType = {};
|
|
@@ -782,19 +796,19 @@ function capitalize2(str) {
|
|
|
782
796
|
// src/mcp/tools/task.manage.ts
|
|
783
797
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
784
798
|
var UUID_REGEX3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
785
|
-
function resolveParentId(value, repo, storage, localCodeMap) {
|
|
799
|
+
function resolveParentId(value, owner, repo, storage, localCodeMap) {
|
|
786
800
|
if (!value) return null;
|
|
787
801
|
if (UUID_REGEX3.test(value)) return value;
|
|
788
802
|
if (localCodeMap?.has(value)) return localCodeMap.get(value);
|
|
789
|
-
const parent = storage.tasks.getTaskByCode(repo, value);
|
|
803
|
+
const parent = storage.tasks.getTaskByCode(owner, repo, value);
|
|
790
804
|
if (!parent) throw new Error(`parent_id: task with code '${value}' not found in repo '${repo}'`);
|
|
791
805
|
return parent.id;
|
|
792
806
|
}
|
|
793
|
-
function resolveDependsOn(value, repo, storage, localCodeMap) {
|
|
807
|
+
function resolveDependsOn(value, owner, repo, storage, localCodeMap) {
|
|
794
808
|
if (!value) return null;
|
|
795
809
|
if (UUID_REGEX3.test(value)) return value;
|
|
796
810
|
if (localCodeMap?.has(value)) return localCodeMap.get(value);
|
|
797
|
-
const task = storage.tasks.getTaskByCode(repo, value);
|
|
811
|
+
const task = storage.tasks.getTaskByCode(owner, repo, value);
|
|
798
812
|
if (!task) throw new Error(`depends_on: task with code '${value}' not found in repo '${repo}'`);
|
|
799
813
|
return task.id;
|
|
800
814
|
}
|
|
@@ -911,7 +925,7 @@ Comments & History:
|
|
|
911
925
|
agent: task.agent || "system",
|
|
912
926
|
role: task.role || "unknown",
|
|
913
927
|
model: "system",
|
|
914
|
-
scope: { repo },
|
|
928
|
+
scope: { repo, owner: task.owner || "" },
|
|
915
929
|
tags: ["task-archive", ...task.tags],
|
|
916
930
|
metadata
|
|
917
931
|
},
|
|
@@ -925,6 +939,7 @@ Comments & History:
|
|
|
925
939
|
async function handleTaskList(args, storage) {
|
|
926
940
|
const validated = TaskListSchema.parse(args);
|
|
927
941
|
const {
|
|
942
|
+
owner,
|
|
928
943
|
repo,
|
|
929
944
|
status = "backlog,pending,in_progress,blocked",
|
|
930
945
|
phase,
|
|
@@ -937,7 +952,7 @@ async function handleTaskList(args, storage) {
|
|
|
937
952
|
if (status !== "all") {
|
|
938
953
|
statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
|
|
939
954
|
}
|
|
940
|
-
const tasks = storage.tasks.getTasksByMultipleStatuses(repo, statuses, limit, offset, query);
|
|
955
|
+
const tasks = storage.tasks.getTasksByMultipleStatuses(owner, repo, statuses, limit, offset, query);
|
|
941
956
|
const filteredTasks = phase ? tasks.filter((t) => t.phase.toLowerCase() === phase.toLowerCase()) : tasks;
|
|
942
957
|
const COLUMNS = ["id", "task_code", "title", "status", "priority", "updated_at", "comments_count"];
|
|
943
958
|
const rows = filteredTasks.map((t) => [
|
|
@@ -977,7 +992,7 @@ async function handleTaskList(args, storage) {
|
|
|
977
992
|
}
|
|
978
993
|
async function handleTaskCreate(args, storage) {
|
|
979
994
|
const parsed = TaskCreateSchema.parse(args);
|
|
980
|
-
const { repo, tasks: bulkTasks, ...singleTask } = parsed;
|
|
995
|
+
const { owner, repo, tasks: bulkTasks, ...singleTask } = parsed;
|
|
981
996
|
if (bulkTasks) {
|
|
982
997
|
const createdTasks = [];
|
|
983
998
|
const tasksToInsert = [];
|
|
@@ -986,13 +1001,13 @@ async function handleTaskCreate(args, storage) {
|
|
|
986
1001
|
const batchCodes = /* @__PURE__ */ new Set();
|
|
987
1002
|
for (const taskData of bulkTasks) {
|
|
988
1003
|
if (!taskData.task_code) {
|
|
989
|
-
taskData.task_code = generateNextCode(repo, "task", storage, batchCodes);
|
|
1004
|
+
taskData.task_code = generateNextCode(owner ?? "", repo, "task", storage, batchCodes);
|
|
990
1005
|
}
|
|
991
1006
|
batchCodes.add(taskData.task_code);
|
|
992
1007
|
}
|
|
993
1008
|
const allCodes = bulkTasks.map((t) => t.task_code);
|
|
994
|
-
const existingCodes = storage.tasks.getExistingTaskCodes(repo, allCodes);
|
|
995
|
-
const initialStats = storage.taskStats.getTaskStats(repo);
|
|
1009
|
+
const existingCodes = storage.tasks.getExistingTaskCodes(owner, repo, allCodes);
|
|
1010
|
+
const initialStats = storage.taskStats.getTaskStats(owner, repo);
|
|
996
1011
|
let pendingInRequestCount = 0;
|
|
997
1012
|
const localCodeMap = /* @__PURE__ */ new Map();
|
|
998
1013
|
for (const taskData of bulkTasks) {
|
|
@@ -1027,6 +1042,7 @@ async function handleTaskCreate(args, storage) {
|
|
|
1027
1042
|
const taskId2 = localCodeMap.get(code);
|
|
1028
1043
|
const task2 = {
|
|
1029
1044
|
id: taskId2,
|
|
1045
|
+
owner,
|
|
1030
1046
|
repo,
|
|
1031
1047
|
task_code: code,
|
|
1032
1048
|
phase: taskData.phase,
|
|
@@ -1048,8 +1064,8 @@ async function handleTaskCreate(args, storage) {
|
|
|
1048
1064
|
commit_id: null,
|
|
1049
1065
|
changed_files: [],
|
|
1050
1066
|
metadata: taskData.metadata || {},
|
|
1051
|
-
parent_id: resolveParentId(taskData.parent_id, repo, storage, localCodeMap),
|
|
1052
|
-
depends_on: resolveDependsOn(taskData.depends_on, repo, storage, localCodeMap)
|
|
1067
|
+
parent_id: resolveParentId(taskData.parent_id, owner, repo, storage, localCodeMap),
|
|
1068
|
+
depends_on: resolveDependsOn(taskData.depends_on, owner, repo, storage, localCodeMap)
|
|
1053
1069
|
};
|
|
1054
1070
|
tasksToInsert.push(task2);
|
|
1055
1071
|
createdTasks.push(code);
|
|
@@ -1083,15 +1099,15 @@ async function handleTaskCreate(args, storage) {
|
|
|
1083
1099
|
if (!phase || !title || !description) {
|
|
1084
1100
|
throw new Error("Missing required fields for single task creation (phase, title, description)");
|
|
1085
1101
|
}
|
|
1086
|
-
const resolvedCode = task_code || generateNextCode(repo, "task", storage);
|
|
1087
|
-
if (storage.tasks.isTaskCodeDuplicate(repo, resolvedCode)) {
|
|
1102
|
+
const resolvedCode = task_code || generateNextCode(owner ?? "", repo, "task", storage);
|
|
1103
|
+
if (storage.tasks.isTaskCodeDuplicate(owner, repo, resolvedCode)) {
|
|
1088
1104
|
throw new Error(`Duplicate task_code: '${resolvedCode}' already exists in repository '${repo}'`);
|
|
1089
1105
|
}
|
|
1090
1106
|
if (status !== "backlog" && status !== "pending" && status !== void 0) {
|
|
1091
1107
|
throw new Error("New tasks must be created with status 'backlog' or 'pending'.");
|
|
1092
1108
|
}
|
|
1093
1109
|
if (status === "pending") {
|
|
1094
|
-
const stats = storage.taskStats.getTaskStats(repo);
|
|
1110
|
+
const stats = storage.taskStats.getTaskStats(owner, repo);
|
|
1095
1111
|
if (stats.todo >= 10) {
|
|
1096
1112
|
throw new Error(
|
|
1097
1113
|
`Cannot create task as 'pending'. Maximum of 10 pending tasks reached. Please use status 'backlog' for new tasks instead.`
|
|
@@ -1108,6 +1124,7 @@ async function handleTaskCreate(args, storage) {
|
|
|
1108
1124
|
}
|
|
1109
1125
|
const task = {
|
|
1110
1126
|
id: taskId,
|
|
1127
|
+
owner,
|
|
1111
1128
|
repo,
|
|
1112
1129
|
task_code: resolvedCode,
|
|
1113
1130
|
phase,
|
|
@@ -1129,8 +1146,8 @@ async function handleTaskCreate(args, storage) {
|
|
|
1129
1146
|
commit_id: null,
|
|
1130
1147
|
changed_files: [],
|
|
1131
1148
|
metadata: metadata || {},
|
|
1132
|
-
parent_id: resolveParentId(parent_id, repo, storage),
|
|
1133
|
-
depends_on: resolveDependsOn(depends_on, repo, storage)
|
|
1149
|
+
parent_id: resolveParentId(parent_id, owner, repo, storage),
|
|
1150
|
+
depends_on: resolveDependsOn(depends_on, owner, repo, storage)
|
|
1134
1151
|
};
|
|
1135
1152
|
storage.tasks.insertTask(task);
|
|
1136
1153
|
return createMcpResponse(
|
|
@@ -1245,10 +1262,10 @@ function addRequiredStringField(properties, required, task, field, schema) {
|
|
|
1245
1262
|
}
|
|
1246
1263
|
async function handleTaskUpdate(args, storage, vectors2) {
|
|
1247
1264
|
const updateData = TaskUpdateSchema.parse(args);
|
|
1248
|
-
const { repo, id, ids, comment, force, ...updates } = updateData;
|
|
1265
|
+
const { owner, repo, id, ids, comment, force, ...updates } = updateData;
|
|
1249
1266
|
let resolvedId = id;
|
|
1250
1267
|
if (!resolvedId && !ids && updates.task_code) {
|
|
1251
|
-
const found = storage.tasks.getTaskByCode(repo, updates.task_code);
|
|
1268
|
+
const found = storage.tasks.getTaskByCode(owner, repo, updates.task_code);
|
|
1252
1269
|
if (!found) throw new Error(`Task not found: ${updates.task_code}`);
|
|
1253
1270
|
resolvedId = found.id;
|
|
1254
1271
|
}
|
|
@@ -1293,10 +1310,10 @@ async function handleTaskUpdate(args, storage, vectors2) {
|
|
|
1293
1310
|
}
|
|
1294
1311
|
const finalUpdates = { ...updates };
|
|
1295
1312
|
if (updates.parent_id !== void 0) {
|
|
1296
|
-
finalUpdates.parent_id = resolveParentId(updates.parent_id, repo, storage);
|
|
1313
|
+
finalUpdates.parent_id = resolveParentId(updates.parent_id, owner, repo, storage);
|
|
1297
1314
|
}
|
|
1298
1315
|
if (updates.depends_on !== void 0) {
|
|
1299
|
-
finalUpdates.depends_on = resolveDependsOn(updates.depends_on, repo, storage);
|
|
1316
|
+
finalUpdates.depends_on = resolveDependsOn(updates.depends_on, owner, repo, storage);
|
|
1300
1317
|
}
|
|
1301
1318
|
if (updates.phase !== void 0 || updates.tags !== void 0) {
|
|
1302
1319
|
let currentTags = updates.tags || existingTask.tags || [];
|
|
@@ -1322,6 +1339,7 @@ async function handleTaskUpdate(args, storage, vectors2) {
|
|
|
1322
1339
|
storage.taskComments.insertTaskComment({
|
|
1323
1340
|
id: randomUUID2(),
|
|
1324
1341
|
task_id: targetId,
|
|
1342
|
+
owner,
|
|
1325
1343
|
repo,
|
|
1326
1344
|
comment: comment || `Status updated to ${updates.status}`,
|
|
1327
1345
|
agent: updates.agent || existingTask.agent || "unknown",
|
|
@@ -1382,12 +1400,12 @@ async function handleTaskUpdate(args, storage, vectors2) {
|
|
|
1382
1400
|
}
|
|
1383
1401
|
async function handleTaskDelete(args, storage) {
|
|
1384
1402
|
const validated = TaskDeleteSchema.parse(args);
|
|
1385
|
-
const { repo, id, ids, task_code } = validated;
|
|
1403
|
+
const { owner, repo, id, ids, task_code } = validated;
|
|
1386
1404
|
const resolvedIds = [];
|
|
1387
1405
|
if (ids) resolvedIds.push(...ids);
|
|
1388
1406
|
if (id) resolvedIds.push(id);
|
|
1389
1407
|
if (task_code) {
|
|
1390
|
-
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
1408
|
+
const task = storage.tasks.getTaskByCode(owner, repo, task_code);
|
|
1391
1409
|
if (!task) throw new Error(`Task not found: ${task_code}`);
|
|
1392
1410
|
resolvedIds.push(task.id);
|
|
1393
1411
|
}
|
|
@@ -1426,10 +1444,14 @@ async function handleMemorySynthesize(params, db2, vectors2, options = {}) {
|
|
|
1426
1444
|
if (!repo) {
|
|
1427
1445
|
throw new Error("repo is required when repo cannot be inferred from active MCP roots");
|
|
1428
1446
|
}
|
|
1429
|
-
const
|
|
1447
|
+
const repoOwner = validated.owner;
|
|
1448
|
+
const recap = await handleMemoryRecap({ owner: repoOwner, repo, limit: 8, offset: 0 }, db2);
|
|
1430
1449
|
const recapText = getPrimaryTextContent(recap);
|
|
1431
|
-
const summary = validated.include_summary ? db2.summaries.getSummary(repo)?.summary : "";
|
|
1432
|
-
const taskSnapshot = validated.include_tasks ? await handleTaskList(
|
|
1450
|
+
const summary = validated.include_summary ? db2.summaries.getSummary(repoOwner, repo)?.summary : "";
|
|
1451
|
+
const taskSnapshot = validated.include_tasks ? await handleTaskList(
|
|
1452
|
+
{ owner: repoOwner, repo, status: "backlog,pending,in_progress,blocked", limit: 15, offset: 0 },
|
|
1453
|
+
db2
|
|
1454
|
+
) : null;
|
|
1433
1455
|
const taskText = taskSnapshot ? getPrimaryTextContent(taskSnapshot) : "";
|
|
1434
1456
|
const systemPrompt = [
|
|
1435
1457
|
"You are a repository memory synthesizer.",
|
|
@@ -1493,7 +1515,7 @@ ${contextBlock || "No additional context provided."}`
|
|
|
1493
1515
|
content: [
|
|
1494
1516
|
{
|
|
1495
1517
|
type: "text",
|
|
1496
|
-
text: await executeSamplingTool(toolUse.name, toolUse.input, db2, vectors2)
|
|
1518
|
+
text: await executeSamplingTool(toolUse.name, toolUse.input, db2, vectors2, repoOwner)
|
|
1497
1519
|
}
|
|
1498
1520
|
]
|
|
1499
1521
|
}))
|
|
@@ -1603,11 +1625,12 @@ function buildSamplingTools(session2, useTools) {
|
|
|
1603
1625
|
}
|
|
1604
1626
|
];
|
|
1605
1627
|
}
|
|
1606
|
-
async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
|
|
1628
|
+
async function executeSamplingTool(toolName, rawInput, db2, vectors2, owner) {
|
|
1607
1629
|
switch (toolName) {
|
|
1608
1630
|
case "memory_search": {
|
|
1609
1631
|
const response = await handleMemorySearch(
|
|
1610
1632
|
{
|
|
1633
|
+
owner,
|
|
1611
1634
|
repo: rawInput.repo,
|
|
1612
1635
|
query: rawInput.query,
|
|
1613
1636
|
limit: rawInput.limit ?? 5
|
|
@@ -1620,6 +1643,7 @@ async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
|
|
|
1620
1643
|
case "memory_recap": {
|
|
1621
1644
|
const response = await handleMemoryRecap(
|
|
1622
1645
|
{
|
|
1646
|
+
owner,
|
|
1623
1647
|
repo: rawInput.repo,
|
|
1624
1648
|
limit: rawInput.limit ?? 8,
|
|
1625
1649
|
offset: 0
|
|
@@ -1631,6 +1655,7 @@ async function executeSamplingTool(toolName, rawInput, db2, vectors2) {
|
|
|
1631
1655
|
case "task_list": {
|
|
1632
1656
|
const response = await handleTaskList(
|
|
1633
1657
|
{
|
|
1658
|
+
owner,
|
|
1634
1659
|
repo: rawInput.repo,
|
|
1635
1660
|
status: rawInput.status,
|
|
1636
1661
|
search: rawInput.search,
|
|
@@ -1810,7 +1835,8 @@ async function storeSingleStandard(params, db2, vectors2) {
|
|
|
1810
1835
|
const conflict = db2.standards.checkConflicts(
|
|
1811
1836
|
params.content,
|
|
1812
1837
|
incomingVersion,
|
|
1813
|
-
params.
|
|
1838
|
+
params.owner,
|
|
1839
|
+
params.repo ?? void 0,
|
|
1814
1840
|
incomingLanguage,
|
|
1815
1841
|
incomingStack,
|
|
1816
1842
|
0.82
|
|
@@ -1837,7 +1863,7 @@ async function storeSingleStandard(params, db2, vectors2) {
|
|
|
1837
1863
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1838
1864
|
const entry = {
|
|
1839
1865
|
id: randomUUID3(),
|
|
1840
|
-
code: generateNextCode(params.repo || "__global__", "standard", db2),
|
|
1866
|
+
code: generateNextCode(params.owner, params.repo || "__global__", "standard", db2),
|
|
1841
1867
|
title: params.name,
|
|
1842
1868
|
content: params.content,
|
|
1843
1869
|
parent_id: resolveStandardParentId(params.parent_id, db2),
|
|
@@ -1846,6 +1872,7 @@ async function storeSingleStandard(params, db2, vectors2) {
|
|
|
1846
1872
|
language: params.language || null,
|
|
1847
1873
|
stack: params.stack || [],
|
|
1848
1874
|
is_global: params.is_global !== false,
|
|
1875
|
+
owner: params.owner,
|
|
1849
1876
|
repo: params.repo || null,
|
|
1850
1877
|
tags: params.tags || [],
|
|
1851
1878
|
metadata: params.metadata,
|
|
@@ -1889,7 +1916,8 @@ async function handleStandardStore(params, db2, vectors2) {
|
|
|
1889
1916
|
const conflict = db2.standards.checkConflicts(
|
|
1890
1917
|
std.content,
|
|
1891
1918
|
incomingVersion,
|
|
1892
|
-
|
|
1919
|
+
validated.owner,
|
|
1920
|
+
validated.repo,
|
|
1893
1921
|
incomingLanguage,
|
|
1894
1922
|
incomingStack,
|
|
1895
1923
|
0.82
|
|
@@ -1914,7 +1942,7 @@ async function handleStandardStore(params, db2, vectors2) {
|
|
|
1914
1942
|
);
|
|
1915
1943
|
}
|
|
1916
1944
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1917
|
-
const code = generateNextCode(standardRepo, "standard", db2, batchCodes);
|
|
1945
|
+
const code = generateNextCode(validated.owner ?? "", standardRepo, "standard", db2, batchCodes);
|
|
1918
1946
|
batchCodes.add(code);
|
|
1919
1947
|
entries.push({
|
|
1920
1948
|
id: randomUUID3(),
|
|
@@ -1927,6 +1955,7 @@ async function handleStandardStore(params, db2, vectors2) {
|
|
|
1927
1955
|
language: std.language || null,
|
|
1928
1956
|
stack: std.stack || [],
|
|
1929
1957
|
is_global: std.is_global !== false,
|
|
1958
|
+
owner: validated.owner,
|
|
1930
1959
|
repo: null,
|
|
1931
1960
|
tags: std.tags || [],
|
|
1932
1961
|
metadata: std.metadata,
|
|
@@ -1963,6 +1992,7 @@ async function handleStandardStore(params, db2, vectors2) {
|
|
|
1963
1992
|
version: validated.version,
|
|
1964
1993
|
language: validated.language,
|
|
1965
1994
|
stack: validated.stack,
|
|
1995
|
+
owner: validated.owner,
|
|
1966
1996
|
repo: validated.repo,
|
|
1967
1997
|
is_global: validated.is_global,
|
|
1968
1998
|
tags: validated.tags,
|
|
@@ -2357,12 +2387,12 @@ async function handleStandardDelete(params, db2, vectors2) {
|
|
|
2357
2387
|
// src/mcp/tools/task.get.ts
|
|
2358
2388
|
async function handleTaskGet(args, storage) {
|
|
2359
2389
|
const validated = TaskGetSchema.parse(args);
|
|
2360
|
-
const { repo, id, task_code, structured: isStructuredRequest } = validated;
|
|
2390
|
+
const { owner, repo, id, task_code, structured: isStructuredRequest } = validated;
|
|
2361
2391
|
let task;
|
|
2362
2392
|
if (id) {
|
|
2363
2393
|
task = storage.tasks.getTaskById(id);
|
|
2364
2394
|
} else if (task_code) {
|
|
2365
|
-
task = storage.tasks.getTaskByCode(repo, task_code);
|
|
2395
|
+
task = storage.tasks.getTaskByCode(owner, repo, task_code);
|
|
2366
2396
|
} else {
|
|
2367
2397
|
throw new Error("Either id or task_code must be provided");
|
|
2368
2398
|
}
|
|
@@ -2398,10 +2428,14 @@ async function handleTaskGet(args, storage) {
|
|
|
2398
2428
|
if (task.comments_count !== void 0) lines.push(`Comments: ${task.comments_count}`);
|
|
2399
2429
|
if (task.coordination) {
|
|
2400
2430
|
if (task.coordination.active_claim_count > 0) {
|
|
2401
|
-
lines.push(
|
|
2431
|
+
lines.push(
|
|
2432
|
+
`Claim: ${task.coordination.active_claim_agent || "?"} (${task.coordination.active_claim_role || ""}) since ${task.coordination.active_claim_claimed_at || ""}`
|
|
2433
|
+
);
|
|
2402
2434
|
}
|
|
2403
2435
|
if (task.coordination.pending_handoff_count > 0) {
|
|
2404
|
-
lines.push(
|
|
2436
|
+
lines.push(
|
|
2437
|
+
`Handoff: ${task.coordination.pending_handoff_summary || ""} \u2192 ${task.coordination.pending_handoff_to_agent || "?"}`
|
|
2438
|
+
);
|
|
2405
2439
|
}
|
|
2406
2440
|
}
|
|
2407
2441
|
lines.push(`Created: ${task.created_at}`);
|
|
@@ -2446,17 +2480,27 @@ async function handleTaskGet(args, storage) {
|
|
|
2446
2480
|
// src/mcp/tools/task.search.ts
|
|
2447
2481
|
async function handleTaskSearch(args, storage) {
|
|
2448
2482
|
const validated = TaskSearchSchema.parse(args);
|
|
2449
|
-
const {
|
|
2483
|
+
const {
|
|
2484
|
+
owner,
|
|
2485
|
+
repo,
|
|
2486
|
+
query,
|
|
2487
|
+
status,
|
|
2488
|
+
limit,
|
|
2489
|
+
offset,
|
|
2490
|
+
structured: isStructuredRequest = false,
|
|
2491
|
+
phase,
|
|
2492
|
+
priority
|
|
2493
|
+
} = validated;
|
|
2450
2494
|
let tasks;
|
|
2451
2495
|
if (status) {
|
|
2452
2496
|
const statuses = status.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2453
2497
|
if (statuses.length > 1) {
|
|
2454
|
-
tasks = storage.tasks.getTasksByMultipleStatuses(repo, statuses, void 0, void 0, query);
|
|
2498
|
+
tasks = storage.tasks.getTasksByMultipleStatuses(owner, repo, statuses, void 0, void 0, query);
|
|
2455
2499
|
} else {
|
|
2456
|
-
tasks = storage.tasks.getTasksByRepo(repo, status, void 0, void 0, query);
|
|
2500
|
+
tasks = storage.tasks.getTasksByRepo(owner, repo, status, void 0, void 0, query);
|
|
2457
2501
|
}
|
|
2458
2502
|
} else {
|
|
2459
|
-
tasks = storage.tasks.getTasksByRepo(repo, void 0, void 0, void 0, query);
|
|
2503
|
+
tasks = storage.tasks.getTasksByRepo(owner, repo, void 0, void 0, void 0, query);
|
|
2460
2504
|
}
|
|
2461
2505
|
if (phase) {
|
|
2462
2506
|
const phaseLower = phase.toLowerCase();
|
|
@@ -2676,9 +2720,9 @@ function createRouter(db2, vectors2, options) {
|
|
|
2676
2720
|
resultCount: Array.isArray(sc?.results) ? sc.results.length : sc?.count || 0
|
|
2677
2721
|
};
|
|
2678
2722
|
if (isWrite) {
|
|
2679
|
-
db2.actions.logAction(actionType, repo, logOptions);
|
|
2723
|
+
db2.actions.logAction(actionType, "", repo, logOptions);
|
|
2680
2724
|
} else {
|
|
2681
|
-
await db2.withWrite(() => db2.actions.logAction(actionType, repo, logOptions));
|
|
2725
|
+
await db2.withWrite(() => db2.actions.logAction(actionType, "", repo, logOptions));
|
|
2682
2726
|
}
|
|
2683
2727
|
} catch (e) {
|
|
2684
2728
|
logger.error("Failed to log action", { toolName, error: String(e) });
|