@hasna/todos 0.13.11 → 0.13.12
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/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/index.js +145 -95
- package/dist/contracts.js +92 -67
- package/dist/db/agent-metrics.d.ts.map +1 -1
- package/dist/db/audit.d.ts.map +1 -1
- package/dist/db/budgets.d.ts.map +1 -1
- package/dist/db/database.d.ts +44 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/handoffs.d.ts.map +1 -1
- package/dist/db/task-crud.d.ts +1 -0
- package/dist/db/task-crud.d.ts.map +1 -1
- package/dist/db/task-files.d.ts.map +1 -1
- package/dist/db/task-lifecycle.d.ts.map +1 -1
- package/dist/db/task-relations.d.ts.map +1 -1
- package/dist/db/task-status.d.ts.map +1 -1
- package/dist/db/webhooks.d.ts.map +1 -1
- package/dist/index.js +119 -85
- package/dist/lib/capacity-forecasts.d.ts.map +1 -1
- package/dist/lib/completion-guard.d.ts.map +1 -1
- package/dist/lib/local-notifications.d.ts.map +1 -1
- package/dist/lib/local-reports.d.ts.map +1 -1
- package/dist/lib/notification-reminders.d.ts.map +1 -1
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/usage-ledger.d.ts.map +1 -1
- package/dist/mcp/index.js +136 -92
- package/dist/mcp/tools/agents.d.ts.map +1 -1
- package/dist/mcp/tools/task-adv-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-resources.d.ts.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/registry.js +92 -67
- package/dist/release-provenance.json +5 -5
- package/dist/server/index.js +136 -92
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/storage.js +57 -42
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2123,7 +2123,7 @@ var package_default;
|
|
|
2123
2123
|
var init_package = __esm(() => {
|
|
2124
2124
|
package_default = {
|
|
2125
2125
|
name: "@hasna/todos",
|
|
2126
|
-
version: "0.13.
|
|
2126
|
+
version: "0.13.12",
|
|
2127
2127
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
2128
2128
|
type: "module",
|
|
2129
2129
|
main: "dist/index.js",
|
|
@@ -6045,8 +6045,10 @@ async function cloudEscalatedTasks(client, opts = {}, at = new Date) {
|
|
|
6045
6045
|
const filter = {};
|
|
6046
6046
|
if (opts.project_id)
|
|
6047
6047
|
filter.project_id = opts.project_id;
|
|
6048
|
+
if (opts.agent_id)
|
|
6049
|
+
filter.assigned_to = opts.agent_id;
|
|
6048
6050
|
const active = await cloudActiveTasks(client, filter);
|
|
6049
|
-
return active.filter((t) => !t.archived_at
|
|
6051
|
+
return active.filter((t) => !t.archived_at).map((task) => {
|
|
6050
6052
|
const reasons = [];
|
|
6051
6053
|
const breachedTimes = [];
|
|
6052
6054
|
if (task.due_at) {
|
|
@@ -6258,7 +6260,11 @@ async function cloudRecap(client, hours, projectId) {
|
|
|
6258
6260
|
const blocked = pending.filter((t) => blockedMap.has(t.id));
|
|
6259
6261
|
const sinceMs = new Date(since).getTime();
|
|
6260
6262
|
const agentSummaries = agents.map((agent) => {
|
|
6261
|
-
const
|
|
6263
|
+
const assignedName = agent.name?.toLowerCase();
|
|
6264
|
+
const owned = all.filter((t) => {
|
|
6265
|
+
const assignedTo = t.assigned_to?.toLowerCase();
|
|
6266
|
+
return assignedTo === agent.id.toLowerCase() || assignedName && assignedTo === assignedName || t.agent_id === agent.id;
|
|
6267
|
+
});
|
|
6262
6268
|
return {
|
|
6263
6269
|
name: agent.name,
|
|
6264
6270
|
completed_count: owned.filter((t) => t.status === "completed" && t.completed_at != null && t.completed_at > since).length,
|
|
@@ -10714,14 +10720,17 @@ var exports_database = {};
|
|
|
10714
10720
|
__export(exports_database, {
|
|
10715
10721
|
uuid: () => uuid,
|
|
10716
10722
|
resolvePartialId: () => resolvePartialId,
|
|
10723
|
+
resolveAssignedToAliases: () => resolveAssignedToAliases,
|
|
10717
10724
|
resetDatabase: () => resetDatabase,
|
|
10718
10725
|
now: () => now,
|
|
10726
|
+
lowerInClause: () => lowerInClause,
|
|
10719
10727
|
lockExpiryCutoff: () => lockExpiryCutoff,
|
|
10720
10728
|
isLockExpired: () => isLockExpired,
|
|
10721
10729
|
getDatabasePath: () => getDatabasePath,
|
|
10722
10730
|
getDatabase: () => getDatabase,
|
|
10723
10731
|
closeDatabase: () => closeDatabase,
|
|
10724
10732
|
clearExpiredLocks: () => clearExpiredLocks,
|
|
10733
|
+
assignedToAliasSet: () => assignedToAliasSet,
|
|
10725
10734
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
10726
10735
|
});
|
|
10727
10736
|
import { Database } from "bun:sqlite";
|
|
@@ -10950,6 +10959,33 @@ function resolvePartialId(db, table, partialId) {
|
|
|
10950
10959
|
}
|
|
10951
10960
|
return null;
|
|
10952
10961
|
}
|
|
10962
|
+
function resolveAssignedToAliases(db, ref) {
|
|
10963
|
+
const aliases = new Set([ref]);
|
|
10964
|
+
let agentId;
|
|
10965
|
+
try {
|
|
10966
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
10967
|
+
} catch (err) {
|
|
10968
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
10969
|
+
throw err;
|
|
10970
|
+
agentId = null;
|
|
10971
|
+
}
|
|
10972
|
+
if (agentId) {
|
|
10973
|
+
aliases.add(agentId);
|
|
10974
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
10975
|
+
if (row?.name)
|
|
10976
|
+
aliases.add(row.name);
|
|
10977
|
+
}
|
|
10978
|
+
return [...aliases];
|
|
10979
|
+
}
|
|
10980
|
+
function assignedToAliasSet(db, ref) {
|
|
10981
|
+
return new Set(resolveAssignedToAliases(db, ref).map((a) => a.toLowerCase()));
|
|
10982
|
+
}
|
|
10983
|
+
function lowerInClause(column, values, params) {
|
|
10984
|
+
if (values.length === 0)
|
|
10985
|
+
return "1=0";
|
|
10986
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
10987
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
10988
|
+
}
|
|
10953
10989
|
var LOCK_EXPIRY_MINUTES = 30, _db = null, _dbPath = null, ALLOWED_TABLES;
|
|
10954
10990
|
var init_database = __esm(() => {
|
|
10955
10991
|
init_schema();
|
|
@@ -11740,17 +11776,19 @@ function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
|
11740
11776
|
throw new CompletionGuardError(`Too fast: task was started ${Math.floor(elapsedSeconds)}s ago. Minimum work duration is ${config.min_work_seconds}s. Wait ${remaining}s.`, remaining);
|
|
11741
11777
|
}
|
|
11742
11778
|
}
|
|
11779
|
+
const assignedAliasParams = [];
|
|
11780
|
+
const assignedInClause = agent ? lowerInClause("assigned_to", resolveAssignedToAliases(db, agent), assignedAliasParams) : "";
|
|
11743
11781
|
if (agent && config.max_completions_per_window && config.window_minutes) {
|
|
11744
11782
|
const windowStart = new Date(Date.now() - config.window_minutes * 60 * 1000).toISOString();
|
|
11745
11783
|
const result = db.query(`SELECT COUNT(*) as count FROM tasks
|
|
11746
|
-
WHERE completed_at > ? AND (
|
|
11784
|
+
WHERE completed_at > ? AND (${assignedInClause} OR agent_id = ?)`).get(windowStart, ...assignedAliasParams, agent);
|
|
11747
11785
|
if (result.count >= config.max_completions_per_window) {
|
|
11748
11786
|
throw new CompletionGuardError(`Rate limit: ${result.count} tasks completed in the last ${config.window_minutes} minutes (max ${config.max_completions_per_window}). Slow down.`);
|
|
11749
11787
|
}
|
|
11750
11788
|
}
|
|
11751
11789
|
if (agent && config.cooldown_seconds) {
|
|
11752
11790
|
const result = db.query(`SELECT MAX(completed_at) as last_completed FROM tasks
|
|
11753
|
-
WHERE completed_at IS NOT NULL AND (
|
|
11791
|
+
WHERE completed_at IS NOT NULL AND (${assignedInClause} OR agent_id = ?) AND id != ?`).get(...assignedAliasParams, agent, task.id);
|
|
11754
11792
|
if (result.last_completed) {
|
|
11755
11793
|
const elapsedSeconds = (Date.now() - new Date(result.last_completed).getTime()) / 1000;
|
|
11756
11794
|
if (elapsedSeconds < config.cooldown_seconds) {
|
|
@@ -11764,6 +11802,7 @@ var init_completion_guard = __esm(() => {
|
|
|
11764
11802
|
init_types();
|
|
11765
11803
|
init_config();
|
|
11766
11804
|
init_projects();
|
|
11805
|
+
init_database();
|
|
11767
11806
|
});
|
|
11768
11807
|
|
|
11769
11808
|
// src/lib/event-emission-safety.ts
|
|
@@ -13862,7 +13901,7 @@ function getRecap(hours = 8, projectId, db) {
|
|
|
13862
13901
|
const in_progress = projectId ? d.query(`SELECT id, short_id, title, assigned_to, started_at FROM tasks WHERE status = 'in_progress' AND project_id = ? ORDER BY updated_at DESC`).all(projectId) : d.query(`SELECT id, short_id, title, assigned_to, started_at FROM tasks WHERE status = 'in_progress' ORDER BY updated_at DESC`).all();
|
|
13863
13902
|
const blocked = projectId ? d.query(`SELECT DISTINCT t.id, t.short_id, t.title, t.assigned_to FROM tasks t JOIN task_dependencies td ON td.task_id = t.id JOIN tasks dep ON dep.id = td.depends_on AND dep.status NOT IN ('completed','cancelled') WHERE t.status = 'pending'${tpf}`).all(projectId) : d.query(`SELECT DISTINCT t.id, t.short_id, t.title, t.assigned_to FROM tasks t JOIN task_dependencies td ON td.task_id = t.id JOIN tasks dep ON dep.id = td.depends_on AND dep.status NOT IN ('completed','cancelled') WHERE t.status = 'pending'`).all();
|
|
13864
13903
|
const stale = projectId ? d.query(`SELECT id, short_id, title, assigned_to, updated_at FROM tasks WHERE status = 'in_progress' AND updated_at < ? AND project_id = ? ORDER BY updated_at ASC`).all(staleWindow, projectId) : d.query(`SELECT id, short_id, title, assigned_to, updated_at FROM tasks WHERE status = 'in_progress' AND updated_at < ? ORDER BY updated_at ASC`).all(staleWindow);
|
|
13865
|
-
const agents = projectId ? d.query(`SELECT a.name, a.last_seen_at, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR t.agent_id = a.id) AND t.status = 'completed' AND t.completed_at > ?${tpf}) as completed_count, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR t.agent_id = a.id) AND t.status = 'in_progress'${tpf}) as in_progress_count FROM agents a WHERE a.status = 'active' AND a.last_seen_at > ? ORDER BY completed_count DESC`).all(since, projectId, projectId, since) : d.query(`SELECT a.name, a.last_seen_at, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR t.agent_id = a.id) AND t.status = 'completed' AND t.completed_at > ?) as completed_count, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR t.agent_id = a.id) AND t.status = 'in_progress') as in_progress_count FROM agents a WHERE a.status = 'active' AND a.last_seen_at > ? ORDER BY completed_count DESC`).all(since, since);
|
|
13904
|
+
const agents = projectId ? d.query(`SELECT a.name, a.last_seen_at, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name) OR t.agent_id = a.id) AND t.status = 'completed' AND t.completed_at > ?${tpf}) as completed_count, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name) OR t.agent_id = a.id) AND t.status = 'in_progress'${tpf}) as in_progress_count FROM agents a WHERE a.status = 'active' AND a.last_seen_at > ? ORDER BY completed_count DESC`).all(since, projectId, projectId, since) : d.query(`SELECT a.name, a.last_seen_at, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name) OR t.agent_id = a.id) AND t.status = 'completed' AND t.completed_at > ?) as completed_count, (SELECT COUNT(*) FROM tasks t WHERE (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name) OR t.agent_id = a.id) AND t.status = 'in_progress') as in_progress_count FROM agents a WHERE a.status = 'active' AND a.last_seen_at > ? ORDER BY completed_count DESC`).all(since, since);
|
|
13866
13905
|
return {
|
|
13867
13906
|
hours,
|
|
13868
13907
|
since,
|
|
@@ -14008,13 +14047,17 @@ function logDelivery(d, webhookId, event, payload, statusCode, response, attempt
|
|
|
14008
14047
|
const id = uuid();
|
|
14009
14048
|
d.run(`INSERT INTO webhook_deliveries (id, webhook_id, event, payload, status_code, response, attempt, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, webhookId, event, payload, statusCode, response, attempt, now()]);
|
|
14010
14049
|
}
|
|
14011
|
-
function matchesScope(wh, payload) {
|
|
14050
|
+
function matchesScope(wh, payload, db) {
|
|
14012
14051
|
if (wh.project_id && payload.project_id !== wh.project_id)
|
|
14013
14052
|
return false;
|
|
14014
14053
|
if (wh.task_list_id && payload.task_list_id !== wh.task_list_id)
|
|
14015
14054
|
return false;
|
|
14016
|
-
if (wh.agent_id && payload.agent_id !== wh.agent_id
|
|
14017
|
-
|
|
14055
|
+
if (wh.agent_id && payload.agent_id !== wh.agent_id) {
|
|
14056
|
+
const aliasSet = assignedToAliasSet(db, wh.agent_id);
|
|
14057
|
+
const assignedTo = typeof payload.assigned_to === "string" ? payload.assigned_to.toLowerCase() : "";
|
|
14058
|
+
if (!aliasSet.has(assignedTo))
|
|
14059
|
+
return false;
|
|
14060
|
+
}
|
|
14018
14061
|
if (wh.task_id && payload.id !== wh.task_id)
|
|
14019
14062
|
return false;
|
|
14020
14063
|
return true;
|
|
@@ -14081,7 +14124,7 @@ async function dispatchWebhook2(event, payload, db) {
|
|
|
14081
14124
|
const webhooks = listWebhooks(d).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
|
|
14082
14125
|
const payloadObj = typeof payload === "object" && payload !== null ? payload : {};
|
|
14083
14126
|
for (const wh of webhooks) {
|
|
14084
|
-
if (!matchesScope(wh, payloadObj))
|
|
14127
|
+
if (!matchesScope(wh, payloadObj, d))
|
|
14085
14128
|
continue;
|
|
14086
14129
|
const body = JSON.stringify({ event, payload, timestamp: now() });
|
|
14087
14130
|
deliverWebhook(wh, event, body, 1, d).catch((err) => {
|
|
@@ -15229,14 +15272,16 @@ function getNextTask(agentId, filters, db) {
|
|
|
15229
15272
|
conditions.push("id NOT IN (SELECT td.task_id FROM task_dependencies td JOIN tasks dep ON dep.id = td.depends_on WHERE dep.status != 'completed')");
|
|
15230
15273
|
const where = conditions.join(" AND ");
|
|
15231
15274
|
let recentProjectIds = [];
|
|
15275
|
+
const assignedAliasParams = [];
|
|
15276
|
+
const assignedInClause = agentId ? lowerInClause("assigned_to", resolveAssignedToAliases(d, agentId), assignedAliasParams) : "";
|
|
15232
15277
|
if (agentId) {
|
|
15233
|
-
const recentRows = d.query(`SELECT DISTINCT project_id FROM tasks WHERE
|
|
15278
|
+
const recentRows = d.query(`SELECT DISTINCT project_id FROM tasks WHERE ${assignedInClause} AND status = 'completed' AND project_id IS NOT NULL ORDER BY completed_at DESC LIMIT 3`).all(...assignedAliasParams);
|
|
15234
15279
|
recentProjectIds = recentRows.map((r) => r.project_id);
|
|
15235
15280
|
}
|
|
15236
15281
|
let sql = `SELECT * FROM tasks WHERE ${where} ORDER BY `;
|
|
15237
15282
|
if (agentId) {
|
|
15238
|
-
sql += `CASE WHEN
|
|
15239
|
-
params.push(
|
|
15283
|
+
sql += `CASE WHEN ${assignedInClause} THEN 0 WHEN assigned_to IS NULL THEN 1 ELSE 2 END, `;
|
|
15284
|
+
params.push(...assignedAliasParams);
|
|
15240
15285
|
}
|
|
15241
15286
|
if (recentProjectIds.length > 0) {
|
|
15242
15287
|
const placeholders = recentProjectIds.map(() => "?").join(",");
|
|
@@ -15630,30 +15675,6 @@ function getTaskWithRelations(id, db) {
|
|
|
15630
15675
|
checklist
|
|
15631
15676
|
};
|
|
15632
15677
|
}
|
|
15633
|
-
function resolveAssignedToAliases(db, ref) {
|
|
15634
|
-
const aliases = new Set([ref]);
|
|
15635
|
-
let agentId;
|
|
15636
|
-
try {
|
|
15637
|
-
agentId = resolvePartialId(db, "agents", ref);
|
|
15638
|
-
} catch (err) {
|
|
15639
|
-
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
15640
|
-
throw err;
|
|
15641
|
-
agentId = null;
|
|
15642
|
-
}
|
|
15643
|
-
if (agentId) {
|
|
15644
|
-
aliases.add(agentId);
|
|
15645
|
-
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
15646
|
-
if (row?.name)
|
|
15647
|
-
aliases.add(row.name);
|
|
15648
|
-
}
|
|
15649
|
-
return [...aliases];
|
|
15650
|
-
}
|
|
15651
|
-
function lowerInClause(column, values, params) {
|
|
15652
|
-
if (values.length === 0)
|
|
15653
|
-
return "1=0";
|
|
15654
|
-
params.push(...values.map((v) => v.toLowerCase()));
|
|
15655
|
-
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
15656
|
-
}
|
|
15657
15678
|
function listTasks(filter = {}, db) {
|
|
15658
15679
|
const d = db || getDatabase();
|
|
15659
15680
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -16126,6 +16147,7 @@ function deleteTask(id, db) {
|
|
|
16126
16147
|
var init_task_crud = __esm(() => {
|
|
16127
16148
|
init_types();
|
|
16128
16149
|
init_database();
|
|
16150
|
+
init_database();
|
|
16129
16151
|
init_completion_guard();
|
|
16130
16152
|
init_event_emission_safety();
|
|
16131
16153
|
init_event_hooks();
|
|
@@ -16288,8 +16310,8 @@ function getTaskStats(filters, db) {
|
|
|
16288
16310
|
params.push(filters.task_list_id);
|
|
16289
16311
|
}
|
|
16290
16312
|
if (filters?.agent_id) {
|
|
16291
|
-
|
|
16292
|
-
|
|
16313
|
+
params.push(filters.agent_id);
|
|
16314
|
+
conditions.push(`(agent_id = ? OR ${lowerInClause("assigned_to", resolveAssignedToAliases(d, filters.agent_id), params)})`);
|
|
16293
16315
|
}
|
|
16294
16316
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
16295
16317
|
const totalRow = d.query(`SELECT COUNT(*) as count FROM tasks ${where}`).get(...params);
|
|
@@ -16472,8 +16494,7 @@ function getEscalatedTasks(opts = {}, db, at = new Date) {
|
|
|
16472
16494
|
params.push(opts.project_id);
|
|
16473
16495
|
}
|
|
16474
16496
|
if (opts.agent_id) {
|
|
16475
|
-
conditions.push("assigned_to
|
|
16476
|
-
params.push(opts.agent_id);
|
|
16497
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
16477
16498
|
}
|
|
16478
16499
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC, created_at ASC`).all(...params);
|
|
16479
16500
|
return rows.map(rowToTask).map((task) => {
|
|
@@ -16521,8 +16542,7 @@ function notifyUpcomingDeadlines(opts = {}, db) {
|
|
|
16521
16542
|
params.push(opts.project_id);
|
|
16522
16543
|
}
|
|
16523
16544
|
if (opts.agent_id) {
|
|
16524
|
-
conditions.push("assigned_to
|
|
16525
|
-
params.push(opts.agent_id);
|
|
16545
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
16526
16546
|
}
|
|
16527
16547
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC`).all(...params);
|
|
16528
16548
|
return rows.map(rowToTask);
|
|
@@ -16780,13 +16800,14 @@ function getTimeReport(opts, db) {
|
|
|
16780
16800
|
params.push(opts.plan_id);
|
|
16781
16801
|
}
|
|
16782
16802
|
if (opts?.agent_id) {
|
|
16803
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.agent_id), params);
|
|
16783
16804
|
conditions.push(`(
|
|
16784
|
-
|
|
16805
|
+
${assignedInClause}
|
|
16785
16806
|
OR t.agent_id = ?
|
|
16786
16807
|
OR EXISTS (SELECT 1 FROM task_time_logs ttl WHERE ttl.task_id = t.id AND ttl.agent_id = ?)
|
|
16787
16808
|
OR EXISTS (SELECT 1 FROM focus_sessions fs WHERE fs.task_id = t.id AND fs.agent_id = ?)
|
|
16788
16809
|
)`);
|
|
16789
|
-
params.push(opts.agent_id, opts.agent_id, opts.agent_id
|
|
16810
|
+
params.push(opts.agent_id, opts.agent_id, opts.agent_id);
|
|
16790
16811
|
}
|
|
16791
16812
|
if (opts?.since) {
|
|
16792
16813
|
conditions.push("(t.completed_at >= ? OR t.updated_at >= ?)");
|
|
@@ -17799,7 +17820,7 @@ function listActiveFiles(db) {
|
|
|
17799
17820
|
a.name AS agent_name
|
|
17800
17821
|
FROM task_files tf
|
|
17801
17822
|
JOIN tasks t ON tf.task_id = t.id
|
|
17802
|
-
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND t.assigned_to = a.id))
|
|
17823
|
+
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name))))
|
|
17803
17824
|
WHERE t.status = 'in_progress'
|
|
17804
17825
|
AND tf.status != 'removed'
|
|
17805
17826
|
ORDER BY tf.updated_at DESC
|
|
@@ -23368,8 +23389,7 @@ function searchTasks(options, projectId, taskListId, db) {
|
|
|
23368
23389
|
}
|
|
23369
23390
|
}
|
|
23370
23391
|
if (opts.assigned_to) {
|
|
23371
|
-
sql +=
|
|
23372
|
-
params.push(opts.assigned_to);
|
|
23392
|
+
sql += ` AND ${lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.assigned_to), params)}`;
|
|
23373
23393
|
}
|
|
23374
23394
|
if (opts.agent_id) {
|
|
23375
23395
|
sql += " AND t.agent_id = ?";
|
|
@@ -34899,8 +34919,9 @@ async function handleAgentMe(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
34899
34919
|
}
|
|
34900
34920
|
}
|
|
34901
34921
|
function handleAgentQueue(agentId, _ctx, json2, taskToSummary2) {
|
|
34922
|
+
const aliasSet = assignedToAliasSet(getDatabase(), agentId);
|
|
34902
34923
|
const pending = listTasks({ status: "pending" });
|
|
34903
|
-
const queue = pending.filter((t) => t.assigned_to
|
|
34924
|
+
const queue = pending.filter((t) => aliasSet.has((t.assigned_to ?? "").toLowerCase()) || t.agent_id === agentId || !t.assigned_to && !t.locked_by);
|
|
34904
34925
|
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
34905
34926
|
queue.sort((a, b) => (order[a.priority] ?? 4) - (order[b.priority] ?? 4) || new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
34906
34927
|
return json2(queue.map((t) => taskToSummary2(t)));
|
|
@@ -44587,11 +44608,12 @@ function runAlerts(input, db, checkedAt, quieted) {
|
|
|
44587
44608
|
if (input.include_runs === false)
|
|
44588
44609
|
return [];
|
|
44589
44610
|
const since = Date.parse(input.run_since || new Date(Date.parse(checkedAt) - 24 * 60 * 60000).toISOString());
|
|
44611
|
+
const runAlertAliases = input.agent_id ? assignedToAliasSet(db, input.agent_id) : null;
|
|
44590
44612
|
return listTaskRuns(undefined, db).filter((run) => run.completed_at && Date.parse(run.completed_at) >= since).map((run) => {
|
|
44591
44613
|
const task = getTask(run.task_id, db);
|
|
44592
44614
|
if (input.project_id && task?.project_id !== input.project_id)
|
|
44593
44615
|
return null;
|
|
44594
|
-
if (input.agent_id && run.agent_id !== input.agent_id && task?.assigned_to
|
|
44616
|
+
if (input.agent_id && run.agent_id !== input.agent_id && !(runAlertAliases && runAlertAliases.has((task?.assigned_to ?? "").toLowerCase())))
|
|
44595
44617
|
return null;
|
|
44596
44618
|
const failed = ["failed", "cancelled"].includes(run.status);
|
|
44597
44619
|
return {
|
|
@@ -44636,6 +44658,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
44636
44658
|
const warnings = [];
|
|
44637
44659
|
if (Number.isNaN(checkedMs))
|
|
44638
44660
|
warnings.push("Invalid check timestamp; due-soon window may be incomplete.");
|
|
44661
|
+
const notifyAgentAliases = input.agent_id ? assignedToAliasSet(d, input.agent_id) : null;
|
|
44639
44662
|
const alerts = [];
|
|
44640
44663
|
for (const escalation of getEscalatedTasks({ project_id: input.project_id, agent_id: input.agent_id }, d, new Date(checkedAt))) {
|
|
44641
44664
|
for (const reason of escalation.reasons) {
|
|
@@ -44647,7 +44670,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
44647
44670
|
for (const task of listTasks({ project_id: input.project_id, include_archived: false, limit: 5000 }, d)) {
|
|
44648
44671
|
if (!unfinished(task) || !task.due_at)
|
|
44649
44672
|
continue;
|
|
44650
|
-
if (input.agent_id && task.
|
|
44673
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
44651
44674
|
continue;
|
|
44652
44675
|
if (task.due_at > checkedAt && task.due_at <= dueSoonUntil) {
|
|
44653
44676
|
alerts.push(taskAlert(task, "task_due_soon", "task.due_soon", "warning", `Due soon: ${task.title}`, task.due_at, quieted));
|
|
@@ -44655,7 +44678,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
44655
44678
|
}
|
|
44656
44679
|
}
|
|
44657
44680
|
for (const task of getStaleTasks(staleMinutes, { project_id: input.project_id }, d)) {
|
|
44658
|
-
if (input.agent_id && task.
|
|
44681
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
44659
44682
|
continue;
|
|
44660
44683
|
alerts.push(taskAlert(task, "task_stale", "task.stale", "warning", `Stale task: ${task.title}`, checkedAt, quieted, { stale_minutes: staleMinutes }));
|
|
44661
44684
|
}
|
|
@@ -46480,10 +46503,12 @@ function matchesProfile(profile, query) {
|
|
|
46480
46503
|
return false;
|
|
46481
46504
|
return true;
|
|
46482
46505
|
}
|
|
46483
|
-
function taskMatchesAgent(task, agentId) {
|
|
46506
|
+
function taskMatchesAgent(task, agentId, aliasSet) {
|
|
46484
46507
|
if (!agentId)
|
|
46485
46508
|
return true;
|
|
46486
|
-
|
|
46509
|
+
if (task.agent_id === agentId)
|
|
46510
|
+
return true;
|
|
46511
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
46487
46512
|
}
|
|
46488
46513
|
function estimateRemaining(task) {
|
|
46489
46514
|
if (task.status === "completed" || task.status === "cancelled")
|
|
@@ -46553,7 +46578,8 @@ function removeCapacityProfile(idOrAgent, projectId) {
|
|
|
46553
46578
|
}
|
|
46554
46579
|
function getPlanningForecast(input = {}, db) {
|
|
46555
46580
|
const startDate = input.start_date ? dateOnly(input.start_date) : todayIso();
|
|
46556
|
-
const
|
|
46581
|
+
const aliasSet = input.agent_id ? assignedToAliasSet(db || getDatabase(), input.agent_id) : undefined;
|
|
46582
|
+
const tasks = listTasks({ project_id: input.project_id, plan_id: input.plan_id, limit: 1e4 }, db).filter((task) => taskMatchesAgent(task, input.agent_id, aliasSet));
|
|
46557
46583
|
const reportByTask = new Map(getTimeReport({ project_id: input.project_id, plan_id: input.plan_id, agent_id: input.agent_id, include_open: true }, db).map((entry2) => [entry2.task_id, entry2]));
|
|
46558
46584
|
const profiles = listCapacityProfiles({ agent_id: input.agent_id, project_id: input.project_id });
|
|
46559
46585
|
const globalProfiles = input.project_id ? listCapacityProfiles({ agent_id: input.agent_id }).filter((profile) => profile.project_id === null) : [];
|
|
@@ -46651,6 +46677,7 @@ function renderPlanningForecastMarkdown(forecast) {
|
|
|
46651
46677
|
}
|
|
46652
46678
|
var LOCAL_CAPACITY_SCHEMA_VERSION = 1;
|
|
46653
46679
|
var init_capacity_forecasts = __esm(() => {
|
|
46680
|
+
init_database();
|
|
46654
46681
|
init_tasks();
|
|
46655
46682
|
init_task_relations();
|
|
46656
46683
|
init_config();
|
|
@@ -49760,8 +49787,10 @@ function getLatestHandoff(agentId, projectId, db) {
|
|
|
49760
49787
|
function createSessionRecoveryHandoff(input, db) {
|
|
49761
49788
|
const d = db || getDatabase();
|
|
49762
49789
|
const limit = input.limit || 20;
|
|
49763
|
-
const
|
|
49764
|
-
const
|
|
49790
|
+
const params = [];
|
|
49791
|
+
const assignedInClause = lowerInClause("assigned_to", resolveAssignedToAliases(d, input.agent_id), params);
|
|
49792
|
+
const conditions = ["status = 'in_progress'", `(${assignedInClause} OR agent_id = ? OR locked_by = ?)`];
|
|
49793
|
+
params.push(input.agent_id, input.agent_id);
|
|
49765
49794
|
if (input.session_id) {
|
|
49766
49795
|
conditions.push("session_id = ?");
|
|
49767
49796
|
params.push(input.session_id);
|
|
@@ -50353,7 +50382,8 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
50353
50382
|
const assigned = listTasks4({ assigned_to: effectiveAgentId, limit: 500 }, undefined);
|
|
50354
50383
|
const now4 = Date.now();
|
|
50355
50384
|
const dueSoonCutoff = now4 + 24 * 60 * 60 * 1000;
|
|
50356
|
-
const
|
|
50385
|
+
const blockedAliases = assignedToAliasSet(getDatabase(), effectiveAgentId);
|
|
50386
|
+
const blocked = getBlockedTasks2().filter((t) => blockedAliases.has((t.assigned_to ?? "").toLowerCase()));
|
|
50357
50387
|
const workload = {
|
|
50358
50388
|
in_progress: assigned.filter((t) => t.status === "in_progress").length,
|
|
50359
50389
|
pending: assigned.filter((t) => t.status === "pending").length,
|
|
@@ -50390,17 +50420,25 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
50390
50420
|
if (agents.length === 0)
|
|
50391
50421
|
return { content: [{ type: "text", text: "No active agents available for rebalancing." }] };
|
|
50392
50422
|
const activeTasks = listTasks4({ project_id: resolvedProjectId, status: ["pending", "in_progress"], limit: 1000 }, undefined);
|
|
50393
|
-
const
|
|
50423
|
+
const agentKeyByAlias = new Map;
|
|
50424
|
+
for (const agent of agents) {
|
|
50425
|
+
agentKeyByAlias.set(String(agent.id).toLowerCase(), agent.id);
|
|
50426
|
+
if (agent.name)
|
|
50427
|
+
agentKeyByAlias.set(String(agent.name).toLowerCase(), agent.id);
|
|
50428
|
+
}
|
|
50429
|
+
const canonicalAgentKey = (assignedTo) => assignedTo ? agentKeyByAlias.get(assignedTo.toLowerCase()) : undefined;
|
|
50430
|
+
const load = new Map(agents.map((agent) => [agent.id, activeTasks.filter((t) => canonicalAgentKey(t.assigned_to) === agent.id).length]));
|
|
50394
50431
|
let moved = 0;
|
|
50395
50432
|
let skipped = 0;
|
|
50396
|
-
for (const task of activeTasks.filter((t) => t.status === "pending" && t.assigned_to && (load.get(t.assigned_to) ?? 0) > limit)) {
|
|
50397
|
-
const
|
|
50433
|
+
for (const task of activeTasks.filter((t) => t.status === "pending" && canonicalAgentKey(t.assigned_to) && (load.get(canonicalAgentKey(t.assigned_to)) ?? 0) > limit)) {
|
|
50434
|
+
const currentAgentKey = canonicalAgentKey(task.assigned_to);
|
|
50435
|
+
const target = agents.filter((agent) => agent.id !== currentAgentKey).sort((a, b) => (load.get(a.id) ?? 0) - (load.get(b.id) ?? 0))[0];
|
|
50398
50436
|
if (!target || (load.get(target.id) ?? 0) >= limit) {
|
|
50399
50437
|
skipped++;
|
|
50400
50438
|
continue;
|
|
50401
50439
|
}
|
|
50402
50440
|
updateTask3(task.id, { assigned_to: target.id, version: task.version });
|
|
50403
|
-
load.set(
|
|
50441
|
+
load.set(currentAgentKey, (load.get(currentAgentKey) ?? 1) - 1);
|
|
50404
50442
|
load.set(target.id, (load.get(target.id) ?? 0) + 1);
|
|
50405
50443
|
moved++;
|
|
50406
50444
|
}
|
|
@@ -50579,6 +50617,7 @@ ${lines.join(`
|
|
|
50579
50617
|
var init_task_auto_tools = __esm(() => {
|
|
50580
50618
|
init_zod();
|
|
50581
50619
|
init_cloud_router();
|
|
50620
|
+
init_database();
|
|
50582
50621
|
});
|
|
50583
50622
|
|
|
50584
50623
|
// src/lib/context-packs.ts
|
|
@@ -51758,7 +51797,8 @@ ${JSON.stringify(task.metadata, null, 2)}` : null
|
|
|
51758
51797
|
}, undefined);
|
|
51759
51798
|
const completedYesterday = completed.filter((t) => t.completed_at && t.completed_at.startsWith(yesterdayStr));
|
|
51760
51799
|
const { getBlockedTasks: getBlockedTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
51761
|
-
const
|
|
51800
|
+
const blockedAliases = effectiveAgentId ? assignedToAliasSet(getDatabase(), effectiveAgentId) : null;
|
|
51801
|
+
const blocked = getBlockedTasks2(effectiveProjectId ? resolveId(effectiveProjectId, "projects") : undefined).filter((t) => blockedAliases ? blockedAliases.has((t.assigned_to ?? "").toLowerCase()) : false);
|
|
51762
51802
|
const lines = [
|
|
51763
51803
|
`Standup for ${effectiveAgentId} (${effectiveProjectId ? `project: ${effectiveProjectId.slice(0, 8)}` : "all projects"})`,
|
|
51764
51804
|
inProgress.length > 0 ? `
|
|
@@ -51986,6 +52026,7 @@ var init_task_adv_tools = __esm(() => {
|
|
|
51986
52026
|
init_zod();
|
|
51987
52027
|
init_token_utils();
|
|
51988
52028
|
init_cloud_router();
|
|
52029
|
+
init_database();
|
|
51989
52030
|
});
|
|
51990
52031
|
|
|
51991
52032
|
// src/mcp/tools/task-meta-tools.ts
|
|
@@ -54182,27 +54223,29 @@ function getAgentMetrics(agentId, opts, db) {
|
|
|
54182
54223
|
const agent = d.query("SELECT id, name FROM agents WHERE id = ? OR LOWER(name) = LOWER(?)").get(agentId, agentId);
|
|
54183
54224
|
if (!agent)
|
|
54184
54225
|
return null;
|
|
54226
|
+
const assignedAliases = resolveAssignedToAliases(d, agent.id).map((a) => a.toLowerCase());
|
|
54227
|
+
const assignedInClause = `LOWER(assigned_to) IN (${assignedAliases.map(() => "?").join(",")})`;
|
|
54185
54228
|
let projectFilter = "";
|
|
54186
|
-
const params = [agent.id,
|
|
54229
|
+
const params = [agent.id, ...assignedAliases];
|
|
54187
54230
|
if (opts?.project_id) {
|
|
54188
54231
|
projectFilter = " AND project_id = ?";
|
|
54189
54232
|
params.push(opts.project_id);
|
|
54190
54233
|
}
|
|
54191
|
-
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
54192
|
-
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
54193
|
-
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
54234
|
+
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}`).get(...params).count;
|
|
54235
|
+
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'failed'${projectFilter}`).get(...params).count;
|
|
54236
|
+
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'in_progress'${projectFilter}`).get(...params).count;
|
|
54194
54237
|
const total = completed + failed;
|
|
54195
54238
|
const completionRate = total > 0 ? completed / total : 0;
|
|
54196
54239
|
const avgTime = d.query(`SELECT AVG(
|
|
54197
54240
|
(julianday(completed_at) - julianday(created_at)) * 24 * 60
|
|
54198
54241
|
) as avg_minutes
|
|
54199
54242
|
FROM tasks
|
|
54200
|
-
WHERE (agent_id = ? OR
|
|
54243
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter}`).get(...params);
|
|
54201
54244
|
const avgConf = d.query(`SELECT AVG(confidence) as avg_confidence
|
|
54202
54245
|
FROM tasks
|
|
54203
|
-
WHERE (agent_id = ? OR
|
|
54246
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND confidence IS NOT NULL${projectFilter}`).get(...params);
|
|
54204
54247
|
const reviewTasks = d.query(`SELECT metadata FROM tasks
|
|
54205
|
-
WHERE (agent_id = ? OR
|
|
54248
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}
|
|
54206
54249
|
AND metadata LIKE '%_review_score%'`).all(...params);
|
|
54207
54250
|
let reviewScoreAvg = null;
|
|
54208
54251
|
if (reviewTasks.length > 0) {
|
|
@@ -54672,14 +54715,15 @@ function millisBetween(start, end) {
|
|
|
54672
54715
|
return 0;
|
|
54673
54716
|
return endMs - startMs;
|
|
54674
54717
|
}
|
|
54675
|
-
function addTaskScope(where, params, options, alias = "t") {
|
|
54718
|
+
function addTaskScope(where, params, options, db, alias = "t") {
|
|
54676
54719
|
if (options.project_id) {
|
|
54677
54720
|
where.push(`${alias}.project_id = ?`);
|
|
54678
54721
|
params.push(options.project_id);
|
|
54679
54722
|
}
|
|
54680
54723
|
if (options.agent_id) {
|
|
54681
|
-
|
|
54682
|
-
|
|
54724
|
+
params.push(options.agent_id);
|
|
54725
|
+
const assignedInClause = lowerInClause(`${alias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
54726
|
+
where.push(`(${alias}.agent_id = ? OR ${assignedInClause})`);
|
|
54683
54727
|
}
|
|
54684
54728
|
if (options.since) {
|
|
54685
54729
|
where.push(`${alias}.created_at >= ?`);
|
|
@@ -54690,14 +54734,15 @@ function addTaskScope(where, params, options, alias = "t") {
|
|
|
54690
54734
|
params.push(options.until);
|
|
54691
54735
|
}
|
|
54692
54736
|
}
|
|
54693
|
-
function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
54737
|
+
function addRunScope(where, params, options, db, runAlias = "r", taskAlias = "t") {
|
|
54694
54738
|
if (options.project_id) {
|
|
54695
54739
|
where.push(`${taskAlias}.project_id = ?`);
|
|
54696
54740
|
params.push(options.project_id);
|
|
54697
54741
|
}
|
|
54698
54742
|
if (options.agent_id) {
|
|
54699
|
-
|
|
54700
|
-
|
|
54743
|
+
params.push(options.agent_id, options.agent_id);
|
|
54744
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
54745
|
+
where.push(`(${runAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
54701
54746
|
}
|
|
54702
54747
|
if (options.since) {
|
|
54703
54748
|
where.push(`${runAlias}.started_at >= ?`);
|
|
@@ -54708,14 +54753,15 @@ function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
|
54708
54753
|
params.push(options.until);
|
|
54709
54754
|
}
|
|
54710
54755
|
}
|
|
54711
|
-
function addTraceScope(where, params, options, traceAlias = "tr", taskAlias = "t") {
|
|
54756
|
+
function addTraceScope(where, params, options, db, traceAlias = "tr", taskAlias = "t") {
|
|
54712
54757
|
if (options.project_id) {
|
|
54713
54758
|
where.push(`${taskAlias}.project_id = ?`);
|
|
54714
54759
|
params.push(options.project_id);
|
|
54715
54760
|
}
|
|
54716
54761
|
if (options.agent_id) {
|
|
54717
|
-
|
|
54718
|
-
|
|
54762
|
+
params.push(options.agent_id, options.agent_id);
|
|
54763
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
54764
|
+
where.push(`(${traceAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
54719
54765
|
}
|
|
54720
54766
|
if (options.since) {
|
|
54721
54767
|
where.push(`${traceAlias}.created_at >= ?`);
|
|
@@ -54775,7 +54821,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
54775
54821
|
const generatedAt = options.generated_at || new Date().toISOString();
|
|
54776
54822
|
const taskWhere = [];
|
|
54777
54823
|
const taskParams = [];
|
|
54778
|
-
addTaskScope(taskWhere, taskParams, options);
|
|
54824
|
+
addTaskScope(taskWhere, taskParams, options, d);
|
|
54779
54825
|
const taskClause = taskWhere.length ? `WHERE ${taskWhere.join(" AND ")}` : "";
|
|
54780
54826
|
const taskTotals = queryOne(d, `SELECT COUNT(*) as tasks, COALESCE(SUM(cost_tokens), 0) as task_tokens, COALESCE(SUM(cost_usd), 0) as task_cost_usd FROM tasks t ${taskClause}`, taskParams);
|
|
54781
54827
|
let projectCount = 0;
|
|
@@ -54784,14 +54830,14 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
54784
54830
|
} else if (options.agent_id) {
|
|
54785
54831
|
const projectWhere = ["t.project_id IS NOT NULL"];
|
|
54786
54832
|
const projectParams = [];
|
|
54787
|
-
addTaskScope(projectWhere, projectParams, options);
|
|
54833
|
+
addTaskScope(projectWhere, projectParams, options, d);
|
|
54788
54834
|
projectCount = queryOne(d, `SELECT COUNT(DISTINCT t.project_id) as count FROM tasks t WHERE ${projectWhere.join(" AND ")}`, projectParams).count;
|
|
54789
54835
|
} else {
|
|
54790
54836
|
projectCount = queryOne(d, "SELECT COUNT(*) as count FROM projects", []).count;
|
|
54791
54837
|
}
|
|
54792
54838
|
const runWhere = [];
|
|
54793
54839
|
const runParams = [];
|
|
54794
|
-
addRunScope(runWhere, runParams, options);
|
|
54840
|
+
addRunScope(runWhere, runParams, options, d);
|
|
54795
54841
|
const runClause = runWhere.length ? `WHERE ${runWhere.join(" AND ")}` : "";
|
|
54796
54842
|
const runs = queryAll(d, `SELECT r.id, r.started_at, r.completed_at, r.metadata
|
|
54797
54843
|
FROM task_runs r JOIN tasks t ON t.id = r.task_id
|
|
@@ -54808,7 +54854,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
54808
54854
|
${runClause}`, runParams);
|
|
54809
54855
|
const traceWhere = [];
|
|
54810
54856
|
const traceParams = [];
|
|
54811
|
-
addTraceScope(traceWhere, traceParams, options);
|
|
54857
|
+
addTraceScope(traceWhere, traceParams, options, d);
|
|
54812
54858
|
const traceClause = traceWhere.length ? `WHERE ${traceWhere.join(" AND ")}` : "";
|
|
54813
54859
|
const traceTotals = queryOne(d, `SELECT COUNT(*) as traces,
|
|
54814
54860
|
COALESCE(SUM(tr.tokens), 0) as tokens,
|
|
@@ -54952,10 +54998,12 @@ function limitValue(value) {
|
|
|
54952
54998
|
function isTerminal2(task) {
|
|
54953
54999
|
return task.status === "completed" || task.status === "failed" || task.status === "cancelled";
|
|
54954
55000
|
}
|
|
54955
|
-
function sameAgent(task, agentId) {
|
|
55001
|
+
function sameAgent(task, agentId, aliasSet) {
|
|
54956
55002
|
if (!agentId)
|
|
54957
55003
|
return true;
|
|
54958
|
-
|
|
55004
|
+
if (task.agent_id === agentId)
|
|
55005
|
+
return true;
|
|
55006
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
54959
55007
|
}
|
|
54960
55008
|
function withinTaskWindow(task, options) {
|
|
54961
55009
|
const time = Date.parse(task.updated_at);
|
|
@@ -54968,11 +55016,12 @@ function withinTaskWindow(task, options) {
|
|
|
54968
55016
|
return true;
|
|
54969
55017
|
}
|
|
54970
55018
|
function scopedTasks(options, db) {
|
|
55019
|
+
const aliasSet = options.agent_id ? assignedToAliasSet(db, options.agent_id) : undefined;
|
|
54971
55020
|
return listTasks({
|
|
54972
55021
|
project_id: options.project_id,
|
|
54973
55022
|
plan_id: options.plan_id,
|
|
54974
55023
|
include_archived: false
|
|
54975
|
-
}, db).filter((task) => sameAgent(task, options.agent_id) && withinTaskWindow(task, options));
|
|
55024
|
+
}, db).filter((task) => sameAgent(task, options.agent_id, aliasSet) && withinTaskWindow(task, options));
|
|
54976
55025
|
}
|
|
54977
55026
|
function summarizeTask(task) {
|
|
54978
55027
|
return {
|
|
@@ -55038,7 +55087,7 @@ function initialAgentSummary(agentId) {
|
|
|
55038
55087
|
}
|
|
55039
55088
|
};
|
|
55040
55089
|
}
|
|
55041
|
-
function addScopeClauses(where, params, options, timeColumn) {
|
|
55090
|
+
function addScopeClauses(where, params, options, timeColumn, db) {
|
|
55042
55091
|
if (options.project_id) {
|
|
55043
55092
|
where.push("t.project_id = ?");
|
|
55044
55093
|
params.push(options.project_id);
|
|
@@ -55048,8 +55097,9 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
55048
55097
|
params.push(options.plan_id);
|
|
55049
55098
|
}
|
|
55050
55099
|
if (options.agent_id) {
|
|
55051
|
-
|
|
55052
|
-
|
|
55100
|
+
params.push(options.agent_id, options.agent_id);
|
|
55101
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
55102
|
+
where.push(`(r.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
55053
55103
|
}
|
|
55054
55104
|
if (options.since) {
|
|
55055
55105
|
where.push(`${timeColumn} >= ?`);
|
|
@@ -55063,7 +55113,7 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
55063
55113
|
function loadRuns(options, db) {
|
|
55064
55114
|
const where = ["t.archived_at IS NULL"];
|
|
55065
55115
|
const params = [];
|
|
55066
|
-
addScopeClauses(where, params, options, "r.started_at");
|
|
55116
|
+
addScopeClauses(where, params, options, "r.started_at", db);
|
|
55067
55117
|
return db.query(`
|
|
55068
55118
|
SELECT
|
|
55069
55119
|
r.id,
|
|
@@ -55103,8 +55153,9 @@ function loadVerifications(options, db) {
|
|
|
55103
55153
|
params.push(options.plan_id);
|
|
55104
55154
|
}
|
|
55105
55155
|
if (options.agent_id) {
|
|
55106
|
-
|
|
55107
|
-
|
|
55156
|
+
params.push(options.agent_id, options.agent_id);
|
|
55157
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
55158
|
+
where.push(`(v.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
55108
55159
|
}
|
|
55109
55160
|
if (options.since) {
|
|
55110
55161
|
where.push("v.run_at >= ?");
|
|
@@ -55326,7 +55377,6 @@ function renderLocalReportMarkdown(report) {
|
|
|
55326
55377
|
}
|
|
55327
55378
|
var LOCAL_REPORT_SCHEMA_VERSION = 1, LOCAL_REPORT_TYPES;
|
|
55328
55379
|
var init_local_reports = __esm(() => {
|
|
55329
|
-
init_database();
|
|
55330
55380
|
init_database();
|
|
55331
55381
|
init_plans();
|
|
55332
55382
|
init_tasks();
|
|
@@ -58382,7 +58432,7 @@ ${lines.join(`
|
|
|
58382
58432
|
a.name AS agent_name
|
|
58383
58433
|
FROM task_files tf
|
|
58384
58434
|
JOIN tasks t ON tf.task_id = t.id
|
|
58385
|
-
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND t.assigned_to = a.id))
|
|
58435
|
+
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND (t.assigned_to = a.id OR LOWER(t.assigned_to) = LOWER(a.name))))
|
|
58386
58436
|
WHERE t.status = 'in_progress'
|
|
58387
58437
|
AND tf.status != 'removed'
|
|
58388
58438
|
AND t.project_id = ?
|
|
@@ -61762,7 +61812,7 @@ ${text2}` }] };
|
|
|
61762
61812
|
const oldName = agent.name;
|
|
61763
61813
|
const updated = updateAgent(agent.id, { name: new_name });
|
|
61764
61814
|
const db = getDatabase();
|
|
61765
|
-
const tasksResult = db.run("UPDATE tasks SET assigned_to = ? WHERE assigned_to = ?", [new_name, oldName]);
|
|
61815
|
+
const tasksResult = db.run("UPDATE tasks SET assigned_to = ? WHERE LOWER(assigned_to) = LOWER(?)", [new_name, oldName]);
|
|
61766
61816
|
const taskNote = tasksResult.changes > 0 ? `
|
|
61767
61817
|
Updated assigned_to on ${tasksResult.changes} task(s).` : "";
|
|
61768
61818
|
return {
|