@hasna/todos 0.13.10 → 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/assignee-guard.d.ts +8 -1
- package/dist/cli/assignee-guard.d.ts.map +1 -1
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +153 -102
- 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/assignee-validation.d.ts +22 -0
- package/dist/lib/assignee-validation.d.ts.map +1 -1
- 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 +138 -93
- 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 +138 -93
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/storage.js +57 -42
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var package_default;
|
|
|
70
70
|
var init_package = __esm(() => {
|
|
71
71
|
package_default = {
|
|
72
72
|
name: "@hasna/todos",
|
|
73
|
-
version: "0.13.
|
|
73
|
+
version: "0.13.12",
|
|
74
74
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
75
75
|
type: "module",
|
|
76
76
|
main: "dist/index.js",
|
|
@@ -9312,14 +9312,17 @@ var exports_database = {};
|
|
|
9312
9312
|
__export(exports_database, {
|
|
9313
9313
|
uuid: () => uuid,
|
|
9314
9314
|
resolvePartialId: () => resolvePartialId,
|
|
9315
|
+
resolveAssignedToAliases: () => resolveAssignedToAliases,
|
|
9315
9316
|
resetDatabase: () => resetDatabase,
|
|
9316
9317
|
now: () => now,
|
|
9318
|
+
lowerInClause: () => lowerInClause,
|
|
9317
9319
|
lockExpiryCutoff: () => lockExpiryCutoff,
|
|
9318
9320
|
isLockExpired: () => isLockExpired,
|
|
9319
9321
|
getDatabasePath: () => getDatabasePath,
|
|
9320
9322
|
getDatabase: () => getDatabase,
|
|
9321
9323
|
closeDatabase: () => closeDatabase,
|
|
9322
9324
|
clearExpiredLocks: () => clearExpiredLocks,
|
|
9325
|
+
assignedToAliasSet: () => assignedToAliasSet,
|
|
9323
9326
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
9324
9327
|
});
|
|
9325
9328
|
import { Database } from "bun:sqlite";
|
|
@@ -9548,6 +9551,33 @@ function resolvePartialId(db, table, partialId) {
|
|
|
9548
9551
|
}
|
|
9549
9552
|
return null;
|
|
9550
9553
|
}
|
|
9554
|
+
function resolveAssignedToAliases(db, ref) {
|
|
9555
|
+
const aliases = new Set([ref]);
|
|
9556
|
+
let agentId;
|
|
9557
|
+
try {
|
|
9558
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
9559
|
+
} catch (err) {
|
|
9560
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
9561
|
+
throw err;
|
|
9562
|
+
agentId = null;
|
|
9563
|
+
}
|
|
9564
|
+
if (agentId) {
|
|
9565
|
+
aliases.add(agentId);
|
|
9566
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
9567
|
+
if (row?.name)
|
|
9568
|
+
aliases.add(row.name);
|
|
9569
|
+
}
|
|
9570
|
+
return [...aliases];
|
|
9571
|
+
}
|
|
9572
|
+
function assignedToAliasSet(db, ref) {
|
|
9573
|
+
return new Set(resolveAssignedToAliases(db, ref).map((a) => a.toLowerCase()));
|
|
9574
|
+
}
|
|
9575
|
+
function lowerInClause(column, values, params) {
|
|
9576
|
+
if (values.length === 0)
|
|
9577
|
+
return "1=0";
|
|
9578
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
9579
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
9580
|
+
}
|
|
9551
9581
|
var LOCK_EXPIRY_MINUTES = 30, _db = null, _dbPath = null, ALLOWED_TABLES;
|
|
9552
9582
|
var init_database = __esm(() => {
|
|
9553
9583
|
init_schema();
|
|
@@ -10117,17 +10147,19 @@ function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
|
10117
10147
|
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);
|
|
10118
10148
|
}
|
|
10119
10149
|
}
|
|
10150
|
+
const assignedAliasParams = [];
|
|
10151
|
+
const assignedInClause = agent ? lowerInClause("assigned_to", resolveAssignedToAliases(db, agent), assignedAliasParams) : "";
|
|
10120
10152
|
if (agent && config.max_completions_per_window && config.window_minutes) {
|
|
10121
10153
|
const windowStart = new Date(Date.now() - config.window_minutes * 60 * 1000).toISOString();
|
|
10122
10154
|
const result = db.query(`SELECT COUNT(*) as count FROM tasks
|
|
10123
|
-
WHERE completed_at > ? AND (
|
|
10155
|
+
WHERE completed_at > ? AND (${assignedInClause} OR agent_id = ?)`).get(windowStart, ...assignedAliasParams, agent);
|
|
10124
10156
|
if (result.count >= config.max_completions_per_window) {
|
|
10125
10157
|
throw new CompletionGuardError(`Rate limit: ${result.count} tasks completed in the last ${config.window_minutes} minutes (max ${config.max_completions_per_window}). Slow down.`);
|
|
10126
10158
|
}
|
|
10127
10159
|
}
|
|
10128
10160
|
if (agent && config.cooldown_seconds) {
|
|
10129
10161
|
const result = db.query(`SELECT MAX(completed_at) as last_completed FROM tasks
|
|
10130
|
-
WHERE completed_at IS NOT NULL AND (
|
|
10162
|
+
WHERE completed_at IS NOT NULL AND (${assignedInClause} OR agent_id = ?) AND id != ?`).get(...assignedAliasParams, agent, task.id);
|
|
10131
10163
|
if (result.last_completed) {
|
|
10132
10164
|
const elapsedSeconds = (Date.now() - new Date(result.last_completed).getTime()) / 1000;
|
|
10133
10165
|
if (elapsedSeconds < config.cooldown_seconds) {
|
|
@@ -10141,6 +10173,7 @@ var init_completion_guard = __esm(() => {
|
|
|
10141
10173
|
init_types();
|
|
10142
10174
|
init_config2();
|
|
10143
10175
|
init_projects();
|
|
10176
|
+
init_database();
|
|
10144
10177
|
});
|
|
10145
10178
|
|
|
10146
10179
|
// src/lib/event-emission-safety.ts
|
|
@@ -12318,13 +12351,17 @@ function logDelivery(d, webhookId, event, payload, statusCode, response, attempt
|
|
|
12318
12351
|
const id = uuid();
|
|
12319
12352
|
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()]);
|
|
12320
12353
|
}
|
|
12321
|
-
function matchesScope(wh, payload) {
|
|
12354
|
+
function matchesScope(wh, payload, db) {
|
|
12322
12355
|
if (wh.project_id && payload.project_id !== wh.project_id)
|
|
12323
12356
|
return false;
|
|
12324
12357
|
if (wh.task_list_id && payload.task_list_id !== wh.task_list_id)
|
|
12325
12358
|
return false;
|
|
12326
|
-
if (wh.agent_id && payload.agent_id !== wh.agent_id
|
|
12327
|
-
|
|
12359
|
+
if (wh.agent_id && payload.agent_id !== wh.agent_id) {
|
|
12360
|
+
const aliasSet = assignedToAliasSet(db, wh.agent_id);
|
|
12361
|
+
const assignedTo = typeof payload.assigned_to === "string" ? payload.assigned_to.toLowerCase() : "";
|
|
12362
|
+
if (!aliasSet.has(assignedTo))
|
|
12363
|
+
return false;
|
|
12364
|
+
}
|
|
12328
12365
|
if (wh.task_id && payload.id !== wh.task_id)
|
|
12329
12366
|
return false;
|
|
12330
12367
|
return true;
|
|
@@ -12391,7 +12428,7 @@ async function dispatchWebhook2(event, payload, db) {
|
|
|
12391
12428
|
const webhooks = listWebhooks(d).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
|
|
12392
12429
|
const payloadObj = typeof payload === "object" && payload !== null ? payload : {};
|
|
12393
12430
|
for (const wh of webhooks) {
|
|
12394
|
-
if (!matchesScope(wh, payloadObj))
|
|
12431
|
+
if (!matchesScope(wh, payloadObj, d))
|
|
12395
12432
|
continue;
|
|
12396
12433
|
const body = JSON.stringify({ event, payload, timestamp: now() });
|
|
12397
12434
|
deliverWebhook(wh, event, body, 1, d).catch((err) => {
|
|
@@ -13463,14 +13500,16 @@ function getNextTask2(agentId, filters, db) {
|
|
|
13463
13500
|
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')");
|
|
13464
13501
|
const where = conditions.join(" AND ");
|
|
13465
13502
|
let recentProjectIds = [];
|
|
13503
|
+
const assignedAliasParams = [];
|
|
13504
|
+
const assignedInClause = agentId ? lowerInClause("assigned_to", resolveAssignedToAliases(d, agentId), assignedAliasParams) : "";
|
|
13466
13505
|
if (agentId) {
|
|
13467
|
-
const recentRows = d.query(`SELECT DISTINCT project_id FROM tasks WHERE
|
|
13506
|
+
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);
|
|
13468
13507
|
recentProjectIds = recentRows.map((r) => r.project_id);
|
|
13469
13508
|
}
|
|
13470
13509
|
let sql = `SELECT * FROM tasks WHERE ${where} ORDER BY `;
|
|
13471
13510
|
if (agentId) {
|
|
13472
|
-
sql += `CASE WHEN
|
|
13473
|
-
params.push(
|
|
13511
|
+
sql += `CASE WHEN ${assignedInClause} THEN 0 WHEN assigned_to IS NULL THEN 1 ELSE 2 END, `;
|
|
13512
|
+
params.push(...assignedAliasParams);
|
|
13474
13513
|
}
|
|
13475
13514
|
if (recentProjectIds.length > 0) {
|
|
13476
13515
|
const placeholders = recentProjectIds.map(() => "?").join(",");
|
|
@@ -13864,30 +13903,6 @@ function getTaskWithRelations(id, db) {
|
|
|
13864
13903
|
checklist
|
|
13865
13904
|
};
|
|
13866
13905
|
}
|
|
13867
|
-
function resolveAssignedToAliases(db, ref) {
|
|
13868
|
-
const aliases = new Set([ref]);
|
|
13869
|
-
let agentId;
|
|
13870
|
-
try {
|
|
13871
|
-
agentId = resolvePartialId(db, "agents", ref);
|
|
13872
|
-
} catch (err) {
|
|
13873
|
-
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
13874
|
-
throw err;
|
|
13875
|
-
agentId = null;
|
|
13876
|
-
}
|
|
13877
|
-
if (agentId) {
|
|
13878
|
-
aliases.add(agentId);
|
|
13879
|
-
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
13880
|
-
if (row?.name)
|
|
13881
|
-
aliases.add(row.name);
|
|
13882
|
-
}
|
|
13883
|
-
return [...aliases];
|
|
13884
|
-
}
|
|
13885
|
-
function lowerInClause(column, values, params) {
|
|
13886
|
-
if (values.length === 0)
|
|
13887
|
-
return "1=0";
|
|
13888
|
-
params.push(...values.map((v) => v.toLowerCase()));
|
|
13889
|
-
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
13890
|
-
}
|
|
13891
13906
|
function listTasks2(filter = {}, db) {
|
|
13892
13907
|
const d = db || getDatabase();
|
|
13893
13908
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -14360,6 +14375,7 @@ function deleteTask(id, db) {
|
|
|
14360
14375
|
var init_task_crud = __esm(() => {
|
|
14361
14376
|
init_types();
|
|
14362
14377
|
init_database();
|
|
14378
|
+
init_database();
|
|
14363
14379
|
init_completion_guard();
|
|
14364
14380
|
init_event_emission_safety();
|
|
14365
14381
|
init_event_hooks();
|
|
@@ -14522,8 +14538,8 @@ function getTaskStats(filters, db) {
|
|
|
14522
14538
|
params.push(filters.task_list_id);
|
|
14523
14539
|
}
|
|
14524
14540
|
if (filters?.agent_id) {
|
|
14525
|
-
|
|
14526
|
-
|
|
14541
|
+
params.push(filters.agent_id);
|
|
14542
|
+
conditions.push(`(agent_id = ? OR ${lowerInClause("assigned_to", resolveAssignedToAliases(d, filters.agent_id), params)})`);
|
|
14527
14543
|
}
|
|
14528
14544
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
14529
14545
|
const totalRow = d.query(`SELECT COUNT(*) as count FROM tasks ${where}`).get(...params);
|
|
@@ -14706,8 +14722,7 @@ function getEscalatedTasks(opts = {}, db, at = new Date) {
|
|
|
14706
14722
|
params.push(opts.project_id);
|
|
14707
14723
|
}
|
|
14708
14724
|
if (opts.agent_id) {
|
|
14709
|
-
conditions.push("assigned_to
|
|
14710
|
-
params.push(opts.agent_id);
|
|
14725
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
14711
14726
|
}
|
|
14712
14727
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC, created_at ASC`).all(...params);
|
|
14713
14728
|
return rows.map(rowToTask).map((task) => {
|
|
@@ -14755,8 +14770,7 @@ function notifyUpcomingDeadlines(opts = {}, db) {
|
|
|
14755
14770
|
params.push(opts.project_id);
|
|
14756
14771
|
}
|
|
14757
14772
|
if (opts.agent_id) {
|
|
14758
|
-
conditions.push("assigned_to
|
|
14759
|
-
params.push(opts.agent_id);
|
|
14773
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
14760
14774
|
}
|
|
14761
14775
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC`).all(...params);
|
|
14762
14776
|
return rows.map(rowToTask);
|
|
@@ -15014,13 +15028,14 @@ function getTimeReport(opts, db) {
|
|
|
15014
15028
|
params.push(opts.plan_id);
|
|
15015
15029
|
}
|
|
15016
15030
|
if (opts?.agent_id) {
|
|
15031
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.agent_id), params);
|
|
15017
15032
|
conditions.push(`(
|
|
15018
|
-
|
|
15033
|
+
${assignedInClause}
|
|
15019
15034
|
OR t.agent_id = ?
|
|
15020
15035
|
OR EXISTS (SELECT 1 FROM task_time_logs ttl WHERE ttl.task_id = t.id AND ttl.agent_id = ?)
|
|
15021
15036
|
OR EXISTS (SELECT 1 FROM focus_sessions fs WHERE fs.task_id = t.id AND fs.agent_id = ?)
|
|
15022
15037
|
)`);
|
|
15023
|
-
params.push(opts.agent_id, opts.agent_id, opts.agent_id
|
|
15038
|
+
params.push(opts.agent_id, opts.agent_id, opts.agent_id);
|
|
15024
15039
|
}
|
|
15025
15040
|
if (opts?.since) {
|
|
15026
15041
|
conditions.push("(t.completed_at >= ? OR t.updated_at >= ?)");
|
|
@@ -16016,7 +16031,7 @@ function listActiveFiles(db) {
|
|
|
16016
16031
|
a.name AS agent_name
|
|
16017
16032
|
FROM task_files tf
|
|
16018
16033
|
JOIN tasks t ON tf.task_id = t.id
|
|
16019
|
-
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND t.assigned_to = a.id))
|
|
16034
|
+
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))))
|
|
16020
16035
|
WHERE t.status = 'in_progress'
|
|
16021
16036
|
AND tf.status != 'removed'
|
|
16022
16037
|
ORDER BY tf.updated_at DESC
|
|
@@ -19048,8 +19063,9 @@ async function handleAgentMe(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
19048
19063
|
}
|
|
19049
19064
|
}
|
|
19050
19065
|
function handleAgentQueue(agentId, _ctx, json2, taskToSummary2) {
|
|
19066
|
+
const aliasSet = assignedToAliasSet(getDatabase(), agentId);
|
|
19051
19067
|
const pending = listTasks2({ status: "pending" });
|
|
19052
|
-
const queue = pending.filter((t) => t.assigned_to
|
|
19068
|
+
const queue = pending.filter((t) => aliasSet.has((t.assigned_to ?? "").toLowerCase()) || t.agent_id === agentId || !t.assigned_to && !t.locked_by);
|
|
19053
19069
|
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
19054
19070
|
queue.sort((a, b) => (order[a.priority] ?? 4) - (order[b.priority] ?? 4) || new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
19055
19071
|
return json2(queue.map((t) => taskToSummary2(t)));
|
|
@@ -19441,8 +19457,7 @@ function searchTasks(options, projectId, taskListId, db) {
|
|
|
19441
19457
|
}
|
|
19442
19458
|
}
|
|
19443
19459
|
if (opts.assigned_to) {
|
|
19444
|
-
sql +=
|
|
19445
|
-
params.push(opts.assigned_to);
|
|
19460
|
+
sql += ` AND ${lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.assigned_to), params)}`;
|
|
19446
19461
|
}
|
|
19447
19462
|
if (opts.agent_id) {
|
|
19448
19463
|
sql += " AND t.agent_id = ?";
|
|
@@ -44798,10 +44813,11 @@ function validateAssignee(input, ctx) {
|
|
|
44798
44813
|
if (ctx.allowSeat) {
|
|
44799
44814
|
return { ok: true, assignee: byId ? byId.name : raw, agentId: byId?.id, isSeat: true };
|
|
44800
44815
|
}
|
|
44816
|
+
const hint = ctx.seatHint?.(raw);
|
|
44801
44817
|
return {
|
|
44802
44818
|
ok: false,
|
|
44803
44819
|
reason: "seat",
|
|
44804
|
-
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or
|
|
44820
|
+
message: `'${raw}' is a durable SEAT, and a task assigned to a seat is assigned to nobody \u2014 no session is watching that queue. ` + `Assign a specific agent, use --unassigned to file it with no owner on purpose, or repeat the command with --assign-seat added to confirm the seat is deliberate` + (hint ? `: ${hint}` : " (see --help for this command's exact form).")
|
|
44805
44821
|
};
|
|
44806
44822
|
}
|
|
44807
44823
|
if (byId) {
|
|
@@ -60746,11 +60762,12 @@ function runAlerts(input, db, checkedAt, quieted) {
|
|
|
60746
60762
|
if (input.include_runs === false)
|
|
60747
60763
|
return [];
|
|
60748
60764
|
const since = Date.parse(input.run_since || new Date(Date.parse(checkedAt) - 24 * 60 * 60000).toISOString());
|
|
60765
|
+
const runAlertAliases = input.agent_id ? assignedToAliasSet(db, input.agent_id) : null;
|
|
60749
60766
|
return listTaskRuns(undefined, db).filter((run) => run.completed_at && Date.parse(run.completed_at) >= since).map((run) => {
|
|
60750
60767
|
const task = getTask(run.task_id, db);
|
|
60751
60768
|
if (input.project_id && task?.project_id !== input.project_id)
|
|
60752
60769
|
return null;
|
|
60753
|
-
if (input.agent_id && run.agent_id !== input.agent_id && task?.assigned_to
|
|
60770
|
+
if (input.agent_id && run.agent_id !== input.agent_id && !(runAlertAliases && runAlertAliases.has((task?.assigned_to ?? "").toLowerCase())))
|
|
60754
60771
|
return null;
|
|
60755
60772
|
const failed = ["failed", "cancelled"].includes(run.status);
|
|
60756
60773
|
return {
|
|
@@ -60795,6 +60812,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60795
60812
|
const warnings = [];
|
|
60796
60813
|
if (Number.isNaN(checkedMs))
|
|
60797
60814
|
warnings.push("Invalid check timestamp; due-soon window may be incomplete.");
|
|
60815
|
+
const notifyAgentAliases = input.agent_id ? assignedToAliasSet(d, input.agent_id) : null;
|
|
60798
60816
|
const alerts = [];
|
|
60799
60817
|
for (const escalation of getEscalatedTasks({ project_id: input.project_id, agent_id: input.agent_id }, d, new Date(checkedAt))) {
|
|
60800
60818
|
for (const reason of escalation.reasons) {
|
|
@@ -60806,7 +60824,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60806
60824
|
for (const task of listTasks2({ project_id: input.project_id, include_archived: false, limit: 5000 }, d)) {
|
|
60807
60825
|
if (!unfinished(task) || !task.due_at)
|
|
60808
60826
|
continue;
|
|
60809
|
-
if (input.agent_id && task.
|
|
60827
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
60810
60828
|
continue;
|
|
60811
60829
|
if (task.due_at > checkedAt && task.due_at <= dueSoonUntil) {
|
|
60812
60830
|
alerts.push(taskAlert(task, "task_due_soon", "task.due_soon", "warning", `Due soon: ${task.title}`, task.due_at, quieted));
|
|
@@ -60814,7 +60832,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60814
60832
|
}
|
|
60815
60833
|
}
|
|
60816
60834
|
for (const task of getStaleTasks(staleMinutes, { project_id: input.project_id }, d)) {
|
|
60817
|
-
if (input.agent_id && task.
|
|
60835
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
60818
60836
|
continue;
|
|
60819
60837
|
alerts.push(taskAlert(task, "task_stale", "task.stale", "warning", `Stale task: ${task.title}`, checkedAt, quieted, { stale_minutes: staleMinutes }));
|
|
60820
60838
|
}
|
|
@@ -62834,10 +62852,12 @@ function matchesProfile(profile, query) {
|
|
|
62834
62852
|
return false;
|
|
62835
62853
|
return true;
|
|
62836
62854
|
}
|
|
62837
|
-
function taskMatchesAgent(task, agentId) {
|
|
62855
|
+
function taskMatchesAgent(task, agentId, aliasSet) {
|
|
62838
62856
|
if (!agentId)
|
|
62839
62857
|
return true;
|
|
62840
|
-
|
|
62858
|
+
if (task.agent_id === agentId)
|
|
62859
|
+
return true;
|
|
62860
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
62841
62861
|
}
|
|
62842
62862
|
function estimateRemaining(task) {
|
|
62843
62863
|
if (task.status === "completed" || task.status === "cancelled")
|
|
@@ -62907,7 +62927,8 @@ function removeCapacityProfile(idOrAgent, projectId) {
|
|
|
62907
62927
|
}
|
|
62908
62928
|
function getPlanningForecast(input = {}, db) {
|
|
62909
62929
|
const startDate = input.start_date ? dateOnly(input.start_date) : todayIso();
|
|
62910
|
-
const
|
|
62930
|
+
const aliasSet = input.agent_id ? assignedToAliasSet(db || getDatabase(), input.agent_id) : undefined;
|
|
62931
|
+
const tasks = listTasks2({ project_id: input.project_id, plan_id: input.plan_id, limit: 1e4 }, db).filter((task) => taskMatchesAgent(task, input.agent_id, aliasSet));
|
|
62911
62932
|
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]));
|
|
62912
62933
|
const profiles = listCapacityProfiles({ agent_id: input.agent_id, project_id: input.project_id });
|
|
62913
62934
|
const globalProfiles = input.project_id ? listCapacityProfiles({ agent_id: input.agent_id }).filter((profile) => profile.project_id === null) : [];
|
|
@@ -63005,6 +63026,7 @@ function renderPlanningForecastMarkdown(forecast) {
|
|
|
63005
63026
|
}
|
|
63006
63027
|
var LOCAL_CAPACITY_SCHEMA_VERSION = 1;
|
|
63007
63028
|
var init_capacity_forecasts = __esm(() => {
|
|
63029
|
+
init_database();
|
|
63008
63030
|
init_tasks();
|
|
63009
63031
|
init_task_relations();
|
|
63010
63032
|
init_config2();
|
|
@@ -66438,8 +66460,10 @@ function getLatestHandoff(agentId, projectId, db) {
|
|
|
66438
66460
|
function createSessionRecoveryHandoff(input, db) {
|
|
66439
66461
|
const d = db || getDatabase();
|
|
66440
66462
|
const limit = input.limit || 20;
|
|
66441
|
-
const
|
|
66442
|
-
const
|
|
66463
|
+
const params = [];
|
|
66464
|
+
const assignedInClause = lowerInClause("assigned_to", resolveAssignedToAliases(d, input.agent_id), params);
|
|
66465
|
+
const conditions = ["status = 'in_progress'", `(${assignedInClause} OR agent_id = ? OR locked_by = ?)`];
|
|
66466
|
+
params.push(input.agent_id, input.agent_id);
|
|
66443
66467
|
if (input.session_id) {
|
|
66444
66468
|
conditions.push("session_id = ?");
|
|
66445
66469
|
params.push(input.session_id);
|
|
@@ -67031,7 +67055,8 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
67031
67055
|
const assigned = listTasks4({ assigned_to: effectiveAgentId, limit: 500 }, undefined);
|
|
67032
67056
|
const now4 = Date.now();
|
|
67033
67057
|
const dueSoonCutoff = now4 + 24 * 60 * 60 * 1000;
|
|
67034
|
-
const
|
|
67058
|
+
const blockedAliases = assignedToAliasSet(getDatabase(), effectiveAgentId);
|
|
67059
|
+
const blocked = getBlockedTasks2().filter((t) => blockedAliases.has((t.assigned_to ?? "").toLowerCase()));
|
|
67035
67060
|
const workload = {
|
|
67036
67061
|
in_progress: assigned.filter((t) => t.status === "in_progress").length,
|
|
67037
67062
|
pending: assigned.filter((t) => t.status === "pending").length,
|
|
@@ -67068,17 +67093,25 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
67068
67093
|
if (agents.length === 0)
|
|
67069
67094
|
return { content: [{ type: "text", text: "No active agents available for rebalancing." }] };
|
|
67070
67095
|
const activeTasks = listTasks4({ project_id: resolvedProjectId, status: ["pending", "in_progress"], limit: 1000 }, undefined);
|
|
67071
|
-
const
|
|
67096
|
+
const agentKeyByAlias = new Map;
|
|
67097
|
+
for (const agent of agents) {
|
|
67098
|
+
agentKeyByAlias.set(String(agent.id).toLowerCase(), agent.id);
|
|
67099
|
+
if (agent.name)
|
|
67100
|
+
agentKeyByAlias.set(String(agent.name).toLowerCase(), agent.id);
|
|
67101
|
+
}
|
|
67102
|
+
const canonicalAgentKey = (assignedTo) => assignedTo ? agentKeyByAlias.get(assignedTo.toLowerCase()) : undefined;
|
|
67103
|
+
const load = new Map(agents.map((agent) => [agent.id, activeTasks.filter((t) => canonicalAgentKey(t.assigned_to) === agent.id).length]));
|
|
67072
67104
|
let moved = 0;
|
|
67073
67105
|
let skipped = 0;
|
|
67074
|
-
for (const task of activeTasks.filter((t) => t.status === "pending" && t.assigned_to && (load.get(t.assigned_to) ?? 0) > limit)) {
|
|
67075
|
-
const
|
|
67106
|
+
for (const task of activeTasks.filter((t) => t.status === "pending" && canonicalAgentKey(t.assigned_to) && (load.get(canonicalAgentKey(t.assigned_to)) ?? 0) > limit)) {
|
|
67107
|
+
const currentAgentKey = canonicalAgentKey(task.assigned_to);
|
|
67108
|
+
const target = agents.filter((agent) => agent.id !== currentAgentKey).sort((a, b) => (load.get(a.id) ?? 0) - (load.get(b.id) ?? 0))[0];
|
|
67076
67109
|
if (!target || (load.get(target.id) ?? 0) >= limit) {
|
|
67077
67110
|
skipped++;
|
|
67078
67111
|
continue;
|
|
67079
67112
|
}
|
|
67080
67113
|
updateTask3(task.id, { assigned_to: target.id, version: task.version });
|
|
67081
|
-
load.set(
|
|
67114
|
+
load.set(currentAgentKey, (load.get(currentAgentKey) ?? 1) - 1);
|
|
67082
67115
|
load.set(target.id, (load.get(target.id) ?? 0) + 1);
|
|
67083
67116
|
moved++;
|
|
67084
67117
|
}
|
|
@@ -67257,6 +67290,7 @@ ${lines.join(`
|
|
|
67257
67290
|
var init_task_auto_tools = __esm(() => {
|
|
67258
67291
|
init_zod();
|
|
67259
67292
|
init_cloud_router();
|
|
67293
|
+
init_database();
|
|
67260
67294
|
});
|
|
67261
67295
|
|
|
67262
67296
|
// src/lib/context-packs.ts
|
|
@@ -68436,7 +68470,8 @@ ${JSON.stringify(task.metadata, null, 2)}` : null
|
|
|
68436
68470
|
}, undefined);
|
|
68437
68471
|
const completedYesterday = completed.filter((t) => t.completed_at && t.completed_at.startsWith(yesterdayStr));
|
|
68438
68472
|
const { getBlockedTasks: getBlockedTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
68439
|
-
const
|
|
68473
|
+
const blockedAliases = effectiveAgentId ? assignedToAliasSet(getDatabase(), effectiveAgentId) : null;
|
|
68474
|
+
const blocked = getBlockedTasks2(effectiveProjectId ? resolveId(effectiveProjectId, "projects") : undefined).filter((t) => blockedAliases ? blockedAliases.has((t.assigned_to ?? "").toLowerCase()) : false);
|
|
68440
68475
|
const lines = [
|
|
68441
68476
|
`Standup for ${effectiveAgentId} (${effectiveProjectId ? `project: ${effectiveProjectId.slice(0, 8)}` : "all projects"})`,
|
|
68442
68477
|
inProgress.length > 0 ? `
|
|
@@ -68664,6 +68699,7 @@ var init_task_adv_tools = __esm(() => {
|
|
|
68664
68699
|
init_zod();
|
|
68665
68700
|
init_token_utils();
|
|
68666
68701
|
init_cloud_router();
|
|
68702
|
+
init_database();
|
|
68667
68703
|
});
|
|
68668
68704
|
|
|
68669
68705
|
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.cjs
|
|
@@ -94355,27 +94391,29 @@ function getAgentMetrics(agentId, opts, db) {
|
|
|
94355
94391
|
const agent = d.query("SELECT id, name FROM agents WHERE id = ? OR LOWER(name) = LOWER(?)").get(agentId, agentId);
|
|
94356
94392
|
if (!agent)
|
|
94357
94393
|
return null;
|
|
94394
|
+
const assignedAliases = resolveAssignedToAliases(d, agent.id).map((a) => a.toLowerCase());
|
|
94395
|
+
const assignedInClause = `LOWER(assigned_to) IN (${assignedAliases.map(() => "?").join(",")})`;
|
|
94358
94396
|
let projectFilter = "";
|
|
94359
|
-
const params = [agent.id,
|
|
94397
|
+
const params = [agent.id, ...assignedAliases];
|
|
94360
94398
|
if (opts?.project_id) {
|
|
94361
94399
|
projectFilter = " AND project_id = ?";
|
|
94362
94400
|
params.push(opts.project_id);
|
|
94363
94401
|
}
|
|
94364
|
-
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94365
|
-
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94366
|
-
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94402
|
+
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}`).get(...params).count;
|
|
94403
|
+
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'failed'${projectFilter}`).get(...params).count;
|
|
94404
|
+
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'in_progress'${projectFilter}`).get(...params).count;
|
|
94367
94405
|
const total = completed + failed;
|
|
94368
94406
|
const completionRate = total > 0 ? completed / total : 0;
|
|
94369
94407
|
const avgTime = d.query(`SELECT AVG(
|
|
94370
94408
|
(julianday(completed_at) - julianday(created_at)) * 24 * 60
|
|
94371
94409
|
) as avg_minutes
|
|
94372
94410
|
FROM tasks
|
|
94373
|
-
WHERE (agent_id = ? OR
|
|
94411
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter}`).get(...params);
|
|
94374
94412
|
const avgConf = d.query(`SELECT AVG(confidence) as avg_confidence
|
|
94375
94413
|
FROM tasks
|
|
94376
|
-
WHERE (agent_id = ? OR
|
|
94414
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND confidence IS NOT NULL${projectFilter}`).get(...params);
|
|
94377
94415
|
const reviewTasks = d.query(`SELECT metadata FROM tasks
|
|
94378
|
-
WHERE (agent_id = ? OR
|
|
94416
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}
|
|
94379
94417
|
AND metadata LIKE '%_review_score%'`).all(...params);
|
|
94380
94418
|
let reviewScoreAvg = null;
|
|
94381
94419
|
if (reviewTasks.length > 0) {
|
|
@@ -94839,14 +94877,15 @@ function millisBetween(start, end) {
|
|
|
94839
94877
|
return 0;
|
|
94840
94878
|
return endMs - startMs;
|
|
94841
94879
|
}
|
|
94842
|
-
function addTaskScope(where, params, options, alias = "t") {
|
|
94880
|
+
function addTaskScope(where, params, options, db, alias = "t") {
|
|
94843
94881
|
if (options.project_id) {
|
|
94844
94882
|
where.push(`${alias}.project_id = ?`);
|
|
94845
94883
|
params.push(options.project_id);
|
|
94846
94884
|
}
|
|
94847
94885
|
if (options.agent_id) {
|
|
94848
|
-
|
|
94849
|
-
|
|
94886
|
+
params.push(options.agent_id);
|
|
94887
|
+
const assignedInClause = lowerInClause(`${alias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
94888
|
+
where.push(`(${alias}.agent_id = ? OR ${assignedInClause})`);
|
|
94850
94889
|
}
|
|
94851
94890
|
if (options.since) {
|
|
94852
94891
|
where.push(`${alias}.created_at >= ?`);
|
|
@@ -94857,14 +94896,15 @@ function addTaskScope(where, params, options, alias = "t") {
|
|
|
94857
94896
|
params.push(options.until);
|
|
94858
94897
|
}
|
|
94859
94898
|
}
|
|
94860
|
-
function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
94899
|
+
function addRunScope(where, params, options, db, runAlias = "r", taskAlias = "t") {
|
|
94861
94900
|
if (options.project_id) {
|
|
94862
94901
|
where.push(`${taskAlias}.project_id = ?`);
|
|
94863
94902
|
params.push(options.project_id);
|
|
94864
94903
|
}
|
|
94865
94904
|
if (options.agent_id) {
|
|
94866
|
-
|
|
94867
|
-
|
|
94905
|
+
params.push(options.agent_id, options.agent_id);
|
|
94906
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
94907
|
+
where.push(`(${runAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
94868
94908
|
}
|
|
94869
94909
|
if (options.since) {
|
|
94870
94910
|
where.push(`${runAlias}.started_at >= ?`);
|
|
@@ -94875,14 +94915,15 @@ function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
|
94875
94915
|
params.push(options.until);
|
|
94876
94916
|
}
|
|
94877
94917
|
}
|
|
94878
|
-
function addTraceScope(where, params, options, traceAlias = "tr", taskAlias = "t") {
|
|
94918
|
+
function addTraceScope(where, params, options, db, traceAlias = "tr", taskAlias = "t") {
|
|
94879
94919
|
if (options.project_id) {
|
|
94880
94920
|
where.push(`${taskAlias}.project_id = ?`);
|
|
94881
94921
|
params.push(options.project_id);
|
|
94882
94922
|
}
|
|
94883
94923
|
if (options.agent_id) {
|
|
94884
|
-
|
|
94885
|
-
|
|
94924
|
+
params.push(options.agent_id, options.agent_id);
|
|
94925
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
94926
|
+
where.push(`(${traceAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
94886
94927
|
}
|
|
94887
94928
|
if (options.since) {
|
|
94888
94929
|
where.push(`${traceAlias}.created_at >= ?`);
|
|
@@ -94942,7 +94983,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94942
94983
|
const generatedAt = options.generated_at || new Date().toISOString();
|
|
94943
94984
|
const taskWhere = [];
|
|
94944
94985
|
const taskParams = [];
|
|
94945
|
-
addTaskScope(taskWhere, taskParams, options);
|
|
94986
|
+
addTaskScope(taskWhere, taskParams, options, d);
|
|
94946
94987
|
const taskClause = taskWhere.length ? `WHERE ${taskWhere.join(" AND ")}` : "";
|
|
94947
94988
|
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);
|
|
94948
94989
|
let projectCount = 0;
|
|
@@ -94951,14 +94992,14 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94951
94992
|
} else if (options.agent_id) {
|
|
94952
94993
|
const projectWhere = ["t.project_id IS NOT NULL"];
|
|
94953
94994
|
const projectParams = [];
|
|
94954
|
-
addTaskScope(projectWhere, projectParams, options);
|
|
94995
|
+
addTaskScope(projectWhere, projectParams, options, d);
|
|
94955
94996
|
projectCount = queryOne(d, `SELECT COUNT(DISTINCT t.project_id) as count FROM tasks t WHERE ${projectWhere.join(" AND ")}`, projectParams).count;
|
|
94956
94997
|
} else {
|
|
94957
94998
|
projectCount = queryOne(d, "SELECT COUNT(*) as count FROM projects", []).count;
|
|
94958
94999
|
}
|
|
94959
95000
|
const runWhere = [];
|
|
94960
95001
|
const runParams = [];
|
|
94961
|
-
addRunScope(runWhere, runParams, options);
|
|
95002
|
+
addRunScope(runWhere, runParams, options, d);
|
|
94962
95003
|
const runClause = runWhere.length ? `WHERE ${runWhere.join(" AND ")}` : "";
|
|
94963
95004
|
const runs = queryAll(d, `SELECT r.id, r.started_at, r.completed_at, r.metadata
|
|
94964
95005
|
FROM task_runs r JOIN tasks t ON t.id = r.task_id
|
|
@@ -94975,7 +95016,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94975
95016
|
${runClause}`, runParams);
|
|
94976
95017
|
const traceWhere = [];
|
|
94977
95018
|
const traceParams = [];
|
|
94978
|
-
addTraceScope(traceWhere, traceParams, options);
|
|
95019
|
+
addTraceScope(traceWhere, traceParams, options, d);
|
|
94979
95020
|
const traceClause = traceWhere.length ? `WHERE ${traceWhere.join(" AND ")}` : "";
|
|
94980
95021
|
const traceTotals = queryOne(d, `SELECT COUNT(*) as traces,
|
|
94981
95022
|
COALESCE(SUM(tr.tokens), 0) as tokens,
|
|
@@ -95119,10 +95160,12 @@ function limitValue(value) {
|
|
|
95119
95160
|
function isTerminal2(task) {
|
|
95120
95161
|
return task.status === "completed" || task.status === "failed" || task.status === "cancelled";
|
|
95121
95162
|
}
|
|
95122
|
-
function sameAgent(task, agentId) {
|
|
95163
|
+
function sameAgent(task, agentId, aliasSet) {
|
|
95123
95164
|
if (!agentId)
|
|
95124
95165
|
return true;
|
|
95125
|
-
|
|
95166
|
+
if (task.agent_id === agentId)
|
|
95167
|
+
return true;
|
|
95168
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
95126
95169
|
}
|
|
95127
95170
|
function withinTaskWindow(task, options) {
|
|
95128
95171
|
const time3 = Date.parse(task.updated_at);
|
|
@@ -95135,11 +95178,12 @@ function withinTaskWindow(task, options) {
|
|
|
95135
95178
|
return true;
|
|
95136
95179
|
}
|
|
95137
95180
|
function scopedTasks(options, db) {
|
|
95181
|
+
const aliasSet = options.agent_id ? assignedToAliasSet(db, options.agent_id) : undefined;
|
|
95138
95182
|
return listTasks2({
|
|
95139
95183
|
project_id: options.project_id,
|
|
95140
95184
|
plan_id: options.plan_id,
|
|
95141
95185
|
include_archived: false
|
|
95142
|
-
}, db).filter((task) => sameAgent(task, options.agent_id) && withinTaskWindow(task, options));
|
|
95186
|
+
}, db).filter((task) => sameAgent(task, options.agent_id, aliasSet) && withinTaskWindow(task, options));
|
|
95143
95187
|
}
|
|
95144
95188
|
function summarizeTask(task) {
|
|
95145
95189
|
return {
|
|
@@ -95205,7 +95249,7 @@ function initialAgentSummary(agentId) {
|
|
|
95205
95249
|
}
|
|
95206
95250
|
};
|
|
95207
95251
|
}
|
|
95208
|
-
function addScopeClauses(where, params, options, timeColumn) {
|
|
95252
|
+
function addScopeClauses(where, params, options, timeColumn, db) {
|
|
95209
95253
|
if (options.project_id) {
|
|
95210
95254
|
where.push("t.project_id = ?");
|
|
95211
95255
|
params.push(options.project_id);
|
|
@@ -95215,8 +95259,9 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
95215
95259
|
params.push(options.plan_id);
|
|
95216
95260
|
}
|
|
95217
95261
|
if (options.agent_id) {
|
|
95218
|
-
|
|
95219
|
-
|
|
95262
|
+
params.push(options.agent_id, options.agent_id);
|
|
95263
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
95264
|
+
where.push(`(r.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
95220
95265
|
}
|
|
95221
95266
|
if (options.since) {
|
|
95222
95267
|
where.push(`${timeColumn} >= ?`);
|
|
@@ -95230,7 +95275,7 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
95230
95275
|
function loadRuns(options, db) {
|
|
95231
95276
|
const where = ["t.archived_at IS NULL"];
|
|
95232
95277
|
const params = [];
|
|
95233
|
-
addScopeClauses(where, params, options, "r.started_at");
|
|
95278
|
+
addScopeClauses(where, params, options, "r.started_at", db);
|
|
95234
95279
|
return db.query(`
|
|
95235
95280
|
SELECT
|
|
95236
95281
|
r.id,
|
|
@@ -95270,8 +95315,9 @@ function loadVerifications(options, db) {
|
|
|
95270
95315
|
params.push(options.plan_id);
|
|
95271
95316
|
}
|
|
95272
95317
|
if (options.agent_id) {
|
|
95273
|
-
|
|
95274
|
-
|
|
95318
|
+
params.push(options.agent_id, options.agent_id);
|
|
95319
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
95320
|
+
where.push(`(v.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
95275
95321
|
}
|
|
95276
95322
|
if (options.since) {
|
|
95277
95323
|
where.push("v.run_at >= ?");
|
|
@@ -95493,7 +95539,6 @@ function renderLocalReportMarkdown(report) {
|
|
|
95493
95539
|
}
|
|
95494
95540
|
var LOCAL_REPORT_SCHEMA_VERSION = 1, LOCAL_REPORT_TYPES;
|
|
95495
95541
|
var init_local_reports = __esm(() => {
|
|
95496
|
-
init_database();
|
|
95497
95542
|
init_database();
|
|
95498
95543
|
init_plans();
|
|
95499
95544
|
init_tasks();
|
|
@@ -99596,7 +99641,7 @@ ${lines.join(`
|
|
|
99596
99641
|
a.name AS agent_name
|
|
99597
99642
|
FROM task_files tf
|
|
99598
99643
|
JOIN tasks t ON tf.task_id = t.id
|
|
99599
|
-
LEFT JOIN agents a ON (tf.agent_id = a.id OR (tf.agent_id IS NULL AND t.assigned_to = a.id))
|
|
99644
|
+
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))))
|
|
99600
99645
|
WHERE t.status = 'in_progress'
|
|
99601
99646
|
AND tf.status != 'removed'
|
|
99602
99647
|
AND t.project_id = ?
|
|
@@ -103360,7 +103405,7 @@ ${text2}` }] };
|
|
|
103360
103405
|
const oldName = agent.name;
|
|
103361
103406
|
const updated = updateAgent2(agent.id, { name: new_name });
|
|
103362
103407
|
const db = getDatabase();
|
|
103363
|
-
const tasksResult = db.run("UPDATE tasks SET assigned_to = ? WHERE assigned_to = ?", [new_name, oldName]);
|
|
103408
|
+
const tasksResult = db.run("UPDATE tasks SET assigned_to = ? WHERE LOWER(assigned_to) = LOWER(?)", [new_name, oldName]);
|
|
103364
103409
|
const taskNote = tasksResult.changes > 0 ? `
|
|
103365
103410
|
Updated assigned_to on ${tasksResult.changes} task(s).` : "";
|
|
103366
103411
|
return {
|