@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.
- package/dist/{chunk-CSEGUZWJ.js → chunk-GAZNK32C.js} +297 -46
- package/dist/dashboard/public/assets/index-C2cM-UXM.css +1 -0
- package/dist/dashboard/public/assets/index-D-xKLFFr.js +86 -0
- package/dist/dashboard/public/index.html +2 -2
- package/dist/dashboard/server.js +109 -53
- package/dist/mcp/server.js +112 -3
- package/dist/prompts/create-task.md +7 -1
- package/dist/prompts/memory-agent-core.md +1 -1
- package/dist/prompts/project-briefing.md +2 -1
- package/dist/prompts/review-and-audit.md +1 -0
- package/dist/prompts/session-planner.md +2 -1
- package/dist/prompts/task-management-guidelines.md +5 -2
- package/dist/prompts/task-memory-executor.md +2 -1
- package/dist/prompts/tool-usage-guidelines.md +4 -2
- package/package.json +1 -1
- package/dist/dashboard/public/assets/index-C9M1BD7U.js +0 -86
- package/dist/dashboard/public/assets/index-CNE1bKgp.css +0 -1
|
@@ -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.
|
|
7
|
-
pkgVersion = "0.9.
|
|
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
|
|
1870
|
+
WHERE ${repoWhere}
|
|
1839
1871
|
AND status = 'completed'
|
|
1840
1872
|
${dateFilter}`,
|
|
1841
|
-
|
|
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(
|
|
1848
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
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.
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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,
|