@hasna/todos 0.13.11 → 0.14.0
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/commands/agent-commands.d.ts +39 -0
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/dispatch.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/helpers.d.ts +64 -2
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/index.js +510 -149
- package/dist/contracts.js +102 -71
- 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 +134 -93
- package/dist/lib/capacity-forecasts.d.ts.map +1 -1
- package/dist/lib/completion-guard.d.ts.map +1 -1
- package/dist/lib/enum-vocabulary.d.ts +72 -0
- package/dist/lib/enum-vocabulary.d.ts.map +1 -0
- 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/saved-search-views.d.ts +12 -1
- package/dist/lib/saved-search-views.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 +349 -115
- 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 +102 -71
- package/dist/release-provenance.json +5 -5
- package/dist/sdk/v1.generated.d.ts +2 -2
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/index.js +349 -115
- package/dist/server/openapi.d.ts +58 -0
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage.js +69 -46
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3430,6 +3430,9 @@ var init_machines = __esm(() => {
|
|
|
3430
3430
|
function isBlockingDependencyStatus(status) {
|
|
3431
3431
|
return status !== "completed" && status !== "cancelled";
|
|
3432
3432
|
}
|
|
3433
|
+
function isTerminalStatus(status) {
|
|
3434
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
3435
|
+
}
|
|
3433
3436
|
var TASK_STATUSES, TASK_PRIORITIES, PLAN_STATUSES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DISPATCH_STATUSES, DispatchNotFoundError;
|
|
3434
3437
|
var init_types = __esm(() => {
|
|
3435
3438
|
TASK_STATUSES = [
|
|
@@ -4103,14 +4106,17 @@ var exports_database = {};
|
|
|
4103
4106
|
__export(exports_database, {
|
|
4104
4107
|
uuid: () => uuid,
|
|
4105
4108
|
resolvePartialId: () => resolvePartialId,
|
|
4109
|
+
resolveAssignedToAliases: () => resolveAssignedToAliases,
|
|
4106
4110
|
resetDatabase: () => resetDatabase,
|
|
4107
4111
|
now: () => now,
|
|
4112
|
+
lowerInClause: () => lowerInClause,
|
|
4108
4113
|
lockExpiryCutoff: () => lockExpiryCutoff,
|
|
4109
4114
|
isLockExpired: () => isLockExpired,
|
|
4110
4115
|
getDatabasePath: () => getDatabasePath,
|
|
4111
4116
|
getDatabase: () => getDatabase,
|
|
4112
4117
|
closeDatabase: () => closeDatabase,
|
|
4113
4118
|
clearExpiredLocks: () => clearExpiredLocks,
|
|
4119
|
+
assignedToAliasSet: () => assignedToAliasSet,
|
|
4114
4120
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
4115
4121
|
});
|
|
4116
4122
|
import { Database } from "bun:sqlite";
|
|
@@ -4339,6 +4345,33 @@ function resolvePartialId(db, table, partialId) {
|
|
|
4339
4345
|
}
|
|
4340
4346
|
return null;
|
|
4341
4347
|
}
|
|
4348
|
+
function resolveAssignedToAliases(db, ref) {
|
|
4349
|
+
const aliases = new Set([ref]);
|
|
4350
|
+
let agentId;
|
|
4351
|
+
try {
|
|
4352
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
4353
|
+
} catch (err) {
|
|
4354
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
4355
|
+
throw err;
|
|
4356
|
+
agentId = null;
|
|
4357
|
+
}
|
|
4358
|
+
if (agentId) {
|
|
4359
|
+
aliases.add(agentId);
|
|
4360
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
4361
|
+
if (row?.name)
|
|
4362
|
+
aliases.add(row.name);
|
|
4363
|
+
}
|
|
4364
|
+
return [...aliases];
|
|
4365
|
+
}
|
|
4366
|
+
function assignedToAliasSet(db, ref) {
|
|
4367
|
+
return new Set(resolveAssignedToAliases(db, ref).map((a) => a.toLowerCase()));
|
|
4368
|
+
}
|
|
4369
|
+
function lowerInClause(column, values, params) {
|
|
4370
|
+
if (values.length === 0)
|
|
4371
|
+
return "1=0";
|
|
4372
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
4373
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
4374
|
+
}
|
|
4342
4375
|
var LOCK_EXPIRY_MINUTES = 30, _db = null, _dbPath = null, ALLOWED_TABLES;
|
|
4343
4376
|
var init_database = __esm(() => {
|
|
4344
4377
|
init_schema();
|
|
@@ -4979,17 +5012,19 @@ function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
|
4979
5012
|
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);
|
|
4980
5013
|
}
|
|
4981
5014
|
}
|
|
5015
|
+
const assignedAliasParams = [];
|
|
5016
|
+
const assignedInClause = agent ? lowerInClause("assigned_to", resolveAssignedToAliases(db, agent), assignedAliasParams) : "";
|
|
4982
5017
|
if (agent && config.max_completions_per_window && config.window_minutes) {
|
|
4983
5018
|
const windowStart = new Date(Date.now() - config.window_minutes * 60 * 1000).toISOString();
|
|
4984
5019
|
const result = db.query(`SELECT COUNT(*) as count FROM tasks
|
|
4985
|
-
WHERE completed_at > ? AND (
|
|
5020
|
+
WHERE completed_at > ? AND (${assignedInClause} OR agent_id = ?)`).get(windowStart, ...assignedAliasParams, agent);
|
|
4986
5021
|
if (result.count >= config.max_completions_per_window) {
|
|
4987
5022
|
throw new CompletionGuardError(`Rate limit: ${result.count} tasks completed in the last ${config.window_minutes} minutes (max ${config.max_completions_per_window}). Slow down.`);
|
|
4988
5023
|
}
|
|
4989
5024
|
}
|
|
4990
5025
|
if (agent && config.cooldown_seconds) {
|
|
4991
5026
|
const result = db.query(`SELECT MAX(completed_at) as last_completed FROM tasks
|
|
4992
|
-
WHERE completed_at IS NOT NULL AND (
|
|
5027
|
+
WHERE completed_at IS NOT NULL AND (${assignedInClause} OR agent_id = ?) AND id != ?`).get(...assignedAliasParams, agent, task.id);
|
|
4993
5028
|
if (result.last_completed) {
|
|
4994
5029
|
const elapsedSeconds = (Date.now() - new Date(result.last_completed).getTime()) / 1000;
|
|
4995
5030
|
if (elapsedSeconds < config.cooldown_seconds) {
|
|
@@ -5003,6 +5038,7 @@ var init_completion_guard = __esm(() => {
|
|
|
5003
5038
|
init_types();
|
|
5004
5039
|
init_config2();
|
|
5005
5040
|
init_projects();
|
|
5041
|
+
init_database();
|
|
5006
5042
|
});
|
|
5007
5043
|
|
|
5008
5044
|
// src/lib/event-emission-safety.ts
|
|
@@ -7232,7 +7268,7 @@ function getRecap(hours = 8, projectId, db) {
|
|
|
7232
7268
|
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();
|
|
7233
7269
|
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();
|
|
7234
7270
|
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);
|
|
7235
|
-
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);
|
|
7271
|
+
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);
|
|
7236
7272
|
return {
|
|
7237
7273
|
hours,
|
|
7238
7274
|
since,
|
|
@@ -7385,13 +7421,17 @@ function logDelivery(d, webhookId, event, payload, statusCode, response, attempt
|
|
|
7385
7421
|
const id = uuid();
|
|
7386
7422
|
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()]);
|
|
7387
7423
|
}
|
|
7388
|
-
function matchesScope(wh, payload) {
|
|
7424
|
+
function matchesScope(wh, payload, db) {
|
|
7389
7425
|
if (wh.project_id && payload.project_id !== wh.project_id)
|
|
7390
7426
|
return false;
|
|
7391
7427
|
if (wh.task_list_id && payload.task_list_id !== wh.task_list_id)
|
|
7392
7428
|
return false;
|
|
7393
|
-
if (wh.agent_id && payload.agent_id !== wh.agent_id
|
|
7394
|
-
|
|
7429
|
+
if (wh.agent_id && payload.agent_id !== wh.agent_id) {
|
|
7430
|
+
const aliasSet = assignedToAliasSet(db, wh.agent_id);
|
|
7431
|
+
const assignedTo = typeof payload.assigned_to === "string" ? payload.assigned_to.toLowerCase() : "";
|
|
7432
|
+
if (!aliasSet.has(assignedTo))
|
|
7433
|
+
return false;
|
|
7434
|
+
}
|
|
7395
7435
|
if (wh.task_id && payload.id !== wh.task_id)
|
|
7396
7436
|
return false;
|
|
7397
7437
|
return true;
|
|
@@ -7458,7 +7498,7 @@ async function dispatchWebhook2(event, payload, db) {
|
|
|
7458
7498
|
const webhooks = listWebhooks(d).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
|
|
7459
7499
|
const payloadObj = typeof payload === "object" && payload !== null ? payload : {};
|
|
7460
7500
|
for (const wh of webhooks) {
|
|
7461
|
-
if (!matchesScope(wh, payloadObj))
|
|
7501
|
+
if (!matchesScope(wh, payloadObj, d))
|
|
7462
7502
|
continue;
|
|
7463
7503
|
const body = JSON.stringify({ event, payload, timestamp: now() });
|
|
7464
7504
|
deliverWebhook(wh, event, body, 1, d).catch((err) => {
|
|
@@ -8561,14 +8601,16 @@ function getNextTask(agentId, filters, db) {
|
|
|
8561
8601
|
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')");
|
|
8562
8602
|
const where = conditions.join(" AND ");
|
|
8563
8603
|
let recentProjectIds = [];
|
|
8604
|
+
const assignedAliasParams = [];
|
|
8605
|
+
const assignedInClause = agentId ? lowerInClause("assigned_to", resolveAssignedToAliases(d, agentId), assignedAliasParams) : "";
|
|
8564
8606
|
if (agentId) {
|
|
8565
|
-
const recentRows = d.query(`SELECT DISTINCT project_id FROM tasks WHERE
|
|
8607
|
+
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);
|
|
8566
8608
|
recentProjectIds = recentRows.map((r) => r.project_id);
|
|
8567
8609
|
}
|
|
8568
8610
|
let sql = `SELECT * FROM tasks WHERE ${where} ORDER BY `;
|
|
8569
8611
|
if (agentId) {
|
|
8570
|
-
sql += `CASE WHEN
|
|
8571
|
-
params.push(
|
|
8612
|
+
sql += `CASE WHEN ${assignedInClause} THEN 0 WHEN assigned_to IS NULL THEN 1 ELSE 2 END, `;
|
|
8613
|
+
params.push(...assignedAliasParams);
|
|
8572
8614
|
}
|
|
8573
8615
|
if (recentProjectIds.length > 0) {
|
|
8574
8616
|
const placeholders = recentProjectIds.map(() => "?").join(",");
|
|
@@ -8962,30 +9004,6 @@ function getTaskWithRelations(id, db) {
|
|
|
8962
9004
|
checklist
|
|
8963
9005
|
};
|
|
8964
9006
|
}
|
|
8965
|
-
function resolveAssignedToAliases(db, ref) {
|
|
8966
|
-
const aliases = new Set([ref]);
|
|
8967
|
-
let agentId;
|
|
8968
|
-
try {
|
|
8969
|
-
agentId = resolvePartialId(db, "agents", ref);
|
|
8970
|
-
} catch (err) {
|
|
8971
|
-
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
8972
|
-
throw err;
|
|
8973
|
-
agentId = null;
|
|
8974
|
-
}
|
|
8975
|
-
if (agentId) {
|
|
8976
|
-
aliases.add(agentId);
|
|
8977
|
-
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
8978
|
-
if (row?.name)
|
|
8979
|
-
aliases.add(row.name);
|
|
8980
|
-
}
|
|
8981
|
-
return [...aliases];
|
|
8982
|
-
}
|
|
8983
|
-
function lowerInClause(column, values, params) {
|
|
8984
|
-
if (values.length === 0)
|
|
8985
|
-
return "1=0";
|
|
8986
|
-
params.push(...values.map((v) => v.toLowerCase()));
|
|
8987
|
-
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
8988
|
-
}
|
|
8989
9007
|
function listTasks(filter = {}, db) {
|
|
8990
9008
|
const d = db || getDatabase();
|
|
8991
9009
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -9271,11 +9289,13 @@ function updateTask(id, input, db) {
|
|
|
9271
9289
|
}
|
|
9272
9290
|
sets.push("status = ?");
|
|
9273
9291
|
params.push(input.status);
|
|
9292
|
+
if (isTerminalStatus(input.status)) {
|
|
9293
|
+
sets.push("locked_by = NULL");
|
|
9294
|
+
sets.push("locked_at = NULL");
|
|
9295
|
+
}
|
|
9274
9296
|
if (input.status === "completed") {
|
|
9275
9297
|
sets.push("completed_at = ?");
|
|
9276
9298
|
params.push(completionTimestamp);
|
|
9277
|
-
sets.push("locked_by = NULL");
|
|
9278
|
-
sets.push("locked_at = NULL");
|
|
9279
9299
|
} else if (task.status === "completed" && input.completed_at === undefined) {
|
|
9280
9300
|
sets.push("completed_at = NULL");
|
|
9281
9301
|
}
|
|
@@ -9399,6 +9419,7 @@ function updateTask(id, input, db) {
|
|
|
9399
9419
|
logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
|
|
9400
9420
|
const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
|
|
9401
9421
|
const completedNow = input.status === "completed";
|
|
9422
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
9402
9423
|
const updatedTask = {
|
|
9403
9424
|
...task,
|
|
9404
9425
|
...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
|
|
@@ -9406,8 +9427,8 @@ function updateTask(id, input, db) {
|
|
|
9406
9427
|
metadata: input.metadata ?? task.metadata,
|
|
9407
9428
|
version: task.version + 1,
|
|
9408
9429
|
updated_at: timestamp2,
|
|
9409
|
-
locked_by:
|
|
9410
|
-
locked_at:
|
|
9430
|
+
locked_by: terminalNow ? null : task.locked_by,
|
|
9431
|
+
locked_at: terminalNow ? null : task.locked_at,
|
|
9411
9432
|
completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
|
|
9412
9433
|
sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
|
|
9413
9434
|
actual_minutes: input.actual_minutes ?? task.actual_minutes,
|
|
@@ -9458,6 +9479,7 @@ function deleteTask(id, db) {
|
|
|
9458
9479
|
var init_task_crud = __esm(() => {
|
|
9459
9480
|
init_types();
|
|
9460
9481
|
init_database();
|
|
9482
|
+
init_database();
|
|
9461
9483
|
init_completion_guard();
|
|
9462
9484
|
init_event_emission_safety();
|
|
9463
9485
|
init_event_hooks();
|
|
@@ -9620,8 +9642,8 @@ function getTaskStats(filters, db) {
|
|
|
9620
9642
|
params.push(filters.task_list_id);
|
|
9621
9643
|
}
|
|
9622
9644
|
if (filters?.agent_id) {
|
|
9623
|
-
|
|
9624
|
-
|
|
9645
|
+
params.push(filters.agent_id);
|
|
9646
|
+
conditions.push(`(agent_id = ? OR ${lowerInClause("assigned_to", resolveAssignedToAliases(d, filters.agent_id), params)})`);
|
|
9625
9647
|
}
|
|
9626
9648
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
9627
9649
|
const totalRow = d.query(`SELECT COUNT(*) as count FROM tasks ${where}`).get(...params);
|
|
@@ -9757,8 +9779,7 @@ function getEscalatedTasks(opts = {}, db, at = new Date) {
|
|
|
9757
9779
|
params.push(opts.project_id);
|
|
9758
9780
|
}
|
|
9759
9781
|
if (opts.agent_id) {
|
|
9760
|
-
conditions.push("assigned_to
|
|
9761
|
-
params.push(opts.agent_id);
|
|
9782
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
9762
9783
|
}
|
|
9763
9784
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC, created_at ASC`).all(...params);
|
|
9764
9785
|
return rows.map(rowToTask).map((task) => {
|
|
@@ -9991,13 +10012,14 @@ function getTimeReport(opts, db) {
|
|
|
9991
10012
|
params.push(opts.plan_id);
|
|
9992
10013
|
}
|
|
9993
10014
|
if (opts?.agent_id) {
|
|
10015
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.agent_id), params);
|
|
9994
10016
|
conditions.push(`(
|
|
9995
|
-
|
|
10017
|
+
${assignedInClause}
|
|
9996
10018
|
OR t.agent_id = ?
|
|
9997
10019
|
OR EXISTS (SELECT 1 FROM task_time_logs ttl WHERE ttl.task_id = t.id AND ttl.agent_id = ?)
|
|
9998
10020
|
OR EXISTS (SELECT 1 FROM focus_sessions fs WHERE fs.task_id = t.id AND fs.agent_id = ?)
|
|
9999
10021
|
)`);
|
|
10000
|
-
params.push(opts.agent_id, opts.agent_id, opts.agent_id
|
|
10022
|
+
params.push(opts.agent_id, opts.agent_id, opts.agent_id);
|
|
10001
10023
|
}
|
|
10002
10024
|
if (opts?.since) {
|
|
10003
10025
|
conditions.push("(t.completed_at >= ? OR t.updated_at >= ?)");
|
|
@@ -12122,7 +12144,7 @@ var init_dispatches = __esm(() => {
|
|
|
12122
12144
|
// package.json
|
|
12123
12145
|
var package_default = {
|
|
12124
12146
|
name: "@hasna/todos",
|
|
12125
|
-
version: "0.
|
|
12147
|
+
version: "0.14.0",
|
|
12126
12148
|
description: "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
|
|
12127
12149
|
type: "module",
|
|
12128
12150
|
main: "dist/index.js",
|
|
@@ -22134,11 +22156,12 @@ function runAlerts(input, db, checkedAt, quieted) {
|
|
|
22134
22156
|
if (input.include_runs === false)
|
|
22135
22157
|
return [];
|
|
22136
22158
|
const since = Date.parse(input.run_since || new Date(Date.parse(checkedAt) - 24 * 60 * 60000).toISOString());
|
|
22159
|
+
const runAlertAliases = input.agent_id ? assignedToAliasSet(db, input.agent_id) : null;
|
|
22137
22160
|
return listTaskRuns(undefined, db).filter((run) => run.completed_at && Date.parse(run.completed_at) >= since).map((run) => {
|
|
22138
22161
|
const task2 = getTask(run.task_id, db);
|
|
22139
22162
|
if (input.project_id && task2?.project_id !== input.project_id)
|
|
22140
22163
|
return null;
|
|
22141
|
-
if (input.agent_id && run.agent_id !== input.agent_id && task2?.assigned_to
|
|
22164
|
+
if (input.agent_id && run.agent_id !== input.agent_id && !(runAlertAliases && runAlertAliases.has((task2?.assigned_to ?? "").toLowerCase())))
|
|
22142
22165
|
return null;
|
|
22143
22166
|
const failed = ["failed", "cancelled"].includes(run.status);
|
|
22144
22167
|
return {
|
|
@@ -22183,6 +22206,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
22183
22206
|
const warnings = [];
|
|
22184
22207
|
if (Number.isNaN(checkedMs))
|
|
22185
22208
|
warnings.push("Invalid check timestamp; due-soon window may be incomplete.");
|
|
22209
|
+
const notifyAgentAliases = input.agent_id ? assignedToAliasSet(d, input.agent_id) : null;
|
|
22186
22210
|
const alerts = [];
|
|
22187
22211
|
for (const escalation of getEscalatedTasks({ project_id: input.project_id, agent_id: input.agent_id }, d, new Date(checkedAt))) {
|
|
22188
22212
|
for (const reason of escalation.reasons) {
|
|
@@ -22194,7 +22218,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
22194
22218
|
for (const task2 of listTasks({ project_id: input.project_id, include_archived: false, limit: 5000 }, d)) {
|
|
22195
22219
|
if (!unfinished(task2) || !task2.due_at)
|
|
22196
22220
|
continue;
|
|
22197
|
-
if (input.agent_id && task2.
|
|
22221
|
+
if (input.agent_id && task2.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task2.assigned_to ?? "").toLowerCase())))
|
|
22198
22222
|
continue;
|
|
22199
22223
|
if (task2.due_at > checkedAt && task2.due_at <= dueSoonUntil) {
|
|
22200
22224
|
alerts.push(taskAlert(task2, "task_due_soon", "task.due_soon", "warning", `Due soon: ${task2.title}`, task2.due_at, quieted));
|
|
@@ -22202,7 +22226,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
22202
22226
|
}
|
|
22203
22227
|
}
|
|
22204
22228
|
for (const task2 of getStaleTasks(staleMinutes, { project_id: input.project_id }, d)) {
|
|
22205
|
-
if (input.agent_id && task2.
|
|
22229
|
+
if (input.agent_id && task2.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task2.assigned_to ?? "").toLowerCase())))
|
|
22206
22230
|
continue;
|
|
22207
22231
|
alerts.push(taskAlert(task2, "task_stale", "task.stale", "warning", `Stale task: ${task2.title}`, checkedAt, quieted, { stale_minutes: staleMinutes }));
|
|
22208
22232
|
}
|
|
@@ -22330,14 +22354,15 @@ function millisBetween(start, end) {
|
|
|
22330
22354
|
return 0;
|
|
22331
22355
|
return endMs - startMs;
|
|
22332
22356
|
}
|
|
22333
|
-
function addTaskScope(where, params, options, alias = "t") {
|
|
22357
|
+
function addTaskScope(where, params, options, db, alias = "t") {
|
|
22334
22358
|
if (options.project_id) {
|
|
22335
22359
|
where.push(`${alias}.project_id = ?`);
|
|
22336
22360
|
params.push(options.project_id);
|
|
22337
22361
|
}
|
|
22338
22362
|
if (options.agent_id) {
|
|
22339
|
-
|
|
22340
|
-
|
|
22363
|
+
params.push(options.agent_id);
|
|
22364
|
+
const assignedInClause = lowerInClause(`${alias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
22365
|
+
where.push(`(${alias}.agent_id = ? OR ${assignedInClause})`);
|
|
22341
22366
|
}
|
|
22342
22367
|
if (options.since) {
|
|
22343
22368
|
where.push(`${alias}.created_at >= ?`);
|
|
@@ -22348,14 +22373,15 @@ function addTaskScope(where, params, options, alias = "t") {
|
|
|
22348
22373
|
params.push(options.until);
|
|
22349
22374
|
}
|
|
22350
22375
|
}
|
|
22351
|
-
function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
22376
|
+
function addRunScope(where, params, options, db, runAlias = "r", taskAlias = "t") {
|
|
22352
22377
|
if (options.project_id) {
|
|
22353
22378
|
where.push(`${taskAlias}.project_id = ?`);
|
|
22354
22379
|
params.push(options.project_id);
|
|
22355
22380
|
}
|
|
22356
22381
|
if (options.agent_id) {
|
|
22357
|
-
|
|
22358
|
-
|
|
22382
|
+
params.push(options.agent_id, options.agent_id);
|
|
22383
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
22384
|
+
where.push(`(${runAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
22359
22385
|
}
|
|
22360
22386
|
if (options.since) {
|
|
22361
22387
|
where.push(`${runAlias}.started_at >= ?`);
|
|
@@ -22366,14 +22392,15 @@ function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
|
22366
22392
|
params.push(options.until);
|
|
22367
22393
|
}
|
|
22368
22394
|
}
|
|
22369
|
-
function addTraceScope(where, params, options, traceAlias = "tr", taskAlias = "t") {
|
|
22395
|
+
function addTraceScope(where, params, options, db, traceAlias = "tr", taskAlias = "t") {
|
|
22370
22396
|
if (options.project_id) {
|
|
22371
22397
|
where.push(`${taskAlias}.project_id = ?`);
|
|
22372
22398
|
params.push(options.project_id);
|
|
22373
22399
|
}
|
|
22374
22400
|
if (options.agent_id) {
|
|
22375
|
-
|
|
22376
|
-
|
|
22401
|
+
params.push(options.agent_id, options.agent_id);
|
|
22402
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
22403
|
+
where.push(`(${traceAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
22377
22404
|
}
|
|
22378
22405
|
if (options.since) {
|
|
22379
22406
|
where.push(`${traceAlias}.created_at >= ?`);
|
|
@@ -22433,7 +22460,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
22433
22460
|
const generatedAt = options.generated_at || new Date().toISOString();
|
|
22434
22461
|
const taskWhere = [];
|
|
22435
22462
|
const taskParams = [];
|
|
22436
|
-
addTaskScope(taskWhere, taskParams, options);
|
|
22463
|
+
addTaskScope(taskWhere, taskParams, options, d);
|
|
22437
22464
|
const taskClause = taskWhere.length ? `WHERE ${taskWhere.join(" AND ")}` : "";
|
|
22438
22465
|
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);
|
|
22439
22466
|
let projectCount = 0;
|
|
@@ -22442,14 +22469,14 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
22442
22469
|
} else if (options.agent_id) {
|
|
22443
22470
|
const projectWhere = ["t.project_id IS NOT NULL"];
|
|
22444
22471
|
const projectParams = [];
|
|
22445
|
-
addTaskScope(projectWhere, projectParams, options);
|
|
22472
|
+
addTaskScope(projectWhere, projectParams, options, d);
|
|
22446
22473
|
projectCount = queryOne(d, `SELECT COUNT(DISTINCT t.project_id) as count FROM tasks t WHERE ${projectWhere.join(" AND ")}`, projectParams).count;
|
|
22447
22474
|
} else {
|
|
22448
22475
|
projectCount = queryOne(d, "SELECT COUNT(*) as count FROM projects", []).count;
|
|
22449
22476
|
}
|
|
22450
22477
|
const runWhere = [];
|
|
22451
22478
|
const runParams = [];
|
|
22452
|
-
addRunScope(runWhere, runParams, options);
|
|
22479
|
+
addRunScope(runWhere, runParams, options, d);
|
|
22453
22480
|
const runClause = runWhere.length ? `WHERE ${runWhere.join(" AND ")}` : "";
|
|
22454
22481
|
const runs = queryAll(d, `SELECT r.id, r.started_at, r.completed_at, r.metadata
|
|
22455
22482
|
FROM task_runs r JOIN tasks t ON t.id = r.task_id
|
|
@@ -22466,7 +22493,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
22466
22493
|
${runClause}`, runParams);
|
|
22467
22494
|
const traceWhere = [];
|
|
22468
22495
|
const traceParams = [];
|
|
22469
|
-
addTraceScope(traceWhere, traceParams, options);
|
|
22496
|
+
addTraceScope(traceWhere, traceParams, options, d);
|
|
22470
22497
|
const traceClause = traceWhere.length ? `WHERE ${traceWhere.join(" AND ")}` : "";
|
|
22471
22498
|
const traceTotals = queryOne(d, `SELECT COUNT(*) as traces,
|
|
22472
22499
|
COALESCE(SUM(tr.tokens), 0) as tokens,
|
|
@@ -22598,7 +22625,6 @@ function renderLocalUsageLedgerMarkdown(report) {
|
|
|
22598
22625
|
}
|
|
22599
22626
|
// src/lib/local-reports.ts
|
|
22600
22627
|
init_database();
|
|
22601
|
-
init_database();
|
|
22602
22628
|
init_plans();
|
|
22603
22629
|
init_tasks();
|
|
22604
22630
|
var LOCAL_REPORT_SCHEMA_VERSION = 1;
|
|
@@ -22621,10 +22647,12 @@ function limitValue(value) {
|
|
|
22621
22647
|
function isTerminal(task2) {
|
|
22622
22648
|
return task2.status === "completed" || task2.status === "failed" || task2.status === "cancelled";
|
|
22623
22649
|
}
|
|
22624
|
-
function sameAgent(task2, agentId) {
|
|
22650
|
+
function sameAgent(task2, agentId, aliasSet) {
|
|
22625
22651
|
if (!agentId)
|
|
22626
22652
|
return true;
|
|
22627
|
-
|
|
22653
|
+
if (task2.agent_id === agentId)
|
|
22654
|
+
return true;
|
|
22655
|
+
return aliasSet ? aliasSet.has((task2.assigned_to ?? "").toLowerCase()) : task2.assigned_to === agentId;
|
|
22628
22656
|
}
|
|
22629
22657
|
function withinTaskWindow(task2, options) {
|
|
22630
22658
|
const time = Date.parse(task2.updated_at);
|
|
@@ -22637,11 +22665,12 @@ function withinTaskWindow(task2, options) {
|
|
|
22637
22665
|
return true;
|
|
22638
22666
|
}
|
|
22639
22667
|
function scopedTasks(options, db) {
|
|
22668
|
+
const aliasSet = options.agent_id ? assignedToAliasSet(db, options.agent_id) : undefined;
|
|
22640
22669
|
return listTasks({
|
|
22641
22670
|
project_id: options.project_id,
|
|
22642
22671
|
plan_id: options.plan_id,
|
|
22643
22672
|
include_archived: false
|
|
22644
|
-
}, db).filter((task2) => sameAgent(task2, options.agent_id) && withinTaskWindow(task2, options));
|
|
22673
|
+
}, db).filter((task2) => sameAgent(task2, options.agent_id, aliasSet) && withinTaskWindow(task2, options));
|
|
22645
22674
|
}
|
|
22646
22675
|
function summarizeTask(task2) {
|
|
22647
22676
|
return {
|
|
@@ -22707,7 +22736,7 @@ function initialAgentSummary(agentId) {
|
|
|
22707
22736
|
}
|
|
22708
22737
|
};
|
|
22709
22738
|
}
|
|
22710
|
-
function addScopeClauses(where, params, options, timeColumn) {
|
|
22739
|
+
function addScopeClauses(where, params, options, timeColumn, db) {
|
|
22711
22740
|
if (options.project_id) {
|
|
22712
22741
|
where.push("t.project_id = ?");
|
|
22713
22742
|
params.push(options.project_id);
|
|
@@ -22717,8 +22746,9 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
22717
22746
|
params.push(options.plan_id);
|
|
22718
22747
|
}
|
|
22719
22748
|
if (options.agent_id) {
|
|
22720
|
-
|
|
22721
|
-
|
|
22749
|
+
params.push(options.agent_id, options.agent_id);
|
|
22750
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
22751
|
+
where.push(`(r.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
22722
22752
|
}
|
|
22723
22753
|
if (options.since) {
|
|
22724
22754
|
where.push(`${timeColumn} >= ?`);
|
|
@@ -22732,7 +22762,7 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
22732
22762
|
function loadRuns(options, db) {
|
|
22733
22763
|
const where = ["t.archived_at IS NULL"];
|
|
22734
22764
|
const params = [];
|
|
22735
|
-
addScopeClauses(where, params, options, "r.started_at");
|
|
22765
|
+
addScopeClauses(where, params, options, "r.started_at", db);
|
|
22736
22766
|
return db.query(`
|
|
22737
22767
|
SELECT
|
|
22738
22768
|
r.id,
|
|
@@ -22772,8 +22802,9 @@ function loadVerifications(options, db) {
|
|
|
22772
22802
|
params.push(options.plan_id);
|
|
22773
22803
|
}
|
|
22774
22804
|
if (options.agent_id) {
|
|
22775
|
-
|
|
22776
|
-
|
|
22805
|
+
params.push(options.agent_id, options.agent_id);
|
|
22806
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
22807
|
+
where.push(`(v.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
22777
22808
|
}
|
|
22778
22809
|
if (options.since) {
|
|
22779
22810
|
where.push("v.run_at >= ?");
|
|
@@ -23955,8 +23986,7 @@ function searchTasks(options, projectId, taskListId, db) {
|
|
|
23955
23986
|
}
|
|
23956
23987
|
}
|
|
23957
23988
|
if (opts.assigned_to) {
|
|
23958
|
-
sql +=
|
|
23959
|
-
params.push(opts.assigned_to);
|
|
23989
|
+
sql += ` AND ${lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.assigned_to), params)}`;
|
|
23960
23990
|
}
|
|
23961
23991
|
if (opts.agent_id) {
|
|
23962
23992
|
sql += " AND t.agent_id = ?";
|
|
@@ -26711,9 +26741,11 @@ async function updateTask2(id, input, store) {
|
|
|
26711
26741
|
throw new Error(`Task ${id} version conflict: expected ${existing.version}, got ${input.version}`);
|
|
26712
26742
|
}
|
|
26713
26743
|
const reopened = existing.status === "completed" && input.status !== undefined && input.status !== "completed" && input.completed_at === undefined;
|
|
26744
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
26714
26745
|
const task2 = {
|
|
26715
26746
|
...existing,
|
|
26716
26747
|
...definedPatch(input),
|
|
26748
|
+
...terminalNow ? { locked_by: null, locked_at: null } : {},
|
|
26717
26749
|
version: existing.version + 1,
|
|
26718
26750
|
updated_at: new Date().toISOString(),
|
|
26719
26751
|
tags: input.tags ?? existing.tags,
|
|
@@ -34947,8 +34979,10 @@ function getLatestHandoff(agentId, projectId, db) {
|
|
|
34947
34979
|
function createSessionRecoveryHandoff(input, db) {
|
|
34948
34980
|
const d = db || getDatabase();
|
|
34949
34981
|
const limit = input.limit || 20;
|
|
34950
|
-
const
|
|
34951
|
-
const
|
|
34982
|
+
const params = [];
|
|
34983
|
+
const assignedInClause = lowerInClause("assigned_to", resolveAssignedToAliases(d, input.agent_id), params);
|
|
34984
|
+
const conditions = ["status = 'in_progress'", `(${assignedInClause} OR agent_id = ? OR locked_by = ?)`];
|
|
34985
|
+
params.push(input.agent_id, input.agent_id);
|
|
34952
34986
|
if (input.session_id) {
|
|
34953
34987
|
conditions.push("session_id = ?");
|
|
34954
34988
|
params.push(input.session_id);
|
|
@@ -41630,8 +41664,7 @@ function getUpcomingDueTasks(filters = {}, db) {
|
|
|
41630
41664
|
params.push(filters.project_id);
|
|
41631
41665
|
}
|
|
41632
41666
|
if (filters.agent_id) {
|
|
41633
|
-
query +=
|
|
41634
|
-
params.push(filters.agent_id);
|
|
41667
|
+
query += ` AND ${lowerInClause("assigned_to", resolveAssignedToAliases(d, filters.agent_id), params)}`;
|
|
41635
41668
|
}
|
|
41636
41669
|
query += " ORDER BY due_at ASC";
|
|
41637
41670
|
const rows = d.query(query).all(...params);
|
|
@@ -41674,8 +41707,9 @@ function scanDueDateReminders(prefs, filters, d) {
|
|
|
41674
41707
|
updated++;
|
|
41675
41708
|
reminders.push(result.reminder);
|
|
41676
41709
|
}
|
|
41710
|
+
const overdueAliases = filters.agent_id ? assignedToAliasSet(d, filters.agent_id) : null;
|
|
41677
41711
|
const overdue = getOverdueTasks(filters.project_id, d).filter((t) => {
|
|
41678
|
-
if (
|
|
41712
|
+
if (overdueAliases && !overdueAliases.has((t.assigned_to ?? "").toLowerCase()))
|
|
41679
41713
|
return false;
|
|
41680
41714
|
return true;
|
|
41681
41715
|
});
|
|
@@ -47635,27 +47669,29 @@ function getAgentMetrics(agentId, opts, db) {
|
|
|
47635
47669
|
const agent = d.query("SELECT id, name FROM agents WHERE id = ? OR LOWER(name) = LOWER(?)").get(agentId, agentId);
|
|
47636
47670
|
if (!agent)
|
|
47637
47671
|
return null;
|
|
47672
|
+
const assignedAliases = resolveAssignedToAliases(d, agent.id).map((a) => a.toLowerCase());
|
|
47673
|
+
const assignedInClause = `LOWER(assigned_to) IN (${assignedAliases.map(() => "?").join(",")})`;
|
|
47638
47674
|
let projectFilter2 = "";
|
|
47639
|
-
const params = [agent.id,
|
|
47675
|
+
const params = [agent.id, ...assignedAliases];
|
|
47640
47676
|
if (opts?.project_id) {
|
|
47641
47677
|
projectFilter2 = " AND project_id = ?";
|
|
47642
47678
|
params.push(opts.project_id);
|
|
47643
47679
|
}
|
|
47644
|
-
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
47645
|
-
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
47646
|
-
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
47680
|
+
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter2}`).get(...params).count;
|
|
47681
|
+
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'failed'${projectFilter2}`).get(...params).count;
|
|
47682
|
+
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'in_progress'${projectFilter2}`).get(...params).count;
|
|
47647
47683
|
const total = completed + failed;
|
|
47648
47684
|
const completionRate = total > 0 ? completed / total : 0;
|
|
47649
47685
|
const avgTime = d.query(`SELECT AVG(
|
|
47650
47686
|
(julianday(completed_at) - julianday(created_at)) * 24 * 60
|
|
47651
47687
|
) as avg_minutes
|
|
47652
47688
|
FROM tasks
|
|
47653
|
-
WHERE (agent_id = ? OR
|
|
47689
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter2}`).get(...params);
|
|
47654
47690
|
const avgConf = d.query(`SELECT AVG(confidence) as avg_confidence
|
|
47655
47691
|
FROM tasks
|
|
47656
|
-
WHERE (agent_id = ? OR
|
|
47692
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND confidence IS NOT NULL${projectFilter2}`).get(...params);
|
|
47657
47693
|
const reviewTasks = d.query(`SELECT metadata FROM tasks
|
|
47658
|
-
WHERE (agent_id = ? OR
|
|
47694
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter2}
|
|
47659
47695
|
AND metadata LIKE '%_review_score%'`).all(...params);
|
|
47660
47696
|
let reviewScoreAvg = null;
|
|
47661
47697
|
if (reviewTasks.length > 0) {
|
|
@@ -48128,6 +48164,7 @@ function queryTasksByLocalFields(query, db) {
|
|
|
48128
48164
|
}
|
|
48129
48165
|
|
|
48130
48166
|
// src/lib/saved-search-views.ts
|
|
48167
|
+
var SAVED_SEARCH_SCOPES = ["all", "tasks", "projects", "plans", "runs", "comments"];
|
|
48131
48168
|
function parseFilters(value) {
|
|
48132
48169
|
if (!value)
|
|
48133
48170
|
return {};
|
|
@@ -48146,10 +48183,8 @@ function rowToSavedSearchView(row) {
|
|
|
48146
48183
|
};
|
|
48147
48184
|
}
|
|
48148
48185
|
function normalizeScope(scope) {
|
|
48149
|
-
|
|
48150
|
-
|
|
48151
|
-
}
|
|
48152
|
-
return "tasks";
|
|
48186
|
+
const candidate = (scope ?? "").trim().toLowerCase();
|
|
48187
|
+
return SAVED_SEARCH_SCOPES.includes(candidate) ? candidate : "tasks";
|
|
48153
48188
|
}
|
|
48154
48189
|
function normalizeName3(name) {
|
|
48155
48190
|
const normalized = name.trim();
|
|
@@ -49524,7 +49559,9 @@ function checkBudget(agentId, db) {
|
|
|
49524
49559
|
}
|
|
49525
49560
|
if (budget.max_cost_usd != null) {
|
|
49526
49561
|
const periodStart = new Date(Date.now() - budget.period_hours * 60 * 60 * 1000).toISOString();
|
|
49527
|
-
const
|
|
49562
|
+
const costParams = [];
|
|
49563
|
+
const assignedInClause = lowerInClause("assigned_to", resolveAssignedToAliases(d, agentId), costParams);
|
|
49564
|
+
const costRow = d.query(`SELECT COALESCE(SUM(cost_usd), 0) as total FROM tasks WHERE (${assignedInClause} OR agent_id = ?) AND updated_at > ?`).get(...costParams, agentId, periodStart);
|
|
49528
49565
|
if (costRow.total >= budget.max_cost_usd) {
|
|
49529
49566
|
return { allowed: false, reason: `Cost limit reached ($${costRow.total.toFixed(2)}/$${budget.max_cost_usd.toFixed(2)} in ${budget.period_hours}h)`, current_concurrent: concurrent, max_concurrent: budget.max_concurrent, current_cost_usd: costRow.total, max_cost_usd: budget.max_cost_usd };
|
|
49530
49567
|
}
|
|
@@ -52350,6 +52387,7 @@ function runTodosDoctor(options = {}) {
|
|
|
52350
52387
|
};
|
|
52351
52388
|
}
|
|
52352
52389
|
// src/lib/capacity-forecasts.ts
|
|
52390
|
+
init_database();
|
|
52353
52391
|
init_tasks();
|
|
52354
52392
|
init_task_relations();
|
|
52355
52393
|
init_config2();
|
|
@@ -52393,10 +52431,12 @@ function matchesProfile(profile, query) {
|
|
|
52393
52431
|
return false;
|
|
52394
52432
|
return true;
|
|
52395
52433
|
}
|
|
52396
|
-
function taskMatchesAgent(task2, agentId) {
|
|
52434
|
+
function taskMatchesAgent(task2, agentId, aliasSet) {
|
|
52397
52435
|
if (!agentId)
|
|
52398
52436
|
return true;
|
|
52399
|
-
|
|
52437
|
+
if (task2.agent_id === agentId)
|
|
52438
|
+
return true;
|
|
52439
|
+
return aliasSet ? aliasSet.has((task2.assigned_to ?? "").toLowerCase()) : task2.assigned_to === agentId;
|
|
52400
52440
|
}
|
|
52401
52441
|
function estimateRemaining(task2) {
|
|
52402
52442
|
if (task2.status === "completed" || task2.status === "cancelled")
|
|
@@ -52466,7 +52506,8 @@ function removeCapacityProfile(idOrAgent, projectId) {
|
|
|
52466
52506
|
}
|
|
52467
52507
|
function getPlanningForecast(input = {}, db) {
|
|
52468
52508
|
const startDate = input.start_date ? dateOnly(input.start_date) : todayIso();
|
|
52469
|
-
const
|
|
52509
|
+
const aliasSet = input.agent_id ? assignedToAliasSet(db || getDatabase(), input.agent_id) : undefined;
|
|
52510
|
+
const tasks = listTasks({ project_id: input.project_id, plan_id: input.plan_id, limit: 1e4 }, db).filter((task2) => taskMatchesAgent(task2, input.agent_id, aliasSet));
|
|
52470
52511
|
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]));
|
|
52471
52512
|
const profiles = listCapacityProfiles({ agent_id: input.agent_id, project_id: input.project_id });
|
|
52472
52513
|
const globalProfiles = input.project_id ? listCapacityProfiles({ agent_id: input.agent_id }).filter((profile) => profile.project_id === null) : [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capacity-forecasts.d.ts","sourceRoot":"","sources":["../../src/lib/capacity-forecasts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"capacity-forecasts.d.ts","sourceRoot":"","sources":["../../src/lib/capacity-forecasts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion-guard.d.ts","sourceRoot":"","sources":["../../src/lib/completion-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"completion-guard.d.ts","sourceRoot":"","sources":["../../src/lib/completion-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAC7D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAInF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,EAAE,EAAE,QAAQ,EACZ,cAAc,CAAC,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAC/C,IAAI,CAqFN"}
|