@vheins/local-memory-mcp 0.9.8 → 0.9.10

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.
@@ -3,8 +3,8 @@ import { fileURLToPath } from "url";
3
3
  import path from "path";
4
4
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
5
5
  var pkgVersion = "0.1.0";
6
- if ("0.9.8") {
7
- pkgVersion = "0.9.8";
6
+ if ("0.9.10") {
7
+ pkgVersion = "0.9.10";
8
8
  } else {
9
9
  let searchDir = __dirname;
10
10
  for (let i = 0; i < 5; i++) {
@@ -981,6 +981,17 @@ var BaseEntity = class {
981
981
  depends_on: r.depends_on || null,
982
982
  parent_code: r.parent_code || null,
983
983
  depends_on_code: r.depends_on_code || null,
984
+ coordination: {
985
+ active_claim_count: r.active_claim_count || 0,
986
+ active_claim_agent: r.active_claim_agent || null,
987
+ active_claim_role: r.active_claim_role || null,
988
+ active_claim_claimed_at: r.active_claim_claimed_at || null,
989
+ pending_handoff_count: r.pending_handoff_count || 0,
990
+ pending_handoff_id: r.pending_handoff_id || null,
991
+ pending_handoff_summary: r.pending_handoff_summary || null,
992
+ pending_handoff_to_agent: r.pending_handoff_to_agent || null,
993
+ pending_handoff_created_at: r.pending_handoff_created_at || null
994
+ },
984
995
  comments_count: r.comments_count || 0
985
996
  };
986
997
  }
@@ -1446,6 +1457,19 @@ var MemoryEntity = class extends BaseEntity {
1446
1457
 
1447
1458
  // src/mcp/entities/task.ts
1448
1459
  var TaskEntity = class extends BaseEntity {
1460
+ coordinationSelect(alias = "t") {
1461
+ return `
1462
+ (SELECT COUNT(*) FROM claims c WHERE c.task_id = ${alias}.id AND c.released_at IS NULL) as active_claim_count,
1463
+ (SELECT c.agent FROM claims c WHERE c.task_id = ${alias}.id AND c.released_at IS NULL ORDER BY c.claimed_at DESC LIMIT 1) as active_claim_agent,
1464
+ (SELECT c.role FROM claims c WHERE c.task_id = ${alias}.id AND c.released_at IS NULL ORDER BY c.claimed_at DESC LIMIT 1) as active_claim_role,
1465
+ (SELECT c.claimed_at FROM claims c WHERE c.task_id = ${alias}.id AND c.released_at IS NULL ORDER BY c.claimed_at DESC LIMIT 1) as active_claim_claimed_at,
1466
+ (SELECT COUNT(*) FROM handoffs h WHERE h.task_id = ${alias}.id AND h.status = 'pending') as pending_handoff_count,
1467
+ (SELECT h.id FROM handoffs h WHERE h.task_id = ${alias}.id AND h.status = 'pending' ORDER BY h.created_at DESC LIMIT 1) as pending_handoff_id,
1468
+ (SELECT h.summary FROM handoffs h WHERE h.task_id = ${alias}.id AND h.status = 'pending' ORDER BY h.created_at DESC LIMIT 1) as pending_handoff_summary,
1469
+ (SELECT h.to_agent FROM handoffs h WHERE h.task_id = ${alias}.id AND h.status = 'pending' ORDER BY h.created_at DESC LIMIT 1) as pending_handoff_to_agent,
1470
+ (SELECT h.created_at FROM handoffs h WHERE h.task_id = ${alias}.id AND h.status = 'pending' ORDER BY h.created_at DESC LIMIT 1) as pending_handoff_created_at
1471
+ `;
1472
+ }
1449
1473
  insertTask(task) {
1450
1474
  this.run(
1451
1475
  `INSERT INTO tasks (
@@ -1524,7 +1548,8 @@ var TaskEntity = class extends BaseEntity {
1524
1548
  }
1525
1549
  getTaskById(id) {
1526
1550
  const row = this.get(
1527
- `SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code
1551
+ `SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code,
1552
+ ${this.coordinationSelect("t")}
1528
1553
  FROM tasks t
1529
1554
  LEFT JOIN tasks d ON t.depends_on = d.id
1530
1555
  LEFT JOIN tasks p ON t.parent_id = p.id
@@ -1538,6 +1563,7 @@ var TaskEntity = class extends BaseEntity {
1538
1563
  const placeholders = ids.map(() => "?").join(",");
1539
1564
  const rows = this.all(
1540
1565
  `SELECT t.*, d.task_code as depends_on_code,
1566
+ ${this.coordinationSelect("t")},
1541
1567
  (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1542
1568
  FROM tasks t
1543
1569
  LEFT JOIN tasks d ON t.depends_on = d.id
@@ -1563,7 +1589,8 @@ var TaskEntity = class extends BaseEntity {
1563
1589
  }
1564
1590
  getTaskByCode(repo, taskCode) {
1565
1591
  const row = this.get(
1566
- `SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code
1592
+ `SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code,
1593
+ ${this.coordinationSelect("t")}
1567
1594
  FROM tasks t
1568
1595
  LEFT JOIN tasks d ON t.depends_on = d.id
1569
1596
  LEFT JOIN tasks p ON t.parent_id = p.id
@@ -1575,6 +1602,7 @@ var TaskEntity = class extends BaseEntity {
1575
1602
  getTasksByRepo(repo, status, limit, offset, search) {
1576
1603
  let query = `
1577
1604
  SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code,
1605
+ ${this.coordinationSelect("t")},
1578
1606
  (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1579
1607
  FROM tasks t
1580
1608
  LEFT JOIN tasks d ON t.depends_on = d.id
@@ -1631,6 +1659,7 @@ var TaskEntity = class extends BaseEntity {
1631
1659
  listRecentTasks(limit = 50, offset = 0) {
1632
1660
  const query = `
1633
1661
  SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code,
1662
+ ${this.coordinationSelect("t")},
1634
1663
  (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1635
1664
  FROM tasks t
1636
1665
  LEFT JOIN tasks d ON t.depends_on = d.id
@@ -1656,6 +1685,7 @@ var TaskEntity = class extends BaseEntity {
1656
1685
  if (!statuses.length) return this.getTasksByRepo(repo, void 0, limit, offset, search);
1657
1686
  let query = `
1658
1687
  SELECT t.*, d.task_code as depends_on_code, p.task_code as parent_code,
1688
+ ${this.coordinationSelect("t")},
1659
1689
  (SELECT COUNT(*) FROM task_comments WHERE task_id = t.id) as comments_count
1660
1690
  FROM tasks t
1661
1691
  LEFT JOIN tasks d ON t.depends_on = d.id
@@ -1823,6 +1853,8 @@ var TaskEntity = class extends BaseEntity {
1823
1853
  else if (period === "weekly") dateFilter = "AND date(COALESCE(finished_at, updated_at)) >= date('now', '-7 days')";
1824
1854
  else if (period === "monthly")
1825
1855
  dateFilter = "AND date(COALESCE(finished_at, updated_at)) >= date('now', '-30 days')";
1856
+ const repoWhere = repo ? "repo = ?" : "1=1";
1857
+ const repoParams = repo ? [repo] : [];
1826
1858
  const stats = this.get(
1827
1859
  `SELECT
1828
1860
  COUNT(*) as completed_count,
@@ -1835,18 +1867,19 @@ var TaskEntity = class extends BaseEntity {
1835
1867
  END
1836
1868
  ) as avg_duration_seconds
1837
1869
  FROM tasks
1838
- WHERE repo = ?
1870
+ WHERE ${repoWhere}
1839
1871
  AND status = 'completed'
1840
1872
  ${dateFilter}`,
1841
- [repo]
1873
+ repoParams
1842
1874
  );
1843
1875
  let addedDateFilter = "";
1844
1876
  if (period === "daily") addedDateFilter = "AND date(created_at) = date('now')";
1845
1877
  else if (period === "weekly") addedDateFilter = "AND date(created_at) >= date('now', '-7 days')";
1846
1878
  else if (period === "monthly") addedDateFilter = "AND date(created_at) >= date('now', '-30 days')";
1847
- const added = this.get(`SELECT COUNT(*) as count FROM tasks WHERE repo = ? ${addedDateFilter}`, [
1848
- repo
1849
- ]);
1879
+ const added = this.get(
1880
+ `SELECT COUNT(*) as count FROM tasks WHERE ${repoWhere} ${addedDateFilter}`,
1881
+ repoParams
1882
+ );
1850
1883
  const avgDurationMinutes = stats?.avg_duration_seconds ? stats.avg_duration_seconds / 60 : 0;
1851
1884
  return {
1852
1885
  completed: stats?.completed_count || 0,
@@ -1871,27 +1904,30 @@ var TaskEntity = class extends BaseEntity {
1871
1904
  labelFormat = "%Y-%m";
1872
1905
  dateFilter = "1=1";
1873
1906
  }
1907
+ const createdDateFilter = dateFilter.replace("COALESCE(finished_at, created_at)", "created_at");
1908
+ const completedDateFilter = dateFilter.replace("COALESCE(finished_at, created_at)", "COALESCE(finished_at, updated_at)");
1909
+ const createdRepoFilter = repo ? "repo = ? AND " : "";
1910
+ const completedRepoFilter = repo ? "repo = ? AND " : "";
1874
1911
  const query = `
1875
1912
  SELECT label, SUM(created) as created, SUM(completed) as completed
1876
1913
  FROM (
1877
1914
  SELECT strftime(?, created_at) as label, 1 as created, 0 as completed
1878
1915
  FROM tasks
1879
- WHERE repo = ? AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "created_at")}
1916
+ WHERE ${createdRepoFilter}${createdDateFilter}
1880
1917
  UNION ALL
1881
1918
  SELECT strftime(?, COALESCE(finished_at, updated_at)) as label, 0 as created, 1 as completed
1882
1919
  FROM tasks
1883
- WHERE repo = ? AND status = 'completed' AND ${dateFilter.replace("COALESCE(finished_at, created_at)", "COALESCE(finished_at, updated_at)")}
1920
+ WHERE ${completedRepoFilter}status = 'completed' AND ${completedDateFilter}
1884
1921
  )
1885
1922
  GROUP BY label
1886
1923
  ORDER BY label ASC
1887
1924
  LIMIT 100
1888
1925
  `;
1889
- return this.all(query, [
1890
- labelFormat,
1891
- repo,
1892
- labelFormat,
1893
- repo
1894
- ]);
1926
+ const params = [labelFormat];
1927
+ if (repo) params.push(repo);
1928
+ params.push(labelFormat);
1929
+ if (repo) params.push(repo);
1930
+ return this.all(query, params);
1895
1931
  }
1896
1932
  };
1897
1933
 
@@ -1983,12 +2019,49 @@ var ActionEntity = class extends BaseEntity {
1983
2019
 
1984
2020
  // src/mcp/entities/system.ts
1985
2021
  var SystemEntity = class extends BaseEntity {
2022
+ buildTaskStats(rows) {
2023
+ const taskStats = {
2024
+ total: 0,
2025
+ backlog: 0,
2026
+ pending: 0,
2027
+ in_progress: 0,
2028
+ completed: 0,
2029
+ blocked: 0,
2030
+ canceled: 0
2031
+ };
2032
+ rows.forEach((r) => {
2033
+ taskStats.total += r.count;
2034
+ if (r.status === "backlog") taskStats.backlog = r.count;
2035
+ else if (r.status === "pending") taskStats.pending = r.count;
2036
+ else if (r.status === "in_progress") taskStats.in_progress = r.count;
2037
+ else if (r.status === "completed") taskStats.completed = r.count;
2038
+ else if (r.status === "blocked") taskStats.blocked = r.count;
2039
+ else if (r.status === "canceled") taskStats.canceled = r.count;
2040
+ });
2041
+ return taskStats;
2042
+ }
1986
2043
  listRepos() {
1987
2044
  const rows = this.all("SELECT DISTINCT repo FROM memories UNION SELECT DISTINCT repo FROM tasks");
1988
2045
  return rows.map((r) => r.repo);
1989
2046
  }
1990
2047
  listRepoNavigation() {
1991
2048
  const repos = this.listRepos();
2049
+ const activeClaimRows = this.all(
2050
+ "SELECT repo, COUNT(*) as count FROM claims WHERE released_at IS NULL GROUP BY repo"
2051
+ );
2052
+ const pendingHandoffRows = this.all(
2053
+ "SELECT repo, COUNT(*) as count FROM handoffs WHERE status = 'pending' GROUP BY repo"
2054
+ );
2055
+ const unassignedHandoffRows = this.all(
2056
+ "SELECT repo, COUNT(*) as count FROM handoffs WHERE status = 'pending' AND to_agent IS NULL GROUP BY repo"
2057
+ );
2058
+ const staleClaimRows = this.all(
2059
+ "SELECT repo, COUNT(*) as count FROM claims WHERE released_at IS NULL AND claimed_at <= datetime('now', '-1 day') GROUP BY repo"
2060
+ );
2061
+ const activeClaimsByRepo = Object.fromEntries(activeClaimRows.map((row) => [row.repo, row.count]));
2062
+ const pendingHandoffsByRepo = Object.fromEntries(pendingHandoffRows.map((row) => [row.repo, row.count]));
2063
+ const unassignedHandoffsByRepo = Object.fromEntries(unassignedHandoffRows.map((row) => [row.repo, row.count]));
2064
+ const staleClaimsByRepo = Object.fromEntries(staleClaimRows.map((row) => [row.repo, row.count]));
1992
2065
  return repos.map((repo) => {
1993
2066
  const memoryCountRow = this.get("SELECT COUNT(*) as count FROM memories WHERE repo = ?", [
1994
2067
  repo
@@ -2014,7 +2087,11 @@ var SystemEntity = class extends BaseEntity {
2014
2087
  pendingCount: taskStatusMap["pending"] ?? 0,
2015
2088
  blockedCount: taskStatusMap["blocked"] ?? 0,
2016
2089
  backlogCount: taskStatusMap["backlog"] ?? 0,
2017
- lastActivity: lastActivityRow?.last ?? null
2090
+ lastActivity: lastActivityRow?.last ?? null,
2091
+ activeClaims: activeClaimsByRepo[repo] ?? 0,
2092
+ pendingHandoffs: pendingHandoffsByRepo[repo] ?? 0,
2093
+ unassignedHandoffs: unassignedHandoffsByRepo[repo] ?? 0,
2094
+ staleClaims: staleClaimsByRepo[repo] ?? 0
2018
2095
  };
2019
2096
  });
2020
2097
  }
@@ -2043,28 +2120,14 @@ var SystemEntity = class extends BaseEntity {
2043
2120
  "SELECT status, COUNT(*) as count FROM tasks WHERE repo = ? GROUP BY status",
2044
2121
  [repo]
2045
2122
  );
2046
- const taskStats = {
2047
- total: 0,
2048
- backlog: 0,
2049
- todo: 0,
2050
- inProgress: 0,
2051
- completed: 0,
2052
- blocked: 0
2053
- };
2054
- taskRows.forEach((r) => {
2055
- taskStats.total += r.count;
2056
- if (r.status === "backlog") taskStats.backlog = r.count;
2057
- else if (r.status === "pending") taskStats.todo = r.count;
2058
- else if (r.status === "in_progress") taskStats.inProgress = r.count;
2059
- else if (r.status === "completed") taskStats.completed = r.count;
2060
- else if (r.status === "blocked") taskStats.blocked = r.count;
2061
- });
2123
+ const taskStats = this.buildTaskStats(taskRows);
2062
2124
  const topMemoriesRows = this.all(
2063
2125
  "SELECT * FROM memories WHERE repo = ? ORDER BY importance DESC, created_at DESC LIMIT 5",
2064
2126
  [repo]
2065
2127
  );
2066
2128
  const topMemories = topMemoriesRows.map((r) => this.rowToMemoryEntry(r));
2067
2129
  return {
2130
+ scope: "repo",
2068
2131
  total: totalCountRow?.count ?? 0,
2069
2132
  avgImportance: (avgImportanceRow?.avg ?? 0).toFixed(1),
2070
2133
  totalHitCount: totalHitCountRow?.count ?? 0,
@@ -2074,6 +2137,64 @@ var SystemEntity = class extends BaseEntity {
2074
2137
  topMemories
2075
2138
  };
2076
2139
  }
2140
+ getGlobalDashboardStats() {
2141
+ const totalCountRow = this.get("SELECT COUNT(*) as count FROM memories");
2142
+ const avgImportanceRow = this.get("SELECT AVG(importance) as avg FROM memories");
2143
+ const totalHitCountRow = this.get("SELECT SUM(hit_count) as count FROM memories");
2144
+ const expiringSoonRow = this.get(
2145
+ "SELECT COUNT(*) as count FROM memories WHERE expires_at IS NOT NULL AND expires_at > ? AND expires_at <= ?",
2146
+ [(/* @__PURE__ */ new Date()).toISOString(), new Date(Date.now() + 7 * 86400 * 1e3).toISOString()]
2147
+ );
2148
+ const typeStats = this.all("SELECT type, COUNT(*) as count FROM memories GROUP BY type");
2149
+ const taskRows = this.all("SELECT status, COUNT(*) as count FROM tasks GROUP BY status");
2150
+ const repos = this.listRepoNavigation().sort((a, b) => {
2151
+ const pressureA = a.blockedCount * 5 + a.inProgressCount * 3 + a.pendingCount * 2 + a.pendingHandoffs * 2 + a.activeClaims;
2152
+ const pressureB = b.blockedCount * 5 + b.inProgressCount * 3 + b.pendingCount * 2 + b.pendingHandoffs * 2 + b.activeClaims;
2153
+ return pressureB - pressureA || (b.taskCount || 0) - (a.taskCount || 0);
2154
+ });
2155
+ const byType = {};
2156
+ typeStats.forEach((t) => {
2157
+ byType[t.type] = t.count;
2158
+ });
2159
+ const activeClaimsRow = this.get(
2160
+ "SELECT COUNT(*) as count FROM claims WHERE released_at IS NULL"
2161
+ );
2162
+ const agentsClaimingRow = this.get(
2163
+ "SELECT COUNT(DISTINCT agent) as count FROM claims WHERE released_at IS NULL"
2164
+ );
2165
+ const pendingHandoffsRow = this.get(
2166
+ "SELECT COUNT(*) as count FROM handoffs WHERE status = 'pending'"
2167
+ );
2168
+ const unassignedHandoffsRow = this.get(
2169
+ "SELECT COUNT(*) as count FROM handoffs WHERE status = 'pending' AND to_agent IS NULL"
2170
+ );
2171
+ const staleClaimsRow = this.get(
2172
+ "SELECT COUNT(*) as count FROM claims WHERE released_at IS NULL AND claimed_at <= datetime('now', '-1 day')"
2173
+ );
2174
+ const staleHandoffsRow = this.get(
2175
+ "SELECT COUNT(*) as count FROM handoffs WHERE status = 'pending' AND created_at <= datetime('now', '-1 day')"
2176
+ );
2177
+ return {
2178
+ scope: "global",
2179
+ total: totalCountRow?.count ?? 0,
2180
+ avgImportance: (avgImportanceRow?.avg ?? 0).toFixed(1),
2181
+ totalHitCount: totalHitCountRow?.count ?? 0,
2182
+ expiringSoon: expiringSoonRow?.count ?? 0,
2183
+ byType,
2184
+ taskStats: this.buildTaskStats(taskRows),
2185
+ repoCount: repos.length,
2186
+ activeRepoCount: repos.filter((repo) => repo.inProgressCount > 0 || repo.pendingCount > 0 || repo.blockedCount > 0).length,
2187
+ coordination: {
2188
+ activeClaims: activeClaimsRow?.count ?? 0,
2189
+ agentsClaiming: agentsClaimingRow?.count ?? 0,
2190
+ pendingHandoffs: pendingHandoffsRow?.count ?? 0,
2191
+ unassignedHandoffs: unassignedHandoffsRow?.count ?? 0,
2192
+ staleClaims: staleClaimsRow?.count ?? 0,
2193
+ staleHandoffs: staleHandoffsRow?.count ?? 0
2194
+ },
2195
+ repos
2196
+ };
2197
+ }
2077
2198
  getGlobalStats() {
2078
2199
  const totalMemoriesRow = this.get("SELECT COUNT(*) as count FROM memories");
2079
2200
  const totalTasksRow = this.get("SELECT COUNT(*) as count FROM tasks");
@@ -2368,6 +2489,7 @@ var HandoffEntity = class extends BaseEntity {
2368
2489
  from_agent: row.from_agent,
2369
2490
  to_agent: row.to_agent ?? null,
2370
2491
  task_id: row.task_id ?? null,
2492
+ task_code: "task_code" in row ? row.task_code ?? null : null,
2371
2493
  summary: row.summary,
2372
2494
  context: this.safeJSONParse(row.context, {}),
2373
2495
  status: row.status,
@@ -2381,6 +2503,7 @@ var HandoffEntity = class extends BaseEntity {
2381
2503
  id: row.id,
2382
2504
  repo: row.repo,
2383
2505
  task_id: row.task_id,
2506
+ task_code: "task_code" in row ? row.task_code ?? null : null,
2384
2507
  agent: row.agent,
2385
2508
  role: row.role,
2386
2509
  claimed_at: row.claimed_at,
@@ -2408,7 +2531,7 @@ var HandoffEntity = class extends BaseEntity {
2408
2531
  params.expires_at ?? null
2409
2532
  ]
2410
2533
  );
2411
- return this.rowToHandoff(this.get("SELECT * FROM handoffs WHERE id = ?", [id]));
2534
+ return this.getHandoffById(id);
2412
2535
  }
2413
2536
  listHandoffs(params) {
2414
2537
  const conditions = ["repo = ?"];
@@ -2429,13 +2552,23 @@ var HandoffEntity = class extends BaseEntity {
2429
2552
  const offset = params.offset ?? 0;
2430
2553
  values.push(limit, offset);
2431
2554
  const rows = this.all(
2432
- `SELECT * FROM handoffs WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
2555
+ `SELECT h.*, t.task_code
2556
+ FROM handoffs h
2557
+ LEFT JOIN tasks t ON h.task_id = t.id
2558
+ WHERE ${conditions.map((condition) => condition.replace(/\brepo\b/g, "h.repo").replace(/\bstatus\b/g, "h.status").replace(/\bto_agent\b/g, "h.to_agent").replace(/\bfrom_agent\b/g, "h.from_agent")).join(" AND ")}
2559
+ ORDER BY h.created_at DESC LIMIT ? OFFSET ?`,
2433
2560
  values
2434
2561
  );
2435
2562
  return rows.map((r) => this.rowToHandoff(r));
2436
2563
  }
2437
2564
  getHandoffById(id) {
2438
- const row = this.get("SELECT * FROM handoffs WHERE id = ?", [id]);
2565
+ const row = this.get(
2566
+ `SELECT h.*, t.task_code
2567
+ FROM handoffs h
2568
+ LEFT JOIN tasks t ON h.task_id = t.id
2569
+ WHERE h.id = ?`,
2570
+ [id]
2571
+ );
2439
2572
  return row ? this.rowToHandoff(row) : null;
2440
2573
  }
2441
2574
  updateHandoffStatus(id, status) {
@@ -2473,11 +2606,23 @@ var HandoffEntity = class extends BaseEntity {
2473
2606
  JSON.stringify(params.metadata ?? {})
2474
2607
  ]
2475
2608
  );
2476
- return this.rowToClaim(this.get("SELECT * FROM claims WHERE id = ?", [id]));
2609
+ return this.rowToClaim(
2610
+ this.get(
2611
+ `SELECT c.*, t.task_code
2612
+ FROM claims c
2613
+ LEFT JOIN tasks t ON c.task_id = t.id
2614
+ WHERE c.id = ?`,
2615
+ [id]
2616
+ )
2617
+ );
2477
2618
  }
2478
2619
  getClaim(task_id) {
2479
2620
  const row = this.get(
2480
- "SELECT * FROM claims WHERE task_id = ? AND released_at IS NULL ORDER BY claimed_at DESC LIMIT 1",
2621
+ `SELECT c.*, t.task_code
2622
+ FROM claims c
2623
+ LEFT JOIN tasks t ON c.task_id = t.id
2624
+ WHERE c.task_id = ? AND c.released_at IS NULL
2625
+ ORDER BY c.claimed_at DESC LIMIT 1`,
2481
2626
  [task_id]
2482
2627
  );
2483
2628
  return row ? this.rowToClaim(row) : null;
@@ -2514,7 +2659,11 @@ var HandoffEntity = class extends BaseEntity {
2514
2659
  const offset = params.offset ?? 0;
2515
2660
  values.push(limit, offset);
2516
2661
  const rows = this.all(
2517
- `SELECT * FROM claims WHERE ${conditions.join(" AND ")} ORDER BY claimed_at DESC LIMIT ? OFFSET ?`,
2662
+ `SELECT c.*, t.task_code
2663
+ FROM claims c
2664
+ LEFT JOIN tasks t ON c.task_id = t.id
2665
+ WHERE ${conditions.map((condition) => condition.replace(/\brepo\b/g, "c.repo").replace(/\bagent\b/g, "c.agent").replace(/released_at/g, "c.released_at")).join(" AND ")}
2666
+ ORDER BY c.claimed_at DESC LIMIT ? OFFSET ?`,
2518
2667
  values
2519
2668
  );
2520
2669
  return rows.map((r) => this.rowToClaim(r));
@@ -3192,6 +3341,25 @@ var TaskClaimSchema = z.object({
3192
3341
  }).refine((data) => !(data.task_id && data.task_code), {
3193
3342
  message: "Provide either task_id or task_code, not both"
3194
3343
  });
3344
+ var ClaimListSchema = z.object({
3345
+ repo: z.string().min(1).transform(normalizeRepo),
3346
+ agent: z.string().min(1).optional(),
3347
+ active_only: z.boolean().default(true),
3348
+ limit: z.number().min(1).max(100).default(20),
3349
+ offset: z.number().min(0).default(0),
3350
+ structured: z.boolean().default(false)
3351
+ });
3352
+ var ClaimReleaseSchema = z.object({
3353
+ repo: z.string().min(1).transform(normalizeRepo),
3354
+ task_id: z.string().uuid().optional(),
3355
+ task_code: z.string().optional(),
3356
+ agent: z.string().min(1).optional(),
3357
+ structured: z.boolean().default(false)
3358
+ }).refine((data) => data.task_id !== void 0 || data.task_code !== void 0, {
3359
+ message: "Either task_id or task_code must be provided"
3360
+ }).refine((data) => !(data.task_id && data.task_code), {
3361
+ message: "Provide either task_id or task_code, not both"
3362
+ });
3195
3363
  var StandardStoreSchema = z.object({
3196
3364
  name: z.string().min(3).max(255),
3197
3365
  content: z.string().min(10),
@@ -3318,7 +3486,7 @@ var TOOL_DEFINITIONS = [
3318
3486
  title: { type: "string", minLength: 3, maxLength: 100 },
3319
3487
  description: { type: "string", minLength: 1 },
3320
3488
  status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3321
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
3489
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3, description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical." },
3322
3490
  agent: { type: "string" },
3323
3491
  role: { type: "string" },
3324
3492
  doc_path: { type: "string" },
@@ -3854,7 +4022,7 @@ var TOOL_DEFINITIONS = [
3854
4022
  default: "backlog",
3855
4023
  description: "New tasks MUST start in 'backlog' if there are already 10 pending tasks. Otherwise can start in 'pending'."
3856
4024
  },
3857
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
4025
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3, description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical." },
3858
4026
  agent: { type: "string" },
3859
4027
  role: { type: "string" },
3860
4028
  doc_path: { type: "string" },
@@ -3873,7 +4041,7 @@ var TOOL_DEFINITIONS = [
3873
4041
  title: { type: "string", minLength: 3, maxLength: 100 },
3874
4042
  description: { type: "string" },
3875
4043
  status: { type: "string", enum: ["backlog", "pending"], default: "backlog" },
3876
- priority: { type: "number", minimum: 1, maximum: 5, default: 3 },
4044
+ priority: { type: "number", minimum: 1, maximum: 5, default: 3, description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical." },
3877
4045
  agent: { type: "string" },
3878
4046
  role: { type: "string" },
3879
4047
  doc_path: { type: "string" },
@@ -3932,7 +4100,7 @@ var TOOL_DEFINITIONS = [
3932
4100
  enum: ["backlog", "pending", "in_progress", "completed", "canceled", "blocked"],
3933
4101
  description: "New status. Transitions from 'backlog', 'pending' or 'blocked' to 'completed' are NOT allowed."
3934
4102
  },
3935
- priority: { type: "number", minimum: 1, maximum: 5 },
4103
+ priority: { type: "number", minimum: 1, maximum: 5, description: "Task priority where 1=Low, 2=Normal, 3=Medium, 4=High, 5=Critical." },
3936
4104
  agent: { type: "string" },
3937
4105
  role: { type: "string" },
3938
4106
  model: { type: "string" },
@@ -4191,12 +4359,12 @@ var TOOL_DEFINITIONS = [
4191
4359
  columns: {
4192
4360
  type: "array",
4193
4361
  items: { type: "string" },
4194
- description: "Column names: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4362
+ description: "Column names: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
4195
4363
  },
4196
4364
  rows: {
4197
4365
  type: "array",
4198
4366
  items: { type: "array" },
4199
- description: "Each row: [id, from_agent, to_agent, task_id, status, created_at, summary]"
4367
+ description: "Each row: [id, from_agent, to_agent, task_id, task_code, status, created_at, updated_at, expires_at, summary, context]"
4200
4368
  }
4201
4369
  },
4202
4370
  required: ["columns", "rows"]
@@ -4246,6 +4414,87 @@ var TOOL_DEFINITIONS = [
4246
4414
  required: ["id", "repo", "task_id", "agent", "role", "claimed_at", "metadata"]
4247
4415
  }
4248
4416
  },
4417
+ {
4418
+ name: "claim-list",
4419
+ title: "Claim List",
4420
+ description: "List task claims in a repository. Use this to inspect active ownership, optionally filtered by agent.",
4421
+ annotations: {
4422
+ readOnlyHint: true,
4423
+ idempotentHint: true,
4424
+ destructiveHint: false,
4425
+ openWorldHint: false
4426
+ },
4427
+ inputSchema: {
4428
+ type: "object",
4429
+ properties: {
4430
+ repo: { type: "string", description: "Repository name" },
4431
+ agent: { type: "string", description: "Optional agent filter" },
4432
+ active_only: { type: "boolean", description: "When true, return only unreleased claims" },
4433
+ limit: { type: "number", minimum: 1, maximum: 100, default: 20 },
4434
+ offset: { type: "number", minimum: 0, default: 0 },
4435
+ structured: { type: "boolean", default: false }
4436
+ },
4437
+ required: ["repo"]
4438
+ },
4439
+ outputSchema: {
4440
+ type: "object",
4441
+ properties: {
4442
+ schema: { type: "string", enum: ["claim-list"] },
4443
+ claims: {
4444
+ type: "object",
4445
+ properties: {
4446
+ columns: {
4447
+ type: "array",
4448
+ items: { type: "string" },
4449
+ description: "Column names: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
4450
+ },
4451
+ rows: {
4452
+ type: "array",
4453
+ items: { type: "array" },
4454
+ description: "Each row: [id, task_id, task_code, agent, role, claimed_at, released_at, metadata]"
4455
+ }
4456
+ },
4457
+ required: ["columns", "rows"]
4458
+ },
4459
+ count: { type: "number" },
4460
+ offset: { type: "number" }
4461
+ },
4462
+ required: ["schema", "claims", "count", "offset"]
4463
+ }
4464
+ },
4465
+ {
4466
+ name: "claim-release",
4467
+ title: "Claim Release",
4468
+ description: "Release an active claim for a task. Optionally restrict the release to a specific agent.",
4469
+ annotations: {
4470
+ readOnlyHint: false,
4471
+ idempotentHint: false,
4472
+ destructiveHint: false,
4473
+ openWorldHint: false
4474
+ },
4475
+ inputSchema: {
4476
+ type: "object",
4477
+ properties: {
4478
+ repo: { type: "string", description: "Repository name" },
4479
+ task_id: { type: "string", format: "uuid", description: "Task id to release. Optional if task_code is provided." },
4480
+ task_code: { type: "string", description: "Task code to release. Optional if task_id is provided." },
4481
+ agent: { type: "string", description: "Optional agent name to release only that claim" },
4482
+ structured: { type: "boolean", default: false }
4483
+ },
4484
+ required: ["repo"]
4485
+ },
4486
+ outputSchema: {
4487
+ type: "object",
4488
+ properties: {
4489
+ success: { type: "boolean" },
4490
+ repo: { type: "string" },
4491
+ task_id: { type: "string" },
4492
+ task_code: { type: "string", nullable: true },
4493
+ agent: { type: "string", nullable: true }
4494
+ },
4495
+ required: ["success", "repo", "task_id"]
4496
+ }
4497
+ },
4249
4498
  {
4250
4499
  name: "standard-store",
4251
4500
  title: "Standard Store",
@@ -5054,6 +5303,8 @@ export {
5054
5303
  HandoffUpdateSchema,
5055
5304
  HandoffListSchema,
5056
5305
  TaskClaimSchema,
5306
+ ClaimListSchema,
5307
+ ClaimReleaseSchema,
5057
5308
  StandardStoreSchema,
5058
5309
  StandardUpdateSchema,
5059
5310
  StandardSearchSchema,