@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/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.
|
|
73
|
+
version: "0.14.0",
|
|
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",
|
|
@@ -850,7 +850,10 @@ var init_cloud_client = __esm(() => {
|
|
|
850
850
|
function isBlockingDependencyStatus(status) {
|
|
851
851
|
return status !== "completed" && status !== "cancelled";
|
|
852
852
|
}
|
|
853
|
-
|
|
853
|
+
function isTerminalStatus(status) {
|
|
854
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
855
|
+
}
|
|
856
|
+
var TASK_STATUSES, TASK_PRIORITIES, VersionConflictError, TaskNotFoundError, TaskNotStartableError, TaskReferenceAmbiguousError, ProjectNotFoundError, ResourceConflictError, PlanNotFoundError, LockError, AgentNotFoundError, IdentityAliasAmbiguousError, IdentityIdImmutableError, TaskListNotFoundError, DependencyCycleError, CompletionGuardError, DispatchNotFoundError;
|
|
854
857
|
var init_types = __esm(() => {
|
|
855
858
|
TASK_STATUSES = [
|
|
856
859
|
"pending",
|
|
@@ -859,6 +862,12 @@ var init_types = __esm(() => {
|
|
|
859
862
|
"failed",
|
|
860
863
|
"cancelled"
|
|
861
864
|
];
|
|
865
|
+
TASK_PRIORITIES = [
|
|
866
|
+
"low",
|
|
867
|
+
"medium",
|
|
868
|
+
"high",
|
|
869
|
+
"critical"
|
|
870
|
+
];
|
|
862
871
|
VersionConflictError = class VersionConflictError extends Error {
|
|
863
872
|
taskId;
|
|
864
873
|
expectedVersion;
|
|
@@ -2770,9 +2779,11 @@ async function updateTask(id, input, store) {
|
|
|
2770
2779
|
throw new Error(`Task ${id} version conflict: expected ${existing.version}, got ${input.version}`);
|
|
2771
2780
|
}
|
|
2772
2781
|
const reopened = existing.status === "completed" && input.status !== undefined && input.status !== "completed" && input.completed_at === undefined;
|
|
2782
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
2773
2783
|
const task = {
|
|
2774
2784
|
...existing,
|
|
2775
2785
|
...definedPatch(input),
|
|
2786
|
+
...terminalNow ? { locked_by: null, locked_at: null } : {},
|
|
2776
2787
|
version: existing.version + 1,
|
|
2777
2788
|
updated_at: new Date().toISOString(),
|
|
2778
2789
|
tags: input.tags ?? existing.tags,
|
|
@@ -9312,14 +9323,17 @@ var exports_database = {};
|
|
|
9312
9323
|
__export(exports_database, {
|
|
9313
9324
|
uuid: () => uuid,
|
|
9314
9325
|
resolvePartialId: () => resolvePartialId,
|
|
9326
|
+
resolveAssignedToAliases: () => resolveAssignedToAliases,
|
|
9315
9327
|
resetDatabase: () => resetDatabase,
|
|
9316
9328
|
now: () => now,
|
|
9329
|
+
lowerInClause: () => lowerInClause,
|
|
9317
9330
|
lockExpiryCutoff: () => lockExpiryCutoff,
|
|
9318
9331
|
isLockExpired: () => isLockExpired,
|
|
9319
9332
|
getDatabasePath: () => getDatabasePath,
|
|
9320
9333
|
getDatabase: () => getDatabase,
|
|
9321
9334
|
closeDatabase: () => closeDatabase,
|
|
9322
9335
|
clearExpiredLocks: () => clearExpiredLocks,
|
|
9336
|
+
assignedToAliasSet: () => assignedToAliasSet,
|
|
9323
9337
|
LOCK_EXPIRY_MINUTES: () => LOCK_EXPIRY_MINUTES
|
|
9324
9338
|
});
|
|
9325
9339
|
import { Database } from "bun:sqlite";
|
|
@@ -9548,6 +9562,33 @@ function resolvePartialId(db, table, partialId) {
|
|
|
9548
9562
|
}
|
|
9549
9563
|
return null;
|
|
9550
9564
|
}
|
|
9565
|
+
function resolveAssignedToAliases(db, ref) {
|
|
9566
|
+
const aliases = new Set([ref]);
|
|
9567
|
+
let agentId;
|
|
9568
|
+
try {
|
|
9569
|
+
agentId = resolvePartialId(db, "agents", ref);
|
|
9570
|
+
} catch (err) {
|
|
9571
|
+
if (!(err instanceof IdentityAliasAmbiguousError))
|
|
9572
|
+
throw err;
|
|
9573
|
+
agentId = null;
|
|
9574
|
+
}
|
|
9575
|
+
if (agentId) {
|
|
9576
|
+
aliases.add(agentId);
|
|
9577
|
+
const row = db.query("SELECT name FROM agents WHERE id = ?").get(agentId);
|
|
9578
|
+
if (row?.name)
|
|
9579
|
+
aliases.add(row.name);
|
|
9580
|
+
}
|
|
9581
|
+
return [...aliases];
|
|
9582
|
+
}
|
|
9583
|
+
function assignedToAliasSet(db, ref) {
|
|
9584
|
+
return new Set(resolveAssignedToAliases(db, ref).map((a) => a.toLowerCase()));
|
|
9585
|
+
}
|
|
9586
|
+
function lowerInClause(column, values, params) {
|
|
9587
|
+
if (values.length === 0)
|
|
9588
|
+
return "1=0";
|
|
9589
|
+
params.push(...values.map((v) => v.toLowerCase()));
|
|
9590
|
+
return `LOWER(${column}) IN (${values.map(() => "?").join(",")})`;
|
|
9591
|
+
}
|
|
9551
9592
|
var LOCK_EXPIRY_MINUTES = 30, _db = null, _dbPath = null, ALLOWED_TABLES;
|
|
9552
9593
|
var init_database = __esm(() => {
|
|
9553
9594
|
init_schema();
|
|
@@ -10117,17 +10158,19 @@ function checkCompletionGuard(task, agentId, db, configOverride) {
|
|
|
10117
10158
|
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
10159
|
}
|
|
10119
10160
|
}
|
|
10161
|
+
const assignedAliasParams = [];
|
|
10162
|
+
const assignedInClause = agent ? lowerInClause("assigned_to", resolveAssignedToAliases(db, agent), assignedAliasParams) : "";
|
|
10120
10163
|
if (agent && config.max_completions_per_window && config.window_minutes) {
|
|
10121
10164
|
const windowStart = new Date(Date.now() - config.window_minutes * 60 * 1000).toISOString();
|
|
10122
10165
|
const result = db.query(`SELECT COUNT(*) as count FROM tasks
|
|
10123
|
-
WHERE completed_at > ? AND (
|
|
10166
|
+
WHERE completed_at > ? AND (${assignedInClause} OR agent_id = ?)`).get(windowStart, ...assignedAliasParams, agent);
|
|
10124
10167
|
if (result.count >= config.max_completions_per_window) {
|
|
10125
10168
|
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
10169
|
}
|
|
10127
10170
|
}
|
|
10128
10171
|
if (agent && config.cooldown_seconds) {
|
|
10129
10172
|
const result = db.query(`SELECT MAX(completed_at) as last_completed FROM tasks
|
|
10130
|
-
WHERE completed_at IS NOT NULL AND (
|
|
10173
|
+
WHERE completed_at IS NOT NULL AND (${assignedInClause} OR agent_id = ?) AND id != ?`).get(...assignedAliasParams, agent, task.id);
|
|
10131
10174
|
if (result.last_completed) {
|
|
10132
10175
|
const elapsedSeconds = (Date.now() - new Date(result.last_completed).getTime()) / 1000;
|
|
10133
10176
|
if (elapsedSeconds < config.cooldown_seconds) {
|
|
@@ -10141,6 +10184,7 @@ var init_completion_guard = __esm(() => {
|
|
|
10141
10184
|
init_types();
|
|
10142
10185
|
init_config2();
|
|
10143
10186
|
init_projects();
|
|
10187
|
+
init_database();
|
|
10144
10188
|
});
|
|
10145
10189
|
|
|
10146
10190
|
// src/lib/event-emission-safety.ts
|
|
@@ -12318,13 +12362,17 @@ function logDelivery(d, webhookId, event, payload, statusCode, response, attempt
|
|
|
12318
12362
|
const id = uuid();
|
|
12319
12363
|
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
12364
|
}
|
|
12321
|
-
function matchesScope(wh, payload) {
|
|
12365
|
+
function matchesScope(wh, payload, db) {
|
|
12322
12366
|
if (wh.project_id && payload.project_id !== wh.project_id)
|
|
12323
12367
|
return false;
|
|
12324
12368
|
if (wh.task_list_id && payload.task_list_id !== wh.task_list_id)
|
|
12325
12369
|
return false;
|
|
12326
|
-
if (wh.agent_id && payload.agent_id !== wh.agent_id
|
|
12327
|
-
|
|
12370
|
+
if (wh.agent_id && payload.agent_id !== wh.agent_id) {
|
|
12371
|
+
const aliasSet = assignedToAliasSet(db, wh.agent_id);
|
|
12372
|
+
const assignedTo = typeof payload.assigned_to === "string" ? payload.assigned_to.toLowerCase() : "";
|
|
12373
|
+
if (!aliasSet.has(assignedTo))
|
|
12374
|
+
return false;
|
|
12375
|
+
}
|
|
12328
12376
|
if (wh.task_id && payload.id !== wh.task_id)
|
|
12329
12377
|
return false;
|
|
12330
12378
|
return true;
|
|
@@ -12391,7 +12439,7 @@ async function dispatchWebhook2(event, payload, db) {
|
|
|
12391
12439
|
const webhooks = listWebhooks(d).filter((w) => w.active && (w.events.length === 0 || w.events.includes(event)));
|
|
12392
12440
|
const payloadObj = typeof payload === "object" && payload !== null ? payload : {};
|
|
12393
12441
|
for (const wh of webhooks) {
|
|
12394
|
-
if (!matchesScope(wh, payloadObj))
|
|
12442
|
+
if (!matchesScope(wh, payloadObj, d))
|
|
12395
12443
|
continue;
|
|
12396
12444
|
const body = JSON.stringify({ event, payload, timestamp: now() });
|
|
12397
12445
|
deliverWebhook(wh, event, body, 1, d).catch((err) => {
|
|
@@ -13463,14 +13511,16 @@ function getNextTask2(agentId, filters, db) {
|
|
|
13463
13511
|
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
13512
|
const where = conditions.join(" AND ");
|
|
13465
13513
|
let recentProjectIds = [];
|
|
13514
|
+
const assignedAliasParams = [];
|
|
13515
|
+
const assignedInClause = agentId ? lowerInClause("assigned_to", resolveAssignedToAliases(d, agentId), assignedAliasParams) : "";
|
|
13466
13516
|
if (agentId) {
|
|
13467
|
-
const recentRows = d.query(`SELECT DISTINCT project_id FROM tasks WHERE
|
|
13517
|
+
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
13518
|
recentProjectIds = recentRows.map((r) => r.project_id);
|
|
13469
13519
|
}
|
|
13470
13520
|
let sql = `SELECT * FROM tasks WHERE ${where} ORDER BY `;
|
|
13471
13521
|
if (agentId) {
|
|
13472
|
-
sql += `CASE WHEN
|
|
13473
|
-
params.push(
|
|
13522
|
+
sql += `CASE WHEN ${assignedInClause} THEN 0 WHEN assigned_to IS NULL THEN 1 ELSE 2 END, `;
|
|
13523
|
+
params.push(...assignedAliasParams);
|
|
13474
13524
|
}
|
|
13475
13525
|
if (recentProjectIds.length > 0) {
|
|
13476
13526
|
const placeholders = recentProjectIds.map(() => "?").join(",");
|
|
@@ -13864,30 +13914,6 @@ function getTaskWithRelations(id, db) {
|
|
|
13864
13914
|
checklist
|
|
13865
13915
|
};
|
|
13866
13916
|
}
|
|
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
13917
|
function listTasks2(filter = {}, db) {
|
|
13892
13918
|
const d = db || getDatabase();
|
|
13893
13919
|
const { clearExpiredLocks: clearExpiredLocks2 } = (init_database(), __toCommonJS(exports_database));
|
|
@@ -14173,11 +14199,13 @@ function updateTask2(id, input, db) {
|
|
|
14173
14199
|
}
|
|
14174
14200
|
sets.push("status = ?");
|
|
14175
14201
|
params.push(input.status);
|
|
14202
|
+
if (isTerminalStatus(input.status)) {
|
|
14203
|
+
sets.push("locked_by = NULL");
|
|
14204
|
+
sets.push("locked_at = NULL");
|
|
14205
|
+
}
|
|
14176
14206
|
if (input.status === "completed") {
|
|
14177
14207
|
sets.push("completed_at = ?");
|
|
14178
14208
|
params.push(completionTimestamp);
|
|
14179
|
-
sets.push("locked_by = NULL");
|
|
14180
|
-
sets.push("locked_at = NULL");
|
|
14181
14209
|
} else if (task.status === "completed" && input.completed_at === undefined) {
|
|
14182
14210
|
sets.push("completed_at = NULL");
|
|
14183
14211
|
}
|
|
@@ -14301,6 +14329,7 @@ function updateTask2(id, input, db) {
|
|
|
14301
14329
|
logTaskChange2(id, "approve", "approved_by", null, input.approved_by, agentId, d);
|
|
14302
14330
|
const reopened = input.status !== undefined && input.status !== "completed" && task.status === "completed" && input.completed_at === undefined;
|
|
14303
14331
|
const completedNow = input.status === "completed";
|
|
14332
|
+
const terminalNow = input.status !== undefined && isTerminalStatus(input.status);
|
|
14304
14333
|
const updatedTask = {
|
|
14305
14334
|
...task,
|
|
14306
14335
|
...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
|
|
@@ -14308,8 +14337,8 @@ function updateTask2(id, input, db) {
|
|
|
14308
14337
|
metadata: input.metadata ?? task.metadata,
|
|
14309
14338
|
version: task.version + 1,
|
|
14310
14339
|
updated_at: timestamp2,
|
|
14311
|
-
locked_by:
|
|
14312
|
-
locked_at:
|
|
14340
|
+
locked_by: terminalNow ? null : task.locked_by,
|
|
14341
|
+
locked_at: terminalNow ? null : task.locked_at,
|
|
14313
14342
|
completed_at: completedNow ? completionTimestamp : reopened ? null : input.completed_at !== undefined ? input.completed_at : task.completed_at,
|
|
14314
14343
|
sla_minutes: input.sla_minutes !== undefined ? input.sla_minutes : task.sla_minutes,
|
|
14315
14344
|
actual_minutes: input.actual_minutes ?? task.actual_minutes,
|
|
@@ -14360,6 +14389,7 @@ function deleteTask(id, db) {
|
|
|
14360
14389
|
var init_task_crud = __esm(() => {
|
|
14361
14390
|
init_types();
|
|
14362
14391
|
init_database();
|
|
14392
|
+
init_database();
|
|
14363
14393
|
init_completion_guard();
|
|
14364
14394
|
init_event_emission_safety();
|
|
14365
14395
|
init_event_hooks();
|
|
@@ -14522,8 +14552,8 @@ function getTaskStats(filters, db) {
|
|
|
14522
14552
|
params.push(filters.task_list_id);
|
|
14523
14553
|
}
|
|
14524
14554
|
if (filters?.agent_id) {
|
|
14525
|
-
|
|
14526
|
-
|
|
14555
|
+
params.push(filters.agent_id);
|
|
14556
|
+
conditions.push(`(agent_id = ? OR ${lowerInClause("assigned_to", resolveAssignedToAliases(d, filters.agent_id), params)})`);
|
|
14527
14557
|
}
|
|
14528
14558
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
14529
14559
|
const totalRow = d.query(`SELECT COUNT(*) as count FROM tasks ${where}`).get(...params);
|
|
@@ -14706,8 +14736,7 @@ function getEscalatedTasks(opts = {}, db, at = new Date) {
|
|
|
14706
14736
|
params.push(opts.project_id);
|
|
14707
14737
|
}
|
|
14708
14738
|
if (opts.agent_id) {
|
|
14709
|
-
conditions.push("assigned_to
|
|
14710
|
-
params.push(opts.agent_id);
|
|
14739
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
14711
14740
|
}
|
|
14712
14741
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC, created_at ASC`).all(...params);
|
|
14713
14742
|
return rows.map(rowToTask).map((task) => {
|
|
@@ -14755,8 +14784,7 @@ function notifyUpcomingDeadlines(opts = {}, db) {
|
|
|
14755
14784
|
params.push(opts.project_id);
|
|
14756
14785
|
}
|
|
14757
14786
|
if (opts.agent_id) {
|
|
14758
|
-
conditions.push("assigned_to
|
|
14759
|
-
params.push(opts.agent_id);
|
|
14787
|
+
conditions.push(lowerInClause("assigned_to", resolveAssignedToAliases(d, opts.agent_id), params));
|
|
14760
14788
|
}
|
|
14761
14789
|
const rows = d.query(`SELECT * FROM tasks WHERE ${conditions.join(" AND ")} ORDER BY due_at ASC`).all(...params);
|
|
14762
14790
|
return rows.map(rowToTask);
|
|
@@ -15014,13 +15042,14 @@ function getTimeReport(opts, db) {
|
|
|
15014
15042
|
params.push(opts.plan_id);
|
|
15015
15043
|
}
|
|
15016
15044
|
if (opts?.agent_id) {
|
|
15045
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.agent_id), params);
|
|
15017
15046
|
conditions.push(`(
|
|
15018
|
-
|
|
15047
|
+
${assignedInClause}
|
|
15019
15048
|
OR t.agent_id = ?
|
|
15020
15049
|
OR EXISTS (SELECT 1 FROM task_time_logs ttl WHERE ttl.task_id = t.id AND ttl.agent_id = ?)
|
|
15021
15050
|
OR EXISTS (SELECT 1 FROM focus_sessions fs WHERE fs.task_id = t.id AND fs.agent_id = ?)
|
|
15022
15051
|
)`);
|
|
15023
|
-
params.push(opts.agent_id, opts.agent_id, opts.agent_id
|
|
15052
|
+
params.push(opts.agent_id, opts.agent_id, opts.agent_id);
|
|
15024
15053
|
}
|
|
15025
15054
|
if (opts?.since) {
|
|
15026
15055
|
conditions.push("(t.completed_at >= ? OR t.updated_at >= ?)");
|
|
@@ -16016,7 +16045,7 @@ function listActiveFiles(db) {
|
|
|
16016
16045
|
a.name AS agent_name
|
|
16017
16046
|
FROM task_files tf
|
|
16018
16047
|
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))
|
|
16048
|
+
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
16049
|
WHERE t.status = 'in_progress'
|
|
16021
16050
|
AND tf.status != 'removed'
|
|
16022
16051
|
ORDER BY tf.updated_at DESC
|
|
@@ -17230,6 +17259,96 @@ var init_tasks = __esm(() => {
|
|
|
17230
17259
|
init_calendar();
|
|
17231
17260
|
});
|
|
17232
17261
|
|
|
17262
|
+
// src/lib/enum-vocabulary.ts
|
|
17263
|
+
function editDistance(a, b) {
|
|
17264
|
+
if (a === b)
|
|
17265
|
+
return 0;
|
|
17266
|
+
if (!a.length)
|
|
17267
|
+
return b.length;
|
|
17268
|
+
if (!b.length)
|
|
17269
|
+
return a.length;
|
|
17270
|
+
let previous = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
17271
|
+
for (let i = 1;i <= a.length; i += 1) {
|
|
17272
|
+
const current = [i];
|
|
17273
|
+
for (let j = 1;j <= b.length; j += 1) {
|
|
17274
|
+
current[j] = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
17275
|
+
}
|
|
17276
|
+
previous = current;
|
|
17277
|
+
}
|
|
17278
|
+
return previous[b.length];
|
|
17279
|
+
}
|
|
17280
|
+
function suggestVocabularyMatches(value, vocabulary, limit = 3) {
|
|
17281
|
+
const needle = value.trim().toLowerCase();
|
|
17282
|
+
if (!needle)
|
|
17283
|
+
return [];
|
|
17284
|
+
const scored = [];
|
|
17285
|
+
for (const member of vocabulary) {
|
|
17286
|
+
const candidate = member.toLowerCase();
|
|
17287
|
+
if (candidate.startsWith(needle) || needle.startsWith(candidate)) {
|
|
17288
|
+
scored.push({ member, score: 0 });
|
|
17289
|
+
continue;
|
|
17290
|
+
}
|
|
17291
|
+
if (candidate.includes(needle) || needle.includes(candidate)) {
|
|
17292
|
+
scored.push({ member, score: 1 });
|
|
17293
|
+
continue;
|
|
17294
|
+
}
|
|
17295
|
+
const distance = editDistance(needle, candidate);
|
|
17296
|
+
if (distance <= Math.max(1, Math.floor(candidate.length / 3))) {
|
|
17297
|
+
scored.push({ member, score: 1 + distance });
|
|
17298
|
+
}
|
|
17299
|
+
}
|
|
17300
|
+
return scored.sort((a, b) => a.score - b.score || a.member.localeCompare(b.member)).slice(0, limit).map((entry2) => entry2.member);
|
|
17301
|
+
}
|
|
17302
|
+
function resolveEnumVocabulary(raw, spec) {
|
|
17303
|
+
const allowList = spec.allowList !== false;
|
|
17304
|
+
const rawElements = (allowList ? raw.split(",") : [raw]).map((element) => element.trim()).filter((element) => element.length > 0);
|
|
17305
|
+
if (rawElements.length === 0) {
|
|
17306
|
+
return {
|
|
17307
|
+
ok: false,
|
|
17308
|
+
message: `${spec.name} requires a value. Allowed values: ${spec.vocabulary.join(", ")}.`,
|
|
17309
|
+
invalid: []
|
|
17310
|
+
};
|
|
17311
|
+
}
|
|
17312
|
+
const normalized = rawElements.map((element) => spec.normalize ? spec.normalize(element) : element);
|
|
17313
|
+
const allowed = new Set(spec.vocabulary);
|
|
17314
|
+
const invalid = [];
|
|
17315
|
+
for (let i = 0;i < normalized.length; i += 1) {
|
|
17316
|
+
if (!allowed.has(normalized[i]))
|
|
17317
|
+
invalid.push(rawElements[i]);
|
|
17318
|
+
}
|
|
17319
|
+
if (invalid.length === 0) {
|
|
17320
|
+
return { ok: true, values: [...new Set(normalized)] };
|
|
17321
|
+
}
|
|
17322
|
+
const label = invalid.length === 1 ? "value" : "values";
|
|
17323
|
+
const parts = [
|
|
17324
|
+
`Invalid ${spec.name} ${label}: ${invalid.join(", ")}.`,
|
|
17325
|
+
`Allowed values: ${spec.vocabulary.join(", ")}.`
|
|
17326
|
+
];
|
|
17327
|
+
const hints = new Set;
|
|
17328
|
+
const suggestions = new Set;
|
|
17329
|
+
for (let i = 0;i < normalized.length; i += 1) {
|
|
17330
|
+
const canonical = normalized[i];
|
|
17331
|
+
if (allowed.has(canonical))
|
|
17332
|
+
continue;
|
|
17333
|
+
const hint = spec.hints?.[canonical.toLowerCase()];
|
|
17334
|
+
if (hint) {
|
|
17335
|
+
hints.add(hint);
|
|
17336
|
+
continue;
|
|
17337
|
+
}
|
|
17338
|
+
for (const match of suggestVocabularyMatches(canonical, spec.vocabulary)) {
|
|
17339
|
+
suggestions.add(match);
|
|
17340
|
+
}
|
|
17341
|
+
}
|
|
17342
|
+
if (suggestions.size > 0)
|
|
17343
|
+
parts.push(`Did you mean ${[...suggestions].join(", ")}?`);
|
|
17344
|
+
for (const hint of hints)
|
|
17345
|
+
parts.push(hint);
|
|
17346
|
+
return { ok: false, message: parts.join(" "), invalid };
|
|
17347
|
+
}
|
|
17348
|
+
function collapseEnumValues(values) {
|
|
17349
|
+
return values.length === 1 ? values[0] : values;
|
|
17350
|
+
}
|
|
17351
|
+
|
|
17233
17352
|
// src/db/agent-names.ts
|
|
17234
17353
|
function hasGeneratedNumericSuffix(name) {
|
|
17235
17354
|
return NUMERIC_SUFFIX_RE.test(normalizeAgentNameInput(name));
|
|
@@ -18657,8 +18776,19 @@ function handleStats(_ctx, json2) {
|
|
|
18657
18776
|
recurring_tasks: countRecurringTasks()
|
|
18658
18777
|
});
|
|
18659
18778
|
}
|
|
18779
|
+
function taskStatusQueryParam(url) {
|
|
18780
|
+
const raw = url.searchParams.get("status");
|
|
18781
|
+
if (!raw)
|
|
18782
|
+
return { ok: true, value: undefined };
|
|
18783
|
+
const result = resolveEnumVocabulary(raw, { name: "status", vocabulary: TASK_STATUSES });
|
|
18784
|
+
if (!result.ok)
|
|
18785
|
+
return { ok: false, message: result.message };
|
|
18786
|
+
return { ok: true, value: collapseEnumValues(result.values) };
|
|
18787
|
+
}
|
|
18660
18788
|
async function handleListTasks(_req, url, _ctx, json2, taskToSummary2) {
|
|
18661
|
-
const
|
|
18789
|
+
const statusParam = taskStatusQueryParam(url);
|
|
18790
|
+
if (!statusParam.ok)
|
|
18791
|
+
return json2({ error: statusParam.message }, 400);
|
|
18662
18792
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
18663
18793
|
const sessionId = url.searchParams.get("session_id") || undefined;
|
|
18664
18794
|
const agentId = url.searchParams.get("agent_id") || undefined;
|
|
@@ -18666,7 +18796,7 @@ async function handleListTasks(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
18666
18796
|
const offsetParam = url.searchParams.get("offset");
|
|
18667
18797
|
const fields = parseFieldsParam(url);
|
|
18668
18798
|
const tasks = listTasks2({
|
|
18669
|
-
status,
|
|
18799
|
+
status: statusParam.value,
|
|
18670
18800
|
project_id: projectId,
|
|
18671
18801
|
session_id: sessionId,
|
|
18672
18802
|
agent_id: agentId,
|
|
@@ -18731,9 +18861,19 @@ async function handleUpsertTask(req, ctx, json2, taskToSummary2) {
|
|
|
18731
18861
|
}
|
|
18732
18862
|
function handleTasksExport(_req, url, _ctx, _json, taskToSummary2) {
|
|
18733
18863
|
const format = url.searchParams.get("format") || "json";
|
|
18734
|
-
const
|
|
18864
|
+
const statusParam = taskStatusQueryParam(url);
|
|
18865
|
+
if (!statusParam.ok) {
|
|
18866
|
+
return new Response(JSON.stringify({ error: statusParam.message }), {
|
|
18867
|
+
status: 400,
|
|
18868
|
+
headers: { "Content-Type": "application/json" }
|
|
18869
|
+
});
|
|
18870
|
+
}
|
|
18735
18871
|
const projectId = url.searchParams.get("project_id") || undefined;
|
|
18736
|
-
const tasks = listTasks2({
|
|
18872
|
+
const tasks = listTasks2({
|
|
18873
|
+
status: statusParam.value,
|
|
18874
|
+
project_id: projectId,
|
|
18875
|
+
limit: 1e4
|
|
18876
|
+
});
|
|
18737
18877
|
const summaries = tasks.map((t) => taskToSummary2(t));
|
|
18738
18878
|
if (format === "csv") {
|
|
18739
18879
|
const headers = ["id", "short_id", "title", "status", "priority", "project_id", "assigned_to", "agent_id", "created_at", "updated_at", "completed_at", "due_at"];
|
|
@@ -19048,8 +19188,9 @@ async function handleAgentMe(_req, url, _ctx, json2, taskToSummary2) {
|
|
|
19048
19188
|
}
|
|
19049
19189
|
}
|
|
19050
19190
|
function handleAgentQueue(agentId, _ctx, json2, taskToSummary2) {
|
|
19191
|
+
const aliasSet = assignedToAliasSet(getDatabase(), agentId);
|
|
19051
19192
|
const pending = listTasks2({ status: "pending" });
|
|
19052
|
-
const queue = pending.filter((t) => t.assigned_to
|
|
19193
|
+
const queue = pending.filter((t) => aliasSet.has((t.assigned_to ?? "").toLowerCase()) || t.agent_id === agentId || !t.assigned_to && !t.locked_by);
|
|
19053
19194
|
const order = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
19054
19195
|
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
19196
|
return json2(queue.map((t) => taskToSummary2(t)));
|
|
@@ -19314,6 +19455,7 @@ var init_routes = __esm(() => {
|
|
|
19314
19455
|
init_tasks();
|
|
19315
19456
|
init_database();
|
|
19316
19457
|
init_types();
|
|
19458
|
+
init_types();
|
|
19317
19459
|
init_projects();
|
|
19318
19460
|
init_agents();
|
|
19319
19461
|
init_plans();
|
|
@@ -19441,8 +19583,7 @@ function searchTasks(options, projectId, taskListId, db) {
|
|
|
19441
19583
|
}
|
|
19442
19584
|
}
|
|
19443
19585
|
if (opts.assigned_to) {
|
|
19444
|
-
sql +=
|
|
19445
|
-
params.push(opts.assigned_to);
|
|
19586
|
+
sql += ` AND ${lowerInClause("t.assigned_to", resolveAssignedToAliases(d, opts.assigned_to), params)}`;
|
|
19446
19587
|
}
|
|
19447
19588
|
if (opts.agent_id) {
|
|
19448
19589
|
sql += " AND t.agent_id = ?";
|
|
@@ -21353,8 +21494,38 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
|
|
|
21353
21494
|
operationId: "listTasks",
|
|
21354
21495
|
summary: "List tasks",
|
|
21355
21496
|
parameters: [
|
|
21356
|
-
{
|
|
21357
|
-
|
|
21497
|
+
{
|
|
21498
|
+
name: "status",
|
|
21499
|
+
in: "query",
|
|
21500
|
+
description: `Task status, or a comma-separated list of statuses. Allowed values: ${TASK_STATUSES.join(", ")}.`,
|
|
21501
|
+
style: "form",
|
|
21502
|
+
explode: false,
|
|
21503
|
+
schema: {
|
|
21504
|
+
oneOf: [
|
|
21505
|
+
{ type: "string", enum: [...TASK_STATUSES] },
|
|
21506
|
+
{
|
|
21507
|
+
type: "array",
|
|
21508
|
+
items: { type: "string", enum: [...TASK_STATUSES] }
|
|
21509
|
+
}
|
|
21510
|
+
]
|
|
21511
|
+
}
|
|
21512
|
+
},
|
|
21513
|
+
{
|
|
21514
|
+
name: "priority",
|
|
21515
|
+
in: "query",
|
|
21516
|
+
description: `Task priority, or a comma-separated list of priorities. Allowed values: ${TASK_PRIORITIES.join(", ")}.`,
|
|
21517
|
+
style: "form",
|
|
21518
|
+
explode: false,
|
|
21519
|
+
schema: {
|
|
21520
|
+
oneOf: [
|
|
21521
|
+
{ type: "string", enum: [...TASK_PRIORITIES] },
|
|
21522
|
+
{
|
|
21523
|
+
type: "array",
|
|
21524
|
+
items: { type: "string", enum: [...TASK_PRIORITIES] }
|
|
21525
|
+
}
|
|
21526
|
+
]
|
|
21527
|
+
}
|
|
21528
|
+
},
|
|
21358
21529
|
{ name: "project_id", in: "query", schema: { type: "string" } },
|
|
21359
21530
|
{ name: "parent_id", in: "query", schema: { type: "string", nullable: true } },
|
|
21360
21531
|
{ name: "include_subtasks", in: "query", schema: { type: "boolean" } },
|
|
@@ -21866,6 +22037,7 @@ function buildV1OpenApiDocument(version = getPackageVersion()) {
|
|
|
21866
22037
|
var taskSchema, projectSchema, taskListSchema, taskCommentSchema, planSchema, templateTaskSchema, templateSchema, templateVariableSchema, createTemplateTaskInputSchema;
|
|
21867
22038
|
var init_openapi = __esm(() => {
|
|
21868
22039
|
init_package_version();
|
|
22040
|
+
init_types();
|
|
21869
22041
|
taskSchema = {
|
|
21870
22042
|
type: "object",
|
|
21871
22043
|
properties: {
|
|
@@ -22133,6 +22305,15 @@ function json3(body, status = 200) {
|
|
|
22133
22305
|
function error(status, message, extra) {
|
|
22134
22306
|
return json3({ error: message, ...extra ?? {} }, status);
|
|
22135
22307
|
}
|
|
22308
|
+
function enumQueryParam(url, name, vocabulary) {
|
|
22309
|
+
const raw = url.searchParams.get(name);
|
|
22310
|
+
if (raw === null || raw === "")
|
|
22311
|
+
return { ok: true, value: undefined };
|
|
22312
|
+
const result = resolveEnumVocabulary(raw, { name, vocabulary });
|
|
22313
|
+
if (!result.ok)
|
|
22314
|
+
return { ok: false, response: error(400, result.message) };
|
|
22315
|
+
return { ok: true, value: collapseEnumValues(result.values) };
|
|
22316
|
+
}
|
|
22136
22317
|
function validateTaskCompletion(value) {
|
|
22137
22318
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
22138
22319
|
return { ok: false, message: "completion body must be an object" };
|
|
@@ -22553,14 +22734,16 @@ async function handleV1Request(req, url, dependencies = {}) {
|
|
|
22553
22734
|
return error(400, "include_subtasks must be true or false");
|
|
22554
22735
|
}
|
|
22555
22736
|
const hasParentFilter = url.searchParams.has("parent_id");
|
|
22737
|
+
const statusParam = enumQueryParam(url, "status", TASK_STATUSES);
|
|
22738
|
+
if (!statusParam.ok)
|
|
22739
|
+
return statusParam.response;
|
|
22740
|
+
const priorityParam = enumQueryParam(url, "priority", TASK_PRIORITIES);
|
|
22741
|
+
if (!priorityParam.ok)
|
|
22742
|
+
return priorityParam.response;
|
|
22556
22743
|
const filter = {
|
|
22557
22744
|
...url.searchParams.get("q") ? { query: url.searchParams.get("q") } : {},
|
|
22558
|
-
...
|
|
22559
|
-
|
|
22560
|
-
} : {},
|
|
22561
|
-
...url.searchParams.get("priority") ? {
|
|
22562
|
-
priority: url.searchParams.get("priority").includes(",") ? url.searchParams.get("priority").split(",") : url.searchParams.get("priority")
|
|
22563
|
-
} : {},
|
|
22745
|
+
...statusParam.value !== undefined ? { status: statusParam.value } : {},
|
|
22746
|
+
...priorityParam.value !== undefined ? { priority: priorityParam.value } : {},
|
|
22564
22747
|
...url.searchParams.get("project_id") ? { project_id: url.searchParams.get("project_id") } : {},
|
|
22565
22748
|
...hasParentFilter ? { parent_id: url.searchParams.get("parent_id") || null, include_subtasks: true } : includeSubtasks !== null ? { include_subtasks: includeSubtasks === "true" } : {},
|
|
22566
22749
|
...url.searchParams.get("plan_id") ? { plan_id: url.searchParams.get("plan_id") } : {},
|
|
@@ -60747,11 +60930,12 @@ function runAlerts(input, db, checkedAt, quieted) {
|
|
|
60747
60930
|
if (input.include_runs === false)
|
|
60748
60931
|
return [];
|
|
60749
60932
|
const since = Date.parse(input.run_since || new Date(Date.parse(checkedAt) - 24 * 60 * 60000).toISOString());
|
|
60933
|
+
const runAlertAliases = input.agent_id ? assignedToAliasSet(db, input.agent_id) : null;
|
|
60750
60934
|
return listTaskRuns(undefined, db).filter((run) => run.completed_at && Date.parse(run.completed_at) >= since).map((run) => {
|
|
60751
60935
|
const task = getTask(run.task_id, db);
|
|
60752
60936
|
if (input.project_id && task?.project_id !== input.project_id)
|
|
60753
60937
|
return null;
|
|
60754
|
-
if (input.agent_id && run.agent_id !== input.agent_id && task?.assigned_to
|
|
60938
|
+
if (input.agent_id && run.agent_id !== input.agent_id && !(runAlertAliases && runAlertAliases.has((task?.assigned_to ?? "").toLowerCase())))
|
|
60755
60939
|
return null;
|
|
60756
60940
|
const failed = ["failed", "cancelled"].includes(run.status);
|
|
60757
60941
|
return {
|
|
@@ -60796,6 +60980,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60796
60980
|
const warnings = [];
|
|
60797
60981
|
if (Number.isNaN(checkedMs))
|
|
60798
60982
|
warnings.push("Invalid check timestamp; due-soon window may be incomplete.");
|
|
60983
|
+
const notifyAgentAliases = input.agent_id ? assignedToAliasSet(d, input.agent_id) : null;
|
|
60799
60984
|
const alerts = [];
|
|
60800
60985
|
for (const escalation of getEscalatedTasks({ project_id: input.project_id, agent_id: input.agent_id }, d, new Date(checkedAt))) {
|
|
60801
60986
|
for (const reason of escalation.reasons) {
|
|
@@ -60807,7 +60992,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60807
60992
|
for (const task of listTasks2({ project_id: input.project_id, include_archived: false, limit: 5000 }, d)) {
|
|
60808
60993
|
if (!unfinished(task) || !task.due_at)
|
|
60809
60994
|
continue;
|
|
60810
|
-
if (input.agent_id && task.
|
|
60995
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
60811
60996
|
continue;
|
|
60812
60997
|
if (task.due_at > checkedAt && task.due_at <= dueSoonUntil) {
|
|
60813
60998
|
alerts.push(taskAlert(task, "task_due_soon", "task.due_soon", "warning", `Due soon: ${task.title}`, task.due_at, quieted));
|
|
@@ -60815,7 +61000,7 @@ async function checkLocalNotifications(input = {}, db) {
|
|
|
60815
61000
|
}
|
|
60816
61001
|
}
|
|
60817
61002
|
for (const task of getStaleTasks(staleMinutes, { project_id: input.project_id }, d)) {
|
|
60818
|
-
if (input.agent_id && task.
|
|
61003
|
+
if (input.agent_id && task.agent_id !== input.agent_id && !(notifyAgentAliases && notifyAgentAliases.has((task.assigned_to ?? "").toLowerCase())))
|
|
60819
61004
|
continue;
|
|
60820
61005
|
alerts.push(taskAlert(task, "task_stale", "task.stale", "warning", `Stale task: ${task.title}`, checkedAt, quieted, { stale_minutes: staleMinutes }));
|
|
60821
61006
|
}
|
|
@@ -62835,10 +63020,12 @@ function matchesProfile(profile, query) {
|
|
|
62835
63020
|
return false;
|
|
62836
63021
|
return true;
|
|
62837
63022
|
}
|
|
62838
|
-
function taskMatchesAgent(task, agentId) {
|
|
63023
|
+
function taskMatchesAgent(task, agentId, aliasSet) {
|
|
62839
63024
|
if (!agentId)
|
|
62840
63025
|
return true;
|
|
62841
|
-
|
|
63026
|
+
if (task.agent_id === agentId)
|
|
63027
|
+
return true;
|
|
63028
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
62842
63029
|
}
|
|
62843
63030
|
function estimateRemaining(task) {
|
|
62844
63031
|
if (task.status === "completed" || task.status === "cancelled")
|
|
@@ -62908,7 +63095,8 @@ function removeCapacityProfile(idOrAgent, projectId) {
|
|
|
62908
63095
|
}
|
|
62909
63096
|
function getPlanningForecast(input = {}, db) {
|
|
62910
63097
|
const startDate = input.start_date ? dateOnly(input.start_date) : todayIso();
|
|
62911
|
-
const
|
|
63098
|
+
const aliasSet = input.agent_id ? assignedToAliasSet(db || getDatabase(), input.agent_id) : undefined;
|
|
63099
|
+
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
63100
|
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
63101
|
const profiles = listCapacityProfiles({ agent_id: input.agent_id, project_id: input.project_id });
|
|
62914
63102
|
const globalProfiles = input.project_id ? listCapacityProfiles({ agent_id: input.agent_id }).filter((profile) => profile.project_id === null) : [];
|
|
@@ -63006,6 +63194,7 @@ function renderPlanningForecastMarkdown(forecast) {
|
|
|
63006
63194
|
}
|
|
63007
63195
|
var LOCAL_CAPACITY_SCHEMA_VERSION = 1;
|
|
63008
63196
|
var init_capacity_forecasts = __esm(() => {
|
|
63197
|
+
init_database();
|
|
63009
63198
|
init_tasks();
|
|
63010
63199
|
init_task_relations();
|
|
63011
63200
|
init_config2();
|
|
@@ -63560,7 +63749,8 @@ __export(exports_saved_search_views, {
|
|
|
63560
63749
|
normalizeScope: () => normalizeScope,
|
|
63561
63750
|
listSearchViews: () => listSearchViews,
|
|
63562
63751
|
getSearchView: () => getSearchView,
|
|
63563
|
-
deleteSearchView: () => deleteSearchView
|
|
63752
|
+
deleteSearchView: () => deleteSearchView,
|
|
63753
|
+
SAVED_SEARCH_SCOPES: () => SAVED_SEARCH_SCOPES
|
|
63564
63754
|
});
|
|
63565
63755
|
function parseFilters(value) {
|
|
63566
63756
|
if (!value)
|
|
@@ -63580,10 +63770,8 @@ function rowToSavedSearchView(row) {
|
|
|
63580
63770
|
};
|
|
63581
63771
|
}
|
|
63582
63772
|
function normalizeScope(scope) {
|
|
63583
|
-
|
|
63584
|
-
|
|
63585
|
-
}
|
|
63586
|
-
return "tasks";
|
|
63773
|
+
const candidate = (scope ?? "").trim().toLowerCase();
|
|
63774
|
+
return SAVED_SEARCH_SCOPES.includes(candidate) ? candidate : "tasks";
|
|
63587
63775
|
}
|
|
63588
63776
|
function normalizeName4(name) {
|
|
63589
63777
|
const normalized = name.trim();
|
|
@@ -63886,10 +64074,12 @@ function runSearchView(idOrName, db) {
|
|
|
63886
64074
|
throw new Error(`Saved search view not found: ${idOrName}`);
|
|
63887
64075
|
return { ...runSavedSearch(view.filters, view.scope, d), view };
|
|
63888
64076
|
}
|
|
64077
|
+
var SAVED_SEARCH_SCOPES;
|
|
63889
64078
|
var init_saved_search_views = __esm(() => {
|
|
63890
64079
|
init_database();
|
|
63891
64080
|
init_local_fields();
|
|
63892
64081
|
init_search();
|
|
64082
|
+
SAVED_SEARCH_SCOPES = ["all", "tasks", "projects", "plans", "runs", "comments"];
|
|
63893
64083
|
});
|
|
63894
64084
|
|
|
63895
64085
|
// src/mcp/tools/task-project-tools.ts
|
|
@@ -66439,8 +66629,10 @@ function getLatestHandoff(agentId, projectId, db) {
|
|
|
66439
66629
|
function createSessionRecoveryHandoff(input, db) {
|
|
66440
66630
|
const d = db || getDatabase();
|
|
66441
66631
|
const limit = input.limit || 20;
|
|
66442
|
-
const
|
|
66443
|
-
const
|
|
66632
|
+
const params = [];
|
|
66633
|
+
const assignedInClause = lowerInClause("assigned_to", resolveAssignedToAliases(d, input.agent_id), params);
|
|
66634
|
+
const conditions = ["status = 'in_progress'", `(${assignedInClause} OR agent_id = ? OR locked_by = ?)`];
|
|
66635
|
+
params.push(input.agent_id, input.agent_id);
|
|
66444
66636
|
if (input.session_id) {
|
|
66445
66637
|
conditions.push("session_id = ?");
|
|
66446
66638
|
params.push(input.session_id);
|
|
@@ -67032,7 +67224,8 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
67032
67224
|
const assigned = listTasks4({ assigned_to: effectiveAgentId, limit: 500 }, undefined);
|
|
67033
67225
|
const now4 = Date.now();
|
|
67034
67226
|
const dueSoonCutoff = now4 + 24 * 60 * 60 * 1000;
|
|
67035
|
-
const
|
|
67227
|
+
const blockedAliases = assignedToAliasSet(getDatabase(), effectiveAgentId);
|
|
67228
|
+
const blocked = getBlockedTasks2().filter((t) => blockedAliases.has((t.assigned_to ?? "").toLowerCase()));
|
|
67036
67229
|
const workload = {
|
|
67037
67230
|
in_progress: assigned.filter((t) => t.status === "in_progress").length,
|
|
67038
67231
|
pending: assigned.filter((t) => t.status === "pending").length,
|
|
@@ -67069,17 +67262,38 @@ function registerTaskAutoTools(server, ctx) {
|
|
|
67069
67262
|
if (agents.length === 0)
|
|
67070
67263
|
return { content: [{ type: "text", text: "No active agents available for rebalancing." }] };
|
|
67071
67264
|
const activeTasks = listTasks4({ project_id: resolvedProjectId, status: ["pending", "in_progress"], limit: 1000 }, undefined);
|
|
67072
|
-
const
|
|
67265
|
+
const agentKeyByAlias = new Map;
|
|
67266
|
+
const ambiguousAgentAliases = new Set;
|
|
67267
|
+
const indexAgentAlias = (alias, agentId) => {
|
|
67268
|
+
const normalizedAlias2 = alias.toLowerCase();
|
|
67269
|
+
if (ambiguousAgentAliases.has(normalizedAlias2))
|
|
67270
|
+
return;
|
|
67271
|
+
const existingAgentId = agentKeyByAlias.get(normalizedAlias2);
|
|
67272
|
+
if (existingAgentId !== undefined && existingAgentId !== agentId) {
|
|
67273
|
+
agentKeyByAlias.delete(normalizedAlias2);
|
|
67274
|
+
ambiguousAgentAliases.add(normalizedAlias2);
|
|
67275
|
+
return;
|
|
67276
|
+
}
|
|
67277
|
+
agentKeyByAlias.set(normalizedAlias2, agentId);
|
|
67278
|
+
};
|
|
67279
|
+
for (const agent of agents) {
|
|
67280
|
+
indexAgentAlias(String(agent.id), agent.id);
|
|
67281
|
+
if (agent.name)
|
|
67282
|
+
indexAgentAlias(String(agent.name), agent.id);
|
|
67283
|
+
}
|
|
67284
|
+
const canonicalAgentKey = (assignedTo) => assignedTo ? agentKeyByAlias.get(assignedTo.toLowerCase()) : undefined;
|
|
67285
|
+
const load = new Map(agents.map((agent) => [agent.id, activeTasks.filter((t) => canonicalAgentKey(t.assigned_to) === agent.id).length]));
|
|
67073
67286
|
let moved = 0;
|
|
67074
67287
|
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
|
|
67288
|
+
for (const task of activeTasks.filter((t) => t.status === "pending" && canonicalAgentKey(t.assigned_to) && (load.get(canonicalAgentKey(t.assigned_to)) ?? 0) > limit)) {
|
|
67289
|
+
const currentAgentKey = canonicalAgentKey(task.assigned_to);
|
|
67290
|
+
const target = agents.filter((agent) => agent.id !== currentAgentKey).sort((a, b) => (load.get(a.id) ?? 0) - (load.get(b.id) ?? 0))[0];
|
|
67077
67291
|
if (!target || (load.get(target.id) ?? 0) >= limit) {
|
|
67078
67292
|
skipped++;
|
|
67079
67293
|
continue;
|
|
67080
67294
|
}
|
|
67081
67295
|
updateTask3(task.id, { assigned_to: target.id, version: task.version });
|
|
67082
|
-
load.set(
|
|
67296
|
+
load.set(currentAgentKey, (load.get(currentAgentKey) ?? 1) - 1);
|
|
67083
67297
|
load.set(target.id, (load.get(target.id) ?? 0) + 1);
|
|
67084
67298
|
moved++;
|
|
67085
67299
|
}
|
|
@@ -67258,6 +67472,7 @@ ${lines.join(`
|
|
|
67258
67472
|
var init_task_auto_tools = __esm(() => {
|
|
67259
67473
|
init_zod();
|
|
67260
67474
|
init_cloud_router();
|
|
67475
|
+
init_database();
|
|
67261
67476
|
});
|
|
67262
67477
|
|
|
67263
67478
|
// src/lib/context-packs.ts
|
|
@@ -68437,7 +68652,8 @@ ${JSON.stringify(task.metadata, null, 2)}` : null
|
|
|
68437
68652
|
}, undefined);
|
|
68438
68653
|
const completedYesterday = completed.filter((t) => t.completed_at && t.completed_at.startsWith(yesterdayStr));
|
|
68439
68654
|
const { getBlockedTasks: getBlockedTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
68440
|
-
const
|
|
68655
|
+
const blockedAliases = effectiveAgentId ? assignedToAliasSet(getDatabase(), effectiveAgentId) : null;
|
|
68656
|
+
const blocked = getBlockedTasks2(effectiveProjectId ? resolveId(effectiveProjectId, "projects") : undefined).filter((t) => blockedAliases ? blockedAliases.has((t.assigned_to ?? "").toLowerCase()) : false);
|
|
68441
68657
|
const lines = [
|
|
68442
68658
|
`Standup for ${effectiveAgentId} (${effectiveProjectId ? `project: ${effectiveProjectId.slice(0, 8)}` : "all projects"})`,
|
|
68443
68659
|
inProgress.length > 0 ? `
|
|
@@ -68665,6 +68881,7 @@ var init_task_adv_tools = __esm(() => {
|
|
|
68665
68881
|
init_zod();
|
|
68666
68882
|
init_token_utils();
|
|
68667
68883
|
init_cloud_router();
|
|
68884
|
+
init_database();
|
|
68668
68885
|
});
|
|
68669
68886
|
|
|
68670
68887
|
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.cjs
|
|
@@ -94356,27 +94573,29 @@ function getAgentMetrics(agentId, opts, db) {
|
|
|
94356
94573
|
const agent = d.query("SELECT id, name FROM agents WHERE id = ? OR LOWER(name) = LOWER(?)").get(agentId, agentId);
|
|
94357
94574
|
if (!agent)
|
|
94358
94575
|
return null;
|
|
94576
|
+
const assignedAliases = resolveAssignedToAliases(d, agent.id).map((a) => a.toLowerCase());
|
|
94577
|
+
const assignedInClause = `LOWER(assigned_to) IN (${assignedAliases.map(() => "?").join(",")})`;
|
|
94359
94578
|
let projectFilter = "";
|
|
94360
|
-
const params = [agent.id,
|
|
94579
|
+
const params = [agent.id, ...assignedAliases];
|
|
94361
94580
|
if (opts?.project_id) {
|
|
94362
94581
|
projectFilter = " AND project_id = ?";
|
|
94363
94582
|
params.push(opts.project_id);
|
|
94364
94583
|
}
|
|
94365
|
-
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94366
|
-
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94367
|
-
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR
|
|
94584
|
+
const completed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}`).get(...params).count;
|
|
94585
|
+
const failed = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'failed'${projectFilter}`).get(...params).count;
|
|
94586
|
+
const inProgress = d.query(`SELECT COUNT(*) as count FROM tasks WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'in_progress'${projectFilter}`).get(...params).count;
|
|
94368
94587
|
const total = completed + failed;
|
|
94369
94588
|
const completionRate = total > 0 ? completed / total : 0;
|
|
94370
94589
|
const avgTime = d.query(`SELECT AVG(
|
|
94371
94590
|
(julianday(completed_at) - julianday(created_at)) * 24 * 60
|
|
94372
94591
|
) as avg_minutes
|
|
94373
94592
|
FROM tasks
|
|
94374
|
-
WHERE (agent_id = ? OR
|
|
94593
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND completed_at IS NOT NULL${projectFilter}`).get(...params);
|
|
94375
94594
|
const avgConf = d.query(`SELECT AVG(confidence) as avg_confidence
|
|
94376
94595
|
FROM tasks
|
|
94377
|
-
WHERE (agent_id = ? OR
|
|
94596
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed' AND confidence IS NOT NULL${projectFilter}`).get(...params);
|
|
94378
94597
|
const reviewTasks = d.query(`SELECT metadata FROM tasks
|
|
94379
|
-
WHERE (agent_id = ? OR
|
|
94598
|
+
WHERE (agent_id = ? OR ${assignedInClause}) AND status = 'completed'${projectFilter}
|
|
94380
94599
|
AND metadata LIKE '%_review_score%'`).all(...params);
|
|
94381
94600
|
let reviewScoreAvg = null;
|
|
94382
94601
|
if (reviewTasks.length > 0) {
|
|
@@ -94840,14 +95059,15 @@ function millisBetween(start, end) {
|
|
|
94840
95059
|
return 0;
|
|
94841
95060
|
return endMs - startMs;
|
|
94842
95061
|
}
|
|
94843
|
-
function addTaskScope(where, params, options, alias = "t") {
|
|
95062
|
+
function addTaskScope(where, params, options, db, alias = "t") {
|
|
94844
95063
|
if (options.project_id) {
|
|
94845
95064
|
where.push(`${alias}.project_id = ?`);
|
|
94846
95065
|
params.push(options.project_id);
|
|
94847
95066
|
}
|
|
94848
95067
|
if (options.agent_id) {
|
|
94849
|
-
|
|
94850
|
-
|
|
95068
|
+
params.push(options.agent_id);
|
|
95069
|
+
const assignedInClause = lowerInClause(`${alias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
95070
|
+
where.push(`(${alias}.agent_id = ? OR ${assignedInClause})`);
|
|
94851
95071
|
}
|
|
94852
95072
|
if (options.since) {
|
|
94853
95073
|
where.push(`${alias}.created_at >= ?`);
|
|
@@ -94858,14 +95078,15 @@ function addTaskScope(where, params, options, alias = "t") {
|
|
|
94858
95078
|
params.push(options.until);
|
|
94859
95079
|
}
|
|
94860
95080
|
}
|
|
94861
|
-
function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
95081
|
+
function addRunScope(where, params, options, db, runAlias = "r", taskAlias = "t") {
|
|
94862
95082
|
if (options.project_id) {
|
|
94863
95083
|
where.push(`${taskAlias}.project_id = ?`);
|
|
94864
95084
|
params.push(options.project_id);
|
|
94865
95085
|
}
|
|
94866
95086
|
if (options.agent_id) {
|
|
94867
|
-
|
|
94868
|
-
|
|
95087
|
+
params.push(options.agent_id, options.agent_id);
|
|
95088
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
95089
|
+
where.push(`(${runAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
94869
95090
|
}
|
|
94870
95091
|
if (options.since) {
|
|
94871
95092
|
where.push(`${runAlias}.started_at >= ?`);
|
|
@@ -94876,14 +95097,15 @@ function addRunScope(where, params, options, runAlias = "r", taskAlias = "t") {
|
|
|
94876
95097
|
params.push(options.until);
|
|
94877
95098
|
}
|
|
94878
95099
|
}
|
|
94879
|
-
function addTraceScope(where, params, options, traceAlias = "tr", taskAlias = "t") {
|
|
95100
|
+
function addTraceScope(where, params, options, db, traceAlias = "tr", taskAlias = "t") {
|
|
94880
95101
|
if (options.project_id) {
|
|
94881
95102
|
where.push(`${taskAlias}.project_id = ?`);
|
|
94882
95103
|
params.push(options.project_id);
|
|
94883
95104
|
}
|
|
94884
95105
|
if (options.agent_id) {
|
|
94885
|
-
|
|
94886
|
-
|
|
95106
|
+
params.push(options.agent_id, options.agent_id);
|
|
95107
|
+
const assignedInClause = lowerInClause(`${taskAlias}.assigned_to`, resolveAssignedToAliases(db, options.agent_id), params);
|
|
95108
|
+
where.push(`(${traceAlias}.agent_id = ? OR ${taskAlias}.agent_id = ? OR ${assignedInClause})`);
|
|
94887
95109
|
}
|
|
94888
95110
|
if (options.since) {
|
|
94889
95111
|
where.push(`${traceAlias}.created_at >= ?`);
|
|
@@ -94943,7 +95165,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94943
95165
|
const generatedAt = options.generated_at || new Date().toISOString();
|
|
94944
95166
|
const taskWhere = [];
|
|
94945
95167
|
const taskParams = [];
|
|
94946
|
-
addTaskScope(taskWhere, taskParams, options);
|
|
95168
|
+
addTaskScope(taskWhere, taskParams, options, d);
|
|
94947
95169
|
const taskClause = taskWhere.length ? `WHERE ${taskWhere.join(" AND ")}` : "";
|
|
94948
95170
|
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
95171
|
let projectCount = 0;
|
|
@@ -94952,14 +95174,14 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94952
95174
|
} else if (options.agent_id) {
|
|
94953
95175
|
const projectWhere = ["t.project_id IS NOT NULL"];
|
|
94954
95176
|
const projectParams = [];
|
|
94955
|
-
addTaskScope(projectWhere, projectParams, options);
|
|
95177
|
+
addTaskScope(projectWhere, projectParams, options, d);
|
|
94956
95178
|
projectCount = queryOne(d, `SELECT COUNT(DISTINCT t.project_id) as count FROM tasks t WHERE ${projectWhere.join(" AND ")}`, projectParams).count;
|
|
94957
95179
|
} else {
|
|
94958
95180
|
projectCount = queryOne(d, "SELECT COUNT(*) as count FROM projects", []).count;
|
|
94959
95181
|
}
|
|
94960
95182
|
const runWhere = [];
|
|
94961
95183
|
const runParams = [];
|
|
94962
|
-
addRunScope(runWhere, runParams, options);
|
|
95184
|
+
addRunScope(runWhere, runParams, options, d);
|
|
94963
95185
|
const runClause = runWhere.length ? `WHERE ${runWhere.join(" AND ")}` : "";
|
|
94964
95186
|
const runs = queryAll(d, `SELECT r.id, r.started_at, r.completed_at, r.metadata
|
|
94965
95187
|
FROM task_runs r JOIN tasks t ON t.id = r.task_id
|
|
@@ -94976,7 +95198,7 @@ function createLocalUsageLedger(options = {}, db) {
|
|
|
94976
95198
|
${runClause}`, runParams);
|
|
94977
95199
|
const traceWhere = [];
|
|
94978
95200
|
const traceParams = [];
|
|
94979
|
-
addTraceScope(traceWhere, traceParams, options);
|
|
95201
|
+
addTraceScope(traceWhere, traceParams, options, d);
|
|
94980
95202
|
const traceClause = traceWhere.length ? `WHERE ${traceWhere.join(" AND ")}` : "";
|
|
94981
95203
|
const traceTotals = queryOne(d, `SELECT COUNT(*) as traces,
|
|
94982
95204
|
COALESCE(SUM(tr.tokens), 0) as tokens,
|
|
@@ -95120,10 +95342,12 @@ function limitValue(value) {
|
|
|
95120
95342
|
function isTerminal2(task) {
|
|
95121
95343
|
return task.status === "completed" || task.status === "failed" || task.status === "cancelled";
|
|
95122
95344
|
}
|
|
95123
|
-
function sameAgent(task, agentId) {
|
|
95345
|
+
function sameAgent(task, agentId, aliasSet) {
|
|
95124
95346
|
if (!agentId)
|
|
95125
95347
|
return true;
|
|
95126
|
-
|
|
95348
|
+
if (task.agent_id === agentId)
|
|
95349
|
+
return true;
|
|
95350
|
+
return aliasSet ? aliasSet.has((task.assigned_to ?? "").toLowerCase()) : task.assigned_to === agentId;
|
|
95127
95351
|
}
|
|
95128
95352
|
function withinTaskWindow(task, options) {
|
|
95129
95353
|
const time3 = Date.parse(task.updated_at);
|
|
@@ -95136,11 +95360,12 @@ function withinTaskWindow(task, options) {
|
|
|
95136
95360
|
return true;
|
|
95137
95361
|
}
|
|
95138
95362
|
function scopedTasks(options, db) {
|
|
95363
|
+
const aliasSet = options.agent_id ? assignedToAliasSet(db, options.agent_id) : undefined;
|
|
95139
95364
|
return listTasks2({
|
|
95140
95365
|
project_id: options.project_id,
|
|
95141
95366
|
plan_id: options.plan_id,
|
|
95142
95367
|
include_archived: false
|
|
95143
|
-
}, db).filter((task) => sameAgent(task, options.agent_id) && withinTaskWindow(task, options));
|
|
95368
|
+
}, db).filter((task) => sameAgent(task, options.agent_id, aliasSet) && withinTaskWindow(task, options));
|
|
95144
95369
|
}
|
|
95145
95370
|
function summarizeTask(task) {
|
|
95146
95371
|
return {
|
|
@@ -95206,7 +95431,7 @@ function initialAgentSummary(agentId) {
|
|
|
95206
95431
|
}
|
|
95207
95432
|
};
|
|
95208
95433
|
}
|
|
95209
|
-
function addScopeClauses(where, params, options, timeColumn) {
|
|
95434
|
+
function addScopeClauses(where, params, options, timeColumn, db) {
|
|
95210
95435
|
if (options.project_id) {
|
|
95211
95436
|
where.push("t.project_id = ?");
|
|
95212
95437
|
params.push(options.project_id);
|
|
@@ -95216,8 +95441,9 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
95216
95441
|
params.push(options.plan_id);
|
|
95217
95442
|
}
|
|
95218
95443
|
if (options.agent_id) {
|
|
95219
|
-
|
|
95220
|
-
|
|
95444
|
+
params.push(options.agent_id, options.agent_id);
|
|
95445
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
95446
|
+
where.push(`(r.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
95221
95447
|
}
|
|
95222
95448
|
if (options.since) {
|
|
95223
95449
|
where.push(`${timeColumn} >= ?`);
|
|
@@ -95231,7 +95457,7 @@ function addScopeClauses(where, params, options, timeColumn) {
|
|
|
95231
95457
|
function loadRuns(options, db) {
|
|
95232
95458
|
const where = ["t.archived_at IS NULL"];
|
|
95233
95459
|
const params = [];
|
|
95234
|
-
addScopeClauses(where, params, options, "r.started_at");
|
|
95460
|
+
addScopeClauses(where, params, options, "r.started_at", db);
|
|
95235
95461
|
return db.query(`
|
|
95236
95462
|
SELECT
|
|
95237
95463
|
r.id,
|
|
@@ -95271,8 +95497,9 @@ function loadVerifications(options, db) {
|
|
|
95271
95497
|
params.push(options.plan_id);
|
|
95272
95498
|
}
|
|
95273
95499
|
if (options.agent_id) {
|
|
95274
|
-
|
|
95275
|
-
|
|
95500
|
+
params.push(options.agent_id, options.agent_id);
|
|
95501
|
+
const assignedInClause = lowerInClause("t.assigned_to", resolveAssignedToAliases(db, options.agent_id), params);
|
|
95502
|
+
where.push(`(v.agent_id = ? OR t.agent_id = ? OR ${assignedInClause})`);
|
|
95276
95503
|
}
|
|
95277
95504
|
if (options.since) {
|
|
95278
95505
|
where.push("v.run_at >= ?");
|
|
@@ -95494,7 +95721,6 @@ function renderLocalReportMarkdown(report) {
|
|
|
95494
95721
|
}
|
|
95495
95722
|
var LOCAL_REPORT_SCHEMA_VERSION = 1, LOCAL_REPORT_TYPES;
|
|
95496
95723
|
var init_local_reports = __esm(() => {
|
|
95497
|
-
init_database();
|
|
95498
95724
|
init_database();
|
|
95499
95725
|
init_plans();
|
|
95500
95726
|
init_tasks();
|
|
@@ -99597,7 +99823,7 @@ ${lines.join(`
|
|
|
99597
99823
|
a.name AS agent_name
|
|
99598
99824
|
FROM task_files tf
|
|
99599
99825
|
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))
|
|
99826
|
+
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
99827
|
WHERE t.status = 'in_progress'
|
|
99602
99828
|
AND tf.status != 'removed'
|
|
99603
99829
|
AND t.project_id = ?
|
|
@@ -103359,9 +103585,16 @@ ${text2}` }] };
|
|
|
103359
103585
|
return { content: [{ type: "text", text: `Agent not found: ${id || name}` }], isError: true };
|
|
103360
103586
|
}
|
|
103361
103587
|
const oldName = agent.name;
|
|
103362
|
-
const updated = updateAgent2(agent.id, { name: new_name });
|
|
103363
103588
|
const db = getDatabase();
|
|
103364
|
-
|
|
103589
|
+
let oldNameUniquelyIdentifiesAgent = false;
|
|
103590
|
+
try {
|
|
103591
|
+
oldNameUniquelyIdentifiesAgent = resolvePartialId(db, "agents", oldName) === agent.id;
|
|
103592
|
+
} catch (error3) {
|
|
103593
|
+
if (!(error3 instanceof IdentityAliasAmbiguousError))
|
|
103594
|
+
throw error3;
|
|
103595
|
+
}
|
|
103596
|
+
const updated = updateAgent2(agent.id, { name: new_name });
|
|
103597
|
+
const tasksResult = db.run(oldNameUniquelyIdentifiesAgent ? "UPDATE tasks SET assigned_to = ? WHERE LOWER(assigned_to) = LOWER(?)" : "UPDATE tasks SET assigned_to = ? WHERE assigned_to = ?", [new_name, oldName]);
|
|
103365
103598
|
const taskNote = tasksResult.changes > 0 ? `
|
|
103366
103599
|
Updated assigned_to on ${tasksResult.changes} task(s).` : "";
|
|
103367
103600
|
return {
|
|
@@ -103545,6 +103778,7 @@ var init_agents2 = __esm(() => {
|
|
|
103545
103778
|
init_agents();
|
|
103546
103779
|
init_config2();
|
|
103547
103780
|
init_database();
|
|
103781
|
+
init_types();
|
|
103548
103782
|
init_cloud_router();
|
|
103549
103783
|
});
|
|
103550
103784
|
|