/** * daemon/todoist-reply.ts — answering on the task you were asked from. * * A task arriving here is often a question, not a work order, and until now the * answer went to a terminal the asker was not looking at. Filing from a watch * and reading the reply at a desk is not a channel; it is two half channels. * * So a session answers on the task itself. The comment carries the agent mark, * which `route()` already drops before anything else, so our own writes cannot * come back as instructions. * * Deliberately does NOT complete the task. Completion is the human saying done * — the same rule the receiver enforces on the way in — and a question whose * answer you have not read yet is not done. Left open, the task keeps its place * in the list with a comment indicator; completed, it vanishes from view and * the answer with it. */ export interface ReplyResult { commentId: string; taskId: string; } /** What a comment event needs from its parent task to be routable at all. */ export interface ParentTask { content: string; projectId: string; labels: string[]; } /** * Fetch the task a comment belongs to. * * A `note:added` payload carries `item_id` and the comment text and nothing * else — no project, no labels. Without them the security boundary cannot be * evaluated, so a comment is unroutable until its parent is resolved. This is * the lookup that makes replying-by-comment possible at all. */ export declare function fetchParentTask(taskId: string, fetchImpl?: typeof fetch): Promise; /** * Post a comment on a task as the agent. * * The mark is added here rather than trusted to callers: every path that can * write to Todoist has to be echo-safe, and "remember the prefix" is not a * safety mechanism. */ export declare function replyToTask(taskId: string, text: string, fetchImpl?: typeof fetch): Promise; /** * How many OPEN tasks in this project share a title. * * Two tasks called the same thing are indistinguishable in a list, so a reply * posted on one looks — to whoever is watching the other — exactly like being * ignored. That cost two full rounds today: comment routing was working * perfectly and the answers were landing on a sibling nobody was looking at. * Being ignored and being answered elsewhere must not look the same. * * Returns 1 in the ordinary case (this task alone) and 0 when it cannot tell — * a lookup failure must not invent a duplicate warning. */ export declare function countTasksWithTitle(projectId: string, title: string, fetchImpl?: typeof fetch): Promise; /** * Create a task as the agent. * * A session that files a task into an ingress project is writing into its own * inbox: `item:added` fires, routing sends it straight back, and the session * receives its own note as a work order. That happened on 2026-08-01 — a * session probing due-date parsing created a dozen test tasks and was handed * every one of them back within seconds. * * The mark is applied here rather than trusted to the caller, for the same * reason it is on replies: "remember the prefix" is not a safety mechanism. * `route()` drops marked content before anything else, so a task created this * way cannot come back as an instruction. */ export declare function createTask(content: string, opts?: { projectId?: string; description?: string; dueString?: string; }, fetchImpl?: typeof fetch): Promise<{ taskId: string; }>; /** * Add or remove a label on a task. * * Used to CLAIM a trigger before dispatching it. Honouring another runner's * claim is only half an interlock: a path that dispatches and leaves the task * unclaimed lets the next poller see an advanced due date with no claim on it, * conclude the box was ticked, and dispatch the same work again. */ export declare function setTaskLabel(taskId: string, label: string, present: boolean, fetchImpl?: typeof fetch, attempt?: number): Promise; /** The task's current due date, or undefined when it has none or cannot be read. */ export declare function fetchTaskDue(taskId: string, fetchImpl?: typeof fetch): Promise; /** * The task's title and web link, for a notification that identifies itself. * * A push saying "a reply was posted" is only marginally better than silence * when the tree holds hundreds of tasks: knowing something happened without * knowing where still means hunting. The url is what Todoist's own clients * open, so the notification is one tap from the conversation it announces. * * Never throws — a notification that cannot name its task still beats none. */ export declare function fetchTaskBrief(taskId: string, fetchImpl?: typeof fetch): Promise<{ title?: string; url?: string; projectId?: string; }>; //# sourceMappingURL=todoist-reply.d.ts.map