@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.
@@ -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.13.1") {
85
- pkgVersion = "0.13.1";
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 !== "id" && k !== "created_at") {
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 === "tags" || key === "metadata") {
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 (!candidates.find((c) => c.id === r.id)) candidates.push(r);
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 VALID_COLUMNS = /* @__PURE__ */ new Set([
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 (VALID_COLUMNS.has(key) && anyUpdates[key] !== void 0) {
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.getTaskCommentsByTaskId(id) } : null;
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.getTaskCommentsByTaskId(row.id) } : null;
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.memories.upsertVectorEmbedding(id, vector);
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.memories.getVectorCandidates(repo, 100).map((row) => ({ id: row.memory_id, vector: row.vector }));
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 {
@@ -3206,7 +3274,8 @@ var MemoryStoreSchema = z.object({
3206
3274
  structured: z.boolean().default(false)
3207
3275
  });
3208
3276
  var MemoryUpdateSchema = z.object({
3209
- id: z.string().uuid(),
3277
+ id: z.string().uuid().optional(),
3278
+ code: z.string().max(20).optional(),
3210
3279
  type: MemoryTypeSchema.optional(),
3211
3280
  title: z.string().min(3).max(255).optional(),
3212
3281
  content: z.string().min(10).optional(),
@@ -3220,6 +3289,8 @@ var MemoryUpdateSchema = z.object({
3220
3289
  is_global: z.boolean().optional(),
3221
3290
  completed_at: z.string().optional(),
3222
3291
  structured: z.boolean().default(false)
3292
+ }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3293
+ message: "Either id or code must be provided"
3223
3294
  }).refine(
3224
3295
  (data) => data.type !== void 0 || data.content !== void 0 || data.title !== void 0 || data.importance !== void 0 || data.status !== void 0 || data.supersedes !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.is_global !== void 0 || data.agent !== void 0 || data.role !== void 0 || data.completed_at !== void 0,
3225
3296
  { message: "At least one field must be provided for update" }
@@ -3240,10 +3311,13 @@ var MemorySearchSchema = z.object({
3240
3311
  structured: z.boolean().default(false)
3241
3312
  });
3242
3313
  var MemoryAcknowledgeSchema = z.object({
3243
- memory_id: z.string().uuid(),
3314
+ memory_id: z.string().uuid().optional(),
3315
+ code: z.string().max(20).optional(),
3244
3316
  status: z.enum(["used", "irrelevant", "contradictory"]),
3245
3317
  application_context: z.string().min(10).optional(),
3246
3318
  structured: z.boolean().default(false)
3319
+ }).refine((data) => data.memory_id !== void 0 || data.code !== void 0, {
3320
+ message: "Either memory_id or code must be provided"
3247
3321
  });
3248
3322
  var MemoryRecapSchema = z.object({
3249
3323
  repo: z.string().min(1).transform(normalizeRepo),
@@ -3255,10 +3329,15 @@ var MemoryDeleteSchema = z.object({
3255
3329
  repo: z.string().min(1).transform(normalizeRepo).optional(),
3256
3330
  id: z.string().uuid().optional(),
3257
3331
  ids: z.array(z.string().uuid()).min(1).optional(),
3332
+ code: z.string().max(20).optional(),
3333
+ codes: z.array(z.string().max(20)).min(1).optional(),
3258
3334
  structured: z.boolean().default(false)
3259
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3260
- message: "Either 'id' or 'ids' must be provided for deletion"
3261
- });
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
+ );
3262
3341
  var MemorySummarizeSchema = z.object({
3263
3342
  repo: z.string().min(1).transform(normalizeRepo),
3264
3343
  signals: z.array(z.string().max(200)).min(1),
@@ -3366,6 +3445,8 @@ var TaskSearchSchema = z.object({
3366
3445
  repo: z.string().min(1).transform(normalizeRepo),
3367
3446
  query: z.string().min(1),
3368
3447
  status: z.string().optional(),
3448
+ phase: z.string().optional(),
3449
+ priority: z.number().min(1).max(5).optional(),
3369
3450
  limit: z.number().min(1).max(100).default(10),
3370
3451
  offset: z.number().min(0).default(0),
3371
3452
  structured: z.boolean().default(false)
@@ -3374,9 +3455,10 @@ var TaskDeleteSchema = z.object({
3374
3455
  repo: z.string().min(1).transform(normalizeRepo),
3375
3456
  id: z.string().uuid().optional(),
3376
3457
  ids: z.array(z.string().uuid()).min(1).optional(),
3458
+ task_code: z.string().optional(),
3377
3459
  structured: z.boolean().default(false)
3378
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3379
- message: "Either 'id' or 'ids' must be provided for deletion"
3460
+ }).refine((data) => data.id !== void 0 || data.ids !== void 0 || data.task_code !== void 0, {
3461
+ message: "Either 'id', 'ids', or 'task_code' must be provided for deletion"
3380
3462
  });
3381
3463
  var MemoryDetailSchema = z.object({
3382
3464
  id: z.string().uuid().optional(),
@@ -3396,10 +3478,15 @@ var StandardDeleteSchema = z.object({
3396
3478
  repo: z.string().min(1).transform(normalizeRepo).optional(),
3397
3479
  id: z.string().uuid().optional(),
3398
3480
  ids: z.array(z.string().uuid()).min(1).optional(),
3481
+ code: z.string().max(20).optional(),
3482
+ codes: z.array(z.string().max(20)).min(1).optional(),
3399
3483
  structured: z.boolean().default(false)
3400
- }).refine((data) => data.id !== void 0 || data.ids !== void 0, {
3401
- message: "Either 'id' or 'ids' must be provided for deletion"
3402
- });
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
+ );
3403
3490
  var TaskGetSchema = z.object({
3404
3491
  repo: z.string().min(1).transform(normalizeRepo),
3405
3492
  id: z.string().uuid().optional(),
@@ -3494,7 +3581,8 @@ var StandardStoreSchema = z.object({
3494
3581
  message: "repo is required for repo-specific standards"
3495
3582
  });
3496
3583
  var StandardUpdateSchema = z.object({
3497
- id: z.string().uuid(),
3584
+ id: z.string().uuid().optional(),
3585
+ code: z.string().max(20).optional(),
3498
3586
  name: z.string().min(3).max(255).optional(),
3499
3587
  content: z.string().min(10).optional(),
3500
3588
  parent_id: z.string().uuid().nullable().optional(),
@@ -3509,6 +3597,8 @@ var StandardUpdateSchema = z.object({
3509
3597
  agent: z.string().optional(),
3510
3598
  model: z.string().optional(),
3511
3599
  structured: z.boolean().default(false)
3600
+ }).refine((data) => data.id !== void 0 || data.code !== void 0, {
3601
+ message: "Either id or code must be provided"
3512
3602
  }).refine(
3513
3603
  (data) => data.name !== void 0 || data.content !== void 0 || data.parent_id !== void 0 || data.context !== void 0 || data.version !== void 0 || data.language !== void 0 || data.stack !== void 0 || data.repo !== void 0 || data.is_global !== void 0 || data.tags !== void 0 || data.metadata !== void 0 || data.agent !== void 0 || data.model !== void 0,
3514
3604
  { message: "At least one field must be provided for update" }
@@ -3781,12 +3871,13 @@ var TOOL_DEFINITIONS = [
3781
3871
  inputSchema: {
3782
3872
  type: "object",
3783
3873
  properties: {
3784
- memory_id: { type: "string", format: "uuid" },
3874
+ memory_id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
3875
+ code: { type: "string", maxLength: 20, description: "Short memory code. Optional if memory_id is provided." },
3785
3876
  status: { type: "string", enum: ["used", "irrelevant", "contradictory"] },
3786
3877
  application_context: { type: "string", minLength: 10 },
3787
3878
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3788
3879
  },
3789
- required: ["memory_id", "status"]
3880
+ required: ["status"]
3790
3881
  },
3791
3882
  outputSchema: {
3792
3883
  type: "object",
@@ -3811,7 +3902,8 @@ var TOOL_DEFINITIONS = [
3811
3902
  inputSchema: {
3812
3903
  type: "object",
3813
3904
  properties: {
3814
- id: { type: "string", format: "uuid" },
3905
+ id: { type: "string", format: "uuid", description: "Memory entry ID. Optional if code is provided." },
3906
+ code: { type: "string", maxLength: 20, description: "Short memory code. Optional if id is provided." },
3815
3907
  type: {
3816
3908
  type: "string",
3817
3909
  enum: ["code_fact", "decision", "mistake", "pattern", "task_archive"]
@@ -3832,21 +3924,21 @@ var TOOL_DEFINITIONS = [
3832
3924
  default: false,
3833
3925
  description: "If true, returns structured JSON of the updated memory."
3834
3926
  }
3835
- },
3836
- required: ["id"]
3927
+ }
3837
3928
  },
3838
3929
  outputSchema: {
3839
3930
  type: "object",
3840
3931
  properties: {
3841
3932
  success: { type: "boolean" },
3842
3933
  id: { type: "string" },
3934
+ code: { type: "string" },
3843
3935
  repo: { type: "string" },
3844
3936
  updatedFields: {
3845
3937
  type: "array",
3846
3938
  items: { type: "string" }
3847
3939
  }
3848
3940
  },
3849
- required: ["success", "id", "repo", "updatedFields"]
3941
+ required: ["success", "repo", "updatedFields"]
3850
3942
  }
3851
3943
  },
3852
3944
  {
@@ -3976,13 +4068,20 @@ var TOOL_DEFINITIONS = [
3976
4068
  type: "object",
3977
4069
  properties: {
3978
4070
  repo: { type: "string", description: "Repository name (optional for single id)" },
3979
- id: { type: "string", format: "uuid", description: "Memory entry ID to delete" },
4071
+ id: { type: "string", format: "uuid", description: "Memory entry ID to delete. Optional if code is provided." },
3980
4072
  ids: {
3981
4073
  type: "array",
3982
4074
  items: { type: "string", format: "uuid" },
3983
4075
  minItems: 1,
3984
4076
  description: "Array of memory IDs to delete"
3985
4077
  },
4078
+ code: { type: "string", maxLength: 20, description: "Short memory code. Optional if id is provided." },
4079
+ codes: {
4080
+ type: "array",
4081
+ items: { type: "string", maxLength: 20 },
4082
+ minItems: 1,
4083
+ description: "Array of memory codes to delete"
4084
+ },
3986
4085
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
3987
4086
  }
3988
4087
  },
@@ -3991,7 +4090,9 @@ var TOOL_DEFINITIONS = [
3991
4090
  properties: {
3992
4091
  success: { type: "boolean" },
3993
4092
  id: { type: "string" },
4093
+ code: { type: "string" },
3994
4094
  ids: { type: "array", items: { type: "string" } },
4095
+ codes: { type: "array", items: { type: "string" } },
3995
4096
  repo: { type: "string" },
3996
4097
  deletedCount: { type: "number" }
3997
4098
  },
@@ -4012,13 +4113,24 @@ var TOOL_DEFINITIONS = [
4012
4113
  type: "object",
4013
4114
  properties: {
4014
4115
  repo: { type: "string", description: "Repository name (optional for single id)" },
4015
- id: { type: "string", format: "uuid", description: "Coding standard ID to delete" },
4116
+ id: {
4117
+ type: "string",
4118
+ format: "uuid",
4119
+ description: "Coding standard ID to delete. Optional if code is provided."
4120
+ },
4016
4121
  ids: {
4017
4122
  type: "array",
4018
4123
  items: { type: "string", format: "uuid" },
4019
4124
  minItems: 1,
4020
4125
  description: "Array of coding standard IDs to delete"
4021
4126
  },
4127
+ code: { type: "string", maxLength: 20, description: "Short standard code. Optional if id is provided." },
4128
+ codes: {
4129
+ type: "array",
4130
+ items: { type: "string", maxLength: 20 },
4131
+ minItems: 1,
4132
+ description: "Array of standard codes to delete"
4133
+ },
4022
4134
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4023
4135
  }
4024
4136
  },
@@ -4027,7 +4139,9 @@ var TOOL_DEFINITIONS = [
4027
4139
  properties: {
4028
4140
  success: { type: "boolean" },
4029
4141
  id: { type: "string" },
4142
+ code: { type: "string" },
4030
4143
  ids: { type: "array", items: { type: "string" } },
4144
+ codes: { type: "array", items: { type: "string" } },
4031
4145
  repo: { type: "string" },
4032
4146
  deletedCount: { type: "number" }
4033
4147
  },
@@ -4150,7 +4264,10 @@ var TOOL_DEFINITIONS = [
4150
4264
  doc_path: { type: "string" },
4151
4265
  tags: { type: "array", items: { type: "string" } },
4152
4266
  metadata: { type: "object" },
4153
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
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
+ },
4154
4271
  depends_on: { type: "string", format: "uuid" },
4155
4272
  est_tokens: { type: "number", minimum: 0, description: "Estimated tokens budget for this task" },
4156
4273
  tasks: {
@@ -4178,7 +4295,10 @@ var TOOL_DEFINITIONS = [
4178
4295
  doc_path: { type: "string" },
4179
4296
  tags: { type: "array", items: { type: "string" } },
4180
4297
  metadata: { type: "object" },
4181
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
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
+ },
4182
4302
  depends_on: { type: "string", format: "uuid" },
4183
4303
  est_tokens: { type: "number", minimum: 0 }
4184
4304
  },
@@ -4250,7 +4370,10 @@ var TOOL_DEFINITIONS = [
4250
4370
  doc_path: { type: "string" },
4251
4371
  tags: { type: "array", items: { type: "string" } },
4252
4372
  metadata: { type: "object" },
4253
- parent_id: { type: "string", description: "Optional parent task ID (UUID) or parent task code (e.g. TASK-001). Resolved to UUID before storing." },
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
+ },
4254
4377
  depends_on: { type: "string", format: "uuid" },
4255
4378
  est_tokens: {
4256
4379
  type: "number",
@@ -4306,8 +4429,13 @@ var TOOL_DEFINITIONS = [
4306
4429
  type: "object",
4307
4430
  properties: {
4308
4431
  repo: { type: "string", description: "Repository name" },
4309
- id: { type: "string", format: "uuid", description: "Task ID (for single deletion)" },
4432
+ id: {
4433
+ type: "string",
4434
+ format: "uuid",
4435
+ description: "Task ID (for single deletion). Optional if task_code is provided."
4436
+ },
4310
4437
  ids: { type: "array", items: { type: "string", format: "uuid" }, description: "Task IDs (for bulk deletion)" },
4438
+ task_code: { type: "string", description: "Task code (e.g. TASK-001). Optional if id is provided." },
4311
4439
  structured: { type: "boolean", default: false, description: "If true, returns structured JSON result." }
4312
4440
  },
4313
4441
  required: ["repo"]
@@ -4317,6 +4445,7 @@ var TOOL_DEFINITIONS = [
4317
4445
  properties: {
4318
4446
  success: { type: "boolean" },
4319
4447
  id: { type: "string" },
4448
+ task_code: { type: "string" },
4320
4449
  ids: { type: "array", items: { type: "string" } },
4321
4450
  repo: { type: "string" },
4322
4451
  deletedCount: { type: "number" }
@@ -4400,6 +4529,58 @@ var TOOL_DEFINITIONS = [
4400
4529
  required: ["schema", "tasks", "count"]
4401
4530
  }
4402
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
+ },
4403
4584
  {
4404
4585
  name: "handoff-create",
4405
4586
  title: "Handoff Create",
@@ -4762,7 +4943,8 @@ var TOOL_DEFINITIONS = [
4762
4943
  inputSchema: {
4763
4944
  type: "object",
4764
4945
  properties: {
4765
- id: { type: "string", description: "Standard ID to update" },
4946
+ id: { type: "string", format: "uuid", description: "Standard ID to update. Optional if code is provided." },
4947
+ code: { type: "string", maxLength: 20, description: "Short standard code. Optional if id is provided." },
4766
4948
  name: { type: "string", minLength: 3, maxLength: 255 },
4767
4949
  content: { type: "string", minLength: 10 },
4768
4950
  parent_id: { type: "string", format: "uuid", nullable: true },
@@ -4777,8 +4959,7 @@ var TOOL_DEFINITIONS = [
4777
4959
  agent: { type: "string" },
4778
4960
  model: { type: "string" },
4779
4961
  structured: { type: "boolean", default: false }
4780
- },
4781
- required: ["id"]
4962
+ }
4782
4963
  },
4783
4964
  outputSchema: {
4784
4965
  type: "object",
@@ -5373,6 +5554,369 @@ async function completePromptArgument(name, argName, value, contextArguments, da
5373
5554
  return [];
5374
5555
  }
5375
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
+
5376
5920
  // src/mcp/tools/standard.shared.ts
5377
5921
  function toContextSlug(value) {
5378
5922
  return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -5414,17 +5958,12 @@ export {
5414
5958
  TaskCreateInteractiveSchema,
5415
5959
  TaskUpdateSchema,
5416
5960
  TaskListSchema,
5961
+ TaskSearchSchema,
5417
5962
  TaskDeleteSchema,
5418
5963
  MemoryDetailSchema,
5419
5964
  StandardDetailSchema,
5420
5965
  StandardDeleteSchema,
5421
5966
  TaskGetSchema,
5422
- HandoffCreateSchema,
5423
- HandoffUpdateSchema,
5424
- HandoffListSchema,
5425
- TaskClaimSchema,
5426
- ClaimListSchema,
5427
- ClaimReleaseSchema,
5428
5967
  StandardStoreSchema,
5429
5968
  StandardUpdateSchema,
5430
5969
  StandardSearchSchema,
@@ -5447,6 +5986,14 @@ export {
5447
5986
  listPrompts,
5448
5987
  getPrompt,
5449
5988
  completePromptArgument,
5989
+ createMcpResponse,
5990
+ getPrimaryTextContent,
5991
+ handleHandoffCreate,
5992
+ handleHandoffList,
5993
+ handleHandoffUpdate,
5994
+ handleTaskClaim,
5995
+ handleClaimList,
5996
+ handleClaimRelease,
5450
5997
  toContextSlug,
5451
5998
  buildStandardVectorText
5452
5999
  };