import type { OrgDaemon } from './daemon.js'; import { type QuestionDismissal } from './question-state.js'; export declare function questionsPath(root: string, org: string): string; export declare function readQuestions(root: string, org: string): { questions: Array; }; export declare function writeQuestions(root: string, org: string, data: ReturnType): void; /** Discard every still-pending question left over from a previous run. Call on * a fresh (non-resume) startOrg — same rule as clearApprovalsForFreshStart * (#165), for the same reason (#248). * * questions.json is keyed per-org, not per-run. A question a role asked in a * PREVIOUS run that was never answered before that run ended otherwise stays * `answer: null` forever: `org questions` and the dashboard list it as * pending, the idle watchdog treats it as a legitimate human wait and never * nudges or stops the new run, and answering it pushes context into a role * that never asked. Answered entries have no effect on a new run, so they are * kept as history; the dropped question's text is still in its own run's * bus.jsonl ('question' event). */ export declare function clearQuestionsForFreshStart(daemon: OrgDaemon, org: string): void; /** Pending questions that legitimately hold the run (ADR-O001 D4). * * THE INCIDENT: a `monomind-dev` run sat wedged for 8.3 hours on * `{"idle_minutes":60,"idle_stop_at":null,"hold":"pending-question"}`. The * question behind that hold had been declared NON-BLOCKING by its own * author, whose text opened with "no answer needed for the run to continue; * I am not blocking on this" — yet every unanswered question suppressed the * idle watchdog identically, so a question that said it was not blocking * disabled the only mechanism that could have stopped or restarted the run. * * A question that does not block is still recorded, listed by `org * questions` and answerable; it simply does not freeze anything. An * unflagged question is treated as blocking, so nothing silently stops * waiting for an answer a role really is waiting on (the hold it sets still * expires — see `advanceHold`). */ export declare function pendingBlockingQuestions(root: string, org: string): ReturnType['questions']; /** Agent-initiated human question (ask_human tool). Persists to questions.json (survives * process/dashboard restarts) and emits a 'question' BusEvent so the dashboard's SSE * stream and global inbox pick it up in real time. Returns a receipt string for the tool call. * Serialized per-org via withQuestionsLock() (same TOCTOU pattern as approvals). */ export declare function askHuman(daemon: OrgDaemon, org: string, role: string, question: string, blocking?: boolean): Promise; /** Delivers a human's answer to a pending ask_human question. If the org is still * running, pushes straight into the role's live mailbox (picked up on its very next * generator tick — see Mailbox.stream()). If the org has since stopped, queues the * answer via the same offline fallback deliver()/receiveRemote() already use * (inbox.ts + autoWake) and it's delivered when the org next starts. * * PERSIST-AFTER-DELIVERY: questions.json is only marked answered once delivery has * actually happened (mailbox push, or the message landing in inbox.jsonl). Marking it * first meant a rejected delivery — unknown role, mailbox closed mid-shutdown, a * queueMessage that threw on a full/read-only disk — left the question recorded as * answered while nobody ever received the answer, and the `already answered` guard * then refused every retry. The answer was simply gone. The inverse failure (crash * between delivery and the write) merely re-shows the question as pending, which a * human can act on; a silently swallowed answer is not recoverable. */ export declare function answerQuestion(daemon: OrgDaemon, org: string, role: string, questionId: string, answer: string, resolvedBy?: string): Promise<{ ok: true; delivery?: 'skipped'; } | { ok: false; error: string; }>; /** #572: close an open question WITHOUT an answer. A blocking question holds * org_complete and the idle watchdog until it is closed (#564); when no * answer is coming, a human dismisses it instead of inventing one. * * The dismissal is recorded whatever happens to the note — its job is to * release the run. The asking role gets a short note so it stops waiting: * pushed into its mailbox while the org runs, queued in the inbox (without * waking the org) while it does not. A role that is no longer in the org * definition gets nothing, and the audit event says so. */ export declare function dismissQuestion(daemon: OrgDaemon, org: string, questionId: string, reason?: string, resolvedBy?: string): Promise<{ ok: true; role: string; delivery: 'live' | 'queued' | 'skipped'; } | { ok: false; error: string; }>; //# sourceMappingURL=questions.d.ts.map