@hasna/todos 0.11.81 → 0.11.83
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 +84 -1
- package/dist/cli/cloud-router.d.ts.map +1 -1
- package/dist/cli/commands/agent-commands.d.ts.map +1 -1
- package/dist/cli/commands/mcp-hooks-commands.d.ts.map +1 -1
- package/dist/cli/commands/plan-template-commands.d.ts.map +1 -1
- package/dist/cli/commands/project-commands.d.ts.map +1 -1
- package/dist/cli/commands/query-commands.d.ts.map +1 -1
- package/dist/cli/commands/task-commands.d.ts.map +1 -1
- package/dist/cli/index.js +569 -45
- package/dist/index.js +115 -4
- package/dist/mcp/index.js +363 -6
- 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-project-tools.d.ts.map +1 -1
- package/dist/mcp/tools/task-workflow-tools.d.ts.map +1 -1
- package/dist/release-provenance.json +3 -3
- package/dist/server/index.js +381 -24
- package/dist/server/v1.d.ts.map +1 -1
- package/dist/storage/interfaces.d.ts +53 -1
- package/dist/storage/interfaces.d.ts.map +1 -1
- package/dist/storage/local-sqlite.d.ts.map +1 -1
- package/dist/storage/postgres-adapter.d.ts.map +1 -1
- package/dist/storage.js +112 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -8548,6 +8548,29 @@ async function cloudGetStats(client) {
|
|
|
8548
8548
|
const raw = await client.transport.get("/stats");
|
|
8549
8549
|
return raw ?? {};
|
|
8550
8550
|
}
|
|
8551
|
+
async function cloudListAgents(client) {
|
|
8552
|
+
const res = await client.list("agents");
|
|
8553
|
+
const envelope = res.raw;
|
|
8554
|
+
return Array.isArray(envelope?.agents) ? envelope.agents : res.items;
|
|
8555
|
+
}
|
|
8556
|
+
async function cloudListProjects(client) {
|
|
8557
|
+
const res = await client.list("projects");
|
|
8558
|
+
const envelope = res.raw;
|
|
8559
|
+
return Array.isArray(envelope?.projects) ? envelope.projects : res.items;
|
|
8560
|
+
}
|
|
8561
|
+
async function cloudListPlans(client, projectId) {
|
|
8562
|
+
const query = projectId ? { project_id: projectId } : {};
|
|
8563
|
+
const res = await client.list("plans", { query });
|
|
8564
|
+
const envelope = res.raw;
|
|
8565
|
+
return Array.isArray(envelope?.plans) ? envelope.plans : res.items;
|
|
8566
|
+
}
|
|
8567
|
+
async function cloudAddComment(client, taskId, input) {
|
|
8568
|
+
const raw = await client.transport.post(`/tasks/${encodeURIComponent(taskId)}/comments`, input);
|
|
8569
|
+
if (raw && typeof raw === "object" && "comment" in raw) {
|
|
8570
|
+
return raw.comment;
|
|
8571
|
+
}
|
|
8572
|
+
return raw;
|
|
8573
|
+
}
|
|
8551
8574
|
async function cloudCountTasks(client, filter = {}) {
|
|
8552
8575
|
const { limit: _drop, offset: _o, ...rest } = filter;
|
|
8553
8576
|
const res = await client.list("tasks", { query: { ...toListQuery(rest), limit: 1 } });
|
|
@@ -8557,6 +8580,53 @@ async function cloudCountTasks(client, filter = {}) {
|
|
|
8557
8580
|
const tasks = await cloudListTasks(client, rest);
|
|
8558
8581
|
return tasks.length;
|
|
8559
8582
|
}
|
|
8583
|
+
async function cloudRegisterAgent(client, input) {
|
|
8584
|
+
const raw = await client.transport.post("/agents", input);
|
|
8585
|
+
if (raw && typeof raw === "object" && "agent" in raw) {
|
|
8586
|
+
return raw.agent;
|
|
8587
|
+
}
|
|
8588
|
+
return raw;
|
|
8589
|
+
}
|
|
8590
|
+
async function cloudLockTask(client, id, agentId) {
|
|
8591
|
+
const raw = await client.transport.post(`/tasks/${encodeURIComponent(id)}/lock`, { agent_id: agentId });
|
|
8592
|
+
if (raw && typeof raw === "object" && "result" in raw) {
|
|
8593
|
+
return raw.result;
|
|
8594
|
+
}
|
|
8595
|
+
return raw ?? { success: true };
|
|
8596
|
+
}
|
|
8597
|
+
async function cloudUnlockTask(client, id, agentId) {
|
|
8598
|
+
const raw = await client.transport.post(`/tasks/${encodeURIComponent(id)}/unlock`, agentId ? { agent_id: agentId } : {});
|
|
8599
|
+
if (raw && typeof raw === "object" && "success" in raw) {
|
|
8600
|
+
return Boolean(raw.success);
|
|
8601
|
+
}
|
|
8602
|
+
return true;
|
|
8603
|
+
}
|
|
8604
|
+
async function cloudGetDependencies(client, id) {
|
|
8605
|
+
const raw = await client.transport.get(`/tasks/${encodeURIComponent(id)}/dependencies`);
|
|
8606
|
+
const env = raw ?? {};
|
|
8607
|
+
return { dependencies: env.dependencies ?? [], blocked_by: env.blocked_by ?? [] };
|
|
8608
|
+
}
|
|
8609
|
+
async function cloudAddDependency(client, id, dependsOn) {
|
|
8610
|
+
const raw = await client.transport.post(`/tasks/${encodeURIComponent(id)}/dependencies`, { depends_on: dependsOn });
|
|
8611
|
+
if (raw && typeof raw === "object" && "dependency" in raw) {
|
|
8612
|
+
return raw.dependency;
|
|
8613
|
+
}
|
|
8614
|
+
return raw;
|
|
8615
|
+
}
|
|
8616
|
+
async function cloudRemoveDependency(client, id, dependsOn) {
|
|
8617
|
+
const raw = await client.transport.del(`/tasks/${encodeURIComponent(id)}/dependencies/${encodeURIComponent(dependsOn)}`);
|
|
8618
|
+
if (raw && typeof raw === "object" && "removed" in raw) {
|
|
8619
|
+
return Boolean(raw.removed);
|
|
8620
|
+
}
|
|
8621
|
+
return true;
|
|
8622
|
+
}
|
|
8623
|
+
async function cloudRecordVerification(client, id, input) {
|
|
8624
|
+
const raw = await client.transport.post(`/tasks/${encodeURIComponent(id)}/verifications`, input);
|
|
8625
|
+
if (raw && typeof raw === "object" && "verification" in raw) {
|
|
8626
|
+
return raw.verification;
|
|
8627
|
+
}
|
|
8628
|
+
return raw;
|
|
8629
|
+
}
|
|
8560
8630
|
var _cache;
|
|
8561
8631
|
var init_cloud_router = __esm(() => {
|
|
8562
8632
|
init_storage();
|
|
@@ -20505,11 +20575,23 @@ function registerTaskCommands(program2) {
|
|
|
20505
20575
|
if (active.length > 0)
|
|
20506
20576
|
resolvedId = active[0].id;
|
|
20507
20577
|
}
|
|
20578
|
+
const cloud = getTodosCloudClient();
|
|
20579
|
+
if (!resolvedId && cloud && globalOpts.agent) {
|
|
20580
|
+
const active = await cloudListTasks(cloud, { status: "in_progress", assigned_to: globalOpts.agent, limit: 1 });
|
|
20581
|
+
if (active.length > 0)
|
|
20582
|
+
resolvedId = active[0].id;
|
|
20583
|
+
}
|
|
20508
20584
|
if (!resolvedId) {
|
|
20509
20585
|
console.error(chalk2.red("No task ID given and no active task found. Pass an ID or use --agent."));
|
|
20510
20586
|
process.exit(1);
|
|
20511
20587
|
}
|
|
20512
|
-
|
|
20588
|
+
let task2;
|
|
20589
|
+
if (cloud) {
|
|
20590
|
+
const remote = await cloudGetTask(cloud, resolvedId);
|
|
20591
|
+
task2 = remote ? { subtasks: [], dependencies: [], blocked_by: [], comments: [], checklist: [], ...remote, tags: remote.tags ?? [] } : null;
|
|
20592
|
+
} else {
|
|
20593
|
+
task2 = getTaskWithRelations(resolvedId);
|
|
20594
|
+
}
|
|
20513
20595
|
if (!task2) {
|
|
20514
20596
|
console.error(chalk2.red(`Task not found: ${id || resolvedId}`));
|
|
20515
20597
|
process.exit(1);
|
|
@@ -20851,13 +20933,14 @@ ${chalk2.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
20851
20933
|
console.log(formatTaskLine(task2));
|
|
20852
20934
|
}
|
|
20853
20935
|
});
|
|
20854
|
-
program2.command("lock <id>").description("Acquire exclusive lock on a task").action((id) => {
|
|
20936
|
+
program2.command("lock <id>").description("Acquire exclusive lock on a task").action(async (id) => {
|
|
20855
20937
|
const globalOpts = program2.opts();
|
|
20856
20938
|
const agentId = globalOpts.agent || "cli";
|
|
20939
|
+
const cloud = getTodosCloudClient();
|
|
20857
20940
|
const resolvedId = resolveTaskId(id);
|
|
20858
20941
|
let result;
|
|
20859
20942
|
try {
|
|
20860
|
-
result = lockTask(resolvedId, agentId);
|
|
20943
|
+
result = cloud ? await cloudLockTask(cloud, resolvedId, agentId) : lockTask(resolvedId, agentId);
|
|
20861
20944
|
} catch (e) {
|
|
20862
20945
|
handleError(e);
|
|
20863
20946
|
}
|
|
@@ -20870,11 +20953,15 @@ ${chalk2.cyan(sid)} ${statusColor(task2.status)} ${prioColor(task2.priority)} ${
|
|
|
20870
20953
|
process.exit(1);
|
|
20871
20954
|
}
|
|
20872
20955
|
});
|
|
20873
|
-
program2.command("unlock <id>").description("Release lock on a task").action((id) => {
|
|
20956
|
+
program2.command("unlock <id>").description("Release lock on a task").action(async (id) => {
|
|
20874
20957
|
const globalOpts = program2.opts();
|
|
20958
|
+
const cloud = getTodosCloudClient();
|
|
20875
20959
|
const resolvedId = resolveTaskId(id);
|
|
20876
20960
|
try {
|
|
20877
|
-
|
|
20961
|
+
if (cloud)
|
|
20962
|
+
await cloudUnlockTask(cloud, resolvedId, globalOpts.agent);
|
|
20963
|
+
else
|
|
20964
|
+
unlockTask(resolvedId, globalOpts.agent);
|
|
20878
20965
|
} catch (e) {
|
|
20879
20966
|
handleError(e);
|
|
20880
20967
|
}
|
|
@@ -21643,9 +21730,10 @@ function resolvePlanCliRef(ref, projectId) {
|
|
|
21643
21730
|
process.exit(1);
|
|
21644
21731
|
}
|
|
21645
21732
|
function registerPlanTemplateCommands(program2) {
|
|
21646
|
-
program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("--slug <slug>", "Readable plan slug (with --add)").option("-d, --description <text>", "Plan description (with --add)").option("--show <id-or-slug>", "Show plan details with its tasks").option("--artifact <id-or-slug>", "Show local Markdown artifact diagnostics for a plan").option("--write-artifacts", "Write local Markdown artifacts for all project-scoped plans in scope").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action((opts) => {
|
|
21733
|
+
program2.command("plans").description("List and manage plans").option("--add <name>", "Create a plan").option("--slug <slug>", "Readable plan slug (with --add)").option("-d, --description <text>", "Plan description (with --add)").option("--show <id-or-slug>", "Show plan details with its tasks").option("--artifact <id-or-slug>", "Show local Markdown artifact diagnostics for a plan").option("--write-artifacts", "Write local Markdown artifacts for all project-scoped plans in scope").option("--delete <id>", "Delete a plan").option("--complete <id>", "Mark a plan as completed").action(async (opts) => {
|
|
21647
21734
|
const globalOpts = program2.opts();
|
|
21648
|
-
const
|
|
21735
|
+
const cloud = getTodosCloudClient();
|
|
21736
|
+
const projectId = cloud ? undefined : autoProject(globalOpts);
|
|
21649
21737
|
if (opts.add) {
|
|
21650
21738
|
let plan;
|
|
21651
21739
|
try {
|
|
@@ -21804,7 +21892,7 @@ function registerPlanTemplateCommands(program2) {
|
|
|
21804
21892
|
}
|
|
21805
21893
|
return;
|
|
21806
21894
|
}
|
|
21807
|
-
const plans = listPlans(projectId);
|
|
21895
|
+
const plans = cloud ? await cloudListPlans(cloud, projectId) : listPlans(projectId);
|
|
21808
21896
|
if (globalOpts.json) {
|
|
21809
21897
|
output(plans, true);
|
|
21810
21898
|
return;
|
|
@@ -22129,6 +22217,7 @@ var init_plan_template_commands = __esm(() => {
|
|
|
22129
22217
|
init_tasks();
|
|
22130
22218
|
init_plan_artifacts();
|
|
22131
22219
|
init_helpers();
|
|
22220
|
+
init_cloud_router();
|
|
22132
22221
|
});
|
|
22133
22222
|
|
|
22134
22223
|
// src/lib/local-fields.ts
|
|
@@ -31376,10 +31465,11 @@ function registerProjectCommands(program2) {
|
|
|
31376
31465
|
handleError(e);
|
|
31377
31466
|
}
|
|
31378
31467
|
});
|
|
31379
|
-
program2.command("comment <id> <text>").alias("log-progress").description("Add a comment to a task (alias: log-progress, for recording intermediate progress)").option("--pct <percent>", "Progress percentage (0-100) to record alongside the note").action((id, text, opts) => {
|
|
31468
|
+
program2.command("comment <id> <text>").alias("log-progress").description("Add a comment to a task (alias: log-progress, for recording intermediate progress)").option("--pct <percent>", "Progress percentage (0-100) to record alongside the note").action(async (id, text, opts) => {
|
|
31380
31469
|
const globalOpts = program2.opts();
|
|
31381
31470
|
const resolvedId = resolveTaskId(id);
|
|
31382
31471
|
let content = text;
|
|
31472
|
+
let progressPct;
|
|
31383
31473
|
if (opts.pct !== undefined) {
|
|
31384
31474
|
const pct = parseInt(opts.pct, 10);
|
|
31385
31475
|
if (!Number.isFinite(pct) || pct < 0 || pct > 100) {
|
|
@@ -31387,17 +31477,28 @@ function registerProjectCommands(program2) {
|
|
|
31387
31477
|
process.exit(1);
|
|
31388
31478
|
}
|
|
31389
31479
|
content = `[progress ${pct}%] ${text}`;
|
|
31480
|
+
progressPct = pct;
|
|
31390
31481
|
}
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
|
|
31395
|
-
|
|
31396
|
-
|
|
31397
|
-
|
|
31398
|
-
|
|
31399
|
-
|
|
31400
|
-
|
|
31482
|
+
try {
|
|
31483
|
+
const cloud = getTodosCloudClient();
|
|
31484
|
+
const comment = cloud ? await cloudAddComment(cloud, resolvedId, {
|
|
31485
|
+
content,
|
|
31486
|
+
agent_id: globalOpts.agent,
|
|
31487
|
+
session_id: globalOpts.session,
|
|
31488
|
+
...progressPct !== undefined ? { type: "progress", progress_pct: progressPct } : {}
|
|
31489
|
+
}) : addComment({
|
|
31490
|
+
task_id: resolvedId,
|
|
31491
|
+
content,
|
|
31492
|
+
agent_id: globalOpts.agent,
|
|
31493
|
+
session_id: globalOpts.session
|
|
31494
|
+
});
|
|
31495
|
+
if (globalOpts.json) {
|
|
31496
|
+
output(comment, true);
|
|
31497
|
+
} else {
|
|
31498
|
+
console.log(chalk4.green("Comment added."));
|
|
31499
|
+
}
|
|
31500
|
+
} catch (e) {
|
|
31501
|
+
handleError(e);
|
|
31401
31502
|
}
|
|
31402
31503
|
});
|
|
31403
31504
|
program2.command("search <query>").description("Search local tasks, or run/save a cross-entity search view").option("--status <status>", "Filter by status").option("--priority <p>", "Filter by priority").option("--assigned <agent>", "Filter by assigned agent").option("--agent-id <agent>", "Filter by creator/run/comment agent").option("--task-list <id>", "Filter by task list").option("--plan <id>", "Filter by plan").option("--task <id>", "Filter runs/comments by task").option("--tag <tag>", "Filter by task tag (repeatable or comma-separated)", collectOption, []).option("--field-label <label>", "Filter by local field label (repeatable or comma-separated)", collectOption, []).option("--field-owner <owner>", "Filter by local field owner").option("--field-area <area>", "Filter by local field area").option("--field-severity <severity>", "Filter by local field severity").option("--field-custom <json>", "Filter by local custom fields as JSON").option("--since <date>", "Only tasks updated after this date (ISO)").option("--created-after <date>", "Only records created after this date (ISO)").option("--blocked", "Only blocked tasks (incomplete dependencies)").option("--has-deps", "Only tasks with dependencies").option("--depends-on <id>", "Only tasks that depend on a task").option("--blocks <id>", "Only tasks that block a task").option("--scope <scope>", "Search scope: tasks, projects, plans, runs, comments, all", "tasks").option("--limit <n>", "Maximum results", "100").option("--filter <json>", "Merge an advanced saved-search filter JSON object").option("--save-as <name>", "Save this search as a named view").option("--description <text>", "Saved view description").option("--all-projects", "Do not auto-scope the search to the current project").action((query, opts) => {
|
|
@@ -31524,6 +31625,49 @@ function registerProjectCommands(program2) {
|
|
|
31524
31625
|
});
|
|
31525
31626
|
program2.command("deps <id>").description("Manage task dependencies").option("--needs <dep-id>", "Add dependency (this task needs dep-id)").option("--remove <dep-id>", "Remove dependency").option("--graph", "Show the dependency graph instead of direct edges").option("--direction <direction>", "Graph direction: up, down, or both", "both").action(async (id, opts) => {
|
|
31526
31627
|
const globalOpts = program2.opts();
|
|
31628
|
+
const cloud = getTodosCloudClient();
|
|
31629
|
+
if (cloud) {
|
|
31630
|
+
const cloudId = resolveTaskId(id);
|
|
31631
|
+
if (opts.needs) {
|
|
31632
|
+
try {
|
|
31633
|
+
const dep = await cloudAddDependency(cloud, cloudId, resolveTaskId(opts.needs));
|
|
31634
|
+
if (globalOpts.json)
|
|
31635
|
+
output(dep, true);
|
|
31636
|
+
else
|
|
31637
|
+
console.log(chalk4.green("Dependency added."));
|
|
31638
|
+
} catch (e) {
|
|
31639
|
+
handleError(e);
|
|
31640
|
+
}
|
|
31641
|
+
return;
|
|
31642
|
+
}
|
|
31643
|
+
if (opts.remove) {
|
|
31644
|
+
const removed = await cloudRemoveDependency(cloud, cloudId, resolveTaskId(opts.remove));
|
|
31645
|
+
if (globalOpts.json)
|
|
31646
|
+
output({ removed }, true);
|
|
31647
|
+
else
|
|
31648
|
+
console.log(removed ? chalk4.green("Dependency removed.") : chalk4.red("Dependency not found."));
|
|
31649
|
+
return;
|
|
31650
|
+
}
|
|
31651
|
+
const edges = await cloudGetDependencies(cloud, cloudId);
|
|
31652
|
+
if (globalOpts.json) {
|
|
31653
|
+
output(edges, true);
|
|
31654
|
+
return;
|
|
31655
|
+
}
|
|
31656
|
+
if (edges.dependencies.length > 0) {
|
|
31657
|
+
console.log(chalk4.bold("Depends on:"));
|
|
31658
|
+
for (const dep of edges.dependencies)
|
|
31659
|
+
console.log(` ${chalk4.cyan(dep.depends_on)}`);
|
|
31660
|
+
}
|
|
31661
|
+
if (edges.blocked_by.length > 0) {
|
|
31662
|
+
console.log(chalk4.bold("Blocks:"));
|
|
31663
|
+
for (const b of edges.blocked_by)
|
|
31664
|
+
console.log(` ${chalk4.cyan(b.task_id)}`);
|
|
31665
|
+
}
|
|
31666
|
+
if (edges.dependencies.length === 0 && edges.blocked_by.length === 0) {
|
|
31667
|
+
console.log(chalk4.dim("No dependencies."));
|
|
31668
|
+
}
|
|
31669
|
+
return;
|
|
31670
|
+
}
|
|
31527
31671
|
const { addDependency: addDependency2, removeDependency: removeDependency2, getTaskGraph: getTaskGraph2, getTaskWithRelations: getTaskWithRelations2 } = await Promise.resolve().then(() => (init_tasks(), exports_tasks));
|
|
31528
31672
|
const resolvedId = resolveTaskId(id);
|
|
31529
31673
|
if (opts.needs) {
|
|
@@ -31651,7 +31795,8 @@ function registerProjectCommands(program2) {
|
|
|
31651
31795
|
}
|
|
31652
31796
|
return;
|
|
31653
31797
|
}
|
|
31654
|
-
const
|
|
31798
|
+
const cloud = getTodosCloudClient();
|
|
31799
|
+
const projects = cloud ? await cloudListProjects(cloud) : listProjects();
|
|
31655
31800
|
if (globalOpts.json) {
|
|
31656
31801
|
output(projects, true);
|
|
31657
31802
|
return;
|
|
@@ -32057,6 +32202,7 @@ var init_project_commands = __esm(() => {
|
|
|
32057
32202
|
init_database();
|
|
32058
32203
|
init_projects();
|
|
32059
32204
|
init_comments();
|
|
32205
|
+
init_cloud_router();
|
|
32060
32206
|
init_saved_search_views();
|
|
32061
32207
|
init_sync();
|
|
32062
32208
|
init_config2();
|
|
@@ -32738,8 +32884,9 @@ function registerAgentCommands(program2) {
|
|
|
32738
32884
|
program2.command("init <name>").description("Register an agents and get a short UUID").option("-d, --description <text>", "Agent description").action(async (name, opts) => {
|
|
32739
32885
|
const globalOpts = program2.opts();
|
|
32740
32886
|
try {
|
|
32741
|
-
const
|
|
32742
|
-
const result =
|
|
32887
|
+
const cloud = getTodosCloudClient();
|
|
32888
|
+
const result = cloud ? await cloudRegisterAgent(cloud, { name, description: opts.description }) : (await Promise.resolve().then(() => (init_agents(), exports_agents))).registerAgent({ name, description: opts.description });
|
|
32889
|
+
const { isAgentConflict: isAgentConflict2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
|
|
32743
32890
|
if (isAgentConflict2(result)) {
|
|
32744
32891
|
console.error(chalk5.red("CONFLICT:"), result.message);
|
|
32745
32892
|
process.exit(1);
|
|
@@ -32826,7 +32973,8 @@ Use ${chalk5.cyan(`--agent ${result.id}`)} on future commands.`);
|
|
|
32826
32973
|
program2.command("agents").description("List registered agents").action(async () => {
|
|
32827
32974
|
const globalOpts = program2.opts();
|
|
32828
32975
|
try {
|
|
32829
|
-
const
|
|
32976
|
+
const cloud = getTodosCloudClient();
|
|
32977
|
+
const agents = cloud ? await cloudListAgents(cloud) : listAgents();
|
|
32830
32978
|
if (globalOpts.json) {
|
|
32831
32979
|
output(agents, true);
|
|
32832
32980
|
return;
|
|
@@ -33095,6 +33243,7 @@ var init_agent_commands = __esm(() => {
|
|
|
33095
33243
|
init_task_lists();
|
|
33096
33244
|
init_tasks();
|
|
33097
33245
|
init_helpers();
|
|
33246
|
+
init_cloud_router();
|
|
33098
33247
|
});
|
|
33099
33248
|
|
|
33100
33249
|
// src/lib/retention-cleanup.ts
|
|
@@ -37343,6 +37492,7 @@ function createLocalSqliteTodosStorageAdapter(options = {}) {
|
|
|
37343
37492
|
audit: {
|
|
37344
37493
|
logTaskChange: (taskId, action, field, oldValue, newValue, agentId) => logTaskChange(taskId, action, field, oldValue, newValue, agentId, database()),
|
|
37345
37494
|
addComment: (input) => addComment(input, database()),
|
|
37495
|
+
getComments: (taskId) => listComments(taskId, database()),
|
|
37346
37496
|
getTaskHistory: (taskId) => getTaskHistory(taskId, database()),
|
|
37347
37497
|
getRecentActivity: (limit) => getRecentActivity(limit, database())
|
|
37348
37498
|
},
|
|
@@ -38310,7 +38460,18 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
38310
38460
|
claimNext: (agentId, filters) => claimNextTask2(agentId, filters, store),
|
|
38311
38461
|
getNext: (_agentId, filters) => getNextTask2(filters, store),
|
|
38312
38462
|
getActiveWork: (filters) => getActiveWork2(filters, store),
|
|
38313
|
-
getChangedSince: (since, filters) => getChangedSince(since, filters, store)
|
|
38463
|
+
getChangedSince: (since, filters) => getChangedSince(since, filters, store),
|
|
38464
|
+
lock: (id, agentId) => lockTask2(id, agentId, store),
|
|
38465
|
+
unlock: (id, agentId) => unlockTask2(id, agentId, store)
|
|
38466
|
+
},
|
|
38467
|
+
dependencies: {
|
|
38468
|
+
add: (taskId, dependsOn, context) => addDependency2(taskId, dependsOn, store, context),
|
|
38469
|
+
remove: (taskId, dependsOn) => removeDependency2(taskId, dependsOn, store),
|
|
38470
|
+
list: (taskId) => listDependencies(taskId, store)
|
|
38471
|
+
},
|
|
38472
|
+
verifications: {
|
|
38473
|
+
add: (input, context) => addVerification(input, store, context),
|
|
38474
|
+
list: (taskId) => listVerifications(taskId, store)
|
|
38314
38475
|
},
|
|
38315
38476
|
projects: {
|
|
38316
38477
|
create: (input, context) => createProject2(input, store, context),
|
|
@@ -38356,6 +38517,7 @@ function createPostgresTodosStorageAdapter(options) {
|
|
|
38356
38517
|
audit: {
|
|
38357
38518
|
logTaskChange: (taskId, action, field, oldValue, newValue, agentId, context) => logTaskChange2(taskId, action, field, oldValue, newValue, agentId, store, context),
|
|
38358
38519
|
addComment: (input, context) => addComment2(input, store, context),
|
|
38520
|
+
getComments: async (taskId) => (await store.list("comments")).filter((comment) => comment.task_id === taskId).sort((a, b) => a.created_at.localeCompare(b.created_at)),
|
|
38359
38521
|
getTaskHistory: async (taskId) => (await store.list("audit_history")).filter((entry2) => entry2.task_id === taskId).sort((a, b) => a.created_at.localeCompare(b.created_at)),
|
|
38360
38522
|
getRecentActivity: async (limit = 20) => (await store.list("audit_history")).sort((a, b) => b.created_at.localeCompare(a.created_at)).slice(0, limit)
|
|
38361
38523
|
},
|
|
@@ -38764,6 +38926,103 @@ async function patchTask(task, patch, store) {
|
|
|
38764
38926
|
await store.upsert("tasks", updated);
|
|
38765
38927
|
return updated;
|
|
38766
38928
|
}
|
|
38929
|
+
function cloudLockExpired(lockedAt) {
|
|
38930
|
+
if (!lockedAt)
|
|
38931
|
+
return true;
|
|
38932
|
+
return new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000 < Date.now();
|
|
38933
|
+
}
|
|
38934
|
+
function cloudLockExpiresAt(lockedAt) {
|
|
38935
|
+
return new Date(new Date(lockedAt).getTime() + CLOUD_LOCK_EXPIRY_MINUTES * 60 * 1000).toISOString();
|
|
38936
|
+
}
|
|
38937
|
+
async function lockTask2(id, agentId, store) {
|
|
38938
|
+
const task = await requireRecord("tasks", id, store);
|
|
38939
|
+
if (task.status === "completed" || task.status === "cancelled") {
|
|
38940
|
+
return { success: false, error: `Task is ${task.status} and cannot be locked` };
|
|
38941
|
+
}
|
|
38942
|
+
if (task.locked_by && task.locked_by !== agentId && !cloudLockExpired(task.locked_at)) {
|
|
38943
|
+
return { success: false, locked_by: task.locked_by, locked_at: task.locked_at ?? undefined, error: `Task is locked by ${task.locked_by}` };
|
|
38944
|
+
}
|
|
38945
|
+
const timestamp = new Date().toISOString();
|
|
38946
|
+
await patchTask(task, { locked_by: agentId, locked_at: timestamp }, store);
|
|
38947
|
+
return { success: true, locked_by: agentId, locked_at: timestamp, expires_at: cloudLockExpiresAt(timestamp) };
|
|
38948
|
+
}
|
|
38949
|
+
async function unlockTask2(id, agentId, store) {
|
|
38950
|
+
const task = await requireRecord("tasks", id, store);
|
|
38951
|
+
if (agentId && task.locked_by && task.locked_by !== agentId) {
|
|
38952
|
+
throw new Error(`Task ${id} is locked by ${task.locked_by}, not ${agentId}`);
|
|
38953
|
+
}
|
|
38954
|
+
await patchTask(task, { locked_by: null, locked_at: null }, store);
|
|
38955
|
+
return true;
|
|
38956
|
+
}
|
|
38957
|
+
function dependencyId(taskId, dependsOn) {
|
|
38958
|
+
return `${taskId}::${dependsOn}`;
|
|
38959
|
+
}
|
|
38960
|
+
async function addDependency2(taskId, dependsOn, store, context) {
|
|
38961
|
+
if (taskId === dependsOn)
|
|
38962
|
+
throw new Error("A task cannot depend on itself");
|
|
38963
|
+
if (!await store.get("tasks", taskId))
|
|
38964
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
38965
|
+
if (!await store.get("tasks", dependsOn))
|
|
38966
|
+
throw new Error(`Task not found: ${dependsOn}`);
|
|
38967
|
+
const edges = await store.list("dependencies");
|
|
38968
|
+
const adjacency = new Map;
|
|
38969
|
+
for (const edge of edges) {
|
|
38970
|
+
if (!adjacency.has(edge.task_id))
|
|
38971
|
+
adjacency.set(edge.task_id, []);
|
|
38972
|
+
adjacency.get(edge.task_id).push(edge.depends_on);
|
|
38973
|
+
}
|
|
38974
|
+
const queue = [dependsOn];
|
|
38975
|
+
const seen = new Set;
|
|
38976
|
+
while (queue.length) {
|
|
38977
|
+
const node = queue.shift();
|
|
38978
|
+
if (node === taskId)
|
|
38979
|
+
throw new Error(`Adding dependency ${taskId} -> ${dependsOn} would create a cycle`);
|
|
38980
|
+
if (seen.has(node))
|
|
38981
|
+
continue;
|
|
38982
|
+
seen.add(node);
|
|
38983
|
+
for (const next of adjacency.get(node) ?? [])
|
|
38984
|
+
queue.push(next);
|
|
38985
|
+
}
|
|
38986
|
+
const timestamp = new Date().toISOString();
|
|
38987
|
+
const record = { id: dependencyId(taskId, dependsOn), task_id: taskId, depends_on: dependsOn, created_at: timestamp, updated_at: timestamp };
|
|
38988
|
+
await store.upsert("dependencies", record, context);
|
|
38989
|
+
return { task_id: taskId, depends_on: dependsOn };
|
|
38990
|
+
}
|
|
38991
|
+
async function removeDependency2(taskId, dependsOn, store) {
|
|
38992
|
+
const existing = await store.get("dependencies", dependencyId(taskId, dependsOn));
|
|
38993
|
+
if (!existing)
|
|
38994
|
+
return false;
|
|
38995
|
+
await store.delete("dependencies", dependencyId(taskId, dependsOn));
|
|
38996
|
+
return true;
|
|
38997
|
+
}
|
|
38998
|
+
async function listDependencies(taskId, store) {
|
|
38999
|
+
const edges = await store.list("dependencies");
|
|
39000
|
+
return {
|
|
39001
|
+
dependencies: edges.filter((edge) => edge.task_id === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on })),
|
|
39002
|
+
blocked_by: edges.filter((edge) => edge.depends_on === taskId).map((edge) => ({ task_id: edge.task_id, depends_on: edge.depends_on }))
|
|
39003
|
+
};
|
|
39004
|
+
}
|
|
39005
|
+
async function addVerification(input, store, context) {
|
|
39006
|
+
if (!await store.get("tasks", input.task_id))
|
|
39007
|
+
throw new Error(`Task not found: ${input.task_id}`);
|
|
39008
|
+
const timestamp = new Date().toISOString();
|
|
39009
|
+
const verification = {
|
|
39010
|
+
id: randomUUID3(),
|
|
39011
|
+
task_id: input.task_id,
|
|
39012
|
+
command: input.command,
|
|
39013
|
+
status: input.status ?? "unknown",
|
|
39014
|
+
output_summary: input.output_summary ?? null,
|
|
39015
|
+
artifact_path: input.artifact_path ?? null,
|
|
39016
|
+
agent_id: input.agent_id ?? context?.agentId ?? null,
|
|
39017
|
+
run_at: timestamp,
|
|
39018
|
+
created_at: timestamp
|
|
39019
|
+
};
|
|
39020
|
+
await store.upsert("verifications", { ...verification, updated_at: timestamp }, context);
|
|
39021
|
+
return verification;
|
|
39022
|
+
}
|
|
39023
|
+
async function listVerifications(taskId, store) {
|
|
39024
|
+
return (await store.list("verifications")).filter((verification) => verification.task_id === taskId).sort((a, b) => b.run_at.localeCompare(a.run_at));
|
|
39025
|
+
}
|
|
38767
39026
|
function toFilterArray(value) {
|
|
38768
39027
|
return Array.isArray(value) ? value : [value];
|
|
38769
39028
|
}
|
|
@@ -39137,7 +39396,7 @@ function compareClock(left, right) {
|
|
|
39137
39396
|
function numberValue2(value) {
|
|
39138
39397
|
return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
|
|
39139
39398
|
}
|
|
39140
|
-
var TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
|
|
39399
|
+
var CLOUD_LOCK_EXPIRY_MINUTES = 30, TASK_ORDER_BY = "ORDER BY CASE payload->>'priority' WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END ASC, payload->>'created_at' ASC, payload->>'id' ASC";
|
|
39141
39400
|
var init_postgres_adapter = () => {};
|
|
39142
39401
|
|
|
39143
39402
|
// src/server/cloud.ts
|
|
@@ -39635,6 +39894,7 @@ async function handleV1Request(req, url) {
|
|
|
39635
39894
|
const resource = segments[1];
|
|
39636
39895
|
const id = segments[2];
|
|
39637
39896
|
const action = segments[3];
|
|
39897
|
+
const subId = segments[4];
|
|
39638
39898
|
try {
|
|
39639
39899
|
if (resource === "tasks") {
|
|
39640
39900
|
if (id === "exists" && !action) {
|
|
@@ -39685,6 +39945,114 @@ async function handleV1Request(req, url) {
|
|
|
39685
39945
|
return error(405, `method ${method} not allowed on /v1/tasks`);
|
|
39686
39946
|
}
|
|
39687
39947
|
if (action) {
|
|
39948
|
+
if (action === "comments") {
|
|
39949
|
+
if (method === "GET") {
|
|
39950
|
+
const comments = await store.audit.getComments(id);
|
|
39951
|
+
return json2({ comments, count: comments.length });
|
|
39952
|
+
}
|
|
39953
|
+
if (method === "POST") {
|
|
39954
|
+
const body2 = await readJson(req) ?? {};
|
|
39955
|
+
if (typeof body2.content !== "string" || !body2.content.trim()) {
|
|
39956
|
+
return error(400, "content is required");
|
|
39957
|
+
}
|
|
39958
|
+
const target = await store.tasks.get(id);
|
|
39959
|
+
if (!target)
|
|
39960
|
+
return error(404, "task not found");
|
|
39961
|
+
const comment = await store.audit.addComment({
|
|
39962
|
+
task_id: id,
|
|
39963
|
+
content: body2.content,
|
|
39964
|
+
agent_id: body2.agent_id ?? principal.agent ?? undefined,
|
|
39965
|
+
session_id: body2.session_id,
|
|
39966
|
+
type: body2.type,
|
|
39967
|
+
progress_pct: body2.progress_pct
|
|
39968
|
+
}, contextFromPrincipal(principal, body2));
|
|
39969
|
+
return json2({ comment }, 201);
|
|
39970
|
+
}
|
|
39971
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/comments`);
|
|
39972
|
+
}
|
|
39973
|
+
if (action === "lock" || action === "unlock") {
|
|
39974
|
+
if (method !== "POST")
|
|
39975
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/${action}`);
|
|
39976
|
+
if (typeof store.tasks.lock !== "function" || typeof store.tasks.unlock !== "function") {
|
|
39977
|
+
return error(501, "task locking is not supported by this storage backend");
|
|
39978
|
+
}
|
|
39979
|
+
const body2 = await readJson(req) ?? {};
|
|
39980
|
+
if (!await store.tasks.get(id))
|
|
39981
|
+
return error(404, "task not found");
|
|
39982
|
+
if (action === "lock") {
|
|
39983
|
+
const agentId2 = body2.agent_id || principal.agent || "todos-serve";
|
|
39984
|
+
return json2({ result: await store.tasks.lock(id, agentId2) });
|
|
39985
|
+
}
|
|
39986
|
+
const released = await store.tasks.unlock(id, body2.agent_id || principal.agent || undefined);
|
|
39987
|
+
return json2({ success: released });
|
|
39988
|
+
}
|
|
39989
|
+
if (action === "dependencies") {
|
|
39990
|
+
if (!store.dependencies)
|
|
39991
|
+
return error(501, "dependencies are not supported by this storage backend");
|
|
39992
|
+
if (method === "GET") {
|
|
39993
|
+
if (!await store.tasks.get(id))
|
|
39994
|
+
return error(404, "task not found");
|
|
39995
|
+
const edges = await store.dependencies.list(id);
|
|
39996
|
+
return json2(edges);
|
|
39997
|
+
}
|
|
39998
|
+
if (method === "POST") {
|
|
39999
|
+
const body2 = await readJson(req) ?? {};
|
|
40000
|
+
if (typeof body2.depends_on !== "string" || !body2.depends_on.trim()) {
|
|
40001
|
+
return error(400, "depends_on is required");
|
|
40002
|
+
}
|
|
40003
|
+
try {
|
|
40004
|
+
const dependency = await store.dependencies.add(id, body2.depends_on, contextFromPrincipal(principal));
|
|
40005
|
+
return json2({ dependency }, 201);
|
|
40006
|
+
} catch (e) {
|
|
40007
|
+
const msg = e.message || "";
|
|
40008
|
+
if (msg.includes("not found"))
|
|
40009
|
+
return error(404, msg);
|
|
40010
|
+
if (msg.includes("cycle") || msg.includes("itself"))
|
|
40011
|
+
return error(409, msg);
|
|
40012
|
+
throw e;
|
|
40013
|
+
}
|
|
40014
|
+
}
|
|
40015
|
+
if (method === "DELETE") {
|
|
40016
|
+
if (!subId)
|
|
40017
|
+
return error(400, "dependency target id is required (/v1/tasks/:id/dependencies/:dep)");
|
|
40018
|
+
const removed = await store.dependencies.remove(id, subId);
|
|
40019
|
+
return json2({ removed });
|
|
40020
|
+
}
|
|
40021
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/dependencies`);
|
|
40022
|
+
}
|
|
40023
|
+
if (action === "verifications") {
|
|
40024
|
+
if (!store.verifications)
|
|
40025
|
+
return error(501, "verifications are not supported by this storage backend");
|
|
40026
|
+
if (method === "GET") {
|
|
40027
|
+
if (!await store.tasks.get(id))
|
|
40028
|
+
return error(404, "task not found");
|
|
40029
|
+
const verifications = await store.verifications.list(id);
|
|
40030
|
+
return json2({ verifications, count: verifications.length });
|
|
40031
|
+
}
|
|
40032
|
+
if (method === "POST") {
|
|
40033
|
+
const body2 = await readJson(req) ?? {};
|
|
40034
|
+
if (typeof body2.command !== "string" || !body2.command.trim()) {
|
|
40035
|
+
return error(400, "command is required");
|
|
40036
|
+
}
|
|
40037
|
+
try {
|
|
40038
|
+
const verification = await store.verifications.add({
|
|
40039
|
+
task_id: id,
|
|
40040
|
+
command: body2.command,
|
|
40041
|
+
status: body2.status,
|
|
40042
|
+
output_summary: body2.output_summary,
|
|
40043
|
+
artifact_path: body2.artifact_path,
|
|
40044
|
+
agent_id: body2.agent_id
|
|
40045
|
+
}, contextFromPrincipal(principal, body2));
|
|
40046
|
+
return json2({ verification }, 201);
|
|
40047
|
+
} catch (e) {
|
|
40048
|
+
const msg = e.message || "";
|
|
40049
|
+
if (msg.includes("not found"))
|
|
40050
|
+
return error(404, msg);
|
|
40051
|
+
throw e;
|
|
40052
|
+
}
|
|
40053
|
+
}
|
|
40054
|
+
return error(405, `method ${method} not allowed on /v1/tasks/:id/verifications`);
|
|
40055
|
+
}
|
|
39688
40056
|
const body = await readJson(req) ?? {};
|
|
39689
40057
|
const agentId = body.agent_id || principal.agent || "todos-serve";
|
|
39690
40058
|
if (action === "start" && method === "POST") {
|
|
@@ -39789,10 +40157,13 @@ async function handleV1Request(req, url) {
|
|
|
39789
40157
|
}
|
|
39790
40158
|
if (!id && method === "POST") {
|
|
39791
40159
|
const body = await readJson(req);
|
|
39792
|
-
if (!body || typeof body.name !== "string")
|
|
40160
|
+
if (!body || typeof body.name !== "string" || !body.name.trim())
|
|
39793
40161
|
return error(400, "name is required");
|
|
39794
|
-
const
|
|
39795
|
-
|
|
40162
|
+
const result = await store.agents.register(body, contextFromPrincipal(principal));
|
|
40163
|
+
if (result && typeof result === "object" && "conflict" in result) {
|
|
40164
|
+
return error(409, result.message ?? "agent name conflict", { conflict: true });
|
|
40165
|
+
}
|
|
40166
|
+
return json2({ agent: result }, 201);
|
|
39796
40167
|
}
|
|
39797
40168
|
if (id && method === "GET") {
|
|
39798
40169
|
const agent = await store.agents.get(id);
|
|
@@ -49865,6 +50236,11 @@ Tasks:` : null,
|
|
|
49865
50236
|
author: exports_external3.string().optional().describe("Author agent ID or name")
|
|
49866
50237
|
}, async ({ task_id, body, author }) => {
|
|
49867
50238
|
try {
|
|
50239
|
+
const cloud = getTodosCloudClient();
|
|
50240
|
+
if (cloud) {
|
|
50241
|
+
await cloudAddComment(cloud, task_id, { content: body, agent_id: author });
|
|
50242
|
+
return { content: [{ type: "text", text: `Comment added to ${task_id.slice(0, 8)}: ${body.slice(0, 50)}${body.length > 50 ? "..." : ""}` }] };
|
|
50243
|
+
}
|
|
49868
50244
|
const resolvedId = resolveId(task_id);
|
|
49869
50245
|
const resolvedAuthor = author ? resolveId(author, "agents") : undefined;
|
|
49870
50246
|
const comment = addComment({ task_id: resolvedId, content: body, agent_id: resolvedAuthor });
|
|
@@ -50775,6 +51151,56 @@ function registerTaskWorkflowTools(server, ctx) {
|
|
|
50775
51151
|
max_description_chars: exports_external3.number().optional().describe("Max task description chars in compact mode (default: 180)")
|
|
50776
51152
|
}, async ({ agent_id, project_id, task_list_id, explain_blocked, detail, max_description_chars }) => {
|
|
50777
51153
|
try {
|
|
51154
|
+
const cloud = getTodosCloudClient();
|
|
51155
|
+
if (cloud) {
|
|
51156
|
+
const baseFilter = {};
|
|
51157
|
+
if (project_id)
|
|
51158
|
+
baseFilter.project_id = project_id;
|
|
51159
|
+
if (task_list_id)
|
|
51160
|
+
baseFilter.task_list_id = task_list_id;
|
|
51161
|
+
const [stats, pending, in_progress, completed, activeTasks, nextTasks] = await Promise.all([
|
|
51162
|
+
cloudGetStats(cloud),
|
|
51163
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "pending" }),
|
|
51164
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "in_progress" }),
|
|
51165
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "completed" }),
|
|
51166
|
+
cloudListTasks(cloud, { ...baseFilter, status: "in_progress", limit: 5 }),
|
|
51167
|
+
cloudListTasks(cloud, { ...baseFilter, status: "pending", limit: 1 })
|
|
51168
|
+
]);
|
|
51169
|
+
const cloudStatus = {
|
|
51170
|
+
source: "cloud",
|
|
51171
|
+
total: stats.tasks ?? pending + in_progress + completed,
|
|
51172
|
+
pending,
|
|
51173
|
+
in_progress,
|
|
51174
|
+
completed,
|
|
51175
|
+
active_work: activeTasks,
|
|
51176
|
+
next_task: nextTasks[0] ?? null,
|
|
51177
|
+
stale_count: 0,
|
|
51178
|
+
overdue_recurring: 0
|
|
51179
|
+
};
|
|
51180
|
+
const next_task2 = nextTasks[0] ?? null;
|
|
51181
|
+
const payload2 = {
|
|
51182
|
+
status: cloudStatus,
|
|
51183
|
+
next_task: next_task2,
|
|
51184
|
+
overdue_count: 0,
|
|
51185
|
+
latest_handoff: null,
|
|
51186
|
+
as_of: new Date().toISOString()
|
|
51187
|
+
};
|
|
51188
|
+
if (detail === "full") {
|
|
51189
|
+
return { content: [{ type: "text", text: JSON.stringify(payload2, null, 2) }] };
|
|
51190
|
+
}
|
|
51191
|
+
return {
|
|
51192
|
+
content: [{
|
|
51193
|
+
type: "text",
|
|
51194
|
+
text: compactJson({
|
|
51195
|
+
status: compactStatus(cloudStatus),
|
|
51196
|
+
next_task: next_task2 ? compactTask(next_task2, max_description_chars || 180) : null,
|
|
51197
|
+
overdue_count: 0,
|
|
51198
|
+
latest_handoff: null,
|
|
51199
|
+
as_of: payload2.as_of
|
|
51200
|
+
})
|
|
51201
|
+
}]
|
|
51202
|
+
};
|
|
51203
|
+
}
|
|
50778
51204
|
const { getStatus: getStatus2, getNextTask: getNextTask3, getOverdueTasks: getOverdueTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
50779
51205
|
const { getLatestHandoff: getLatestHandoff2 } = (init_handoffs(), __toCommonJS(exports_handoffs));
|
|
50780
51206
|
const filters = {};
|
|
@@ -51210,6 +51636,27 @@ ${lines.join(`
|
|
|
51210
51636
|
if (shouldRegisterTool("get_health")) {
|
|
51211
51637
|
server.tool("get_health", "Get system health: task counts by status, active agents, project summary.", async () => {
|
|
51212
51638
|
try {
|
|
51639
|
+
const cloud = getTodosCloudClient();
|
|
51640
|
+
if (cloud) {
|
|
51641
|
+
const [stats, pending2, inProgress2, completed2, cancelled2, projects2, agents2] = await Promise.all([
|
|
51642
|
+
cloudGetStats(cloud),
|
|
51643
|
+
cloudCountTasks(cloud, { status: "pending" }),
|
|
51644
|
+
cloudCountTasks(cloud, { status: "in_progress" }),
|
|
51645
|
+
cloudCountTasks(cloud, { status: "completed" }),
|
|
51646
|
+
cloudCountTasks(cloud, { status: "cancelled" }),
|
|
51647
|
+
cloudListProjects(cloud),
|
|
51648
|
+
cloudListAgents(cloud)
|
|
51649
|
+
]);
|
|
51650
|
+
const projectCount = stats.projects ?? projects2.length;
|
|
51651
|
+
const lines2 = [
|
|
51652
|
+
`=== System Health (cloud) ===`,
|
|
51653
|
+
`Tasks: ${pending2} pending | ${inProgress2} in progress | ${completed2} completed | ${cancelled2} cancelled`,
|
|
51654
|
+
`Projects: ${projectCount} total`,
|
|
51655
|
+
`Agents: ${agents2.length} registered`
|
|
51656
|
+
];
|
|
51657
|
+
return { content: [{ type: "text", text: lines2.join(`
|
|
51658
|
+
`) }] };
|
|
51659
|
+
}
|
|
51213
51660
|
const { countTasks: countTasks2 } = (init_tasks(), __toCommonJS(exports_tasks));
|
|
51214
51661
|
const { listProjects: listProjects2 } = (init_projects(), __toCommonJS(exports_projects));
|
|
51215
51662
|
const { listAgents: listAgents2 } = (init_agents(), __toCommonJS(exports_agents));
|
|
@@ -51248,6 +51695,7 @@ ${lines.join(`
|
|
|
51248
51695
|
}
|
|
51249
51696
|
var init_task_auto_tools = __esm(() => {
|
|
51250
51697
|
init_zod();
|
|
51698
|
+
init_cloud_router();
|
|
51251
51699
|
});
|
|
51252
51700
|
|
|
51253
51701
|
// src/lib/context-packs.ts
|
|
@@ -52570,6 +53018,11 @@ No blocked tasks.`,
|
|
|
52570
53018
|
author: exports_external3.string().optional().describe("Author agent ID or name")
|
|
52571
53019
|
}, async ({ task_id, body, author }) => {
|
|
52572
53020
|
try {
|
|
53021
|
+
const cloud = getTodosCloudClient();
|
|
53022
|
+
if (cloud) {
|
|
53023
|
+
await cloudAddComment(cloud, task_id, { content: body, agent_id: author });
|
|
53024
|
+
return { content: [{ type: "text", text: `Comment added to ${task_id.slice(0, 8)}` }] };
|
|
53025
|
+
}
|
|
52573
53026
|
const { addComment: addComment3 } = (init_comments(), __toCommonJS(exports_comments));
|
|
52574
53027
|
const resolvedId = resolveId(task_id);
|
|
52575
53028
|
const resolvedAuthor = author ? resolveId(author, "agents") : undefined;
|
|
@@ -62237,6 +62690,33 @@ function registerAgentTools(server, { shouldRegisterTool, resolveId, formatError
|
|
|
62237
62690
|
force: exports_external3.boolean().optional().describe("Force takeover of an active agent's name. Use with caution \u2014 only when you know the previous session is dead.")
|
|
62238
62691
|
}, async ({ name, description, role, title, level, permissions, capabilities, session_id, working_dir, force }) => {
|
|
62239
62692
|
try {
|
|
62693
|
+
const cloud = getTodosCloudClient();
|
|
62694
|
+
if (cloud) {
|
|
62695
|
+
const agent2 = await cloudRegisterAgent(cloud, {
|
|
62696
|
+
name,
|
|
62697
|
+
description,
|
|
62698
|
+
role,
|
|
62699
|
+
title,
|
|
62700
|
+
level,
|
|
62701
|
+
permissions,
|
|
62702
|
+
capabilities,
|
|
62703
|
+
session_id,
|
|
62704
|
+
working_dir,
|
|
62705
|
+
force
|
|
62706
|
+
});
|
|
62707
|
+
return {
|
|
62708
|
+
content: [{
|
|
62709
|
+
type: "text",
|
|
62710
|
+
text: `Agent registered:
|
|
62711
|
+
ID: ${agent2.id}
|
|
62712
|
+
Name: ${agent2.name}${agent2.description ? `
|
|
62713
|
+
Description: ${agent2.description}` : ""}
|
|
62714
|
+
Session: ${agent2.session_id ?? "unbound"}
|
|
62715
|
+
Created: ${agent2.created_at}
|
|
62716
|
+
Last seen: ${agent2.last_seen_at}`
|
|
62717
|
+
}]
|
|
62718
|
+
};
|
|
62719
|
+
}
|
|
62240
62720
|
const pool = getAgentPoolForProject(working_dir);
|
|
62241
62721
|
const result = registerAgent({ name, description, role, title, level, permissions, capabilities, session_id, working_dir, force, pool: pool || undefined });
|
|
62242
62722
|
if (isAgentConflict(result)) {
|
|
@@ -62330,7 +62810,8 @@ No names available. Wait for an active agent to go stale (30min timeout).`
|
|
|
62330
62810
|
include_archived: exports_external3.boolean().optional().describe("Include archived agents in the list (default: false)")
|
|
62331
62811
|
}, async ({ include_archived }) => {
|
|
62332
62812
|
try {
|
|
62333
|
-
const
|
|
62813
|
+
const cloud = getTodosCloudClient();
|
|
62814
|
+
const agents = cloud ? await cloudListAgents(cloud) : listAgents({ include_archived: include_archived ?? false });
|
|
62334
62815
|
if (agents.length === 0) {
|
|
62335
62816
|
return { content: [{ type: "text", text: "No agents registered." }] };
|
|
62336
62817
|
}
|
|
@@ -62550,6 +63031,7 @@ var init_agents2 = __esm(() => {
|
|
|
62550
63031
|
init_agents();
|
|
62551
63032
|
init_config2();
|
|
62552
63033
|
init_database();
|
|
63034
|
+
init_cloud_router();
|
|
62553
63035
|
});
|
|
62554
63036
|
|
|
62555
63037
|
// src/mcp/tools/templates.ts
|
|
@@ -68219,11 +68701,42 @@ function registerQueryCommands(program2) {
|
|
|
68219
68701
|
program2.command("status").description("Show full project health snapshot").option("--agent <id>", "Include next task for this agent").option("--project <id>", "Filter to project").option("-j, --json", "Output as JSON").action(async (opts) => {
|
|
68220
68702
|
const globalOpts = program2.opts();
|
|
68221
68703
|
const json3 = opts.json || globalOpts.json;
|
|
68222
|
-
const db = getDatabase();
|
|
68223
68704
|
const filters = {};
|
|
68224
68705
|
if (opts.project)
|
|
68225
68706
|
filters.project_id = opts.project;
|
|
68226
|
-
const
|
|
68707
|
+
const cloud = getTodosCloudClient();
|
|
68708
|
+
let s;
|
|
68709
|
+
if (cloud) {
|
|
68710
|
+
const baseFilter = opts.project ? { project_id: opts.project } : {};
|
|
68711
|
+
const [stats2, pending, in_progress, completed, activeTasks, nextTasks] = await Promise.all([
|
|
68712
|
+
cloudGetStats(cloud),
|
|
68713
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "pending" }),
|
|
68714
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "in_progress" }),
|
|
68715
|
+
cloudCountTasks(cloud, { ...baseFilter, status: "completed" }),
|
|
68716
|
+
cloudListTasks(cloud, { ...baseFilter, status: "in_progress", limit: 5 }),
|
|
68717
|
+
cloudListTasks(cloud, { ...baseFilter, status: "pending", limit: 1 })
|
|
68718
|
+
]);
|
|
68719
|
+
s = {
|
|
68720
|
+
source: "cloud",
|
|
68721
|
+
pending,
|
|
68722
|
+
in_progress,
|
|
68723
|
+
completed,
|
|
68724
|
+
total: stats2.tasks ?? pending + in_progress + completed,
|
|
68725
|
+
active_work: activeTasks.map((t) => ({
|
|
68726
|
+
id: t.id,
|
|
68727
|
+
short_id: t.short_id ?? null,
|
|
68728
|
+
title: t.title,
|
|
68729
|
+
assigned_to: t.assigned_to ?? null,
|
|
68730
|
+
locked_by: t.locked_by ?? null
|
|
68731
|
+
})),
|
|
68732
|
+
next_task: nextTasks[0] ?? null,
|
|
68733
|
+
stale_count: 0,
|
|
68734
|
+
overdue_recurring: 0
|
|
68735
|
+
};
|
|
68736
|
+
} else {
|
|
68737
|
+
const db = getDatabase();
|
|
68738
|
+
s = getStatus(Object.keys(filters).length ? filters : undefined, opts.agent, undefined, db);
|
|
68739
|
+
}
|
|
68227
68740
|
if (json3) {
|
|
68228
68741
|
console.log(JSON.stringify(s, null, 2));
|
|
68229
68742
|
return;
|
|
@@ -70617,6 +71130,7 @@ var init_query_commands = __esm(() => {
|
|
|
70617
71130
|
init_workflow_states();
|
|
70618
71131
|
init_local_reports();
|
|
70619
71132
|
init_helpers();
|
|
71133
|
+
init_cloud_router();
|
|
70620
71134
|
init_types();
|
|
70621
71135
|
});
|
|
70622
71136
|
|
|
@@ -71062,25 +71576,34 @@ Commands:`));
|
|
|
71062
71576
|
});
|
|
71063
71577
|
program2.command("record-verification <task-id> <command>").description("Record a verification command and result for a task").option("--status <status>", "Verification status: passed, failed, or unknown", "unknown").option("--summary <text>", "Short output summary").option("--artifact <path>", "Artifact or log path").option("--agent <name>", "Agent that ran the command").action(async (taskId, command, opts) => {
|
|
71064
71578
|
const globalOpts = program2.opts();
|
|
71065
|
-
const resolvedId = resolveTaskId(taskId);
|
|
71066
71579
|
if (opts.status !== "passed" && opts.status !== "failed" && opts.status !== "unknown") {
|
|
71067
71580
|
console.error(chalk8.red("--status must be passed, failed, or unknown"));
|
|
71068
71581
|
process.exit(1);
|
|
71069
71582
|
}
|
|
71070
|
-
|
|
71071
|
-
|
|
71072
|
-
|
|
71073
|
-
|
|
71074
|
-
|
|
71075
|
-
|
|
71076
|
-
|
|
71077
|
-
|
|
71078
|
-
|
|
71079
|
-
|
|
71080
|
-
|
|
71081
|
-
|
|
71583
|
+
try {
|
|
71584
|
+
const cloud = getTodosCloudClient();
|
|
71585
|
+
const verification = cloud ? await cloudRecordVerification(cloud, resolveTaskId(taskId), {
|
|
71586
|
+
command,
|
|
71587
|
+
status: opts.status,
|
|
71588
|
+
output_summary: opts.summary,
|
|
71589
|
+
artifact_path: opts.artifact,
|
|
71590
|
+
agent_id: opts.agent
|
|
71591
|
+
}) : (await Promise.resolve().then(() => (init_task_commits(), exports_task_commits))).addTaskVerification({
|
|
71592
|
+
task_id: resolveTaskId(taskId),
|
|
71593
|
+
command,
|
|
71594
|
+
status: opts.status,
|
|
71595
|
+
output_summary: opts.summary,
|
|
71596
|
+
artifact_path: opts.artifact,
|
|
71597
|
+
agent_id: opts.agent
|
|
71598
|
+
});
|
|
71599
|
+
if (globalOpts.json) {
|
|
71600
|
+
output(verification, true);
|
|
71601
|
+
return;
|
|
71602
|
+
}
|
|
71603
|
+
console.log(chalk8.green(`Recorded ${verification.status} verification for task ${taskId}`));
|
|
71604
|
+
} catch (e) {
|
|
71605
|
+
handleError(e);
|
|
71082
71606
|
}
|
|
71083
|
-
console.log(chalk8.green(`Recorded ${verification.status} verification for task ${taskId}`));
|
|
71084
71607
|
});
|
|
71085
71608
|
program2.command("trace <task-id>").description("Show local git refs, commits, changed files, and verification commands for a task").action(async (taskId) => {
|
|
71086
71609
|
const globalOpts = program2.opts();
|
|
@@ -71786,6 +72309,7 @@ var HOME2;
|
|
|
71786
72309
|
var init_mcp_hooks_commands = __esm(() => {
|
|
71787
72310
|
init_tasks();
|
|
71788
72311
|
init_helpers();
|
|
72312
|
+
init_cloud_router();
|
|
71789
72313
|
HOME2 = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
71790
72314
|
});
|
|
71791
72315
|
|