@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.
Files changed (36) hide show
  1. package/dist/cli/cloud-router.d.ts.map +1 -1
  2. package/dist/cli/index.js +145 -95
  3. package/dist/contracts.js +92 -67
  4. package/dist/db/agent-metrics.d.ts.map +1 -1
  5. package/dist/db/audit.d.ts.map +1 -1
  6. package/dist/db/budgets.d.ts.map +1 -1
  7. package/dist/db/database.d.ts +44 -0
  8. package/dist/db/database.d.ts.map +1 -1
  9. package/dist/db/handoffs.d.ts.map +1 -1
  10. package/dist/db/task-crud.d.ts +1 -0
  11. package/dist/db/task-crud.d.ts.map +1 -1
  12. package/dist/db/task-files.d.ts.map +1 -1
  13. package/dist/db/task-lifecycle.d.ts.map +1 -1
  14. package/dist/db/task-relations.d.ts.map +1 -1
  15. package/dist/db/task-status.d.ts.map +1 -1
  16. package/dist/db/webhooks.d.ts.map +1 -1
  17. package/dist/index.js +119 -85
  18. package/dist/lib/capacity-forecasts.d.ts.map +1 -1
  19. package/dist/lib/completion-guard.d.ts.map +1 -1
  20. package/dist/lib/local-notifications.d.ts.map +1 -1
  21. package/dist/lib/local-reports.d.ts.map +1 -1
  22. package/dist/lib/notification-reminders.d.ts.map +1 -1
  23. package/dist/lib/search.d.ts.map +1 -1
  24. package/dist/lib/usage-ledger.d.ts.map +1 -1
  25. package/dist/mcp/index.js +136 -92
  26. package/dist/mcp/tools/agents.d.ts.map +1 -1
  27. package/dist/mcp/tools/task-adv-tools.d.ts.map +1 -1
  28. package/dist/mcp/tools/task-auto-tools.d.ts.map +1 -1
  29. package/dist/mcp/tools/task-resources.d.ts.map +1 -1
  30. package/dist/mcp.js +1 -1
  31. package/dist/registry.js +92 -67
  32. package/dist/release-provenance.json +5 -5
  33. package/dist/server/index.js +136 -92
  34. package/dist/server/routes.d.ts.map +1 -1
  35. package/dist/storage.js +57 -42
  36. package/package.json +1 -1
@@ -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.11",
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 (assigned_to = ? OR agent_id = ?)`).get(windowStart, agent, agent);
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 (assigned_to = ? OR agent_id = ?) AND id != ?`).get(agent, agent, task.id);
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 && payload.assigned_to !== wh.agent_id)
12327
- return false;
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 assigned_to = ? AND status = 'completed' AND project_id IS NOT NULL ORDER BY completed_at DESC LIMIT 3`).all(agentId);
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 assigned_to = ? THEN 0 WHEN assigned_to IS NULL THEN 1 ELSE 2 END, `;
13473
- params.push(agentId);
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
- conditions.push("(agent_id = ? OR assigned_to = ?)");
14526
- params.push(filters.agent_id, filters.agent_id);
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
- t.assigned_to = ?
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, 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 === agentId || t.agent_id === agentId || !t.assigned_to && !t.locked_by);
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 += " AND t.assigned_to = ?";
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 = ?";
@@ -60747,11 +60762,12 @@ function runAlerts(input, db, checkedAt, quieted) {
60747
60762
  if (input.include_runs === false)
60748
60763
  return [];
60749
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;
60750
60766
  return listTaskRuns(undefined, db).filter((run) => run.completed_at && Date.parse(run.completed_at) >= since).map((run) => {
60751
60767
  const task = getTask(run.task_id, db);
60752
60768
  if (input.project_id && task?.project_id !== input.project_id)
60753
60769
  return null;
60754
- if (input.agent_id && run.agent_id !== input.agent_id && task?.assigned_to !== input.agent_id)
60770
+ if (input.agent_id && run.agent_id !== input.agent_id && !(runAlertAliases && runAlertAliases.has((task?.assigned_to ?? "").toLowerCase())))
60755
60771
  return null;
60756
60772
  const failed = ["failed", "cancelled"].includes(run.status);
60757
60773
  return {
@@ -60796,6 +60812,7 @@ async function checkLocalNotifications(input = {}, db) {
60796
60812
  const warnings = [];
60797
60813
  if (Number.isNaN(checkedMs))
60798
60814
  warnings.push("Invalid check timestamp; due-soon window may be incomplete.");
60815
+ const notifyAgentAliases = input.agent_id ? assignedToAliasSet(d, input.agent_id) : null;
60799
60816
  const alerts = [];
60800
60817
  for (const escalation of getEscalatedTasks({ project_id: input.project_id, agent_id: input.agent_id }, d, new Date(checkedAt))) {
60801
60818
  for (const reason of escalation.reasons) {
@@ -60807,7 +60824,7 @@ async function checkLocalNotifications(input = {}, db) {
60807
60824
  for (const task of listTasks2({ project_id: input.project_id, include_archived: false, limit: 5000 }, d)) {
60808
60825
  if (!unfinished(task) || !task.due_at)
60809
60826
  continue;
60810
- if (input.agent_id && task.assigned_to !== input.agent_id && task.agent_id !== input.agent_id)
60827
+ if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
60811
60828
  continue;
60812
60829
  if (task.due_at > checkedAt && task.due_at <= dueSoonUntil) {
60813
60830
  alerts.push(taskAlert(task, "task_due_soon", "task.due_soon", "warning", `Due soon: ${task.title}`, task.due_at, quieted));
@@ -60815,7 +60832,7 @@ async function checkLocalNotifications(input = {}, db) {
60815
60832
  }
60816
60833
  }
60817
60834
  for (const task of getStaleTasks(staleMinutes, { project_id: input.project_id }, d)) {
60818
- if (input.agent_id && task.assigned_to !== input.agent_id && task.agent_id !== input.agent_id)
60835
+ if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
60819
60836
  continue;
60820
60837
  alerts.push(taskAlert(task, "task_stale", "task.stale", "warning", `Stale task: ${task.title}`, checkedAt, quieted, { stale_minutes: staleMinutes }));
60821
60838
  }
@@ -62835,10 +62852,12 @@ function matchesProfile(profile, query) {
62835
62852
  return false;
62836
62853
  return true;
62837
62854
  }
62838
- function taskMatchesAgent(task, agentId) {
62855
+ function taskMatchesAgent(task, agentId, aliasSet) {
62839
62856
  if (!agentId)
62840
62857
  return true;
62841
- return task.assigned_to === agentId || task.agent_id === agentId;
62858
+ if (task.agent_id === agentId)
62859
+ return true;
62860
+ return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
62842
62861
  }
62843
62862
  function estimateRemaining(task) {
62844
62863
  if (task.status === "completed" || task.status === "cancelled")
@@ -62908,7 +62927,8 @@ function removeCapacityProfile(idOrAgent, projectId) {
62908
62927
  }
62909
62928
  function getPlanningForecast(input = {}, db) {
62910
62929
  const startDate = input.start_date ? dateOnly(input.start_date) : todayIso();
62911
- const tasks = listTasks2({ project_id: input.project_id, plan_id: input.plan_id, limit: 1e4 }, db).filter((task) => taskMatchesAgent(task, input.agent_id));
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));
62912
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]));
62913
62933
  const profiles = listCapacityProfiles({ agent_id: input.agent_id, project_id: input.project_id });
62914
62934
  const globalProfiles = input.project_id ? listCapacityProfiles({ agent_id: input.agent_id }).filter((profile) => profile.project_id === null) : [];
@@ -63006,6 +63026,7 @@ function renderPlanningForecastMarkdown(forecast) {
63006
63026
  }
63007
63027
  var LOCAL_CAPACITY_SCHEMA_VERSION = 1;
63008
63028
  var init_capacity_forecasts = __esm(() => {
63029
+ init_database();
63009
63030
  init_tasks();
63010
63031
  init_task_relations();
63011
63032
  init_config2();
@@ -66439,8 +66460,10 @@ function getLatestHandoff(agentId, projectId, db) {
66439
66460
  function createSessionRecoveryHandoff(input, db) {
66440
66461
  const d = db || getDatabase();
66441
66462
  const limit = input.limit || 20;
66442
- const conditions = ["status = 'in_progress'", "(assigned_to = ? OR agent_id = ? OR locked_by = ?)"];
66443
- const params = [input.agent_id, input.agent_id, input.agent_id];
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);
66444
66467
  if (input.session_id) {
66445
66468
  conditions.push("session_id = ?");
66446
66469
  params.push(input.session_id);
@@ -67032,7 +67055,8 @@ function registerTaskAutoTools(server, ctx) {
67032
67055
  const assigned = listTasks4({ assigned_to: effectiveAgentId, limit: 500 }, undefined);
67033
67056
  const now4 = Date.now();
67034
67057
  const dueSoonCutoff = now4 + 24 * 60 * 60 * 1000;
67035
- const blocked = getBlockedTasks2().filter((t) => t.assigned_to === effectiveAgentId);
67058
+ const blockedAliases = assignedToAliasSet(getDatabase(), effectiveAgentId);
67059
+ const blocked = getBlockedTasks2().filter((t) => blockedAliases.has((t.assigned_to ?? "").toLowerCase()));
67036
67060
  const workload = {
67037
67061
  in_progress: assigned.filter((t) => t.status === "in_progress").length,
67038
67062
  pending: assigned.filter((t) => t.status === "pending").length,
@@ -67069,17 +67093,25 @@ function registerTaskAutoTools(server, ctx) {
67069
67093
  if (agents.length === 0)
67070
67094
  return { content: [{ type: "text", text: "No active agents available for rebalancing." }] };
67071
67095
  const activeTasks = listTasks4({ project_id: resolvedProjectId, status: ["pending", "in_progress"], limit: 1000 }, undefined);
67072
- const load = new Map(agents.map((agent) => [agent.id, activeTasks.filter((t) => t.assigned_to === agent.id).length]));
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]));
67073
67104
  let moved = 0;
67074
67105
  let skipped = 0;
67075
- for (const task of activeTasks.filter((t) => t.status === "pending" && t.assigned_to && (load.get(t.assigned_to) ?? 0) > limit)) {
67076
- const target = agents.filter((agent) => agent.id !== task.assigned_to).sort((a, b) => (load.get(a.id) ?? 0) - (load.get(b.id) ?? 0))[0];
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];
67077
67109
  if (!target || (load.get(target.id) ?? 0) >= limit) {
67078
67110
  skipped++;
67079
67111
  continue;
67080
67112
  }
67081
67113
  updateTask3(task.id, { assigned_to: target.id, version: task.version });
67082
- load.set(task.assigned_to, (load.get(task.assigned_to) ?? 1) - 1);
67114
+ load.set(currentAgentKey, (load.get(currentAgentKey) ?? 1) - 1);
67083
67115
  load.set(target.id, (load.get(target.id) ?? 0) + 1);
67084
67116
  moved++;
67085
67117
  }
@@ -67258,6 +67290,7 @@ ${lines.join(`
67258
67290
  var init_task_auto_tools = __esm(() => {
67259
67291
  init_zod();
67260
67292
  init_cloud_router();
67293
+ init_database();
67261
67294
  });
67262
67295
 
67263
67296
  // src/lib/context-packs.ts
@@ -68437,7 +68470,8 @@ ${JSON.stringify(task.metadata, null, 2)}` : null
68437
68470
  }, undefined);
68438
68471
  const completedYesterday = completed.filter((t) => t.completed_at && t.completed_at.startsWith(yesterdayStr));
68439
68472
  const { getBlockedTasks: getBlockedTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
68440
- const blocked = getBlockedTasks2(effectiveProjectId ? resolveId(effectiveProjectId, "projects") : undefined).filter((t) => t.assigned_to === effectiveAgentId);
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);
68441
68475
  const lines = [
68442
68476
  `Standup for ${effectiveAgentId} (${effectiveProjectId ? `project: ${effectiveProjectId.slice(0, 8)}` : "all projects"})`,
68443
68477
  inProgress.length > 0 ? `
@@ -68665,6 +68699,7 @@ var init_task_adv_tools = __esm(() => {
68665
68699
  init_zod();
68666
68700
  init_token_utils();
68667
68701
  init_cloud_router();
68702
+ init_database();
68668
68703
  });
68669
68704
 
68670
68705
  // node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.cjs
@@ -94356,27 +94391,29 @@ function getAgentMetrics(agentId, opts, db) {
94356
94391
  const agent = d.query("SELECT id, name FROM agents WHERE id = ? OR LOWER(name) = LOWER(?)").get(agentId, agentId);
94357
94392
  if (!agent)
94358
94393
  return null;
94394
+ const assignedAliases = resolveAssignedToAliases(d, agent.id).map((a) => a.toLowerCase());
94395
+ const assignedInClause = `LOWER(assigned_to) IN (${assignedAliases.map(() => "?").join(",")})`;
94359
94396
  let projectFilter = "";
94360
- const params = [agent.id, agent.id];
94397
+ const params = [agent.id, ...assignedAliases];
94361
94398
  if (opts?.project_id) {
94362
94399
  projectFilter = " AND project_id = ?";
94363
94400
  params.push(opts.project_id);
94364
94401
  }
94365
- const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR assigned_to = ?) AND status = 'completed'${projectFilter}`).get(...params).count;
94366
- const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR assigned_to = ?) AND status = 'failed'${projectFilter}`).get(...params).count;
94367
- const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR assigned_to = ?) AND status = 'in_progress'${projectFilter}`).get(...params).count;
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;
94368
94405
  const total = completed + failed;
94369
94406
  const completionRate = total > 0 ? completed / total : 0;
94370
94407
  const avgTime = d.query(`SELECT AVG(
94371
94408
  (julianday(completed_at) - julianday(created_at)) * 24 * 60
94372
94409
  ) as avg_minutes
94373
94410
  FROM tasks
94374
- WHERE (agent_id = ? OR assigned_to = ?) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter}`).get(...params);
94411
+ WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter}`).get(...params);
94375
94412
  const avgConf = d.query(`SELECT AVG(confidence) as avg_confidence
94376
94413
  FROM tasks
94377
- WHERE (agent_id = ? OR assigned_to = ?) AND status = 'completed' AND confidence IS NOT NULL${projectFilter}`).get(...params);
94414
+ WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND confidence IS NOT NULL${projectFilter}`).get(...params);
94378
94415
  const reviewTasks = d.query(`SELECT metadata FROM tasks
94379
- WHERE (agent_id = ? OR assigned_to = ?) AND status = 'completed'${projectFilter}
94416
+ WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}
94380
94417
  AND metadata LIKE '%_review_score%'`).all(...params);
94381
94418
  let reviewScoreAvg = null;
94382
94419
  if (reviewTasks.length > 0) {
@@ -94840,14 +94877,15 @@ function millisBetween(start, end) {
94840
94877
  return 0;
94841
94878
  return endMs - startMs;
94842
94879
  }
94843
- function addTaskScope(where, params, options, alias = "t") {
94880
+ function addTaskScope(where, params, options, db, alias = "t") {
94844
94881
  if (options.project_id) {
94845
94882
  where.push(`${alias}.project_id = ?`);
94846
94883
  params.push(options.project_id);
94847
94884
  }
94848
94885
  if (options.agent_id) {
94849
- where.push(`(${alias}.agent_id = ? OR ${alias}.assigned_to = ?)`);
94850
- params.push(options.agent_id, options.agent_id);
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})`);
94851
94889
  }
94852
94890
  if (options.since) {
94853
94891
  where.push(`${alias}.created_at >= ?`);
@@ -94858,14 +94896,15 @@ function addTaskScope(where, params, options, alias = "t") {
94858
94896
  params.push(options.until);
94859
94897
  }
94860
94898
  }
94861
- function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
94899
+ function addRunScope(where, params, options, db, runAlias = "r", taskAlias = "t") {
94862
94900
  if (options.project_id) {
94863
94901
  where.push(`${taskAlias}.project_id = ?`);
94864
94902
  params.push(options.project_id);
94865
94903
  }
94866
94904
  if (options.agent_id) {
94867
- where.push(`(${runAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${taskAlias}.assigned_to = ?)`);
94868
- params.push(options.agent_id, options.agent_id, options.agent_id);
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})`);
94869
94908
  }
94870
94909
  if (options.since) {
94871
94910
  where.push(`${runAlias}.started_at >= ?`);
@@ -94876,14 +94915,15 @@ function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
94876
94915
  params.push(options.until);
94877
94916
  }
94878
94917
  }
94879
- function addTraceScope(where, params, options, traceAlias = "tr", taskAlias = "t") {
94918
+ function addTraceScope(where, params, options, db, traceAlias = "tr", taskAlias = "t") {
94880
94919
  if (options.project_id) {
94881
94920
  where.push(`${taskAlias}.project_id = ?`);
94882
94921
  params.push(options.project_id);
94883
94922
  }
94884
94923
  if (options.agent_id) {
94885
- where.push(`(${traceAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${taskAlias}.assigned_to = ?)`);
94886
- params.push(options.agent_id, options.agent_id, options.agent_id);
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})`);
94887
94927
  }
94888
94928
  if (options.since) {
94889
94929
  where.push(`${traceAlias}.created_at >= ?`);
@@ -94943,7 +94983,7 @@ function createLocalUsageLedger(options = {}, db) {
94943
94983
  const generatedAt = options.generated_at || new Date().toISOString();
94944
94984
  const taskWhere = [];
94945
94985
  const taskParams = [];
94946
- addTaskScope(taskWhere, taskParams, options);
94986
+ addTaskScope(taskWhere, taskParams, options, d);
94947
94987
  const taskClause = taskWhere.length ? `WHERE ${taskWhere.join(" AND ")}` : "";
94948
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);
94949
94989
  let projectCount = 0;
@@ -94952,14 +94992,14 @@ function createLocalUsageLedger(options = {}, db) {
94952
94992
  } else if (options.agent_id) {
94953
94993
  const projectWhere = ["t.project_id IS NOT NULL"];
94954
94994
  const projectParams = [];
94955
- addTaskScope(projectWhere, projectParams, options);
94995
+ addTaskScope(projectWhere, projectParams, options, d);
94956
94996
  projectCount = queryOne(d, `SELECT COUNT(DISTINCT t.project_id) as count FROM tasks t WHERE ${projectWhere.join(" AND ")}`, projectParams).count;
94957
94997
  } else {
94958
94998
  projectCount = queryOne(d, "SELECT COUNT(*) as count FROM projects", []).count;
94959
94999
  }
94960
95000
  const runWhere = [];
94961
95001
  const runParams = [];
94962
- addRunScope(runWhere, runParams, options);
95002
+ addRunScope(runWhere, runParams, options, d);
94963
95003
  const runClause = runWhere.length ? `WHERE ${runWhere.join(" AND ")}` : "";
94964
95004
  const runs = queryAll(d, `SELECT r.id, r.started_at, r.completed_at, r.metadata
94965
95005
  FROM task_runs r JOIN tasks t ON t.id = r.task_id
@@ -94976,7 +95016,7 @@ function createLocalUsageLedger(options = {}, db) {
94976
95016
  ${runClause}`, runParams);
94977
95017
  const traceWhere = [];
94978
95018
  const traceParams = [];
94979
- addTraceScope(traceWhere, traceParams, options);
95019
+ addTraceScope(traceWhere, traceParams, options, d);
94980
95020
  const traceClause = traceWhere.length ? `WHERE ${traceWhere.join(" AND ")}` : "";
94981
95021
  const traceTotals = queryOne(d, `SELECT COUNT(*) as traces,
94982
95022
  COALESCE(SUM(tr.tokens), 0) as tokens,
@@ -95120,10 +95160,12 @@ function limitValue(value) {
95120
95160
  function isTerminal2(task) {
95121
95161
  return task.status === "completed" || task.status === "failed" || task.status === "cancelled";
95122
95162
  }
95123
- function sameAgent(task, agentId) {
95163
+ function sameAgent(task, agentId, aliasSet) {
95124
95164
  if (!agentId)
95125
95165
  return true;
95126
- return task.assigned_to === agentId || task.agent_id === agentId;
95166
+ if (task.agent_id === agentId)
95167
+ return true;
95168
+ return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
95127
95169
  }
95128
95170
  function withinTaskWindow(task, options) {
95129
95171
  const time3 = Date.parse(task.updated_at);
@@ -95136,11 +95178,12 @@ function withinTaskWindow(task, options) {
95136
95178
  return true;
95137
95179
  }
95138
95180
  function scopedTasks(options, db) {
95181
+ const aliasSet = options.agent_id ? assignedToAliasSet(db, options.agent_id) : undefined;
95139
95182
  return listTasks2({
95140
95183
  project_id: options.project_id,
95141
95184
  plan_id: options.plan_id,
95142
95185
  include_archived: false
95143
- }, db).filter((task) => sameAgent(task, options.agent_id) && withinTaskWindow(task, options));
95186
+ }, db).filter((task) => sameAgent(task, options.agent_id, aliasSet) && withinTaskWindow(task, options));
95144
95187
  }
95145
95188
  function summarizeTask(task) {
95146
95189
  return {
@@ -95206,7 +95249,7 @@ function initialAgentSummary(agentId) {
95206
95249
  }
95207
95250
  };
95208
95251
  }
95209
- function addScopeClauses(where, params, options, timeColumn) {
95252
+ function addScopeClauses(where, params, options, timeColumn, db) {
95210
95253
  if (options.project_id) {
95211
95254
  where.push("t.project_id = ?");
95212
95255
  params.push(options.project_id);
@@ -95216,8 +95259,9 @@ function addScopeClauses(where, params, options, timeColumn) {
95216
95259
  params.push(options.plan_id);
95217
95260
  }
95218
95261
  if (options.agent_id) {
95219
- where.push("(r.agent_id = ? OR t.agent_id = ? OR t.assigned_to = ?)");
95220
- params.push(options.agent_id, options.agent_id, options.agent_id);
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})`);
95221
95265
  }
95222
95266
  if (options.since) {
95223
95267
  where.push(`${timeColumn} >= ?`);
@@ -95231,7 +95275,7 @@ function addScopeClauses(where, params, options, timeColumn) {
95231
95275
  function loadRuns(options, db) {
95232
95276
  const where = ["t.archived_at IS NULL"];
95233
95277
  const params = [];
95234
- addScopeClauses(where, params, options, "r.started_at");
95278
+ addScopeClauses(where, params, options, "r.started_at", db);
95235
95279
  return db.query(`
95236
95280
  SELECT
95237
95281
  r.id,
@@ -95271,8 +95315,9 @@ function loadVerifications(options, db) {
95271
95315
  params.push(options.plan_id);
95272
95316
  }
95273
95317
  if (options.agent_id) {
95274
- where.push("(v.agent_id = ? OR t.agent_id = ? OR t.assigned_to = ?)");
95275
- params.push(options.agent_id, options.agent_id, options.agent_id);
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})`);
95276
95321
  }
95277
95322
  if (options.since) {
95278
95323
  where.push("v.run_at >= ?");
@@ -95494,7 +95539,6 @@ function renderLocalReportMarkdown(report) {
95494
95539
  }
95495
95540
  var LOCAL_REPORT_SCHEMA_VERSION = 1, LOCAL_REPORT_TYPES;
95496
95541
  var init_local_reports = __esm(() => {
95497
- init_database();
95498
95542
  init_database();
95499
95543
  init_plans();
95500
95544
  init_tasks();
@@ -99597,7 +99641,7 @@ ${lines.join(`
99597
99641
  a.name AS agent_name
99598
99642
  FROM task_files tf
99599
99643
  JOIN tasks t ON tf.task_id = t.id
99600
- 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))))
99601
99645
  WHERE t.status = 'in_progress'
99602
99646
  AND tf.status != 'removed'
99603
99647
  AND t.project_id = ?
@@ -103361,7 +103405,7 @@ ${text2}` }] };
103361
103405
  const oldName = agent.name;
103362
103406
  const updated = updateAgent2(agent.id, { name: new_name });
103363
103407
  const db = getDatabase();
103364
- 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]);
103365
103409
  const taskNote = tasksResult.changes > 0 ? `
103366
103410
  Updated assigned_to on ${tasksResult.changes} task(s).` : "";
103367
103411
  return {