@hasna/todos 0.11.62 → 0.11.64

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/README.md CHANGED
@@ -425,19 +425,23 @@ todos webhooks add loops \
425
425
  --arg=todos-task \
426
426
  --arg=--provider \
427
427
  --arg=codewith \
428
- --arg=--auth-profile \
429
- --arg=account005 \
428
+ --arg=--auth-profile-pool \
429
+ --arg=account004,account005,account006 \
430
430
  --arg=--permission-mode \
431
431
  --arg=bypass \
432
432
  --arg=--sandbox \
433
433
  --arg=danger-full-access \
434
+ --arg=--worktree-mode \
435
+ --arg=required \
434
436
  --timeout-ms 900000 \
435
437
  --json
436
438
  ```
437
439
 
438
440
  When a task is created, `@hasna/events` sends the event JSON on stdin and in
439
441
  `HASNA_EVENT_JSON`. OpenLoops uses that event to create a deduped one-shot
440
- worker/verifier workflow for the task. The event data includes task identity,
442
+ worker/verifier workflow for the task. Use account-profile pools instead of a
443
+ single pinned profile, and require isolated worktrees for repo-mutating routes.
444
+ The event data includes task identity,
441
445
  title, description, project/list ids, working directory, tags, metadata, status,
442
446
  priority, approval state, and timestamps. Event metadata includes routing-safe
443
447
  project/list/path fields, `route_enabled` when the task metadata opts in, and an
package/dist/cli/index.js CHANGED
@@ -26418,7 +26418,7 @@ var init_dispatch = __esm(() => {
26418
26418
  // src/mcp/tools/dispatch.ts
26419
26419
  function registerDispatchTools(server, { shouldRegisterTool, resolveId, formatError }) {
26420
26420
  if (shouldRegisterTool("dispatch_tasks")) {
26421
- server.tool("dispatch_tasks", "Send specific tasks to a tmux window. Formats a message from the given task IDs and dispatches it with a configurable delay before hitting Enter. Supports dry-run preview and scheduled sending.", {
26421
+ server.tool("dispatch_tasks", "Legacy/emergency only: send specific tasks to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports dry-run preview and scheduled sending.", {
26422
26422
  task_ids: exports_external.array(exports_external.string()).min(1).describe("IDs of the tasks to dispatch"),
26423
26423
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
26424
26424
  delay_ms: exports_external.number().optional().describe("Delay in ms between sending the message and hitting Enter. Auto-calculated from message length (3-5s) if omitted."),
@@ -26461,7 +26461,7 @@ ${message}`
26461
26461
  });
26462
26462
  }
26463
26463
  if (shouldRegisterTool("dispatch_task_list")) {
26464
- server.tool("dispatch_task_list", "Send all tasks from a task list to a tmux window. Fetches matching tasks, formats them as a grouped message with a list header, and dispatches. Supports status filtering, dry-run, and scheduled sending.", {
26464
+ server.tool("dispatch_task_list", "Legacy/emergency only: send all tasks from a task list to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports filtering, dry-run, and scheduled sending.", {
26465
26465
  task_list_id: exports_external.string().describe("ID or slug of the task list to dispatch"),
26466
26466
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
26467
26467
  filter_status: exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"])).optional().describe("Only include tasks with these statuses. Default: pending."),
@@ -26510,8 +26510,8 @@ ${message}`
26510
26510
  });
26511
26511
  }
26512
26512
  if (shouldRegisterTool("dispatch_to_multiple")) {
26513
- server.tool("dispatch_to_multiple", "Fan-out: send the same tasks or task list to multiple tmux windows in sequence. A stagger delay is applied between each window.", {
26514
- targets: exports_external.array(exports_external.string()).min(2).describe("Array of tmux targets to dispatch to"),
26513
+ server.tool("dispatch_to_multiple", "Legacy/emergency fan-out: send the same tasks or task list to multiple tmux windows in sequence after a human explicitly chooses tmux delivery. A stagger delay is applied between each window.", {
26514
+ targets: exports_external.array(exports_external.string()).min(2).describe("Legacy/emergency tmux targets selected explicitly by a human operator"),
26515
26515
  task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs to dispatch (use this or task_list_id)"),
26516
26516
  task_list_id: exports_external.string().optional().describe("Task list ID to dispatch (use this or task_ids)"),
26517
26517
  stagger_ms: exports_external.number().optional().describe("Delay between each window dispatch. Default: 500ms."),
@@ -26568,7 +26568,7 @@ ${lines.join(`
26568
26568
  });
26569
26569
  }
26570
26570
  if (shouldRegisterTool("run_due_dispatches")) {
26571
- server.tool("run_due_dispatches", "Manually trigger all pending dispatches that are due (scheduled_at <= now). Returns the count fired.", {
26571
+ server.tool("run_due_dispatches", "Legacy/emergency only: manually trigger all pending tmux dispatches that are due (scheduled_at <= now). Returns the count fired.", {
26572
26572
  dry_run: exports_external.boolean().optional().describe("Preview without sending. Default: false."),
26573
26573
  confirm_busy: exports_external.boolean().optional().describe("Send even if target tmux panes appear busy. Default: false."),
26574
26574
  all: exports_external.boolean().optional().describe("Ignore scheduled_at and fire all pending dispatches immediately.")
package/dist/index.js CHANGED
@@ -29862,7 +29862,7 @@ var AGENT_ADAPTER_DOCS = {
29862
29862
  ],
29863
29863
  examples: [
29864
29864
  { title: "Manual Takumi MCP add", command: "takumi mcp add --scope project todos -- todos-mcp" },
29865
- { title: "Dispatch to tmux pane", command: "todos dispatch agents:0 --tasks <id>" },
29865
+ { title: "Legacy tmux handoff", command: "todos dispatch agents:0 --tasks <id>" },
29866
29866
  { title: "Handoff on session end", command: "todos goal handoff release-v2 --format md --agent takumi-agent" }
29867
29867
  ]
29868
29868
  }
@@ -2,7 +2,8 @@ import type { Database } from "bun:sqlite";
2
2
  import type { CreateDispatchInput, Dispatch } from "../types/index.js";
3
3
  export type { FormatOpts } from "./dispatch-formatter.js";
4
4
  /**
5
- * Execute a single dispatch: resolve tasks, format, send to tmux, update status.
5
+ * Legacy/emergency path: resolve tasks, format, send to tmux, update status.
6
+ * Default pending-task routing should use task-created headless workflows.
6
7
  */
7
8
  export declare function executeDispatch(dispatch: Dispatch, opts?: {
8
9
  dryRun?: boolean;
@@ -18,7 +19,7 @@ export declare function runDueDispatches(opts?: {
18
19
  confirmBusy?: boolean;
19
20
  }, db?: Database): Promise<number>;
20
21
  /**
21
- * Fan-out: dispatch the same task set to multiple tmux windows.
22
+ * Legacy/emergency fan-out: dispatch the same task set to multiple tmux windows.
22
23
  * Returns the list of created Dispatch objects.
23
24
  */
24
25
  export declare function dispatchToMultiple(input: Omit<CreateDispatchInput, "target_window"> & {
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/lib/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAW3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGvE,YAAY,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,yBAAyB,EAAE,UAAU,CAAA;CAAO,EACjH,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,EACtD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,MAAM,CAAC,CAejB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9F,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,EACtD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,QAAQ,EAAE,CAAC,CAmBrB"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/lib/dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAW3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGvE,YAAY,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,yBAAyB,EAAE,UAAU,CAAA;CAAO,EACjH,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,EACtD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,MAAM,CAAC,CAejB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,eAAe,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAC9F,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,EACtD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,QAAQ,EAAE,CAAC,CAmBrB"}
package/dist/mcp/index.js CHANGED
@@ -14839,7 +14839,7 @@ var init_dispatch = __esm(() => {
14839
14839
  // src/mcp/tools/dispatch.ts
14840
14840
  function registerDispatchTools(server, { shouldRegisterTool, resolveId, formatError }) {
14841
14841
  if (shouldRegisterTool("dispatch_tasks")) {
14842
- server.tool("dispatch_tasks", "Send specific tasks to a tmux window. Formats a message from the given task IDs and dispatches it with a configurable delay before hitting Enter. Supports dry-run preview and scheduled sending.", {
14842
+ server.tool("dispatch_tasks", "Legacy/emergency only: send specific tasks to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports dry-run preview and scheduled sending.", {
14843
14843
  task_ids: exports_external.array(exports_external.string()).min(1).describe("IDs of the tasks to dispatch"),
14844
14844
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
14845
14845
  delay_ms: exports_external.number().optional().describe("Delay in ms between sending the message and hitting Enter. Auto-calculated from message length (3-5s) if omitted."),
@@ -14882,7 +14882,7 @@ ${message}`
14882
14882
  });
14883
14883
  }
14884
14884
  if (shouldRegisterTool("dispatch_task_list")) {
14885
- server.tool("dispatch_task_list", "Send all tasks from a task list to a tmux window. Fetches matching tasks, formats them as a grouped message with a list header, and dispatches. Supports status filtering, dry-run, and scheduled sending.", {
14885
+ server.tool("dispatch_task_list", "Legacy/emergency only: send all tasks from a task list to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports filtering, dry-run, and scheduled sending.", {
14886
14886
  task_list_id: exports_external.string().describe("ID or slug of the task list to dispatch"),
14887
14887
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
14888
14888
  filter_status: exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"])).optional().describe("Only include tasks with these statuses. Default: pending."),
@@ -14931,8 +14931,8 @@ ${message}`
14931
14931
  });
14932
14932
  }
14933
14933
  if (shouldRegisterTool("dispatch_to_multiple")) {
14934
- server.tool("dispatch_to_multiple", "Fan-out: send the same tasks or task list to multiple tmux windows in sequence. A stagger delay is applied between each window.", {
14935
- targets: exports_external.array(exports_external.string()).min(2).describe("Array of tmux targets to dispatch to"),
14934
+ server.tool("dispatch_to_multiple", "Legacy/emergency fan-out: send the same tasks or task list to multiple tmux windows in sequence after a human explicitly chooses tmux delivery. A stagger delay is applied between each window.", {
14935
+ targets: exports_external.array(exports_external.string()).min(2).describe("Legacy/emergency tmux targets selected explicitly by a human operator"),
14936
14936
  task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs to dispatch (use this or task_list_id)"),
14937
14937
  task_list_id: exports_external.string().optional().describe("Task list ID to dispatch (use this or task_ids)"),
14938
14938
  stagger_ms: exports_external.number().optional().describe("Delay between each window dispatch. Default: 500ms."),
@@ -14989,7 +14989,7 @@ ${lines.join(`
14989
14989
  });
14990
14990
  }
14991
14991
  if (shouldRegisterTool("run_due_dispatches")) {
14992
- server.tool("run_due_dispatches", "Manually trigger all pending dispatches that are due (scheduled_at <= now). Returns the count fired.", {
14992
+ server.tool("run_due_dispatches", "Legacy/emergency only: manually trigger all pending tmux dispatches that are due (scheduled_at <= now). Returns the count fired.", {
14993
14993
  dry_run: exports_external.boolean().optional().describe("Preview without sending. Default: false."),
14994
14994
  confirm_busy: exports_external.boolean().optional().describe("Send even if target tmux panes appear busy. Default: false."),
14995
14995
  all: exports_external.boolean().optional().describe("Ignore scheduled_at and fire all pending dispatches immediately.")
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "packageName": "@hasna/todos",
3
- "packageVersion": "0.11.62",
3
+ "packageVersion": "0.11.64",
4
4
  "repository": "https://github.com/hasna/todos.git",
5
- "gitCommit": "5a46ee0eef4646de46ae89504827c8e5f4169629",
6
- "generatedAt": "2026-06-27T15:15:19.162Z"
5
+ "gitCommit": "d6dc5c7140c0b282b651d93459857034ca67b220",
6
+ "generatedAt": "2026-06-28T08:55:52.193Z"
7
7
  }
@@ -32524,7 +32524,7 @@ var init_dispatch = __esm(() => {
32524
32524
  // src/mcp/tools/dispatch.ts
32525
32525
  function registerDispatchTools(server, { shouldRegisterTool, resolveId, formatError: formatError2 }) {
32526
32526
  if (shouldRegisterTool("dispatch_tasks")) {
32527
- server.tool("dispatch_tasks", "Send specific tasks to a tmux window. Formats a message from the given task IDs and dispatches it with a configurable delay before hitting Enter. Supports dry-run preview and scheduled sending.", {
32527
+ server.tool("dispatch_tasks", "Legacy/emergency only: send specific tasks to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports dry-run preview and scheduled sending.", {
32528
32528
  task_ids: exports_external.array(exports_external.string()).min(1).describe("IDs of the tasks to dispatch"),
32529
32529
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
32530
32530
  delay_ms: exports_external.number().optional().describe("Delay in ms between sending the message and hitting Enter. Auto-calculated from message length (3-5s) if omitted."),
@@ -32567,7 +32567,7 @@ ${message}`
32567
32567
  });
32568
32568
  }
32569
32569
  if (shouldRegisterTool("dispatch_task_list")) {
32570
- server.tool("dispatch_task_list", "Send all tasks from a task list to a tmux window. Fetches matching tasks, formats them as a grouped message with a list header, and dispatches. Supports status filtering, dry-run, and scheduled sending.", {
32570
+ server.tool("dispatch_task_list", "Legacy/emergency only: send all tasks from a task list to a tmux window after a human explicitly chooses tmux delivery. Normal pending-task routing should use task-created headless workflows. Supports filtering, dry-run, and scheduled sending.", {
32571
32571
  task_list_id: exports_external.string().describe("ID or slug of the task list to dispatch"),
32572
32572
  target: exports_external.string().describe("tmux target \u2014 window name, session:window, or session:window.pane"),
32573
32573
  filter_status: exports_external.array(exports_external.enum(["pending", "in_progress", "completed", "failed", "cancelled"])).optional().describe("Only include tasks with these statuses. Default: pending."),
@@ -32616,8 +32616,8 @@ ${message}`
32616
32616
  });
32617
32617
  }
32618
32618
  if (shouldRegisterTool("dispatch_to_multiple")) {
32619
- server.tool("dispatch_to_multiple", "Fan-out: send the same tasks or task list to multiple tmux windows in sequence. A stagger delay is applied between each window.", {
32620
- targets: exports_external.array(exports_external.string()).min(2).describe("Array of tmux targets to dispatch to"),
32619
+ server.tool("dispatch_to_multiple", "Legacy/emergency fan-out: send the same tasks or task list to multiple tmux windows in sequence after a human explicitly chooses tmux delivery. A stagger delay is applied between each window.", {
32620
+ targets: exports_external.array(exports_external.string()).min(2).describe("Legacy/emergency tmux targets selected explicitly by a human operator"),
32621
32621
  task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs to dispatch (use this or task_list_id)"),
32622
32622
  task_list_id: exports_external.string().optional().describe("Task list ID to dispatch (use this or task_ids)"),
32623
32623
  stagger_ms: exports_external.number().optional().describe("Delay between each window dispatch. Default: 500ms."),
@@ -32674,7 +32674,7 @@ ${lines.join(`
32674
32674
  });
32675
32675
  }
32676
32676
  if (shouldRegisterTool("run_due_dispatches")) {
32677
- server.tool("run_due_dispatches", "Manually trigger all pending dispatches that are due (scheduled_at <= now). Returns the count fired.", {
32677
+ server.tool("run_due_dispatches", "Legacy/emergency only: manually trigger all pending tmux dispatches that are due (scheduled_at <= now). Returns the count fired.", {
32678
32678
  dry_run: exports_external.boolean().optional().describe("Preview without sending. Default: false."),
32679
32679
  confirm_busy: exports_external.boolean().optional().describe("Send even if target tmux panes appear busy. Default: false."),
32680
32680
  all: exports_external.boolean().optional().describe("Ignore scheduled_at and fire all pending dispatches immediately.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/todos",
3
- "version": "0.11.62",
3
+ "version": "0.11.64",
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",