@hasna/todos 0.9.76 → 0.9.77

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
@@ -11135,16 +11135,59 @@ In Progress:`);
11135
11135
  });
11136
11136
  }
11137
11137
  if (shouldRegisterTool("bulk_update_tasks")) {
11138
- server.tool("bulk_update_tasks", "Update multiple tasks at once with the same changes.", {
11139
- task_ids: exports_external.array(exports_external.string()),
11138
+ server.tool("bulk_update_tasks", "Update multiple tasks at once. Two modes: (1) task_ids + shared fields \u2014 apply the same changes to all; (2) updates array \u2014 per-task fields, each entry has id plus any fields to update.", {
11139
+ task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs to update with the same fields (mode 1)"),
11140
11140
  status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
11141
11141
  priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
11142
11142
  assigned_to: exports_external.string().optional(),
11143
- tags: exports_external.array(exports_external.string()).optional()
11144
- }, async ({ task_ids, ...updates }) => {
11143
+ tags: exports_external.array(exports_external.string()).optional(),
11144
+ updates: exports_external.array(exports_external.object({
11145
+ id: exports_external.string(),
11146
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
11147
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
11148
+ assigned_to: exports_external.string().optional(),
11149
+ tags: exports_external.array(exports_external.string()).optional(),
11150
+ title: exports_external.string().optional(),
11151
+ description: exports_external.string().optional(),
11152
+ plan_id: exports_external.string().optional(),
11153
+ task_list_id: exports_external.string().optional()
11154
+ })).optional().describe("Per-task updates \u2014 each entry has id plus fields to update (mode 2)")
11155
+ }, async ({ task_ids, updates, ...sharedFields }) => {
11145
11156
  try {
11146
- const resolvedIds = task_ids.map((id) => resolveId(id));
11147
- const result = bulkUpdateTasks(resolvedIds, updates);
11157
+ let result;
11158
+ if (updates && updates.length > 0) {
11159
+ const d = getDatabase();
11160
+ let updated = 0;
11161
+ const failed = [];
11162
+ const tx = d.transaction(() => {
11163
+ for (const entry of updates) {
11164
+ try {
11165
+ const { id, ...fields } = entry;
11166
+ const resolvedId = resolveId(id);
11167
+ const task = getTask(resolvedId);
11168
+ if (!task) {
11169
+ failed.push({ id, error: "Task not found" });
11170
+ continue;
11171
+ }
11172
+ if (fields.plan_id)
11173
+ fields.plan_id = resolveId(fields.plan_id, "plans");
11174
+ if (fields.task_list_id)
11175
+ fields.task_list_id = resolveId(fields.task_list_id, "task_lists");
11176
+ updateTask(resolvedId, { ...fields, version: task.version }, d);
11177
+ updated++;
11178
+ } catch (e) {
11179
+ failed.push({ id: entry.id, error: e instanceof Error ? e.message : String(e) });
11180
+ }
11181
+ }
11182
+ });
11183
+ tx();
11184
+ result = { updated, failed };
11185
+ } else if (task_ids && task_ids.length > 0) {
11186
+ const resolvedIds = task_ids.map((id) => resolveId(id));
11187
+ result = bulkUpdateTasks(resolvedIds, sharedFields);
11188
+ } else {
11189
+ return { content: [{ type: "text", text: "Provide either task_ids (mode 1) or updates array (mode 2)." }], isError: true };
11190
+ }
11148
11191
  const parts = [`Updated ${result.updated} task(s).`];
11149
11192
  if (result.failed.length > 0) {
11150
11193
  parts.push(`Failed ${result.failed.length}:`);
@@ -11960,9 +12003,11 @@ Claimed: ${formatTask(result.claimed)}`);
11960
12003
  move_task: `Move a task to a different list, project, or plan.
11961
12004
  Params: task_id(string, req), task_list_id(string|null), project_id(string|null), plan_id(string|null)
11962
12005
  Example: {task_id: 'a1b2c3d4', task_list_id: 'e5f6g7h8'}`,
11963
- bulk_update_tasks: `Update multiple tasks at once with the same changes.
11964
- Params: task_ids(string[], req), status(pending|in_progress|completed|failed|cancelled), priority(low|medium|high|critical), assigned_to(string), tags(string[])
11965
- Example: {task_ids: ['abc12345', 'def67890'], status: 'completed'}`,
12006
+ bulk_update_tasks: `Update multiple tasks at once. Two modes:
12007
+ Mode 1 (same fields to all): task_ids(string[], req), status, priority, assigned_to, tags
12008
+ Mode 2 (per-task fields): updates([{id, status?, priority?, assigned_to?, tags?, title?, description?, plan_id?, task_list_id?}], req)
12009
+ Example mode 1: {task_ids: ['abc12345', 'def67890'], assigned_to: 'agent-id'}
12010
+ Example mode 2: {updates: [{id: 'abc12345', assigned_to: 'agent-1'}, {id: 'def67890', status: 'in_progress'}]}`,
11966
12011
  bulk_create_tasks: `Create multiple tasks atomically. Supports inter-task dependencies via temp_id references.
11967
12012
  Params: tasks(array, req \u2014 [{temp_id, title, description, priority, status, project_id, plan_id, task_list_id, agent_id, assigned_to, tags, estimated_minutes, depends_on_temp_ids}]), project_id(string \u2014 default for all), plan_id(string \u2014 default for all), task_list_id(string \u2014 default for all)
11968
12013
  Example: {tasks: [{temp_id: 'a', title: 'First'}, {temp_id: 'b', title: 'Second', depends_on_temp_ids: ['a']}]}`,
package/dist/mcp/index.js CHANGED
@@ -8852,16 +8852,59 @@ if (shouldRegisterTool("set_reports_to")) {
8852
8852
  });
8853
8853
  }
8854
8854
  if (shouldRegisterTool("bulk_update_tasks")) {
8855
- server.tool("bulk_update_tasks", "Update multiple tasks at once with the same changes.", {
8856
- task_ids: exports_external.array(exports_external.string()),
8855
+ server.tool("bulk_update_tasks", "Update multiple tasks at once. Two modes: (1) task_ids + shared fields \u2014 apply the same changes to all; (2) updates array \u2014 per-task fields, each entry has id plus any fields to update.", {
8856
+ task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs to update with the same fields (mode 1)"),
8857
8857
  status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8858
8858
  priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8859
8859
  assigned_to: exports_external.string().optional(),
8860
- tags: exports_external.array(exports_external.string()).optional()
8861
- }, async ({ task_ids, ...updates }) => {
8860
+ tags: exports_external.array(exports_external.string()).optional(),
8861
+ updates: exports_external.array(exports_external.object({
8862
+ id: exports_external.string(),
8863
+ status: exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"]).optional(),
8864
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional(),
8865
+ assigned_to: exports_external.string().optional(),
8866
+ tags: exports_external.array(exports_external.string()).optional(),
8867
+ title: exports_external.string().optional(),
8868
+ description: exports_external.string().optional(),
8869
+ plan_id: exports_external.string().optional(),
8870
+ task_list_id: exports_external.string().optional()
8871
+ })).optional().describe("Per-task updates \u2014 each entry has id plus fields to update (mode 2)")
8872
+ }, async ({ task_ids, updates, ...sharedFields }) => {
8862
8873
  try {
8863
- const resolvedIds = task_ids.map((id) => resolveId(id));
8864
- const result = bulkUpdateTasks(resolvedIds, updates);
8874
+ let result;
8875
+ if (updates && updates.length > 0) {
8876
+ const d = getDatabase();
8877
+ let updated = 0;
8878
+ const failed = [];
8879
+ const tx = d.transaction(() => {
8880
+ for (const entry of updates) {
8881
+ try {
8882
+ const { id, ...fields } = entry;
8883
+ const resolvedId = resolveId(id);
8884
+ const task = getTask(resolvedId);
8885
+ if (!task) {
8886
+ failed.push({ id, error: "Task not found" });
8887
+ continue;
8888
+ }
8889
+ if (fields.plan_id)
8890
+ fields.plan_id = resolveId(fields.plan_id, "plans");
8891
+ if (fields.task_list_id)
8892
+ fields.task_list_id = resolveId(fields.task_list_id, "task_lists");
8893
+ updateTask(resolvedId, { ...fields, version: task.version }, d);
8894
+ updated++;
8895
+ } catch (e) {
8896
+ failed.push({ id: entry.id, error: e instanceof Error ? e.message : String(e) });
8897
+ }
8898
+ }
8899
+ });
8900
+ tx();
8901
+ result = { updated, failed };
8902
+ } else if (task_ids && task_ids.length > 0) {
8903
+ const resolvedIds = task_ids.map((id) => resolveId(id));
8904
+ result = bulkUpdateTasks(resolvedIds, sharedFields);
8905
+ } else {
8906
+ return { content: [{ type: "text", text: "Provide either task_ids (mode 1) or updates array (mode 2)." }], isError: true };
8907
+ }
8865
8908
  const parts = [`Updated ${result.updated} task(s).`];
8866
8909
  if (result.failed.length > 0) {
8867
8910
  parts.push(`Failed ${result.failed.length}:`);
@@ -9677,9 +9720,11 @@ if (shouldRegisterTool("describe_tools")) {
9677
9720
  move_task: `Move a task to a different list, project, or plan.
9678
9721
  Params: task_id(string, req), task_list_id(string|null), project_id(string|null), plan_id(string|null)
9679
9722
  Example: {task_id: 'a1b2c3d4', task_list_id: 'e5f6g7h8'}`,
9680
- bulk_update_tasks: `Update multiple tasks at once with the same changes.
9681
- Params: task_ids(string[], req), status(pending|in_progress|completed|failed|cancelled), priority(low|medium|high|critical), assigned_to(string), tags(string[])
9682
- Example: {task_ids: ['abc12345', 'def67890'], status: 'completed'}`,
9723
+ bulk_update_tasks: `Update multiple tasks at once. Two modes:
9724
+ Mode 1 (same fields to all): task_ids(string[], req), status, priority, assigned_to, tags
9725
+ Mode 2 (per-task fields): updates([{id, status?, priority?, assigned_to?, tags?, title?, description?, plan_id?, task_list_id?}], req)
9726
+ Example mode 1: {task_ids: ['abc12345', 'def67890'], assigned_to: 'agent-id'}
9727
+ Example mode 2: {updates: [{id: 'abc12345', assigned_to: 'agent-1'}, {id: 'def67890', status: 'in_progress'}]}`,
9683
9728
  bulk_create_tasks: `Create multiple tasks atomically. Supports inter-task dependencies via temp_id references.
9684
9729
  Params: tasks(array, req \u2014 [{temp_id, title, description, priority, status, project_id, plan_id, task_list_id, agent_id, assigned_to, tags, estimated_minutes, depends_on_temp_ids}]), project_id(string \u2014 default for all), plan_id(string \u2014 default for all), task_list_id(string \u2014 default for all)
9685
9730
  Example: {tasks: [{temp_id: 'a', title: 'First'}, {temp_id: 'b', title: 'Second', depends_on_temp_ids: ['a']}]}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.9.76",
3
+ "version": "0.9.77",
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",