@hasna/todos 0.9.27 → 0.9.29

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
@@ -3198,7 +3198,18 @@ function updateTask(id, input, db) {
3198
3198
  logTaskChange(id, "update", "assigned_to", task.assigned_to, input.assigned_to, agentId, d);
3199
3199
  if (input.approved_by !== undefined)
3200
3200
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
3201
- return getTask(id, d);
3201
+ return {
3202
+ ...task,
3203
+ ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
3204
+ tags: input.tags ?? task.tags,
3205
+ metadata: input.metadata ?? task.metadata,
3206
+ version: task.version + 1,
3207
+ updated_at: now(),
3208
+ completed_at: input.status === "completed" ? now() : task.completed_at,
3209
+ requires_approval: input.requires_approval !== undefined ? input.requires_approval : task.requires_approval,
3210
+ approved_by: input.approved_by ?? task.approved_by,
3211
+ approved_at: input.approved_by ? now() : task.approved_at
3212
+ };
3202
3213
  }
3203
3214
  function deleteTask(id, db) {
3204
3215
  const d = db || getDatabase();
@@ -3220,6 +3231,9 @@ function getBlockingDeps(id, db) {
3220
3231
  }
3221
3232
  function startTask(id, agentId, db) {
3222
3233
  const d = db || getDatabase();
3234
+ const task = getTask(id, d);
3235
+ if (!task)
3236
+ throw new TaskNotFoundError(id);
3223
3237
  const blocking = getBlockingDeps(id, d);
3224
3238
  if (blocking.length > 0) {
3225
3239
  const blockerIds = blocking.map((b) => b.id.slice(0, 8)).join(", ");
@@ -3230,15 +3244,12 @@ function startTask(id, agentId, db) {
3230
3244
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
3231
3245
  WHERE id = ? AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, id, agentId, cutoff]);
3232
3246
  if (result.changes === 0) {
3233
- const current = getTask(id, d);
3234
- if (!current)
3235
- throw new TaskNotFoundError(id);
3236
- if (current.locked_by && current.locked_by !== agentId && !isLockExpired(current.locked_at)) {
3237
- throw new LockError(id, current.locked_by);
3247
+ if (task.locked_by && task.locked_by !== agentId && !isLockExpired(task.locked_at)) {
3248
+ throw new LockError(id, task.locked_by);
3238
3249
  }
3239
3250
  }
3240
3251
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
3241
- return getTask(id, d);
3252
+ return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, version: task.version + 1, updated_at: timestamp };
3242
3253
  }
3243
3254
  function completeTask(id, agentId, db, evidence) {
3244
3255
  const d = db || getDatabase();
@@ -3250,14 +3261,15 @@ function completeTask(id, agentId, db, evidence) {
3250
3261
  }
3251
3262
  checkCompletionGuard(task, agentId || null, d);
3252
3263
  if (evidence) {
3253
- const meta = { ...task.metadata, _evidence: evidence };
3254
- d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta), id]);
3264
+ const meta2 = { ...task.metadata, _evidence: evidence };
3265
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta2), id]);
3255
3266
  }
3256
3267
  const timestamp = now();
3257
3268
  d.run(`UPDATE tasks SET status = 'completed', locked_by = NULL, locked_at = NULL, completed_at = ?, version = version + 1, updated_at = ?
3258
3269
  WHERE id = ?`, [timestamp, timestamp, id]);
3259
3270
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
3260
- return getTask(id, d);
3271
+ const meta = evidence ? { ...task.metadata, _evidence: evidence } : task.metadata;
3272
+ return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, version: task.version + 1, updated_at: timestamp, metadata: meta };
3261
3273
  }
3262
3274
  function lockTask(id, agentId, db) {
3263
3275
  const d = db || getDatabase();
@@ -8363,22 +8375,22 @@ var init_mcp = __esm(() => {
8363
8375
  version: "0.9.15"
8364
8376
  });
8365
8377
  server.tool("create_task", "Create a new task", {
8366
- title: exports_external.string().describe("Task title"),
8367
- description: exports_external.string().optional().describe("Task description"),
8368
- project_id: exports_external.string().optional().describe("Project ID"),
8369
- parent_id: exports_external.string().optional().describe("Parent task ID (for subtasks)"),
8370
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Task priority"),
8371
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("Initial status"),
8372
- agent_id: exports_external.string().optional().describe("Creator agent ID"),
8373
- assigned_to: exports_external.string().optional().describe("Assigned agent ID"),
8374
- session_id: exports_external.string().optional().describe("Session ID"),
8375
- working_dir: exports_external.string().optional().describe("Working directory context"),
8376
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
8377
- task_list_id: exports_external.string().optional().describe("Task list ID to assign task to"),
8378
- tags: exports_external.array(exports_external.string()).optional().describe("Task tags"),
8379
- metadata: exports_external.record(exports_external.unknown()).optional().describe("Arbitrary metadata"),
8380
- estimated_minutes: exports_external.number().optional().describe("Estimated time in minutes"),
8381
- requires_approval: exports_external.boolean().optional().describe("Require approval before completion")
8378
+ title: exports_external.string(),
8379
+ description: exports_external.string().optional(),
8380
+ project_id: exports_external.string().optional(),
8381
+ parent_id: exports_external.string().optional(),
8382
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8383
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8384
+ agent_id: exports_external.string().optional(),
8385
+ assigned_to: exports_external.string().optional(),
8386
+ session_id: exports_external.string().optional(),
8387
+ working_dir: exports_external.string().optional(),
8388
+ plan_id: exports_external.string().optional(),
8389
+ task_list_id: exports_external.string().optional(),
8390
+ tags: exports_external.array(exports_external.string()).optional(),
8391
+ metadata: exports_external.record(exports_external.unknown()).optional(),
8392
+ estimated_minutes: exports_external.number().optional(),
8393
+ requires_approval: exports_external.boolean().optional()
8382
8394
  }, async (params) => {
8383
8395
  try {
8384
8396
  const resolved = { ...params };
@@ -8397,19 +8409,19 @@ var init_mcp = __esm(() => {
8397
8409
  }
8398
8410
  });
8399
8411
  server.tool("list_tasks", "List tasks with optional filters", {
8400
- project_id: exports_external.string().optional().describe("Filter by project"),
8412
+ project_id: exports_external.string().optional(),
8401
8413
  status: exports_external.union([
8402
8414
  exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]),
8403
8415
  exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]))
8404
- ]).optional().describe("Filter by status"),
8416
+ ]).optional(),
8405
8417
  priority: exports_external.union([
8406
8418
  exports_external.enum(["low", "medium", "high", "critical"]),
8407
8419
  exports_external.array(exports_external.enum(["low", "medium", "high", "critical"]))
8408
- ]).optional().describe("Filter by priority"),
8409
- assigned_to: exports_external.string().optional().describe("Filter by assigned agent"),
8410
- tags: exports_external.array(exports_external.string()).optional().describe("Filter by tags (any match)"),
8411
- plan_id: exports_external.string().optional().describe("Filter by plan"),
8412
- task_list_id: exports_external.string().optional().describe("Filter by task list")
8420
+ ]).optional(),
8421
+ assigned_to: exports_external.string().optional(),
8422
+ tags: exports_external.array(exports_external.string()).optional(),
8423
+ plan_id: exports_external.string().optional(),
8424
+ task_list_id: exports_external.string().optional()
8413
8425
  }, async (params) => {
8414
8426
  try {
8415
8427
  const resolved = { ...params };
@@ -8436,7 +8448,7 @@ ${text}` }] };
8436
8448
  }
8437
8449
  });
8438
8450
  server.tool("get_task", "Get full task details with relations", {
8439
- id: exports_external.string().describe("Task ID (full or partial)")
8451
+ id: exports_external.string()
8440
8452
  }, async ({ id }) => {
8441
8453
  try {
8442
8454
  const resolvedId = resolveId(id);
@@ -8484,17 +8496,17 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8484
8496
  }
8485
8497
  });
8486
8498
  server.tool("update_task", "Update task fields. Version required for optimistic locking.", {
8487
- id: exports_external.string().describe("Task ID (full or partial)"),
8488
- version: exports_external.number().describe("Current version (for optimistic locking)"),
8489
- title: exports_external.string().optional().describe("New title"),
8490
- description: exports_external.string().optional().describe("New description"),
8491
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("New status"),
8492
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("New priority"),
8493
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
8494
- tags: exports_external.array(exports_external.string()).optional().describe("New tags"),
8495
- metadata: exports_external.record(exports_external.unknown()).optional().describe("New metadata"),
8496
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
8497
- task_list_id: exports_external.string().optional().describe("Task list ID")
8499
+ id: exports_external.string(),
8500
+ version: exports_external.number(),
8501
+ title: exports_external.string().optional(),
8502
+ description: exports_external.string().optional(),
8503
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8504
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8505
+ assigned_to: exports_external.string().optional(),
8506
+ tags: exports_external.array(exports_external.string()).optional(),
8507
+ metadata: exports_external.record(exports_external.unknown()).optional(),
8508
+ plan_id: exports_external.string().optional(),
8509
+ task_list_id: exports_external.string().optional()
8498
8510
  }, async ({ id, ...rest }) => {
8499
8511
  try {
8500
8512
  const resolvedId = resolveId(id);
@@ -8505,7 +8517,7 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8505
8517
  }
8506
8518
  });
8507
8519
  server.tool("delete_task", "Delete a task permanently", {
8508
- id: exports_external.string().describe("Task ID (full or partial)")
8520
+ id: exports_external.string()
8509
8521
  }, async ({ id }) => {
8510
8522
  try {
8511
8523
  const resolvedId = resolveId(id);
@@ -8521,8 +8533,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8521
8533
  }
8522
8534
  });
8523
8535
  server.tool("start_task", "Claim, lock, and set task status to in_progress.", {
8524
- id: exports_external.string().describe("Task ID (full or partial)"),
8525
- agent_id: exports_external.string().describe("Agent claiming the task")
8536
+ id: exports_external.string(),
8537
+ agent_id: exports_external.string()
8526
8538
  }, async ({ id, agent_id }) => {
8527
8539
  try {
8528
8540
  const resolvedId = resolveId(id);
@@ -8533,8 +8545,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8533
8545
  }
8534
8546
  });
8535
8547
  server.tool("complete_task", "Mark task completed and release lock.", {
8536
- id: exports_external.string().describe("Task ID (full or partial)"),
8537
- agent_id: exports_external.string().optional().describe("Agent completing the task")
8548
+ id: exports_external.string(),
8549
+ agent_id: exports_external.string().optional()
8538
8550
  }, async ({ id, agent_id }) => {
8539
8551
  try {
8540
8552
  const resolvedId = resolveId(id);
@@ -8545,8 +8557,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8545
8557
  }
8546
8558
  });
8547
8559
  server.tool("lock_task", "Acquire exclusive lock on a task", {
8548
- id: exports_external.string().describe("Task ID (full or partial)"),
8549
- agent_id: exports_external.string().describe("Agent acquiring lock")
8560
+ id: exports_external.string(),
8561
+ agent_id: exports_external.string()
8550
8562
  }, async ({ id, agent_id }) => {
8551
8563
  try {
8552
8564
  const resolvedId = resolveId(id);
@@ -8560,8 +8572,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8560
8572
  }
8561
8573
  });
8562
8574
  server.tool("unlock_task", "Release exclusive lock on a task", {
8563
- id: exports_external.string().describe("Task ID (full or partial)"),
8564
- agent_id: exports_external.string().optional().describe("Agent releasing lock (omit to force)")
8575
+ id: exports_external.string(),
8576
+ agent_id: exports_external.string().optional()
8565
8577
  }, async ({ id, agent_id }) => {
8566
8578
  try {
8567
8579
  const resolvedId = resolveId(id);
@@ -8572,8 +8584,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8572
8584
  }
8573
8585
  });
8574
8586
  server.tool("add_dependency", "Add a dependency: task_id depends on depends_on.", {
8575
- task_id: exports_external.string().describe("Task that depends on another"),
8576
- depends_on: exports_external.string().describe("Task that must complete first")
8587
+ task_id: exports_external.string(),
8588
+ depends_on: exports_external.string()
8577
8589
  }, async ({ task_id, depends_on }) => {
8578
8590
  try {
8579
8591
  const resolvedTaskId = resolveId(task_id);
@@ -8585,8 +8597,8 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8585
8597
  }
8586
8598
  });
8587
8599
  server.tool("remove_dependency", "Remove a dependency between tasks", {
8588
- task_id: exports_external.string().describe("Task ID"),
8589
- depends_on: exports_external.string().describe("Dependency to remove")
8600
+ task_id: exports_external.string(),
8601
+ depends_on: exports_external.string()
8590
8602
  }, async ({ task_id, depends_on }) => {
8591
8603
  try {
8592
8604
  const resolvedTaskId = resolveId(task_id);
@@ -8603,10 +8615,10 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
8603
8615
  }
8604
8616
  });
8605
8617
  server.tool("add_comment", "Add a comment/note to a task", {
8606
- task_id: exports_external.string().describe("Task ID (full or partial)"),
8607
- content: exports_external.string().describe("Comment content"),
8608
- agent_id: exports_external.string().optional().describe("Agent adding comment"),
8609
- session_id: exports_external.string().optional().describe("Session ID")
8618
+ task_id: exports_external.string(),
8619
+ content: exports_external.string(),
8620
+ agent_id: exports_external.string().optional(),
8621
+ session_id: exports_external.string().optional()
8610
8622
  }, async ({ task_id, ...rest }) => {
8611
8623
  try {
8612
8624
  const resolvedId = resolveId(task_id);
@@ -8634,10 +8646,10 @@ ${text}` }] };
8634
8646
  }
8635
8647
  });
8636
8648
  server.tool("create_project", "Register a new project", {
8637
- name: exports_external.string().describe("Project name"),
8638
- path: exports_external.string().describe("Absolute path to project"),
8639
- description: exports_external.string().optional().describe("Project description"),
8640
- task_list_id: exports_external.string().optional().describe("Custom task list ID for Claude Code sync (defaults to todos-<slugified-name>)")
8649
+ name: exports_external.string(),
8650
+ path: exports_external.string(),
8651
+ description: exports_external.string().optional(),
8652
+ task_list_id: exports_external.string().optional()
8641
8653
  }, async (params) => {
8642
8654
  try {
8643
8655
  const project = createProject(params);
@@ -8653,12 +8665,12 @@ ${text}` }] };
8653
8665
  }
8654
8666
  });
8655
8667
  server.tool("create_plan", "Create a new plan", {
8656
- name: exports_external.string().describe("Plan name"),
8657
- project_id: exports_external.string().optional().describe("Project ID"),
8658
- description: exports_external.string().optional().describe("Plan description"),
8659
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("Plan status"),
8660
- task_list_id: exports_external.string().optional().describe("Task list ID"),
8661
- agent_id: exports_external.string().optional().describe("Owner agent ID")
8668
+ name: exports_external.string(),
8669
+ project_id: exports_external.string().optional(),
8670
+ description: exports_external.string().optional(),
8671
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
8672
+ task_list_id: exports_external.string().optional(),
8673
+ agent_id: exports_external.string().optional()
8662
8674
  }, async (params) => {
8663
8675
  try {
8664
8676
  const resolved = { ...params };
@@ -8678,7 +8690,7 @@ ${text}` }] };
8678
8690
  }
8679
8691
  });
8680
8692
  server.tool("list_plans", "List plans with optional project filter", {
8681
- project_id: exports_external.string().optional().describe("Filter by project")
8693
+ project_id: exports_external.string().optional()
8682
8694
  }, async ({ project_id }) => {
8683
8695
  try {
8684
8696
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8698,7 +8710,7 @@ ${text}` }] };
8698
8710
  }
8699
8711
  });
8700
8712
  server.tool("get_plan", "Get plan details", {
8701
- id: exports_external.string().describe("Plan ID (full or partial)")
8713
+ id: exports_external.string()
8702
8714
  }, async ({ id }) => {
8703
8715
  try {
8704
8716
  const resolvedId = resolveId(id, "plans");
@@ -8723,12 +8735,12 @@ ${text}` }] };
8723
8735
  }
8724
8736
  });
8725
8737
  server.tool("update_plan", "Update a plan", {
8726
- id: exports_external.string().describe("Plan ID (full or partial)"),
8727
- name: exports_external.string().optional().describe("New name"),
8728
- description: exports_external.string().optional().describe("New description"),
8729
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("New status"),
8730
- task_list_id: exports_external.string().optional().describe("Task list ID"),
8731
- agent_id: exports_external.string().optional().describe("Owner agent ID")
8738
+ id: exports_external.string(),
8739
+ name: exports_external.string().optional(),
8740
+ description: exports_external.string().optional(),
8741
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
8742
+ task_list_id: exports_external.string().optional(),
8743
+ agent_id: exports_external.string().optional()
8732
8744
  }, async ({ id, ...rest }) => {
8733
8745
  try {
8734
8746
  const resolvedId = resolveId(id, "plans");
@@ -8747,7 +8759,7 @@ ${text}` }] };
8747
8759
  }
8748
8760
  });
8749
8761
  server.tool("delete_plan", "Delete a plan", {
8750
- id: exports_external.string().describe("Plan ID (full or partial)")
8762
+ id: exports_external.string()
8751
8763
  }, async ({ id }) => {
8752
8764
  try {
8753
8765
  const resolvedId = resolveId(id, "plans");
@@ -8763,9 +8775,9 @@ ${text}` }] };
8763
8775
  }
8764
8776
  });
8765
8777
  server.tool("search_tasks", "Full-text search across task titles, descriptions, tags.", {
8766
- query: exports_external.string().describe("Search query"),
8767
- project_id: exports_external.string().optional().describe("Limit to project"),
8768
- task_list_id: exports_external.string().optional().describe("Filter by task list")
8778
+ query: exports_external.string(),
8779
+ project_id: exports_external.string().optional(),
8780
+ task_list_id: exports_external.string().optional()
8769
8781
  }, async ({ query, project_id, task_list_id }) => {
8770
8782
  try {
8771
8783
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8783,12 +8795,12 @@ ${text}` }] };
8783
8795
  }
8784
8796
  });
8785
8797
  server.tool("sync", "Sync tasks with an agent task list.", {
8786
- task_list_id: exports_external.string().optional().describe("Task list ID (required for Claude)"),
8787
- agent: exports_external.string().optional().describe("Agent/provider name (default: claude)"),
8788
- all_agents: exports_external.boolean().optional().describe("Sync across all configured agents"),
8789
- project_id: exports_external.string().optional().describe("Project ID \u2014 its task_list_id will be used for Claude if task_list_id is not provided"),
8790
- direction: exports_external.enum(["push", "pull", "both"]).optional().describe("Sync direction: push (SQLite->agent), pull (agent->SQLite), or both (default)"),
8791
- prefer: exports_external.enum(["local", "remote"]).optional().describe("Conflict strategy")
8798
+ task_list_id: exports_external.string().optional(),
8799
+ agent: exports_external.string().optional(),
8800
+ all_agents: exports_external.boolean().optional(),
8801
+ project_id: exports_external.string().optional(),
8802
+ direction: exports_external.enum(["push", "pull", "both"]).optional(),
8803
+ prefer: exports_external.enum(["local", "remote"]).optional()
8792
8804
  }, async ({ task_list_id, agent, all_agents, project_id, direction, prefer }) => {
8793
8805
  try {
8794
8806
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8831,8 +8843,8 @@ ${text}` }] };
8831
8843
  }
8832
8844
  });
8833
8845
  server.tool("register_agent", "Register an agent (idempotent by name).", {
8834
- name: exports_external.string().describe("Agent name"),
8835
- description: exports_external.string().optional().describe("Agent description")
8846
+ name: exports_external.string(),
8847
+ description: exports_external.string().optional()
8836
8848
  }, async ({ name, description }) => {
8837
8849
  try {
8838
8850
  const agent = registerAgent({ name, description });
@@ -8868,8 +8880,8 @@ ${text}` }] };
8868
8880
  }
8869
8881
  });
8870
8882
  server.tool("get_agent", "Get agent details by ID or name", {
8871
- id: exports_external.string().optional().describe("Agent ID"),
8872
- name: exports_external.string().optional().describe("Agent name")
8883
+ id: exports_external.string().optional(),
8884
+ name: exports_external.string().optional()
8873
8885
  }, async ({ id, name }) => {
8874
8886
  try {
8875
8887
  if (!id && !name) {
@@ -8896,10 +8908,10 @@ ${text}` }] };
8896
8908
  }
8897
8909
  });
8898
8910
  server.tool("create_task_list", "Create a new task list", {
8899
- name: exports_external.string().describe("Task list name"),
8900
- slug: exports_external.string().optional().describe("URL-friendly slug (auto-generated from name if omitted)"),
8901
- project_id: exports_external.string().optional().describe("Project ID to associate with"),
8902
- description: exports_external.string().optional().describe("Task list description")
8911
+ name: exports_external.string(),
8912
+ slug: exports_external.string().optional(),
8913
+ project_id: exports_external.string().optional(),
8914
+ description: exports_external.string().optional()
8903
8915
  }, async (params) => {
8904
8916
  try {
8905
8917
  const resolved = { ...params };
@@ -8922,7 +8934,7 @@ Description: ${list.description}` : ""}`
8922
8934
  }
8923
8935
  });
8924
8936
  server.tool("list_task_lists", "List task lists, optionally filtered by project", {
8925
- project_id: exports_external.string().optional().describe("Filter by project")
8937
+ project_id: exports_external.string().optional()
8926
8938
  }, async ({ project_id }) => {
8927
8939
  try {
8928
8940
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -8942,7 +8954,7 @@ ${text}` }] };
8942
8954
  }
8943
8955
  });
8944
8956
  server.tool("get_task_list", "Get task list details", {
8945
- id: exports_external.string().describe("Task list ID (full or partial)")
8957
+ id: exports_external.string()
8946
8958
  }, async ({ id }) => {
8947
8959
  try {
8948
8960
  const resolvedId = resolveId(id, "task_lists");
@@ -8970,9 +8982,9 @@ ${text}` }] };
8970
8982
  }
8971
8983
  });
8972
8984
  server.tool("update_task_list", "Update a task list", {
8973
- id: exports_external.string().describe("Task list ID (full or partial)"),
8974
- name: exports_external.string().optional().describe("New name"),
8975
- description: exports_external.string().optional().describe("New description")
8985
+ id: exports_external.string(),
8986
+ name: exports_external.string().optional(),
8987
+ description: exports_external.string().optional()
8976
8988
  }, async ({ id, ...rest }) => {
8977
8989
  try {
8978
8990
  const resolvedId = resolveId(id, "task_lists");
@@ -8991,7 +9003,7 @@ Slug: ${list.slug}`
8991
9003
  }
8992
9004
  });
8993
9005
  server.tool("delete_task_list", "Delete a task list. Tasks lose association but keep data.", {
8994
- id: exports_external.string().describe("Task list ID (full or partial)")
9006
+ id: exports_external.string()
8995
9007
  }, async ({ id }) => {
8996
9008
  try {
8997
9009
  const resolvedId = resolveId(id, "task_lists");
@@ -9007,7 +9019,7 @@ Slug: ${list.slug}`
9007
9019
  }
9008
9020
  });
9009
9021
  server.tool("get_task_history", "Get audit log for a task.", {
9010
- task_id: exports_external.string().describe("Task ID (full or partial)")
9022
+ task_id: exports_external.string()
9011
9023
  }, async ({ task_id }) => {
9012
9024
  try {
9013
9025
  const resolvedId = resolveId(task_id);
@@ -9024,7 +9036,7 @@ ${text}` }] };
9024
9036
  }
9025
9037
  });
9026
9038
  server.tool("get_recent_activity", "Get recent task changes across all tasks.", {
9027
- limit: exports_external.number().optional().describe("Max entries (default 50)")
9039
+ limit: exports_external.number().optional()
9028
9040
  }, async ({ limit }) => {
9029
9041
  try {
9030
9042
  const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
@@ -9040,9 +9052,9 @@ ${text}` }] };
9040
9052
  }
9041
9053
  });
9042
9054
  server.tool("create_webhook", "Register a webhook to receive task change events.", {
9043
- url: exports_external.string().describe("Webhook URL"),
9044
- events: exports_external.array(exports_external.string()).optional().describe("Event types to subscribe to (empty = all)"),
9045
- secret: exports_external.string().optional().describe("HMAC secret for signature verification")
9055
+ url: exports_external.string(),
9056
+ events: exports_external.array(exports_external.string()).optional(),
9057
+ secret: exports_external.string().optional()
9046
9058
  }, async (params) => {
9047
9059
  try {
9048
9060
  const { createWebhook: createWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -9067,7 +9079,7 @@ ${text}` }] };
9067
9079
  }
9068
9080
  });
9069
9081
  server.tool("delete_webhook", "Delete a webhook", {
9070
- id: exports_external.string().describe("Webhook ID")
9082
+ id: exports_external.string()
9071
9083
  }, async ({ id }) => {
9072
9084
  try {
9073
9085
  const { deleteWebhook: deleteWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -9078,13 +9090,13 @@ ${text}` }] };
9078
9090
  }
9079
9091
  });
9080
9092
  server.tool("create_template", "Create a reusable task template.", {
9081
- name: exports_external.string().describe("Template name"),
9082
- title_pattern: exports_external.string().describe("Title pattern for tasks created from this template"),
9083
- description: exports_external.string().optional().describe("Default description"),
9084
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default priority"),
9085
- tags: exports_external.array(exports_external.string()).optional().describe("Default tags"),
9086
- project_id: exports_external.string().optional().describe("Default project"),
9087
- plan_id: exports_external.string().optional().describe("Default plan")
9093
+ name: exports_external.string(),
9094
+ title_pattern: exports_external.string(),
9095
+ description: exports_external.string().optional(),
9096
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
9097
+ tags: exports_external.array(exports_external.string()).optional(),
9098
+ project_id: exports_external.string().optional(),
9099
+ plan_id: exports_external.string().optional()
9088
9100
  }, async (params) => {
9089
9101
  try {
9090
9102
  const { createTemplate: createTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -9109,12 +9121,12 @@ ${text}` }] };
9109
9121
  }
9110
9122
  });
9111
9123
  server.tool("create_task_from_template", "Create a task from a template with optional overrides.", {
9112
- template_id: exports_external.string().describe("Template ID"),
9113
- title: exports_external.string().optional().describe("Override title"),
9114
- description: exports_external.string().optional().describe("Override description"),
9115
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Override priority"),
9116
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
9117
- project_id: exports_external.string().optional().describe("Override project")
9124
+ template_id: exports_external.string(),
9125
+ title: exports_external.string().optional(),
9126
+ description: exports_external.string().optional(),
9127
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
9128
+ assigned_to: exports_external.string().optional(),
9129
+ project_id: exports_external.string().optional()
9118
9130
  }, async (params) => {
9119
9131
  try {
9120
9132
  const { taskFromTemplate: taskFromTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -9132,7 +9144,7 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9132
9144
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9133
9145
  }
9134
9146
  });
9135
- server.tool("delete_template", "Delete a task template", { id: exports_external.string().describe("Template ID") }, async ({ id }) => {
9147
+ server.tool("delete_template", "Delete a task template", { id: exports_external.string() }, async ({ id }) => {
9136
9148
  try {
9137
9149
  const { deleteTemplate: deleteTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
9138
9150
  const deleted = deleteTemplate2(id);
@@ -9142,8 +9154,8 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9142
9154
  }
9143
9155
  });
9144
9156
  server.tool("approve_task", "Approve a task that requires approval.", {
9145
- id: exports_external.string().describe("Task ID (full or partial)"),
9146
- agent_id: exports_external.string().optional().describe("Agent approving the task")
9157
+ id: exports_external.string(),
9158
+ agent_id: exports_external.string().optional()
9147
9159
  }, async ({ id, agent_id }) => {
9148
9160
  try {
9149
9161
  const resolvedId = resolveId(id);
@@ -9161,7 +9173,7 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
9161
9173
  }
9162
9174
  });
9163
9175
  server.tool("get_my_tasks", "Get assigned tasks and stats for an agent.", {
9164
- agent_name: exports_external.string().describe("Your agent name")
9176
+ agent_name: exports_external.string()
9165
9177
  }, async ({ agent_name }) => {
9166
9178
  try {
9167
9179
  const agent = registerAgent({ name: agent_name });
@@ -9193,7 +9205,7 @@ In Progress:`);
9193
9205
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9194
9206
  }
9195
9207
  });
9196
- server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional().describe("Keyword to filter tools") }, async ({ query }) => {
9208
+ server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
9197
9209
  const all = [
9198
9210
  "create_task",
9199
9211
  "list_tasks",
@@ -9242,7 +9254,7 @@ In Progress:`);
9242
9254
  const matches = q ? all.filter((n) => n.includes(q)) : all;
9243
9255
  return { content: [{ type: "text", text: matches.join(", ") }] };
9244
9256
  });
9245
- server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()).describe("Tool names from search_tools") }, async ({ names }) => {
9257
+ server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()) }, async ({ names }) => {
9246
9258
  const descriptions = {
9247
9259
  create_task: "Create a task. Params: title(req), description, priority, project_id, plan_id, tags, assigned_to, estimated_minutes, requires_approval",
9248
9260
  list_tasks: "List tasks. Params: status, priority, project_id, plan_id, assigned_to, tags, limit",
package/dist/index.js CHANGED
@@ -1115,7 +1115,18 @@ function updateTask(id, input, db) {
1115
1115
  logTaskChange(id, "update", "assigned_to", task.assigned_to, input.assigned_to, agentId, d);
1116
1116
  if (input.approved_by !== undefined)
1117
1117
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
1118
- return getTask(id, d);
1118
+ return {
1119
+ ...task,
1120
+ ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
1121
+ tags: input.tags ?? task.tags,
1122
+ metadata: input.metadata ?? task.metadata,
1123
+ version: task.version + 1,
1124
+ updated_at: now(),
1125
+ completed_at: input.status === "completed" ? now() : task.completed_at,
1126
+ requires_approval: input.requires_approval !== undefined ? input.requires_approval : task.requires_approval,
1127
+ approved_by: input.approved_by ?? task.approved_by,
1128
+ approved_at: input.approved_by ? now() : task.approved_at
1129
+ };
1119
1130
  }
1120
1131
  function deleteTask(id, db) {
1121
1132
  const d = db || getDatabase();
@@ -1137,6 +1148,9 @@ function getBlockingDeps(id, db) {
1137
1148
  }
1138
1149
  function startTask(id, agentId, db) {
1139
1150
  const d = db || getDatabase();
1151
+ const task = getTask(id, d);
1152
+ if (!task)
1153
+ throw new TaskNotFoundError(id);
1140
1154
  const blocking = getBlockingDeps(id, d);
1141
1155
  if (blocking.length > 0) {
1142
1156
  const blockerIds = blocking.map((b) => b.id.slice(0, 8)).join(", ");
@@ -1147,15 +1161,12 @@ function startTask(id, agentId, db) {
1147
1161
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
1148
1162
  WHERE id = ? AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, id, agentId, cutoff]);
1149
1163
  if (result.changes === 0) {
1150
- const current = getTask(id, d);
1151
- if (!current)
1152
- throw new TaskNotFoundError(id);
1153
- if (current.locked_by && current.locked_by !== agentId && !isLockExpired(current.locked_at)) {
1154
- throw new LockError(id, current.locked_by);
1164
+ if (task.locked_by && task.locked_by !== agentId && !isLockExpired(task.locked_at)) {
1165
+ throw new LockError(id, task.locked_by);
1155
1166
  }
1156
1167
  }
1157
1168
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
1158
- return getTask(id, d);
1169
+ return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, version: task.version + 1, updated_at: timestamp };
1159
1170
  }
1160
1171
  function completeTask(id, agentId, db, evidence) {
1161
1172
  const d = db || getDatabase();
@@ -1167,14 +1178,15 @@ function completeTask(id, agentId, db, evidence) {
1167
1178
  }
1168
1179
  checkCompletionGuard(task, agentId || null, d);
1169
1180
  if (evidence) {
1170
- const meta = { ...task.metadata, _evidence: evidence };
1171
- d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta), id]);
1181
+ const meta2 = { ...task.metadata, _evidence: evidence };
1182
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta2), id]);
1172
1183
  }
1173
1184
  const timestamp = now();
1174
1185
  d.run(`UPDATE tasks SET status = 'completed', locked_by = NULL, locked_at = NULL, completed_at = ?, version = version + 1, updated_at = ?
1175
1186
  WHERE id = ?`, [timestamp, timestamp, id]);
1176
1187
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
1177
- return getTask(id, d);
1188
+ const meta = evidence ? { ...task.metadata, _evidence: evidence } : task.metadata;
1189
+ return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, version: task.version + 1, updated_at: timestamp, metadata: meta };
1178
1190
  }
1179
1191
  function lockTask(id, agentId, db) {
1180
1192
  const d = db || getDatabase();
package/dist/mcp/index.js CHANGED
@@ -5154,7 +5154,18 @@ function updateTask(id, input, db) {
5154
5154
  logTaskChange(id, "update", "assigned_to", task.assigned_to, input.assigned_to, agentId, d);
5155
5155
  if (input.approved_by !== undefined)
5156
5156
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
5157
- return getTask(id, d);
5157
+ return {
5158
+ ...task,
5159
+ ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
5160
+ tags: input.tags ?? task.tags,
5161
+ metadata: input.metadata ?? task.metadata,
5162
+ version: task.version + 1,
5163
+ updated_at: now(),
5164
+ completed_at: input.status === "completed" ? now() : task.completed_at,
5165
+ requires_approval: input.requires_approval !== undefined ? input.requires_approval : task.requires_approval,
5166
+ approved_by: input.approved_by ?? task.approved_by,
5167
+ approved_at: input.approved_by ? now() : task.approved_at
5168
+ };
5158
5169
  }
5159
5170
  function deleteTask(id, db) {
5160
5171
  const d = db || getDatabase();
@@ -5176,6 +5187,9 @@ function getBlockingDeps(id, db) {
5176
5187
  }
5177
5188
  function startTask(id, agentId, db) {
5178
5189
  const d = db || getDatabase();
5190
+ const task = getTask(id, d);
5191
+ if (!task)
5192
+ throw new TaskNotFoundError(id);
5179
5193
  const blocking = getBlockingDeps(id, d);
5180
5194
  if (blocking.length > 0) {
5181
5195
  const blockerIds = blocking.map((b) => b.id.slice(0, 8)).join(", ");
@@ -5186,15 +5200,12 @@ function startTask(id, agentId, db) {
5186
5200
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
5187
5201
  WHERE id = ? AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, id, agentId, cutoff]);
5188
5202
  if (result.changes === 0) {
5189
- const current = getTask(id, d);
5190
- if (!current)
5191
- throw new TaskNotFoundError(id);
5192
- if (current.locked_by && current.locked_by !== agentId && !isLockExpired(current.locked_at)) {
5193
- throw new LockError(id, current.locked_by);
5203
+ if (task.locked_by && task.locked_by !== agentId && !isLockExpired(task.locked_at)) {
5204
+ throw new LockError(id, task.locked_by);
5194
5205
  }
5195
5206
  }
5196
5207
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
5197
- return getTask(id, d);
5208
+ return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, version: task.version + 1, updated_at: timestamp };
5198
5209
  }
5199
5210
  function completeTask(id, agentId, db, evidence) {
5200
5211
  const d = db || getDatabase();
@@ -5206,14 +5217,15 @@ function completeTask(id, agentId, db, evidence) {
5206
5217
  }
5207
5218
  checkCompletionGuard(task, agentId || null, d);
5208
5219
  if (evidence) {
5209
- const meta = { ...task.metadata, _evidence: evidence };
5210
- d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta), id]);
5220
+ const meta2 = { ...task.metadata, _evidence: evidence };
5221
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta2), id]);
5211
5222
  }
5212
5223
  const timestamp = now();
5213
5224
  d.run(`UPDATE tasks SET status = 'completed', locked_by = NULL, locked_at = NULL, completed_at = ?, version = version + 1, updated_at = ?
5214
5225
  WHERE id = ?`, [timestamp, timestamp, id]);
5215
5226
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
5216
- return getTask(id, d);
5227
+ const meta = evidence ? { ...task.metadata, _evidence: evidence } : task.metadata;
5228
+ return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, version: task.version + 1, updated_at: timestamp, metadata: meta };
5217
5229
  }
5218
5230
  function lockTask(id, agentId, db) {
5219
5231
  const d = db || getDatabase();
@@ -6129,22 +6141,22 @@ function formatTaskDetail(task) {
6129
6141
  `);
6130
6142
  }
6131
6143
  server.tool("create_task", "Create a new task", {
6132
- title: exports_external.string().describe("Task title"),
6133
- description: exports_external.string().optional().describe("Task description"),
6134
- project_id: exports_external.string().optional().describe("Project ID"),
6135
- parent_id: exports_external.string().optional().describe("Parent task ID (for subtasks)"),
6136
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Task priority"),
6137
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("Initial status"),
6138
- agent_id: exports_external.string().optional().describe("Creator agent ID"),
6139
- assigned_to: exports_external.string().optional().describe("Assigned agent ID"),
6140
- session_id: exports_external.string().optional().describe("Session ID"),
6141
- working_dir: exports_external.string().optional().describe("Working directory context"),
6142
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
6143
- task_list_id: exports_external.string().optional().describe("Task list ID to assign task to"),
6144
- tags: exports_external.array(exports_external.string()).optional().describe("Task tags"),
6145
- metadata: exports_external.record(exports_external.unknown()).optional().describe("Arbitrary metadata"),
6146
- estimated_minutes: exports_external.number().optional().describe("Estimated time in minutes"),
6147
- requires_approval: exports_external.boolean().optional().describe("Require approval before completion")
6144
+ title: exports_external.string(),
6145
+ description: exports_external.string().optional(),
6146
+ project_id: exports_external.string().optional(),
6147
+ parent_id: exports_external.string().optional(),
6148
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
6149
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
6150
+ agent_id: exports_external.string().optional(),
6151
+ assigned_to: exports_external.string().optional(),
6152
+ session_id: exports_external.string().optional(),
6153
+ working_dir: exports_external.string().optional(),
6154
+ plan_id: exports_external.string().optional(),
6155
+ task_list_id: exports_external.string().optional(),
6156
+ tags: exports_external.array(exports_external.string()).optional(),
6157
+ metadata: exports_external.record(exports_external.unknown()).optional(),
6158
+ estimated_minutes: exports_external.number().optional(),
6159
+ requires_approval: exports_external.boolean().optional()
6148
6160
  }, async (params) => {
6149
6161
  try {
6150
6162
  const resolved = { ...params };
@@ -6163,19 +6175,19 @@ server.tool("create_task", "Create a new task", {
6163
6175
  }
6164
6176
  });
6165
6177
  server.tool("list_tasks", "List tasks with optional filters", {
6166
- project_id: exports_external.string().optional().describe("Filter by project"),
6178
+ project_id: exports_external.string().optional(),
6167
6179
  status: exports_external.union([
6168
6180
  exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]),
6169
6181
  exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]))
6170
- ]).optional().describe("Filter by status"),
6182
+ ]).optional(),
6171
6183
  priority: exports_external.union([
6172
6184
  exports_external.enum(["low", "medium", "high", "critical"]),
6173
6185
  exports_external.array(exports_external.enum(["low", "medium", "high", "critical"]))
6174
- ]).optional().describe("Filter by priority"),
6175
- assigned_to: exports_external.string().optional().describe("Filter by assigned agent"),
6176
- tags: exports_external.array(exports_external.string()).optional().describe("Filter by tags (any match)"),
6177
- plan_id: exports_external.string().optional().describe("Filter by plan"),
6178
- task_list_id: exports_external.string().optional().describe("Filter by task list")
6186
+ ]).optional(),
6187
+ assigned_to: exports_external.string().optional(),
6188
+ tags: exports_external.array(exports_external.string()).optional(),
6189
+ plan_id: exports_external.string().optional(),
6190
+ task_list_id: exports_external.string().optional()
6179
6191
  }, async (params) => {
6180
6192
  try {
6181
6193
  const resolved = { ...params };
@@ -6202,7 +6214,7 @@ ${text}` }] };
6202
6214
  }
6203
6215
  });
6204
6216
  server.tool("get_task", "Get full task details with relations", {
6205
- id: exports_external.string().describe("Task ID (full or partial)")
6217
+ id: exports_external.string()
6206
6218
  }, async ({ id }) => {
6207
6219
  try {
6208
6220
  const resolvedId = resolveId(id);
@@ -6250,17 +6262,17 @@ Parent: ${task.parent.id.slice(0, 8)} | ${task.parent.title}`);
6250
6262
  }
6251
6263
  });
6252
6264
  server.tool("update_task", "Update task fields. Version required for optimistic locking.", {
6253
- id: exports_external.string().describe("Task ID (full or partial)"),
6254
- version: exports_external.number().describe("Current version (for optimistic locking)"),
6255
- title: exports_external.string().optional().describe("New title"),
6256
- description: exports_external.string().optional().describe("New description"),
6257
- status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional().describe("New status"),
6258
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("New priority"),
6259
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
6260
- tags: exports_external.array(exports_external.string()).optional().describe("New tags"),
6261
- metadata: exports_external.record(exports_external.unknown()).optional().describe("New metadata"),
6262
- plan_id: exports_external.string().optional().describe("Plan ID to assign task to"),
6263
- task_list_id: exports_external.string().optional().describe("Task list ID")
6265
+ id: exports_external.string(),
6266
+ version: exports_external.number(),
6267
+ title: exports_external.string().optional(),
6268
+ description: exports_external.string().optional(),
6269
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
6270
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
6271
+ assigned_to: exports_external.string().optional(),
6272
+ tags: exports_external.array(exports_external.string()).optional(),
6273
+ metadata: exports_external.record(exports_external.unknown()).optional(),
6274
+ plan_id: exports_external.string().optional(),
6275
+ task_list_id: exports_external.string().optional()
6264
6276
  }, async ({ id, ...rest }) => {
6265
6277
  try {
6266
6278
  const resolvedId = resolveId(id);
@@ -6271,7 +6283,7 @@ server.tool("update_task", "Update task fields. Version required for optimistic
6271
6283
  }
6272
6284
  });
6273
6285
  server.tool("delete_task", "Delete a task permanently", {
6274
- id: exports_external.string().describe("Task ID (full or partial)")
6286
+ id: exports_external.string()
6275
6287
  }, async ({ id }) => {
6276
6288
  try {
6277
6289
  const resolvedId = resolveId(id);
@@ -6287,8 +6299,8 @@ server.tool("delete_task", "Delete a task permanently", {
6287
6299
  }
6288
6300
  });
6289
6301
  server.tool("start_task", "Claim, lock, and set task status to in_progress.", {
6290
- id: exports_external.string().describe("Task ID (full or partial)"),
6291
- agent_id: exports_external.string().describe("Agent claiming the task")
6302
+ id: exports_external.string(),
6303
+ agent_id: exports_external.string()
6292
6304
  }, async ({ id, agent_id }) => {
6293
6305
  try {
6294
6306
  const resolvedId = resolveId(id);
@@ -6299,8 +6311,8 @@ server.tool("start_task", "Claim, lock, and set task status to in_progress.", {
6299
6311
  }
6300
6312
  });
6301
6313
  server.tool("complete_task", "Mark task completed and release lock.", {
6302
- id: exports_external.string().describe("Task ID (full or partial)"),
6303
- agent_id: exports_external.string().optional().describe("Agent completing the task")
6314
+ id: exports_external.string(),
6315
+ agent_id: exports_external.string().optional()
6304
6316
  }, async ({ id, agent_id }) => {
6305
6317
  try {
6306
6318
  const resolvedId = resolveId(id);
@@ -6311,8 +6323,8 @@ server.tool("complete_task", "Mark task completed and release lock.", {
6311
6323
  }
6312
6324
  });
6313
6325
  server.tool("lock_task", "Acquire exclusive lock on a task", {
6314
- id: exports_external.string().describe("Task ID (full or partial)"),
6315
- agent_id: exports_external.string().describe("Agent acquiring lock")
6326
+ id: exports_external.string(),
6327
+ agent_id: exports_external.string()
6316
6328
  }, async ({ id, agent_id }) => {
6317
6329
  try {
6318
6330
  const resolvedId = resolveId(id);
@@ -6326,8 +6338,8 @@ server.tool("lock_task", "Acquire exclusive lock on a task", {
6326
6338
  }
6327
6339
  });
6328
6340
  server.tool("unlock_task", "Release exclusive lock on a task", {
6329
- id: exports_external.string().describe("Task ID (full or partial)"),
6330
- agent_id: exports_external.string().optional().describe("Agent releasing lock (omit to force)")
6341
+ id: exports_external.string(),
6342
+ agent_id: exports_external.string().optional()
6331
6343
  }, async ({ id, agent_id }) => {
6332
6344
  try {
6333
6345
  const resolvedId = resolveId(id);
@@ -6338,8 +6350,8 @@ server.tool("unlock_task", "Release exclusive lock on a task", {
6338
6350
  }
6339
6351
  });
6340
6352
  server.tool("add_dependency", "Add a dependency: task_id depends on depends_on.", {
6341
- task_id: exports_external.string().describe("Task that depends on another"),
6342
- depends_on: exports_external.string().describe("Task that must complete first")
6353
+ task_id: exports_external.string(),
6354
+ depends_on: exports_external.string()
6343
6355
  }, async ({ task_id, depends_on }) => {
6344
6356
  try {
6345
6357
  const resolvedTaskId = resolveId(task_id);
@@ -6351,8 +6363,8 @@ server.tool("add_dependency", "Add a dependency: task_id depends on depends_on."
6351
6363
  }
6352
6364
  });
6353
6365
  server.tool("remove_dependency", "Remove a dependency between tasks", {
6354
- task_id: exports_external.string().describe("Task ID"),
6355
- depends_on: exports_external.string().describe("Dependency to remove")
6366
+ task_id: exports_external.string(),
6367
+ depends_on: exports_external.string()
6356
6368
  }, async ({ task_id, depends_on }) => {
6357
6369
  try {
6358
6370
  const resolvedTaskId = resolveId(task_id);
@@ -6369,10 +6381,10 @@ server.tool("remove_dependency", "Remove a dependency between tasks", {
6369
6381
  }
6370
6382
  });
6371
6383
  server.tool("add_comment", "Add a comment/note to a task", {
6372
- task_id: exports_external.string().describe("Task ID (full or partial)"),
6373
- content: exports_external.string().describe("Comment content"),
6374
- agent_id: exports_external.string().optional().describe("Agent adding comment"),
6375
- session_id: exports_external.string().optional().describe("Session ID")
6384
+ task_id: exports_external.string(),
6385
+ content: exports_external.string(),
6386
+ agent_id: exports_external.string().optional(),
6387
+ session_id: exports_external.string().optional()
6376
6388
  }, async ({ task_id, ...rest }) => {
6377
6389
  try {
6378
6390
  const resolvedId = resolveId(task_id);
@@ -6400,10 +6412,10 @@ ${text}` }] };
6400
6412
  }
6401
6413
  });
6402
6414
  server.tool("create_project", "Register a new project", {
6403
- name: exports_external.string().describe("Project name"),
6404
- path: exports_external.string().describe("Absolute path to project"),
6405
- description: exports_external.string().optional().describe("Project description"),
6406
- task_list_id: exports_external.string().optional().describe("Custom task list ID for Claude Code sync (defaults to todos-<slugified-name>)")
6415
+ name: exports_external.string(),
6416
+ path: exports_external.string(),
6417
+ description: exports_external.string().optional(),
6418
+ task_list_id: exports_external.string().optional()
6407
6419
  }, async (params) => {
6408
6420
  try {
6409
6421
  const project = createProject(params);
@@ -6419,12 +6431,12 @@ server.tool("create_project", "Register a new project", {
6419
6431
  }
6420
6432
  });
6421
6433
  server.tool("create_plan", "Create a new plan", {
6422
- name: exports_external.string().describe("Plan name"),
6423
- project_id: exports_external.string().optional().describe("Project ID"),
6424
- description: exports_external.string().optional().describe("Plan description"),
6425
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("Plan status"),
6426
- task_list_id: exports_external.string().optional().describe("Task list ID"),
6427
- agent_id: exports_external.string().optional().describe("Owner agent ID")
6434
+ name: exports_external.string(),
6435
+ project_id: exports_external.string().optional(),
6436
+ description: exports_external.string().optional(),
6437
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
6438
+ task_list_id: exports_external.string().optional(),
6439
+ agent_id: exports_external.string().optional()
6428
6440
  }, async (params) => {
6429
6441
  try {
6430
6442
  const resolved = { ...params };
@@ -6444,7 +6456,7 @@ server.tool("create_plan", "Create a new plan", {
6444
6456
  }
6445
6457
  });
6446
6458
  server.tool("list_plans", "List plans with optional project filter", {
6447
- project_id: exports_external.string().optional().describe("Filter by project")
6459
+ project_id: exports_external.string().optional()
6448
6460
  }, async ({ project_id }) => {
6449
6461
  try {
6450
6462
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -6464,7 +6476,7 @@ ${text}` }] };
6464
6476
  }
6465
6477
  });
6466
6478
  server.tool("get_plan", "Get plan details", {
6467
- id: exports_external.string().describe("Plan ID (full or partial)")
6479
+ id: exports_external.string()
6468
6480
  }, async ({ id }) => {
6469
6481
  try {
6470
6482
  const resolvedId = resolveId(id, "plans");
@@ -6489,12 +6501,12 @@ server.tool("get_plan", "Get plan details", {
6489
6501
  }
6490
6502
  });
6491
6503
  server.tool("update_plan", "Update a plan", {
6492
- id: exports_external.string().describe("Plan ID (full or partial)"),
6493
- name: exports_external.string().optional().describe("New name"),
6494
- description: exports_external.string().optional().describe("New description"),
6495
- status: exports_external.enum(["active", "completed", "archived"]).optional().describe("New status"),
6496
- task_list_id: exports_external.string().optional().describe("Task list ID"),
6497
- agent_id: exports_external.string().optional().describe("Owner agent ID")
6504
+ id: exports_external.string(),
6505
+ name: exports_external.string().optional(),
6506
+ description: exports_external.string().optional(),
6507
+ status: exports_external.enum(["active", "completed", "archived"]).optional(),
6508
+ task_list_id: exports_external.string().optional(),
6509
+ agent_id: exports_external.string().optional()
6498
6510
  }, async ({ id, ...rest }) => {
6499
6511
  try {
6500
6512
  const resolvedId = resolveId(id, "plans");
@@ -6513,7 +6525,7 @@ server.tool("update_plan", "Update a plan", {
6513
6525
  }
6514
6526
  });
6515
6527
  server.tool("delete_plan", "Delete a plan", {
6516
- id: exports_external.string().describe("Plan ID (full or partial)")
6528
+ id: exports_external.string()
6517
6529
  }, async ({ id }) => {
6518
6530
  try {
6519
6531
  const resolvedId = resolveId(id, "plans");
@@ -6529,9 +6541,9 @@ server.tool("delete_plan", "Delete a plan", {
6529
6541
  }
6530
6542
  });
6531
6543
  server.tool("search_tasks", "Full-text search across task titles, descriptions, tags.", {
6532
- query: exports_external.string().describe("Search query"),
6533
- project_id: exports_external.string().optional().describe("Limit to project"),
6534
- task_list_id: exports_external.string().optional().describe("Filter by task list")
6544
+ query: exports_external.string(),
6545
+ project_id: exports_external.string().optional(),
6546
+ task_list_id: exports_external.string().optional()
6535
6547
  }, async ({ query, project_id, task_list_id }) => {
6536
6548
  try {
6537
6549
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -6549,12 +6561,12 @@ ${text}` }] };
6549
6561
  }
6550
6562
  });
6551
6563
  server.tool("sync", "Sync tasks with an agent task list.", {
6552
- task_list_id: exports_external.string().optional().describe("Task list ID (required for Claude)"),
6553
- agent: exports_external.string().optional().describe("Agent/provider name (default: claude)"),
6554
- all_agents: exports_external.boolean().optional().describe("Sync across all configured agents"),
6555
- project_id: exports_external.string().optional().describe("Project ID \u2014 its task_list_id will be used for Claude if task_list_id is not provided"),
6556
- direction: exports_external.enum(["push", "pull", "both"]).optional().describe("Sync direction: push (SQLite->agent), pull (agent->SQLite), or both (default)"),
6557
- prefer: exports_external.enum(["local", "remote"]).optional().describe("Conflict strategy")
6564
+ task_list_id: exports_external.string().optional(),
6565
+ agent: exports_external.string().optional(),
6566
+ all_agents: exports_external.boolean().optional(),
6567
+ project_id: exports_external.string().optional(),
6568
+ direction: exports_external.enum(["push", "pull", "both"]).optional(),
6569
+ prefer: exports_external.enum(["local", "remote"]).optional()
6558
6570
  }, async ({ task_list_id, agent, all_agents, project_id, direction, prefer }) => {
6559
6571
  try {
6560
6572
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -6597,8 +6609,8 @@ server.tool("sync", "Sync tasks with an agent task list.", {
6597
6609
  }
6598
6610
  });
6599
6611
  server.tool("register_agent", "Register an agent (idempotent by name).", {
6600
- name: exports_external.string().describe("Agent name"),
6601
- description: exports_external.string().optional().describe("Agent description")
6612
+ name: exports_external.string(),
6613
+ description: exports_external.string().optional()
6602
6614
  }, async ({ name, description }) => {
6603
6615
  try {
6604
6616
  const agent = registerAgent({ name, description });
@@ -6634,8 +6646,8 @@ ${text}` }] };
6634
6646
  }
6635
6647
  });
6636
6648
  server.tool("get_agent", "Get agent details by ID or name", {
6637
- id: exports_external.string().optional().describe("Agent ID"),
6638
- name: exports_external.string().optional().describe("Agent name")
6649
+ id: exports_external.string().optional(),
6650
+ name: exports_external.string().optional()
6639
6651
  }, async ({ id, name }) => {
6640
6652
  try {
6641
6653
  if (!id && !name) {
@@ -6662,10 +6674,10 @@ server.tool("get_agent", "Get agent details by ID or name", {
6662
6674
  }
6663
6675
  });
6664
6676
  server.tool("create_task_list", "Create a new task list", {
6665
- name: exports_external.string().describe("Task list name"),
6666
- slug: exports_external.string().optional().describe("URL-friendly slug (auto-generated from name if omitted)"),
6667
- project_id: exports_external.string().optional().describe("Project ID to associate with"),
6668
- description: exports_external.string().optional().describe("Task list description")
6677
+ name: exports_external.string(),
6678
+ slug: exports_external.string().optional(),
6679
+ project_id: exports_external.string().optional(),
6680
+ description: exports_external.string().optional()
6669
6681
  }, async (params) => {
6670
6682
  try {
6671
6683
  const resolved = { ...params };
@@ -6688,7 +6700,7 @@ Description: ${list.description}` : ""}`
6688
6700
  }
6689
6701
  });
6690
6702
  server.tool("list_task_lists", "List task lists, optionally filtered by project", {
6691
- project_id: exports_external.string().optional().describe("Filter by project")
6703
+ project_id: exports_external.string().optional()
6692
6704
  }, async ({ project_id }) => {
6693
6705
  try {
6694
6706
  const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
@@ -6708,7 +6720,7 @@ ${text}` }] };
6708
6720
  }
6709
6721
  });
6710
6722
  server.tool("get_task_list", "Get task list details", {
6711
- id: exports_external.string().describe("Task list ID (full or partial)")
6723
+ id: exports_external.string()
6712
6724
  }, async ({ id }) => {
6713
6725
  try {
6714
6726
  const resolvedId = resolveId(id, "task_lists");
@@ -6736,9 +6748,9 @@ server.tool("get_task_list", "Get task list details", {
6736
6748
  }
6737
6749
  });
6738
6750
  server.tool("update_task_list", "Update a task list", {
6739
- id: exports_external.string().describe("Task list ID (full or partial)"),
6740
- name: exports_external.string().optional().describe("New name"),
6741
- description: exports_external.string().optional().describe("New description")
6751
+ id: exports_external.string(),
6752
+ name: exports_external.string().optional(),
6753
+ description: exports_external.string().optional()
6742
6754
  }, async ({ id, ...rest }) => {
6743
6755
  try {
6744
6756
  const resolvedId = resolveId(id, "task_lists");
@@ -6757,7 +6769,7 @@ Slug: ${list.slug}`
6757
6769
  }
6758
6770
  });
6759
6771
  server.tool("delete_task_list", "Delete a task list. Tasks lose association but keep data.", {
6760
- id: exports_external.string().describe("Task list ID (full or partial)")
6772
+ id: exports_external.string()
6761
6773
  }, async ({ id }) => {
6762
6774
  try {
6763
6775
  const resolvedId = resolveId(id, "task_lists");
@@ -6773,7 +6785,7 @@ server.tool("delete_task_list", "Delete a task list. Tasks lose association but
6773
6785
  }
6774
6786
  });
6775
6787
  server.tool("get_task_history", "Get audit log for a task.", {
6776
- task_id: exports_external.string().describe("Task ID (full or partial)")
6788
+ task_id: exports_external.string()
6777
6789
  }, async ({ task_id }) => {
6778
6790
  try {
6779
6791
  const resolvedId = resolveId(task_id);
@@ -6790,7 +6802,7 @@ ${text}` }] };
6790
6802
  }
6791
6803
  });
6792
6804
  server.tool("get_recent_activity", "Get recent task changes across all tasks.", {
6793
- limit: exports_external.number().optional().describe("Max entries (default 50)")
6805
+ limit: exports_external.number().optional()
6794
6806
  }, async ({ limit }) => {
6795
6807
  try {
6796
6808
  const { getRecentActivity: getRecentActivity2 } = await Promise.resolve().then(() => (init_audit(), exports_audit));
@@ -6806,9 +6818,9 @@ ${text}` }] };
6806
6818
  }
6807
6819
  });
6808
6820
  server.tool("create_webhook", "Register a webhook to receive task change events.", {
6809
- url: exports_external.string().describe("Webhook URL"),
6810
- events: exports_external.array(exports_external.string()).optional().describe("Event types to subscribe to (empty = all)"),
6811
- secret: exports_external.string().optional().describe("HMAC secret for signature verification")
6821
+ url: exports_external.string(),
6822
+ events: exports_external.array(exports_external.string()).optional(),
6823
+ secret: exports_external.string().optional()
6812
6824
  }, async (params) => {
6813
6825
  try {
6814
6826
  const { createWebhook: createWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -6833,7 +6845,7 @@ ${text}` }] };
6833
6845
  }
6834
6846
  });
6835
6847
  server.tool("delete_webhook", "Delete a webhook", {
6836
- id: exports_external.string().describe("Webhook ID")
6848
+ id: exports_external.string()
6837
6849
  }, async ({ id }) => {
6838
6850
  try {
6839
6851
  const { deleteWebhook: deleteWebhook2 } = await Promise.resolve().then(() => (init_webhooks(), exports_webhooks));
@@ -6844,13 +6856,13 @@ server.tool("delete_webhook", "Delete a webhook", {
6844
6856
  }
6845
6857
  });
6846
6858
  server.tool("create_template", "Create a reusable task template.", {
6847
- name: exports_external.string().describe("Template name"),
6848
- title_pattern: exports_external.string().describe("Title pattern for tasks created from this template"),
6849
- description: exports_external.string().optional().describe("Default description"),
6850
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default priority"),
6851
- tags: exports_external.array(exports_external.string()).optional().describe("Default tags"),
6852
- project_id: exports_external.string().optional().describe("Default project"),
6853
- plan_id: exports_external.string().optional().describe("Default plan")
6859
+ name: exports_external.string(),
6860
+ title_pattern: exports_external.string(),
6861
+ description: exports_external.string().optional(),
6862
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
6863
+ tags: exports_external.array(exports_external.string()).optional(),
6864
+ project_id: exports_external.string().optional(),
6865
+ plan_id: exports_external.string().optional()
6854
6866
  }, async (params) => {
6855
6867
  try {
6856
6868
  const { createTemplate: createTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -6875,12 +6887,12 @@ ${text}` }] };
6875
6887
  }
6876
6888
  });
6877
6889
  server.tool("create_task_from_template", "Create a task from a template with optional overrides.", {
6878
- template_id: exports_external.string().describe("Template ID"),
6879
- title: exports_external.string().optional().describe("Override title"),
6880
- description: exports_external.string().optional().describe("Override description"),
6881
- priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Override priority"),
6882
- assigned_to: exports_external.string().optional().describe("Assign to agent"),
6883
- project_id: exports_external.string().optional().describe("Override project")
6890
+ template_id: exports_external.string(),
6891
+ title: exports_external.string().optional(),
6892
+ description: exports_external.string().optional(),
6893
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
6894
+ assigned_to: exports_external.string().optional(),
6895
+ project_id: exports_external.string().optional()
6884
6896
  }, async (params) => {
6885
6897
  try {
6886
6898
  const { taskFromTemplate: taskFromTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
@@ -6898,7 +6910,7 @@ ${task.id.slice(0, 8)} | ${task.priority} | ${task.title}` }] };
6898
6910
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6899
6911
  }
6900
6912
  });
6901
- server.tool("delete_template", "Delete a task template", { id: exports_external.string().describe("Template ID") }, async ({ id }) => {
6913
+ server.tool("delete_template", "Delete a task template", { id: exports_external.string() }, async ({ id }) => {
6902
6914
  try {
6903
6915
  const { deleteTemplate: deleteTemplate2 } = await Promise.resolve().then(() => (init_templates(), exports_templates));
6904
6916
  const deleted = deleteTemplate2(id);
@@ -6908,8 +6920,8 @@ server.tool("delete_template", "Delete a task template", { id: exports_external.
6908
6920
  }
6909
6921
  });
6910
6922
  server.tool("approve_task", "Approve a task that requires approval.", {
6911
- id: exports_external.string().describe("Task ID (full or partial)"),
6912
- agent_id: exports_external.string().optional().describe("Agent approving the task")
6923
+ id: exports_external.string(),
6924
+ agent_id: exports_external.string().optional()
6913
6925
  }, async ({ id, agent_id }) => {
6914
6926
  try {
6915
6927
  const resolvedId = resolveId(id);
@@ -6927,7 +6939,7 @@ server.tool("approve_task", "Approve a task that requires approval.", {
6927
6939
  }
6928
6940
  });
6929
6941
  server.tool("get_my_tasks", "Get assigned tasks and stats for an agent.", {
6930
- agent_name: exports_external.string().describe("Your agent name")
6942
+ agent_name: exports_external.string()
6931
6943
  }, async ({ agent_name }) => {
6932
6944
  try {
6933
6945
  const agent = registerAgent({ name: agent_name });
@@ -6959,7 +6971,7 @@ In Progress:`);
6959
6971
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6960
6972
  }
6961
6973
  });
6962
- server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional().describe("Keyword to filter tools") }, async ({ query }) => {
6974
+ server.tool("search_tools", "List tool names matching a query.", { query: exports_external.string().optional() }, async ({ query }) => {
6963
6975
  const all = [
6964
6976
  "create_task",
6965
6977
  "list_tasks",
@@ -7008,7 +7020,7 @@ server.tool("search_tools", "List tool names matching a query.", { query: export
7008
7020
  const matches = q ? all.filter((n) => n.includes(q)) : all;
7009
7021
  return { content: [{ type: "text", text: matches.join(", ") }] };
7010
7022
  });
7011
- server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()).describe("Tool names from search_tools") }, async ({ names }) => {
7023
+ server.tool("describe_tools", "Get descriptions for specific tools by name.", { names: exports_external.array(exports_external.string()) }, async ({ names }) => {
7012
7024
  const descriptions = {
7013
7025
  create_task: "Create a task. Params: title(req), description, priority, project_id, plan_id, tags, assigned_to, estimated_minutes, requires_approval",
7014
7026
  list_tasks: "List tasks. Params: status, priority, project_id, plan_id, assigned_to, tags, limit",
@@ -1233,7 +1233,18 @@ function updateTask(id, input, db) {
1233
1233
  logTaskChange(id, "update", "assigned_to", task.assigned_to, input.assigned_to, agentId, d);
1234
1234
  if (input.approved_by !== undefined)
1235
1235
  logTaskChange(id, "approve", "approved_by", null, input.approved_by, agentId, d);
1236
- return getTask(id, d);
1236
+ return {
1237
+ ...task,
1238
+ ...Object.fromEntries(Object.entries(input).filter(([, v]) => v !== undefined)),
1239
+ tags: input.tags ?? task.tags,
1240
+ metadata: input.metadata ?? task.metadata,
1241
+ version: task.version + 1,
1242
+ updated_at: now(),
1243
+ completed_at: input.status === "completed" ? now() : task.completed_at,
1244
+ requires_approval: input.requires_approval !== undefined ? input.requires_approval : task.requires_approval,
1245
+ approved_by: input.approved_by ?? task.approved_by,
1246
+ approved_at: input.approved_by ? now() : task.approved_at
1247
+ };
1237
1248
  }
1238
1249
  function deleteTask(id, db) {
1239
1250
  const d = db || getDatabase();
@@ -1255,6 +1266,9 @@ function getBlockingDeps(id, db) {
1255
1266
  }
1256
1267
  function startTask(id, agentId, db) {
1257
1268
  const d = db || getDatabase();
1269
+ const task = getTask(id, d);
1270
+ if (!task)
1271
+ throw new TaskNotFoundError(id);
1258
1272
  const blocking = getBlockingDeps(id, d);
1259
1273
  if (blocking.length > 0) {
1260
1274
  const blockerIds = blocking.map((b) => b.id.slice(0, 8)).join(", ");
@@ -1265,15 +1279,12 @@ function startTask(id, agentId, db) {
1265
1279
  const result = d.run(`UPDATE tasks SET status = 'in_progress', assigned_to = ?, locked_by = ?, locked_at = ?, version = version + 1, updated_at = ?
1266
1280
  WHERE id = ? AND (locked_by IS NULL OR locked_by = ? OR locked_at < ?)`, [agentId, agentId, timestamp, timestamp, id, agentId, cutoff]);
1267
1281
  if (result.changes === 0) {
1268
- const current = getTask(id, d);
1269
- if (!current)
1270
- throw new TaskNotFoundError(id);
1271
- if (current.locked_by && current.locked_by !== agentId && !isLockExpired(current.locked_at)) {
1272
- throw new LockError(id, current.locked_by);
1282
+ if (task.locked_by && task.locked_by !== agentId && !isLockExpired(task.locked_at)) {
1283
+ throw new LockError(id, task.locked_by);
1273
1284
  }
1274
1285
  }
1275
1286
  logTaskChange(id, "start", "status", "pending", "in_progress", agentId, d);
1276
- return getTask(id, d);
1287
+ return { ...task, status: "in_progress", assigned_to: agentId, locked_by: agentId, locked_at: timestamp, version: task.version + 1, updated_at: timestamp };
1277
1288
  }
1278
1289
  function completeTask(id, agentId, db, evidence) {
1279
1290
  const d = db || getDatabase();
@@ -1285,14 +1296,15 @@ function completeTask(id, agentId, db, evidence) {
1285
1296
  }
1286
1297
  checkCompletionGuard(task, agentId || null, d);
1287
1298
  if (evidence) {
1288
- const meta = { ...task.metadata, _evidence: evidence };
1289
- d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta), id]);
1299
+ const meta2 = { ...task.metadata, _evidence: evidence };
1300
+ d.run("UPDATE tasks SET metadata = ? WHERE id = ?", [JSON.stringify(meta2), id]);
1290
1301
  }
1291
1302
  const timestamp = now();
1292
1303
  d.run(`UPDATE tasks SET status = 'completed', locked_by = NULL, locked_at = NULL, completed_at = ?, version = version + 1, updated_at = ?
1293
1304
  WHERE id = ?`, [timestamp, timestamp, id]);
1294
1305
  logTaskChange(id, "complete", "status", task.status, "completed", agentId || null, d);
1295
- return getTask(id, d);
1306
+ const meta = evidence ? { ...task.metadata, _evidence: evidence } : task.metadata;
1307
+ return { ...task, status: "completed", locked_by: null, locked_at: null, completed_at: timestamp, version: task.version + 1, updated_at: timestamp, metadata: meta };
1296
1308
  }
1297
1309
  function getTaskDependencies(taskId, db) {
1298
1310
  const d = db || getDatabase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.9.27",
3
+ "version": "0.9.29",
4
4
  "description": "Universal task management for AI coding agents - CLI + MCP server + interactive TUI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",