@hasna/todos 0.9.24 → 0.9.26

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/mcp/index.js CHANGED
@@ -6093,6 +6093,12 @@ function resolveTaskListId(agent, explicit) {
6093
6093
  return process.env[key] || process.env["TODOS_TASK_LIST_ID"] || getAgentTaskListId(normalized) || "default";
6094
6094
  }
6095
6095
  function formatTask(task) {
6096
+ const id = task.short_id || task.id.slice(0, 8);
6097
+ const assigned = task.assigned_to ? ` -> ${task.assigned_to}` : "";
6098
+ const lock = task.locked_by ? ` [locked:${task.locked_by}]` : "";
6099
+ return `${id} ${task.status.padEnd(11)} ${task.priority.padEnd(8)} ${task.title}${assigned}${lock}`;
6100
+ }
6101
+ function formatTaskDetail(task) {
6096
6102
  const parts = [
6097
6103
  `ID: ${task.id}`,
6098
6104
  `Title: ${task.title}`,
@@ -6151,8 +6157,7 @@ server.tool("create_task", "Create a new task", {
6151
6157
  if (resolved.task_list_id)
6152
6158
  resolved.task_list_id = resolveId(resolved.task_list_id, "task_lists");
6153
6159
  const task = createTask(resolved);
6154
- return { content: [{ type: "text", text: `Task created:
6155
- ${formatTask(task)}` }] };
6160
+ return { content: [{ type: "text", text: `created: ${formatTask(task)}` }] };
6156
6161
  } catch (e) {
6157
6162
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6158
6163
  }
@@ -6204,7 +6209,7 @@ server.tool("get_task", "Get full task details with relations", {
6204
6209
  const task = getTaskWithRelations(resolvedId);
6205
6210
  if (!task)
6206
6211
  return { content: [{ type: "text", text: `Task not found: ${id}` }], isError: true };
6207
- const parts = [formatTask(task)];
6212
+ const parts = [formatTaskDetail(task)];
6208
6213
  if (task.subtasks.length > 0) {
6209
6214
  parts.push(`
6210
6215
  Subtasks (${task.subtasks.length}):`);
@@ -6260,8 +6265,7 @@ server.tool("update_task", "Update task fields. Version required for optimistic
6260
6265
  try {
6261
6266
  const resolvedId = resolveId(id);
6262
6267
  const task = updateTask(resolvedId, rest);
6263
- return { content: [{ type: "text", text: `Task updated:
6264
- ${formatTask(task)}` }] };
6268
+ return { content: [{ type: "text", text: `updated: ${formatTask(task)}` }] };
6265
6269
  } catch (e) {
6266
6270
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6267
6271
  }
@@ -6289,8 +6293,7 @@ server.tool("start_task", "Claim, lock, and set task status to in_progress.", {
6289
6293
  try {
6290
6294
  const resolvedId = resolveId(id);
6291
6295
  const task = startTask(resolvedId, agent_id);
6292
- return { content: [{ type: "text", text: `Task started:
6293
- ${formatTask(task)}` }] };
6296
+ return { content: [{ type: "text", text: `started: ${formatTask(task)}` }] };
6294
6297
  } catch (e) {
6295
6298
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6296
6299
  }
@@ -6302,8 +6305,7 @@ server.tool("complete_task", "Mark task completed and release lock.", {
6302
6305
  try {
6303
6306
  const resolvedId = resolveId(id);
6304
6307
  const task = completeTask(resolvedId, agent_id);
6305
- return { content: [{ type: "text", text: `Task completed:
6306
- ${formatTask(task)}` }] };
6308
+ return { content: [{ type: "text", text: `completed: ${formatTask(task)}` }] };
6307
6309
  } catch (e) {
6308
6310
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6309
6311
  }
@@ -1429,8 +1429,8 @@ function serveStaticFile(filePath) {
1429
1429
  headers: { "Content-Type": contentType }
1430
1430
  });
1431
1431
  }
1432
- function taskToSummary(task) {
1433
- return {
1432
+ function taskToSummary(task, fields) {
1433
+ const full = {
1434
1434
  id: task.id,
1435
1435
  short_id: task.short_id,
1436
1436
  title: task.title,
@@ -1450,6 +1450,9 @@ function taskToSummary(task) {
1450
1450
  completed_at: task.completed_at,
1451
1451
  due_at: task.due_at
1452
1452
  };
1453
+ if (!fields || fields.length === 0)
1454
+ return full;
1455
+ return Object.fromEntries(fields.map((f) => [f, full[f] ?? null]));
1453
1456
  }
1454
1457
  async function startServer(port, options) {
1455
1458
  const shouldOpen = options?.open ?? true;
@@ -1532,12 +1535,14 @@ Dashboard not found at: ${dashboardDir}`);
1532
1535
  const status = url.searchParams.get("status") || undefined;
1533
1536
  const projectId = url.searchParams.get("project_id") || undefined;
1534
1537
  const limitParam = url.searchParams.get("limit");
1538
+ const fieldsParam = url.searchParams.get("fields");
1539
+ const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
1535
1540
  const tasks = listTasks({
1536
1541
  status,
1537
1542
  project_id: projectId,
1538
1543
  limit: limitParam ? parseInt(limitParam, 10) : undefined
1539
1544
  });
1540
- return json(tasks.map(taskToSummary), 200, port);
1545
+ return json(tasks.map((t) => taskToSummary(t, fields)), 200, port);
1541
1546
  }
1542
1547
  if (path === "/api/tasks" && method === "POST") {
1543
1548
  try {
@@ -1561,7 +1566,7 @@ Dashboard not found at: ${dashboardDir}`);
1561
1566
  const status = url.searchParams.get("status") || undefined;
1562
1567
  const projectId = url.searchParams.get("project_id") || undefined;
1563
1568
  const tasks = listTasks({ status, project_id: projectId, limit: 1e4 });
1564
- const summaries = tasks.map(taskToSummary);
1569
+ const summaries = tasks.map((t) => taskToSummary(t));
1565
1570
  if (format === "csv") {
1566
1571
  const headers = ["id", "short_id", "title", "status", "priority", "project_id", "assigned_to", "agent_id", "created_at", "updated_at", "completed_at", "due_at"];
1567
1572
  const rows = summaries.map((t) => headers.map((h) => {
@@ -1687,8 +1692,8 @@ Dashboard not found at: ${dashboardDir}`);
1687
1692
  const completed = allTasks.filter((t) => t.status === "completed");
1688
1693
  return json({
1689
1694
  agent,
1690
- pending_tasks: pending.map(taskToSummary),
1691
- in_progress_tasks: inProgress.map(taskToSummary),
1695
+ pending_tasks: pending.map((t) => taskToSummary(t)),
1696
+ in_progress_tasks: inProgress.map((t) => taskToSummary(t)),
1692
1697
  stats: {
1693
1698
  total: allTasks.length,
1694
1699
  pending: pending.length,
@@ -1705,7 +1710,7 @@ Dashboard not found at: ${dashboardDir}`);
1705
1710
  const queue = pending.filter((t) => t.assigned_to === agentId || t.agent_id === agentId || !t.assigned_to && !t.locked_by);
1706
1711
  const order = { critical: 0, high: 1, medium: 2, low: 3 };
1707
1712
  queue.sort((a, b) => (order[a.priority] ?? 4) - (order[b.priority] ?? 4) || new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
1708
- return json(queue.map(taskToSummary), 200, port);
1713
+ return json(queue.map((t) => taskToSummary(t)), 200, port);
1709
1714
  }
1710
1715
  if (path === "/api/tasks/claim" && method === "POST") {
1711
1716
  try {
@@ -1921,7 +1926,7 @@ Dashboard not found at: ${dashboardDir}`);
1921
1926
  if (!plan)
1922
1927
  return json({ error: "Plan not found" }, 404, port);
1923
1928
  const tasks = listTasks({ plan_id: id });
1924
- return json({ ...plan, tasks: tasks.map(taskToSummary) }, 200, port);
1929
+ return json({ ...plan, tasks: tasks.map((t) => taskToSummary(t)) }, 200, port);
1925
1930
  }
1926
1931
  if (method === "PATCH") {
1927
1932
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.9.24",
3
+ "version": "0.9.26",
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",