@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/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
- const task2 = getTaskWithRelations(resolvedId);
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
- unlockTask(resolvedId, globalOpts.agent);
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 projectId = autoProject(globalOpts);
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
- const comment = addComment({
31392
- task_id: resolvedId,
31393
- content,
31394
- agent_id: globalOpts.agent,
31395
- session_id: globalOpts.session
31396
- });
31397
- if (globalOpts.json) {
31398
- output(comment, true);
31399
- } else {
31400
- console.log(chalk4.green("Comment added."));
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 projects = listProjects();
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 { registerAgent: registerAgent2, isAgentConflict: isAgentConflict2 } = await Promise.resolve().then(() => (init_agents(), exports_agents));
32742
- const result = registerAgent2({ name, description: opts.description });
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 agents = listAgents();
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 agent = await store.agents.register(body, contextFromPrincipal(principal));
39795
- return json2({ agent }, 201);
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 agents = listAgents({ include_archived: include_archived ?? false });
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 s = getStatus(Object.keys(filters).length ? filters : undefined, opts.agent, undefined, db);
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
- const { addTaskVerification: addTaskVerification2 } = await Promise.resolve().then(() => (init_task_commits(), exports_task_commits));
71071
- const verification = addTaskVerification2({
71072
- task_id: resolvedId,
71073
- command,
71074
- status: opts.status,
71075
- output_summary: opts.summary,
71076
- artifact_path: opts.artifact,
71077
- agent_id: opts.agent
71078
- });
71079
- if (globalOpts.json) {
71080
- output(verification, true);
71081
- return;
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