@vheins/local-memory-mcp 0.13.2 → 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-O4B6AFYU.js → chunk-GXQCHTXK.js} +572 -61
- 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 +34 -15
- package/dist/mcp/server.js +102 -393
- 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
|
@@ -81,8 +81,8 @@ function loadServerInstructions() {
|
|
|
81
81
|
// src/mcp/capabilities.ts
|
|
82
82
|
var __dirname2 = path2.dirname(fileURLToPath2(import.meta.url));
|
|
83
83
|
var pkgVersion = "0.1.0";
|
|
84
|
-
if ("0.
|
|
85
|
-
pkgVersion = "0.
|
|
84
|
+
if ("0.14.0") {
|
|
85
|
+
pkgVersion = "0.14.0";
|
|
86
86
|
} else {
|
|
87
87
|
let searchDir = __dirname2;
|
|
88
88
|
for (let i = 0; i < 5; i++) {
|
|
@@ -1119,6 +1119,23 @@ var BaseEntity = class {
|
|
|
1119
1119
|
};
|
|
1120
1120
|
|
|
1121
1121
|
// src/mcp/entities/memory.ts
|
|
1122
|
+
var VALID_COLUMNS = /* @__PURE__ */ new Set([
|
|
1123
|
+
"code",
|
|
1124
|
+
"type",
|
|
1125
|
+
"title",
|
|
1126
|
+
"content",
|
|
1127
|
+
"importance",
|
|
1128
|
+
"agent",
|
|
1129
|
+
"role",
|
|
1130
|
+
"model",
|
|
1131
|
+
"completed_at",
|
|
1132
|
+
"expires_at",
|
|
1133
|
+
"supersedes",
|
|
1134
|
+
"status",
|
|
1135
|
+
"hit_count",
|
|
1136
|
+
"recall_count",
|
|
1137
|
+
"last_used_at"
|
|
1138
|
+
]);
|
|
1122
1139
|
var MemoryEntity = class extends BaseEntity {
|
|
1123
1140
|
insert(entry) {
|
|
1124
1141
|
this.run(
|
|
@@ -1179,7 +1196,7 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1179
1196
|
} else if (k === "is_global") {
|
|
1180
1197
|
fields.push(`${k} = ?`);
|
|
1181
1198
|
values.push(val ? 1 : 0);
|
|
1182
|
-
} else if (k
|
|
1199
|
+
} else if (VALID_COLUMNS.has(k)) {
|
|
1183
1200
|
fields.push(`${k} = ?`);
|
|
1184
1201
|
values.push(val);
|
|
1185
1202
|
}
|
|
@@ -1303,13 +1320,27 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1303
1320
|
Object.keys(updates).forEach((key) => {
|
|
1304
1321
|
const value = updates[key];
|
|
1305
1322
|
if (value !== void 0) {
|
|
1306
|
-
if (key === "
|
|
1323
|
+
if (key === "scope") {
|
|
1324
|
+
const scope = updates.scope;
|
|
1325
|
+
if (scope?.repo) {
|
|
1326
|
+
fields.push("repo = ?");
|
|
1327
|
+
values.push(scope.repo);
|
|
1328
|
+
}
|
|
1329
|
+
if (scope?.folder !== void 0) {
|
|
1330
|
+
fields.push("folder = ?");
|
|
1331
|
+
values.push(scope.folder);
|
|
1332
|
+
}
|
|
1333
|
+
if (scope?.language !== void 0) {
|
|
1334
|
+
fields.push("language = ?");
|
|
1335
|
+
values.push(scope.language);
|
|
1336
|
+
}
|
|
1337
|
+
} else if (key === "tags" || key === "metadata") {
|
|
1307
1338
|
fields.push(`${key} = ?`);
|
|
1308
1339
|
values.push(JSON.stringify(value));
|
|
1309
1340
|
} else if (key === "is_global") {
|
|
1310
1341
|
fields.push(`${key} = ?`);
|
|
1311
1342
|
values.push(value ? 1 : 0);
|
|
1312
|
-
} else {
|
|
1343
|
+
} else if (VALID_COLUMNS.has(key)) {
|
|
1313
1344
|
fields.push(`${key} = ?`);
|
|
1314
1345
|
values.push(value);
|
|
1315
1346
|
}
|
|
@@ -1332,19 +1363,6 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1332
1363
|
return count;
|
|
1333
1364
|
});
|
|
1334
1365
|
}
|
|
1335
|
-
bulkDeleteMemories(ids) {
|
|
1336
|
-
if (ids.length === 0) return 0;
|
|
1337
|
-
return this.transaction(() => {
|
|
1338
|
-
let count = 0;
|
|
1339
|
-
const chunkSize = 500;
|
|
1340
|
-
for (let i = 0; i < ids.length; i += chunkSize) {
|
|
1341
|
-
const chunk = ids.slice(i, i + chunkSize);
|
|
1342
|
-
const result = this.run(`DELETE FROM memories WHERE id IN (${chunk.map(() => "?").join(",")})`, chunk);
|
|
1343
|
-
count += result.changes;
|
|
1344
|
-
}
|
|
1345
|
-
return count;
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
1366
|
getRecentMemories(repo, limit, offset = 0, includeArchived = false, excludeTypes = [], sortOrder = "DESC") {
|
|
1349
1367
|
let query = "SELECT * FROM memories WHERE repo = ?";
|
|
1350
1368
|
const params = [repo];
|
|
@@ -1390,24 +1408,6 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1390
1408
|
id
|
|
1391
1409
|
]);
|
|
1392
1410
|
}
|
|
1393
|
-
getVectorCandidates(repo, limit = 100) {
|
|
1394
|
-
let sql = `SELECT mv.memory_id, mv.vector FROM memory_vectors mv JOIN memories m ON mv.memory_id = m.id`;
|
|
1395
|
-
const params = [];
|
|
1396
|
-
if (repo) {
|
|
1397
|
-
sql += " WHERE m.repo = ?";
|
|
1398
|
-
params.push(repo);
|
|
1399
|
-
}
|
|
1400
|
-
sql += " LIMIT ?";
|
|
1401
|
-
params.push(limit);
|
|
1402
|
-
return this.all(sql, params);
|
|
1403
|
-
}
|
|
1404
|
-
upsertVectorEmbedding(memoryId, vector) {
|
|
1405
|
-
this.run(
|
|
1406
|
-
`INSERT INTO memory_vectors (memory_id, vector, updated_at) VALUES (?, ?, ?)
|
|
1407
|
-
ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, updated_at = excluded.updated_at`,
|
|
1408
|
-
[memoryId, JSON.stringify(vector), (/* @__PURE__ */ new Date()).toISOString()]
|
|
1409
|
-
);
|
|
1410
|
-
}
|
|
1411
1411
|
getSummary(repo) {
|
|
1412
1412
|
const row = this.get(
|
|
1413
1413
|
"SELECT summary, updated_at FROM memory_summary WHERE repo = ?",
|
|
@@ -1487,6 +1487,28 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1487
1487
|
}));
|
|
1488
1488
|
return { items, memories: items, total, limit, offset };
|
|
1489
1489
|
}
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
// src/mcp/entities/memory.vector.ts
|
|
1493
|
+
var MemoryVectorEntity = class extends BaseEntity {
|
|
1494
|
+
getVectorCandidates(repo, limit = 100) {
|
|
1495
|
+
let sql = `SELECT mv.memory_id, mv.vector FROM memory_vectors mv JOIN memories m ON mv.memory_id = m.id`;
|
|
1496
|
+
const params = [];
|
|
1497
|
+
if (repo) {
|
|
1498
|
+
sql += " WHERE m.repo = ?";
|
|
1499
|
+
params.push(repo);
|
|
1500
|
+
}
|
|
1501
|
+
sql += " LIMIT ?";
|
|
1502
|
+
params.push(limit);
|
|
1503
|
+
return this.all(sql, params);
|
|
1504
|
+
}
|
|
1505
|
+
upsertVectorEmbedding(memoryId, vector) {
|
|
1506
|
+
this.run(
|
|
1507
|
+
`INSERT INTO memory_vectors (memory_id, vector, updated_at) VALUES (?, ?, ?)
|
|
1508
|
+
ON CONFLICT(memory_id) DO UPDATE SET vector = excluded.vector, updated_at = excluded.updated_at`,
|
|
1509
|
+
[memoryId, JSON.stringify(vector), (/* @__PURE__ */ new Date()).toISOString()]
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1490
1512
|
searchBySimilarity(query, repo, limit = 10, includeArchived = false, currentTags = []) {
|
|
1491
1513
|
const queryVector = this.computeVector(query);
|
|
1492
1514
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1504,8 +1526,12 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1504
1526
|
if (candidates.length < 5) {
|
|
1505
1527
|
const recentSql = `SELECT * FROM memories WHERE (${where.join(" OR ")}) AND status = 'active' AND (expires_at IS NULL OR expires_at > ?) ORDER BY created_at DESC LIMIT 10`;
|
|
1506
1528
|
const recent = this.all(recentSql, [...params, now.toISOString()]);
|
|
1529
|
+
const candidateIds = new Set(candidates.map((c) => c.id));
|
|
1507
1530
|
for (const r of recent) {
|
|
1508
|
-
if (!
|
|
1531
|
+
if (!candidateIds.has(r.id)) {
|
|
1532
|
+
candidateIds.add(r.id);
|
|
1533
|
+
candidates.push(r);
|
|
1534
|
+
}
|
|
1509
1535
|
}
|
|
1510
1536
|
}
|
|
1511
1537
|
return candidates.map((row) => {
|
|
@@ -1531,6 +1557,23 @@ var MemoryEntity = class extends BaseEntity {
|
|
|
1531
1557
|
}
|
|
1532
1558
|
return null;
|
|
1533
1559
|
}
|
|
1560
|
+
};
|
|
1561
|
+
|
|
1562
|
+
// src/mcp/entities/memory.archive.ts
|
|
1563
|
+
var MemoryArchiveEntity = class extends BaseEntity {
|
|
1564
|
+
bulkDeleteMemories(ids) {
|
|
1565
|
+
if (ids.length === 0) return 0;
|
|
1566
|
+
return this.transaction(() => {
|
|
1567
|
+
let count = 0;
|
|
1568
|
+
const chunkSize = 500;
|
|
1569
|
+
for (let i = 0; i < ids.length; i += chunkSize) {
|
|
1570
|
+
const chunk = ids.slice(i, i + chunkSize);
|
|
1571
|
+
const result = this.run(`DELETE FROM memories WHERE id IN (${chunk.map(() => "?").join(",")})`, chunk);
|
|
1572
|
+
count += result.changes;
|
|
1573
|
+
}
|
|
1574
|
+
return count;
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1534
1577
|
archiveExpiredMemories(force = false) {
|
|
1535
1578
|
if (process.env.ENABLE_AUTO_ARCHIVE !== "true" && !force) return 0;
|
|
1536
1579
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1606,7 +1649,7 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1606
1649
|
const fields = [];
|
|
1607
1650
|
const values = [];
|
|
1608
1651
|
const anyUpdates = updates;
|
|
1609
|
-
const
|
|
1652
|
+
const VALID_COLUMNS2 = /* @__PURE__ */ new Set([
|
|
1610
1653
|
"repo",
|
|
1611
1654
|
"task_code",
|
|
1612
1655
|
"phase",
|
|
@@ -1629,7 +1672,7 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1629
1672
|
"changed_files"
|
|
1630
1673
|
]);
|
|
1631
1674
|
Object.keys(updates).forEach((key) => {
|
|
1632
|
-
if (
|
|
1675
|
+
if (VALID_COLUMNS2.has(key) && anyUpdates[key] !== void 0) {
|
|
1633
1676
|
if (key === "tags" || key === "metadata" || key === "changed_files") {
|
|
1634
1677
|
fields.push(`${key} = ?`);
|
|
1635
1678
|
values.push(JSON.stringify(anyUpdates[key]));
|
|
@@ -1659,7 +1702,7 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1659
1702
|
WHERE t.id = ?`,
|
|
1660
1703
|
[id]
|
|
1661
1704
|
);
|
|
1662
|
-
return row ? { ...this.rowToTask(row), comments: this.
|
|
1705
|
+
return row ? { ...this.rowToTask(row), comments: this.all("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at DESC, id DESC", [id]) } : null;
|
|
1663
1706
|
}
|
|
1664
1707
|
getTasksByIds(ids) {
|
|
1665
1708
|
if (ids.length === 0) return [];
|
|
@@ -1700,7 +1743,7 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1700
1743
|
WHERE t.repo = ? AND t.task_code = ?`,
|
|
1701
1744
|
[repo, taskCode]
|
|
1702
1745
|
);
|
|
1703
|
-
return row ? { ...this.rowToTask(row), comments: this.
|
|
1746
|
+
return row ? { ...this.rowToTask(row), comments: this.all("SELECT * FROM task_comments WHERE task_id = ? ORDER BY created_at DESC, id DESC", [row.id]) } : null;
|
|
1704
1747
|
}
|
|
1705
1748
|
getTasksByRepo(repo, status, limit, offset, search) {
|
|
1706
1749
|
let query = `
|
|
@@ -1886,6 +1929,10 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1886
1929
|
return count;
|
|
1887
1930
|
});
|
|
1888
1931
|
}
|
|
1932
|
+
};
|
|
1933
|
+
|
|
1934
|
+
// src/mcp/entities/task-comment.ts
|
|
1935
|
+
var TaskCommentEntity = class extends BaseEntity {
|
|
1889
1936
|
insertTaskComment(comment) {
|
|
1890
1937
|
this.run(
|
|
1891
1938
|
`INSERT INTO task_comments (
|
|
@@ -1909,8 +1956,17 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1909
1956
|
const fields = [];
|
|
1910
1957
|
const values = [];
|
|
1911
1958
|
const anyUpdates = updates;
|
|
1959
|
+
const VALID_COLUMNS2 = /* @__PURE__ */ new Set([
|
|
1960
|
+
"repo",
|
|
1961
|
+
"comment",
|
|
1962
|
+
"agent",
|
|
1963
|
+
"role",
|
|
1964
|
+
"model",
|
|
1965
|
+
"previous_status",
|
|
1966
|
+
"next_status"
|
|
1967
|
+
]);
|
|
1912
1968
|
Object.keys(updates).forEach((key) => {
|
|
1913
|
-
if (anyUpdates[key] !== void 0) {
|
|
1969
|
+
if (VALID_COLUMNS2.has(key) && anyUpdates[key] !== void 0) {
|
|
1914
1970
|
fields.push(`${key} = ?`);
|
|
1915
1971
|
values.push(anyUpdates[key]);
|
|
1916
1972
|
}
|
|
@@ -1935,6 +1991,10 @@ var TaskEntity = class extends BaseEntity {
|
|
|
1935
1991
|
repo
|
|
1936
1992
|
]);
|
|
1937
1993
|
}
|
|
1994
|
+
};
|
|
1995
|
+
|
|
1996
|
+
// src/mcp/entities/task-stats.ts
|
|
1997
|
+
var TaskStatsEntity = class extends BaseEntity {
|
|
1938
1998
|
getTaskStats(repo) {
|
|
1939
1999
|
const rows = this.all(
|
|
1940
2000
|
"SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status",
|
|
@@ -2863,7 +2923,11 @@ var DB_PATH = resolveDbPath();
|
|
|
2863
2923
|
var SQLiteStore = class _SQLiteStore {
|
|
2864
2924
|
db;
|
|
2865
2925
|
memories;
|
|
2926
|
+
memoryVectors;
|
|
2927
|
+
memoryArchives;
|
|
2866
2928
|
tasks;
|
|
2929
|
+
taskComments;
|
|
2930
|
+
taskStats;
|
|
2867
2931
|
actions;
|
|
2868
2932
|
system;
|
|
2869
2933
|
summaries;
|
|
@@ -2894,7 +2958,11 @@ var SQLiteStore = class _SQLiteStore {
|
|
|
2894
2958
|
migrator.addMemoryCodeColumn();
|
|
2895
2959
|
migrator.addStandardCodeColumn();
|
|
2896
2960
|
this.memories = new MemoryEntity(this.db);
|
|
2961
|
+
this.memoryVectors = new MemoryVectorEntity(this.db);
|
|
2962
|
+
this.memoryArchives = new MemoryArchiveEntity(this.db);
|
|
2897
2963
|
this.tasks = new TaskEntity(this.db);
|
|
2964
|
+
this.taskComments = new TaskCommentEntity(this.db);
|
|
2965
|
+
this.taskStats = new TaskStatsEntity(this.db);
|
|
2898
2966
|
this.actions = new ActionEntity(this.db);
|
|
2899
2967
|
this.system = new SystemEntity(this.db);
|
|
2900
2968
|
this.summaries = new SummaryEntity(this.db);
|
|
@@ -3045,7 +3113,7 @@ var RealVectorStore = class {
|
|
|
3045
3113
|
if (kind === "standard") {
|
|
3046
3114
|
this.db.standards.upsertVectorEmbedding(id, vector);
|
|
3047
3115
|
} else {
|
|
3048
|
-
this.db.
|
|
3116
|
+
this.db.memoryVectors.upsertVectorEmbedding(id, vector);
|
|
3049
3117
|
}
|
|
3050
3118
|
} catch (error) {
|
|
3051
3119
|
logger.error("[Vectors] Error during upsert", { id, kind, error: String(error) });
|
|
@@ -3061,7 +3129,7 @@ var RealVectorStore = class {
|
|
|
3061
3129
|
const extractor = await this.getExtractor();
|
|
3062
3130
|
const output = await extractor(query, { pooling: "mean", normalize: true });
|
|
3063
3131
|
const queryVector = Array.from(output.data);
|
|
3064
|
-
const rows = kind === "standard" ? this.db.standards.getVectorCandidates(repo, 100).map((row) => ({ id: row.standard_id, vector: row.vector })) : this.db.
|
|
3132
|
+
const rows = kind === "standard" ? this.db.standards.getVectorCandidates(repo, 100).map((row) => ({ id: row.standard_id, vector: row.vector })) : this.db.memoryVectors.getVectorCandidates(repo, 100).map((row) => ({ id: row.memory_id, vector: row.vector }));
|
|
3065
3133
|
const results = rows.map((row) => {
|
|
3066
3134
|
const memoryVector = JSON.parse(row.vector);
|
|
3067
3135
|
return {
|
|
@@ -3264,9 +3332,12 @@ var MemoryDeleteSchema = z.object({
|
|
|
3264
3332
|
code: z.string().max(20).optional(),
|
|
3265
3333
|
codes: z.array(z.string().max(20)).min(1).optional(),
|
|
3266
3334
|
structured: z.boolean().default(false)
|
|
3267
|
-
}).refine(
|
|
3268
|
-
|
|
3269
|
-
|
|
3335
|
+
}).refine(
|
|
3336
|
+
(data) => data.id !== void 0 || data.ids !== void 0 || data.code !== void 0 || data.codes !== void 0,
|
|
3337
|
+
{
|
|
3338
|
+
message: "Either 'id', 'ids', 'code', or 'codes' must be provided for deletion"
|
|
3339
|
+
}
|
|
3340
|
+
);
|
|
3270
3341
|
var MemorySummarizeSchema = z.object({
|
|
3271
3342
|
repo: z.string().min(1).transform(normalizeRepo),
|
|
3272
3343
|
signals: z.array(z.string().max(200)).min(1),
|
|
@@ -3374,6 +3445,8 @@ var TaskSearchSchema = z.object({
|
|
|
3374
3445
|
repo: z.string().min(1).transform(normalizeRepo),
|
|
3375
3446
|
query: z.string().min(1),
|
|
3376
3447
|
status: z.string().optional(),
|
|
3448
|
+
phase: z.string().optional(),
|
|
3449
|
+
priority: z.number().min(1).max(5).optional(),
|
|
3377
3450
|
limit: z.number().min(1).max(100).default(10),
|
|
3378
3451
|
offset: z.number().min(0).default(0),
|
|
3379
3452
|
structured: z.boolean().default(false)
|
|
@@ -3408,9 +3481,12 @@ var StandardDeleteSchema = z.object({
|
|
|
3408
3481
|
code: z.string().max(20).optional(),
|
|
3409
3482
|
codes: z.array(z.string().max(20)).min(1).optional(),
|
|
3410
3483
|
structured: z.boolean().default(false)
|
|
3411
|
-
}).refine(
|
|
3412
|
-
|
|
3413
|
-
|
|
3484
|
+
}).refine(
|
|
3485
|
+
(data) => data.id !== void 0 || data.ids !== void 0 || data.code !== void 0 || data.codes !== void 0,
|
|
3486
|
+
{
|
|
3487
|
+
message: "Either 'id', 'ids', 'code', or 'codes' must be provided for deletion"
|
|
3488
|
+
}
|
|
3489
|
+
);
|
|
3414
3490
|
var TaskGetSchema = z.object({
|
|
3415
3491
|
repo: z.string().min(1).transform(normalizeRepo),
|
|
3416
3492
|
id: z.string().uuid().optional(),
|
|
@@ -4037,7 +4113,11 @@ var TOOL_DEFINITIONS = [
|
|
|
4037
4113
|
type: "object",
|
|
4038
4114
|
properties: {
|
|
4039
4115
|
repo: { type: "string", description: "Repository name (optional for single id)" },
|
|
4040
|
-
id: {
|
|
4116
|
+
id: {
|
|
4117
|
+
type: "string",
|
|
4118
|
+
format: "uuid",
|
|
4119
|
+
description: "Coding standard ID to delete. Optional if code is provided."
|
|
4120
|
+
},
|
|
4041
4121
|
ids: {
|
|
4042
4122
|
type: "array",
|
|
4043
4123
|
items: { type: "string", format: "uuid" },
|
|
@@ -4184,7 +4264,10 @@ var TOOL_DEFINITIONS = [
|
|
|
4184
4264
|
doc_path: { type: "string" },
|
|
4185
4265
|
tags: { type: "array", items: { type: "string" } },
|
|
4186
4266
|
metadata: { type: "object" },
|
|
4187
|
-
parent_id: {
|
|
4267
|
+
parent_id: {
|
|
4268
|
+
type: "string",
|
|
4269
|
+
description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing."
|
|
4270
|
+
},
|
|
4188
4271
|
depends_on: { type: "string", format: "uuid" },
|
|
4189
4272
|
est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
|
|
4190
4273
|
tasks: {
|
|
@@ -4212,7 +4295,10 @@ var TOOL_DEFINITIONS = [
|
|
|
4212
4295
|
doc_path: { type: "string" },
|
|
4213
4296
|
tags: { type: "array", items: { type: "string" } },
|
|
4214
4297
|
metadata: { type: "object" },
|
|
4215
|
-
parent_id: {
|
|
4298
|
+
parent_id: {
|
|
4299
|
+
type: "string",
|
|
4300
|
+
description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing."
|
|
4301
|
+
},
|
|
4216
4302
|
depends_on: { type: "string", format: "uuid" },
|
|
4217
4303
|
est_tokens: { type: "number", minimum: 0 }
|
|
4218
4304
|
},
|
|
@@ -4284,7 +4370,10 @@ var TOOL_DEFINITIONS = [
|
|
|
4284
4370
|
doc_path: { type: "string" },
|
|
4285
4371
|
tags: { type: "array", items: { type: "string" } },
|
|
4286
4372
|
metadata: { type: "object" },
|
|
4287
|
-
parent_id: {
|
|
4373
|
+
parent_id: {
|
|
4374
|
+
type: "string",
|
|
4375
|
+
description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing."
|
|
4376
|
+
},
|
|
4288
4377
|
depends_on: { type: "string", format: "uuid" },
|
|
4289
4378
|
est_tokens: {
|
|
4290
4379
|
type: "number",
|
|
@@ -4340,7 +4429,11 @@ var TOOL_DEFINITIONS = [
|
|
|
4340
4429
|
type: "object",
|
|
4341
4430
|
properties: {
|
|
4342
4431
|
repo: { type: "string", description: "Repository name" },
|
|
4343
|
-
id: {
|
|
4432
|
+
id: {
|
|
4433
|
+
type: "string",
|
|
4434
|
+
format: "uuid",
|
|
4435
|
+
description: "Task ID (for single deletion). Optional if task_code is provided."
|
|
4436
|
+
},
|
|
4344
4437
|
ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
|
|
4345
4438
|
task_code: { type: "string", description: "Task code (e.g. TASK-001). Optional if id is provided." },
|
|
4346
4439
|
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
@@ -4436,6 +4529,58 @@ var TOOL_DEFINITIONS = [
|
|
|
4436
4529
|
required: ["schema", "tasks", "count"]
|
|
4437
4530
|
}
|
|
4438
4531
|
},
|
|
4532
|
+
{
|
|
4533
|
+
name: "task-search",
|
|
4534
|
+
title: "Task Search",
|
|
4535
|
+
description: "Dedicated search tool for tasks. Returns a compact pointer table of matching tasks [id, task_code, title, status, priority, updated_at, phase]. Use task-detail for full task content.",
|
|
4536
|
+
annotations: {
|
|
4537
|
+
readOnlyHint: true,
|
|
4538
|
+
idempotentHint: true,
|
|
4539
|
+
openWorldHint: false
|
|
4540
|
+
},
|
|
4541
|
+
inputSchema: {
|
|
4542
|
+
type: "object",
|
|
4543
|
+
properties: {
|
|
4544
|
+
repo: { type: "string", description: "Repository name" },
|
|
4545
|
+
query: { type: "string", minLength: 1, description: "Search keyword matching task code, title, or description" },
|
|
4546
|
+
status: { type: "string", description: "Optional status filter (single or comma-separated)" },
|
|
4547
|
+
phase: { type: "string", description: "Filter by phase (e.g., 'research', 'implementation')" },
|
|
4548
|
+
priority: { type: "number", minimum: 1, maximum: 5, description: "Filter by priority (1-5)" },
|
|
4549
|
+
limit: { type: "number", minimum: 1, maximum: 100, default: 10 },
|
|
4550
|
+
offset: { type: "number", minimum: 0, default: 0 },
|
|
4551
|
+
structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
|
|
4552
|
+
},
|
|
4553
|
+
required: ["repo", "query"]
|
|
4554
|
+
},
|
|
4555
|
+
outputSchema: {
|
|
4556
|
+
type: "object",
|
|
4557
|
+
properties: {
|
|
4558
|
+
schema: { type: "string", enum: ["task-search"] },
|
|
4559
|
+
query: { type: "string" },
|
|
4560
|
+
count: { type: "number", description: "Number of rows returned" },
|
|
4561
|
+
total: { type: "number", description: "Total matching tasks before pagination" },
|
|
4562
|
+
offset: { type: "number" },
|
|
4563
|
+
limit: { type: "number" },
|
|
4564
|
+
results: {
|
|
4565
|
+
type: "object",
|
|
4566
|
+
properties: {
|
|
4567
|
+
columns: {
|
|
4568
|
+
type: "array",
|
|
4569
|
+
items: { type: "string" },
|
|
4570
|
+
description: "Column names: [id, task_code, title, status, priority, updated_at, phase]"
|
|
4571
|
+
},
|
|
4572
|
+
rows: {
|
|
4573
|
+
type: "array",
|
|
4574
|
+
items: { type: "array" },
|
|
4575
|
+
description: "Each row: [id, task_code, title, status, priority, updated_at, phase]. Use task-detail to fetch full task."
|
|
4576
|
+
}
|
|
4577
|
+
},
|
|
4578
|
+
required: ["columns", "rows"]
|
|
4579
|
+
}
|
|
4580
|
+
},
|
|
4581
|
+
required: ["schema", "query", "count", "total", "offset", "limit", "results"]
|
|
4582
|
+
}
|
|
4583
|
+
},
|
|
4439
4584
|
{
|
|
4440
4585
|
name: "handoff-create",
|
|
4441
4586
|
title: "Handoff Create",
|
|
@@ -5409,6 +5554,369 @@ async function completePromptArgument(name, argName, value, contextArguments, da
|
|
|
5409
5554
|
return [];
|
|
5410
5555
|
}
|
|
5411
5556
|
|
|
5557
|
+
// src/mcp/utils/mcp-response.ts
|
|
5558
|
+
import { z as z2 } from "zod";
|
|
5559
|
+
var McpAnnotationsSchema = z2.object({
|
|
5560
|
+
audience: z2.array(z2.enum(["user", "assistant"])).optional(),
|
|
5561
|
+
priority: z2.number().min(0).max(1).optional(),
|
|
5562
|
+
lastModified: z2.string().optional()
|
|
5563
|
+
}).strict().optional();
|
|
5564
|
+
var McpContentSchema = z2.discriminatedUnion("type", [
|
|
5565
|
+
z2.object({
|
|
5566
|
+
type: z2.literal("text"),
|
|
5567
|
+
text: z2.string(),
|
|
5568
|
+
annotations: McpAnnotationsSchema
|
|
5569
|
+
}),
|
|
5570
|
+
z2.object({
|
|
5571
|
+
type: z2.literal("image"),
|
|
5572
|
+
data: z2.string(),
|
|
5573
|
+
mimeType: z2.string(),
|
|
5574
|
+
annotations: McpAnnotationsSchema
|
|
5575
|
+
}),
|
|
5576
|
+
z2.object({
|
|
5577
|
+
type: z2.literal("resource"),
|
|
5578
|
+
resource: z2.object({
|
|
5579
|
+
uri: z2.string(),
|
|
5580
|
+
mimeType: z2.string().optional(),
|
|
5581
|
+
text: z2.string().optional(),
|
|
5582
|
+
annotations: McpAnnotationsSchema
|
|
5583
|
+
})
|
|
5584
|
+
})
|
|
5585
|
+
]);
|
|
5586
|
+
function createMcpResponse(data, summary, options) {
|
|
5587
|
+
const { structuredContentPathHint, contentSummary, includeSerializedStructuredContent = false } = options || {};
|
|
5588
|
+
void includeSerializedStructuredContent;
|
|
5589
|
+
let finalData = data;
|
|
5590
|
+
if (data && typeof data === "object") {
|
|
5591
|
+
const cloned = JSON.parse(JSON.stringify(data));
|
|
5592
|
+
finalData = cloned;
|
|
5593
|
+
const arrayKeys = ["results", "tasks", "memories", "items"];
|
|
5594
|
+
let foundArray = false;
|
|
5595
|
+
for (const key of arrayKeys) {
|
|
5596
|
+
const value = cloned[key];
|
|
5597
|
+
if (Array.isArray(value)) {
|
|
5598
|
+
cloned[key] = value.map(
|
|
5599
|
+
(item) => pruneMetadata(item)
|
|
5600
|
+
);
|
|
5601
|
+
foundArray = true;
|
|
5602
|
+
}
|
|
5603
|
+
}
|
|
5604
|
+
if (Array.isArray(cloned)) {
|
|
5605
|
+
finalData = cloned.map((item) => pruneMetadata(item));
|
|
5606
|
+
} else if (!foundArray) {
|
|
5607
|
+
finalData = pruneMetadata(cloned);
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
const content = [];
|
|
5611
|
+
if (contentSummary && contentSummary.trim().length > 0) {
|
|
5612
|
+
content.push({
|
|
5613
|
+
type: "text",
|
|
5614
|
+
text: contentSummary.trim()
|
|
5615
|
+
});
|
|
5616
|
+
} else if (summary && summary.trim().length > 0) {
|
|
5617
|
+
const pointerText = structuredContentPathHint ? `Read structuredContent.${structuredContentPathHint} for details.` : `Read structuredContent for machine-readable results.`;
|
|
5618
|
+
content.push({
|
|
5619
|
+
type: "text",
|
|
5620
|
+
text: `${summary.trim()} ${pointerText}`
|
|
5621
|
+
});
|
|
5622
|
+
}
|
|
5623
|
+
const response = {
|
|
5624
|
+
structuredContent: finalData,
|
|
5625
|
+
isError: false
|
|
5626
|
+
};
|
|
5627
|
+
if (includeSerializedStructuredContent === false) {
|
|
5628
|
+
delete response.structuredContent;
|
|
5629
|
+
}
|
|
5630
|
+
response.content = content;
|
|
5631
|
+
return response;
|
|
5632
|
+
}
|
|
5633
|
+
function pruneMetadata(item) {
|
|
5634
|
+
if (!item || typeof item !== "object") return item;
|
|
5635
|
+
const pruned = { ...item };
|
|
5636
|
+
const toRemove = [
|
|
5637
|
+
"hit_count",
|
|
5638
|
+
"recall_count",
|
|
5639
|
+
"last_used_at",
|
|
5640
|
+
"expires_at",
|
|
5641
|
+
"agent",
|
|
5642
|
+
"role",
|
|
5643
|
+
"model",
|
|
5644
|
+
"recall_rate",
|
|
5645
|
+
"vector_version",
|
|
5646
|
+
"similarity"
|
|
5647
|
+
// Similarity is useful but adds noise if many results
|
|
5648
|
+
];
|
|
5649
|
+
for (const field of toRemove) {
|
|
5650
|
+
delete pruned[field];
|
|
5651
|
+
}
|
|
5652
|
+
return pruned;
|
|
5653
|
+
}
|
|
5654
|
+
function getPrimaryTextContent(response) {
|
|
5655
|
+
if (!Array.isArray(response.content)) return "";
|
|
5656
|
+
const textItem = response.content.find((item) => item.type === "text");
|
|
5657
|
+
return textItem?.type === "text" ? textItem.text : "";
|
|
5658
|
+
}
|
|
5659
|
+
|
|
5660
|
+
// src/mcp/tools/handoff.manage.ts
|
|
5661
|
+
function buildHandoffListSummary(repo, count, status, fromAgent, toAgent) {
|
|
5662
|
+
const parts = [`Found ${count} handoff${count === 1 ? "" : "s"} in repo "${repo}".`];
|
|
5663
|
+
if (status) {
|
|
5664
|
+
parts.push(`Status filter: ${status}.`);
|
|
5665
|
+
}
|
|
5666
|
+
if (fromAgent) {
|
|
5667
|
+
parts.push(`From agent: ${fromAgent}.`);
|
|
5668
|
+
}
|
|
5669
|
+
if (toAgent) {
|
|
5670
|
+
parts.push(`To agent: ${toAgent}.`);
|
|
5671
|
+
}
|
|
5672
|
+
return parts.join("\n");
|
|
5673
|
+
}
|
|
5674
|
+
function buildClaimListSummary(repo, count, agent, activeOnly) {
|
|
5675
|
+
const parts = [`Found ${count} claim${count === 1 ? "" : "s"} in repo "${repo}".`];
|
|
5676
|
+
if (agent) {
|
|
5677
|
+
parts.push(`Agent filter: ${agent}.`);
|
|
5678
|
+
}
|
|
5679
|
+
if (activeOnly) {
|
|
5680
|
+
parts.push("Showing active claims only.");
|
|
5681
|
+
}
|
|
5682
|
+
return parts.join("\n");
|
|
5683
|
+
}
|
|
5684
|
+
async function handleHandoffCreate(args, storage) {
|
|
5685
|
+
const validated = HandoffCreateSchema.parse(args);
|
|
5686
|
+
const { repo, from_agent, to_agent, task_id, task_code, summary, context, expires_at, structured } = validated;
|
|
5687
|
+
let resolvedTaskId = task_id ?? null;
|
|
5688
|
+
if (!resolvedTaskId && task_code) {
|
|
5689
|
+
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
5690
|
+
if (!task) {
|
|
5691
|
+
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
5692
|
+
}
|
|
5693
|
+
resolvedTaskId = task.id;
|
|
5694
|
+
}
|
|
5695
|
+
const handoff = storage.handoffs.createHandoff({
|
|
5696
|
+
repo,
|
|
5697
|
+
from_agent,
|
|
5698
|
+
to_agent,
|
|
5699
|
+
task_id: resolvedTaskId,
|
|
5700
|
+
summary,
|
|
5701
|
+
context,
|
|
5702
|
+
expires_at
|
|
5703
|
+
});
|
|
5704
|
+
const contentSummary = [
|
|
5705
|
+
`Created handoff ${handoff.id}.`,
|
|
5706
|
+
`Repo: ${handoff.repo}`,
|
|
5707
|
+
`From: ${handoff.from_agent}`,
|
|
5708
|
+
`To: ${handoff.to_agent || "unassigned"}`,
|
|
5709
|
+
`Status: ${handoff.status}`,
|
|
5710
|
+
`Task ID: ${handoff.task_id || "-"}`,
|
|
5711
|
+
`Summary: ${handoff.summary}`
|
|
5712
|
+
].join("\n");
|
|
5713
|
+
return createMcpResponse(handoff, contentSummary, {
|
|
5714
|
+
contentSummary,
|
|
5715
|
+
includeSerializedStructuredContent: structured
|
|
5716
|
+
});
|
|
5717
|
+
}
|
|
5718
|
+
async function handleHandoffList(args, storage) {
|
|
5719
|
+
const validated = HandoffListSchema.parse(args);
|
|
5720
|
+
const { repo, status, from_agent, to_agent, limit, offset, structured } = validated;
|
|
5721
|
+
const handoffs = storage.handoffs.listHandoffs({
|
|
5722
|
+
repo,
|
|
5723
|
+
status,
|
|
5724
|
+
from_agent,
|
|
5725
|
+
to_agent,
|
|
5726
|
+
limit,
|
|
5727
|
+
offset
|
|
5728
|
+
});
|
|
5729
|
+
const COLUMNS = [
|
|
5730
|
+
"id",
|
|
5731
|
+
"from_agent",
|
|
5732
|
+
"to_agent",
|
|
5733
|
+
"task_id",
|
|
5734
|
+
"task_code",
|
|
5735
|
+
"status",
|
|
5736
|
+
"created_at",
|
|
5737
|
+
"updated_at",
|
|
5738
|
+
"expires_at",
|
|
5739
|
+
"summary",
|
|
5740
|
+
"context"
|
|
5741
|
+
];
|
|
5742
|
+
const rows = handoffs.map((handoff) => [
|
|
5743
|
+
handoff.id,
|
|
5744
|
+
handoff.from_agent,
|
|
5745
|
+
handoff.to_agent,
|
|
5746
|
+
handoff.task_id,
|
|
5747
|
+
handoff.task_code ?? null,
|
|
5748
|
+
handoff.status,
|
|
5749
|
+
handoff.created_at,
|
|
5750
|
+
handoff.updated_at,
|
|
5751
|
+
handoff.expires_at,
|
|
5752
|
+
handoff.summary,
|
|
5753
|
+
handoff.context
|
|
5754
|
+
]);
|
|
5755
|
+
const structuredData = {
|
|
5756
|
+
schema: "handoff-list",
|
|
5757
|
+
handoffs: {
|
|
5758
|
+
columns: [...COLUMNS],
|
|
5759
|
+
rows
|
|
5760
|
+
},
|
|
5761
|
+
count: rows.length,
|
|
5762
|
+
offset
|
|
5763
|
+
};
|
|
5764
|
+
const contentSummary = buildHandoffListSummary(repo, rows.length, status, from_agent, to_agent);
|
|
5765
|
+
return createMcpResponse(structuredData, contentSummary, {
|
|
5766
|
+
contentSummary,
|
|
5767
|
+
includeSerializedStructuredContent: structured
|
|
5768
|
+
});
|
|
5769
|
+
}
|
|
5770
|
+
async function handleHandoffUpdate(args, storage) {
|
|
5771
|
+
const validated = HandoffUpdateSchema.parse(args);
|
|
5772
|
+
const { id, status, structured } = validated;
|
|
5773
|
+
const existing = storage.handoffs.getHandoffById(id);
|
|
5774
|
+
if (!existing) {
|
|
5775
|
+
throw new Error(`Handoff not found: ${id}`);
|
|
5776
|
+
}
|
|
5777
|
+
const success = storage.handoffs.updateHandoffStatus(id, status);
|
|
5778
|
+
if (!success) {
|
|
5779
|
+
throw new Error(`Failed to update handoff: ${id}`);
|
|
5780
|
+
}
|
|
5781
|
+
const updated = storage.handoffs.getHandoffById(id);
|
|
5782
|
+
const result = {
|
|
5783
|
+
success,
|
|
5784
|
+
id,
|
|
5785
|
+
status,
|
|
5786
|
+
handoff: updated
|
|
5787
|
+
};
|
|
5788
|
+
const contentSummary = [`Updated handoff ${id}.`, `Status: ${status}`].join("\n");
|
|
5789
|
+
return createMcpResponse(result, contentSummary, {
|
|
5790
|
+
contentSummary,
|
|
5791
|
+
includeSerializedStructuredContent: structured
|
|
5792
|
+
});
|
|
5793
|
+
}
|
|
5794
|
+
async function handleTaskClaim(args, storage) {
|
|
5795
|
+
const validated = TaskClaimSchema.parse(args);
|
|
5796
|
+
const { repo, task_id, task_code, agent, role, metadata, structured } = validated;
|
|
5797
|
+
let taskId = task_id;
|
|
5798
|
+
let resolvedTaskCode;
|
|
5799
|
+
if (taskId) {
|
|
5800
|
+
const task = storage.tasks.getTaskById(taskId);
|
|
5801
|
+
if (!task || task.repo !== repo) {
|
|
5802
|
+
throw new Error(`Task not found: ${taskId} in repo ${repo}`);
|
|
5803
|
+
}
|
|
5804
|
+
resolvedTaskCode = task.task_code;
|
|
5805
|
+
} else if (task_code) {
|
|
5806
|
+
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
5807
|
+
if (!task) {
|
|
5808
|
+
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
5809
|
+
}
|
|
5810
|
+
taskId = task.id;
|
|
5811
|
+
resolvedTaskCode = task.task_code;
|
|
5812
|
+
} else {
|
|
5813
|
+
throw new Error("Either task_id or task_code must be provided");
|
|
5814
|
+
}
|
|
5815
|
+
const claim = storage.handoffs.claimTask({
|
|
5816
|
+
repo,
|
|
5817
|
+
task_id: taskId,
|
|
5818
|
+
agent,
|
|
5819
|
+
role,
|
|
5820
|
+
metadata
|
|
5821
|
+
});
|
|
5822
|
+
const responseData = {
|
|
5823
|
+
...claim,
|
|
5824
|
+
task_code: resolvedTaskCode
|
|
5825
|
+
};
|
|
5826
|
+
const contentSummary = [
|
|
5827
|
+
`Claimed task ${resolvedTaskCode || claim.task_id}.`,
|
|
5828
|
+
`Repo: ${claim.repo}`,
|
|
5829
|
+
`Task ID: ${claim.task_id}`,
|
|
5830
|
+
`Agent: ${claim.agent}`,
|
|
5831
|
+
`Role: ${claim.role}`,
|
|
5832
|
+
`Claimed At: ${claim.claimed_at}`
|
|
5833
|
+
].join("\n");
|
|
5834
|
+
const response = createMcpResponse(responseData, contentSummary, {
|
|
5835
|
+
contentSummary,
|
|
5836
|
+
includeSerializedStructuredContent: structured
|
|
5837
|
+
});
|
|
5838
|
+
if (structured) {
|
|
5839
|
+
response.structuredContent = responseData;
|
|
5840
|
+
}
|
|
5841
|
+
return response;
|
|
5842
|
+
}
|
|
5843
|
+
async function handleClaimList(args, storage) {
|
|
5844
|
+
const validated = ClaimListSchema.parse(args);
|
|
5845
|
+
const { repo, agent, active_only, limit, offset, structured } = validated;
|
|
5846
|
+
const claims = storage.handoffs.listClaims({
|
|
5847
|
+
repo,
|
|
5848
|
+
agent,
|
|
5849
|
+
active_only,
|
|
5850
|
+
limit,
|
|
5851
|
+
offset
|
|
5852
|
+
});
|
|
5853
|
+
const COLUMNS = ["id", "task_id", "task_code", "agent", "role", "claimed_at", "released_at", "metadata"];
|
|
5854
|
+
const rows = claims.map((claim) => [
|
|
5855
|
+
claim.id,
|
|
5856
|
+
claim.task_id,
|
|
5857
|
+
claim.task_code ?? null,
|
|
5858
|
+
claim.agent,
|
|
5859
|
+
claim.role,
|
|
5860
|
+
claim.claimed_at,
|
|
5861
|
+
claim.released_at,
|
|
5862
|
+
claim.metadata
|
|
5863
|
+
]);
|
|
5864
|
+
const structuredData = {
|
|
5865
|
+
schema: "claim-list",
|
|
5866
|
+
claims: {
|
|
5867
|
+
columns: [...COLUMNS],
|
|
5868
|
+
rows
|
|
5869
|
+
},
|
|
5870
|
+
count: rows.length,
|
|
5871
|
+
offset
|
|
5872
|
+
};
|
|
5873
|
+
const contentSummary = buildClaimListSummary(repo, rows.length, agent, active_only);
|
|
5874
|
+
return createMcpResponse(structuredData, contentSummary, {
|
|
5875
|
+
contentSummary,
|
|
5876
|
+
includeSerializedStructuredContent: structured
|
|
5877
|
+
});
|
|
5878
|
+
}
|
|
5879
|
+
async function handleClaimRelease(args, storage) {
|
|
5880
|
+
const validated = ClaimReleaseSchema.parse(args);
|
|
5881
|
+
const { repo, task_id, task_code, agent, structured } = validated;
|
|
5882
|
+
let resolvedTaskId = task_id;
|
|
5883
|
+
let resolvedTaskCode = task_code ?? null;
|
|
5884
|
+
if (resolvedTaskId) {
|
|
5885
|
+
const task = storage.tasks.getTaskById(resolvedTaskId);
|
|
5886
|
+
if (!task || task.repo !== repo) {
|
|
5887
|
+
throw new Error(`Task not found: ${resolvedTaskId} in repo ${repo}`);
|
|
5888
|
+
}
|
|
5889
|
+
resolvedTaskCode = task.task_code;
|
|
5890
|
+
} else if (task_code) {
|
|
5891
|
+
const task = storage.tasks.getTaskByCode(repo, task_code);
|
|
5892
|
+
if (!task) {
|
|
5893
|
+
throw new Error(`Task not found: ${task_code} in repo ${repo}`);
|
|
5894
|
+
}
|
|
5895
|
+
resolvedTaskId = task.id;
|
|
5896
|
+
resolvedTaskCode = task.task_code;
|
|
5897
|
+
}
|
|
5898
|
+
const success = storage.handoffs.releaseClaim(resolvedTaskId, agent);
|
|
5899
|
+
if (!success) {
|
|
5900
|
+
throw new Error(`No active claim found for task ${resolvedTaskCode || resolvedTaskId}`);
|
|
5901
|
+
}
|
|
5902
|
+
const result = {
|
|
5903
|
+
success,
|
|
5904
|
+
repo,
|
|
5905
|
+
task_id: resolvedTaskId,
|
|
5906
|
+
task_code: resolvedTaskCode,
|
|
5907
|
+
agent: agent ?? null
|
|
5908
|
+
};
|
|
5909
|
+
const contentSummary = [
|
|
5910
|
+
`Released claim for task ${resolvedTaskCode || resolvedTaskId}.`,
|
|
5911
|
+
`Repo: ${repo}`,
|
|
5912
|
+
agent ? `Agent: ${agent}` : "Agent: any active claimant"
|
|
5913
|
+
].join("\n");
|
|
5914
|
+
return createMcpResponse(result, contentSummary, {
|
|
5915
|
+
contentSummary,
|
|
5916
|
+
includeSerializedStructuredContent: structured
|
|
5917
|
+
});
|
|
5918
|
+
}
|
|
5919
|
+
|
|
5412
5920
|
// src/mcp/tools/standard.shared.ts
|
|
5413
5921
|
function toContextSlug(value) {
|
|
5414
5922
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -5450,17 +5958,12 @@ export {
|
|
|
5450
5958
|
TaskCreateInteractiveSchema,
|
|
5451
5959
|
TaskUpdateSchema,
|
|
5452
5960
|
TaskListSchema,
|
|
5961
|
+
TaskSearchSchema,
|
|
5453
5962
|
TaskDeleteSchema,
|
|
5454
5963
|
MemoryDetailSchema,
|
|
5455
5964
|
StandardDetailSchema,
|
|
5456
5965
|
StandardDeleteSchema,
|
|
5457
5966
|
TaskGetSchema,
|
|
5458
|
-
HandoffCreateSchema,
|
|
5459
|
-
HandoffUpdateSchema,
|
|
5460
|
-
HandoffListSchema,
|
|
5461
|
-
TaskClaimSchema,
|
|
5462
|
-
ClaimListSchema,
|
|
5463
|
-
ClaimReleaseSchema,
|
|
5464
5967
|
StandardStoreSchema,
|
|
5465
5968
|
StandardUpdateSchema,
|
|
5466
5969
|
StandardSearchSchema,
|
|
@@ -5483,6 +5986,14 @@ export {
|
|
|
5483
5986
|
listPrompts,
|
|
5484
5987
|
getPrompt,
|
|
5485
5988
|
completePromptArgument,
|
|
5989
|
+
createMcpResponse,
|
|
5990
|
+
getPrimaryTextContent,
|
|
5991
|
+
handleHandoffCreate,
|
|
5992
|
+
handleHandoffList,
|
|
5993
|
+
handleHandoffUpdate,
|
|
5994
|
+
handleTaskClaim,
|
|
5995
|
+
handleClaimList,
|
|
5996
|
+
handleClaimRelease,
|
|
5486
5997
|
toContextSlug,
|
|
5487
5998
|
buildStandardVectorText
|
|
5488
5999
|
};
|