@hasna/todos 0.10.14 → 0.10.16

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
@@ -13238,6 +13238,57 @@ Claimed: ${formatTask(result.claimed)}`);
13238
13238
  }
13239
13239
  });
13240
13240
  }
13241
+ if (shouldRegisterTool("create_failure_task")) {
13242
+ server.tool("create_failure_task", "Create a task from a test/build/typecheck failure. Auto-assigns to the most likely agent based on file ownership and org chart.", {
13243
+ failure_type: exports_external.enum(["test", "build", "typecheck", "runtime", "other"]).describe("Type of failure"),
13244
+ title: exports_external.string().optional().describe("Task title (auto-generated from error if omitted)"),
13245
+ error_message: exports_external.string().describe("The error message or summary"),
13246
+ file_path: exports_external.string().optional().describe("File where the failure occurred"),
13247
+ stack_trace: exports_external.string().optional().describe("Stack trace or detailed output (truncated to 2000 chars)"),
13248
+ project_id: exports_external.string().optional().describe("Project to associate the task with"),
13249
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default: high for build/typecheck, medium for test")
13250
+ }, async ({ failure_type, title, error_message, file_path, stack_trace, project_id, priority }) => {
13251
+ try {
13252
+ const { createTask: createTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
13253
+ const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
13254
+ const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
13255
+ const defaultPriority = failure_type === "build" || failure_type === "typecheck" ? "high" : "medium";
13256
+ const taskPriority = priority ?? defaultPriority;
13257
+ const autoTitle = title || `${failure_type.toUpperCase()} failure${file_path ? ` in ${file_path.split("/").pop()}` : ""}: ${error_message.slice(0, 60)}`;
13258
+ const description = [
13259
+ `**Failure type:** ${failure_type}`,
13260
+ file_path ? `**File:** ${file_path}` : null,
13261
+ `**Error:**
13262
+ \`\`\`
13263
+ ${error_message.slice(0, 500)}
13264
+ \`\`\``,
13265
+ stack_trace ? `**Stack trace:**
13266
+ \`\`\`
13267
+ ${stack_trace.slice(0, 1500)}
13268
+ \`\`\`` : null
13269
+ ].filter(Boolean).join(`
13270
+
13271
+ `);
13272
+ const task = createTask2({
13273
+ title: autoTitle,
13274
+ description,
13275
+ priority: taskPriority,
13276
+ project_id: resolvedProjectId,
13277
+ tags: ["failure", failure_type, "auto-created"],
13278
+ status: "pending"
13279
+ });
13280
+ const assignResult = await autoAssignTask2(task.id);
13281
+ return {
13282
+ content: [{
13283
+ type: "text",
13284
+ text: JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, assign_method: assignResult.method }, null, 2)
13285
+ }]
13286
+ };
13287
+ } catch (e) {
13288
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
13289
+ }
13290
+ });
13291
+ }
13241
13292
  if (shouldRegisterTool("auto_assign_task")) {
13242
13293
  server.tool("auto_assign_task", "Auto-assign a task to the best available agent. Uses Cerebras LLM (llama-3.3-70b) if CEREBRAS_API_KEY is set, otherwise falls back to capability-based matching.", {
13243
13294
  task_id: exports_external.string().describe("Task to auto-assign")
@@ -17525,6 +17576,45 @@ Use ${chalk.cyan(`--agent ${result.id}`)} on future commands.`);
17525
17576
  handleError(e);
17526
17577
  }
17527
17578
  });
17579
+ program2.command("heartbeat [agent]").description("Update last_seen_at to signal you're still active").action((agent) => {
17580
+ const globalOpts = program2.opts();
17581
+ const agentId = agent || globalOpts.agent;
17582
+ if (!agentId) {
17583
+ console.error(chalk.red("Agent ID required. Use --agent or pass as argument."));
17584
+ process.exit(1);
17585
+ }
17586
+ const { updateAgentActivity: updateAgentActivity2, getAgent: getAgent2 } = (init_agents(), __toCommonJS(exports_agents));
17587
+ const a = getAgent2(agentId) || (init_agents(), __toCommonJS(exports_agents)).getAgentByName(agentId);
17588
+ if (!a) {
17589
+ console.error(chalk.red(`Agent not found: ${agentId}`));
17590
+ process.exit(1);
17591
+ }
17592
+ updateAgentActivity2(a.id);
17593
+ if (globalOpts.json) {
17594
+ console.log(JSON.stringify({ agent_id: a.id, name: a.name, last_seen_at: new Date().toISOString() }));
17595
+ } else {
17596
+ console.log(chalk.green(`\u2665 ${a.name} (${a.id.slice(0, 8)}) \u2014 heartbeat sent`));
17597
+ }
17598
+ });
17599
+ program2.command("focus [project]").description("Focus on a project (or clear focus if no project given)").action((project) => {
17600
+ const globalOpts = program2.opts();
17601
+ const agentId = globalOpts.agent;
17602
+ if (!agentId) {
17603
+ console.error(chalk.red("Agent ID required. Use --agent."));
17604
+ process.exit(1);
17605
+ }
17606
+ const db = getDatabase();
17607
+ if (project) {
17608
+ const { getProjectByPath: getProjectByPath2, getProjectByName } = (init_projects(), __toCommonJS(exports_projects));
17609
+ const p = getProjectByPath2(process.cwd(), db) || getProjectByName(project, db);
17610
+ const projectId = p?.id || project;
17611
+ db.run("UPDATE agents SET active_project_id = ? WHERE id = ? OR name = ?", [projectId, agentId, agentId]);
17612
+ console.log(chalk.green(`Focused on: ${p?.name || projectId}`));
17613
+ } else {
17614
+ db.run("UPDATE agents SET active_project_id = NULL WHERE id = ? OR name = ?", [agentId, agentId]);
17615
+ console.log(chalk.dim("Focus cleared."));
17616
+ }
17617
+ });
17528
17618
  program2.command("agents").description("List registered agents").action(() => {
17529
17619
  const globalOpts = program2.opts();
17530
17620
  try {
@@ -18933,6 +19023,49 @@ program2.command("context").description("Session start context: status, latest h
18933
19023
  console.log(chalk.dim(`
18934
19024
  as_of: ${new Date().toISOString()}`));
18935
19025
  });
19026
+ program2.command("report-failure").description("Create a task from a test/build/typecheck failure and auto-assign it").requiredOption("--error <message>", "Error message or summary").option("--type <type>", "Failure type: test, build, typecheck, runtime, other", "test").option("--file <path>", "File where failure occurred").option("--stack <trace>", "Stack trace or detailed output").option("--title <title>", "Custom task title (auto-generated if omitted)").option("--priority <p>", "Priority: low, medium, high, critical").option("--json", "Output as JSON").action(async (opts) => {
19027
+ const globalOpts = program2.opts();
19028
+ const { createTask: createTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
19029
+ const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
19030
+ const projectId = autoProject(globalOpts);
19031
+ const failureType = opts.type || "test";
19032
+ const defaultPriority = failureType === "build" || failureType === "typecheck" ? "high" : "medium";
19033
+ const taskPriority = opts.priority || defaultPriority;
19034
+ const autoTitle = opts.title || `${failureType.toUpperCase()} failure${opts.file ? ` in ${opts.file.split("/").pop()}` : ""}: ${opts.error.slice(0, 60)}`;
19035
+ const descParts = [
19036
+ `**Failure type:** ${failureType}`,
19037
+ opts.file ? `**File:** ${opts.file}` : null,
19038
+ `**Error:**
19039
+ \`\`\`
19040
+ ${opts.error.slice(0, 500)}
19041
+ \`\`\``,
19042
+ opts.stack ? `**Stack trace:**
19043
+ \`\`\`
19044
+ ${opts.stack.slice(0, 1500)}
19045
+ \`\`\`` : null
19046
+ ].filter(Boolean).join(`
19047
+
19048
+ `);
19049
+ const task = createTask2({
19050
+ title: autoTitle,
19051
+ description: descParts,
19052
+ priority: taskPriority,
19053
+ project_id: projectId || undefined,
19054
+ tags: ["failure", failureType, "auto-created"],
19055
+ status: "pending"
19056
+ });
19057
+ const assignResult = await autoAssignTask2(task.id);
19058
+ if (opts.json || globalOpts.json) {
19059
+ console.log(JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, method: assignResult.method }));
19060
+ return;
19061
+ }
19062
+ console.log(chalk.green(`\u2713 Created task ${task.short_id || task.id.slice(0, 8)}: ${task.title}`));
19063
+ if (assignResult.agent_name) {
19064
+ console.log(chalk.cyan(` Assigned to: ${assignResult.agent_name} (via ${assignResult.method})`));
19065
+ if (assignResult.reason)
19066
+ console.log(chalk.dim(` Reason: ${assignResult.reason}`));
19067
+ }
19068
+ });
18936
19069
  program2.action(async () => {
18937
19070
  if (process.stdout.isTTY) {
18938
19071
  try {
package/dist/mcp/index.js CHANGED
@@ -11050,6 +11050,57 @@ Claimed: ${formatTask(result.claimed)}`);
11050
11050
  }
11051
11051
  });
11052
11052
  }
11053
+ if (shouldRegisterTool("create_failure_task")) {
11054
+ server.tool("create_failure_task", "Create a task from a test/build/typecheck failure. Auto-assigns to the most likely agent based on file ownership and org chart.", {
11055
+ failure_type: exports_external.enum(["test", "build", "typecheck", "runtime", "other"]).describe("Type of failure"),
11056
+ title: exports_external.string().optional().describe("Task title (auto-generated from error if omitted)"),
11057
+ error_message: exports_external.string().describe("The error message or summary"),
11058
+ file_path: exports_external.string().optional().describe("File where the failure occurred"),
11059
+ stack_trace: exports_external.string().optional().describe("Stack trace or detailed output (truncated to 2000 chars)"),
11060
+ project_id: exports_external.string().optional().describe("Project to associate the task with"),
11061
+ priority: exports_external.enum(["low", "medium", "high", "critical"]).optional().describe("Default: high for build/typecheck, medium for test")
11062
+ }, async ({ failure_type, title, error_message, file_path, stack_trace, project_id, priority }) => {
11063
+ try {
11064
+ const { createTask: createTask2 } = (init_tasks(), __toCommonJS(exports_tasks));
11065
+ const { autoAssignTask: autoAssignTask2 } = await Promise.resolve().then(() => (init_auto_assign(), exports_auto_assign));
11066
+ const resolvedProjectId = project_id ? resolveId(project_id, "projects") : undefined;
11067
+ const defaultPriority = failure_type === "build" || failure_type === "typecheck" ? "high" : "medium";
11068
+ const taskPriority = priority ?? defaultPriority;
11069
+ const autoTitle = title || `${failure_type.toUpperCase()} failure${file_path ? ` in ${file_path.split("/").pop()}` : ""}: ${error_message.slice(0, 60)}`;
11070
+ const description = [
11071
+ `**Failure type:** ${failure_type}`,
11072
+ file_path ? `**File:** ${file_path}` : null,
11073
+ `**Error:**
11074
+ \`\`\`
11075
+ ${error_message.slice(0, 500)}
11076
+ \`\`\``,
11077
+ stack_trace ? `**Stack trace:**
11078
+ \`\`\`
11079
+ ${stack_trace.slice(0, 1500)}
11080
+ \`\`\`` : null
11081
+ ].filter(Boolean).join(`
11082
+
11083
+ `);
11084
+ const task = createTask2({
11085
+ title: autoTitle,
11086
+ description,
11087
+ priority: taskPriority,
11088
+ project_id: resolvedProjectId,
11089
+ tags: ["failure", failure_type, "auto-created"],
11090
+ status: "pending"
11091
+ });
11092
+ const assignResult = await autoAssignTask2(task.id);
11093
+ return {
11094
+ content: [{
11095
+ type: "text",
11096
+ text: JSON.stringify({ task_id: task.id, short_id: task.short_id, title: task.title, assigned_to: assignResult.agent_name, assign_method: assignResult.method }, null, 2)
11097
+ }]
11098
+ };
11099
+ } catch (e) {
11100
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
11101
+ }
11102
+ });
11103
+ }
11053
11104
  if (shouldRegisterTool("auto_assign_task")) {
11054
11105
  server.tool("auto_assign_task", "Auto-assign a task to the best available agent. Uses Cerebras LLM (llama-3.3-70b) if CEREBRAS_API_KEY is set, otherwise falls back to capability-based matching.", {
11055
11106
  task_id: exports_external.string().describe("Task to auto-assign")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.10.14",
3
+ "version": "0.10.16",
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",