/** * The ask-owner contract (specs/2026-10-01-decision-cards.md §1): validate a * structured owner question and turn it into a {@link ValidatedAsk}. Pure. * * Every rejection says what to fix and shows a correct ask, because the * reader is an agent that will retry with whatever the error tells it. * * @module services/decisions/decision-contract */ import type { AskOwnerInput, DecisionLanguage, DecisionOption, DecisionSensitiveKind, ValidatedAsk } from '../../types/decision.types.js'; /** A rejected ask. */ export declare class DecisionContractError extends Error { constructor(message: string); } /** The example appended to every contract error. */ export declare const ASK_OWNER_EXAMPLE = "Example: ask-owner --question \"Send the partner email on Monday?\" --option \"Send Monday \u2014 after the review call\" --option \"Hold \u2014 wait for legal\" [--option \"Third choice\"] --default \"Hold\" [--deadline 2026-10-02T12:00] [--ticket APP-12 --project P] [--sensitive email]"; /** The example appended to a merge card's contract errors. */ export declare const MERGE_ASK_EXAMPLE: string; /** * The fix-it message for a question with nothing left once internal * references are stripped (crewly#1367). * * @param raw - The question as asked * @returns Error text */ export declare function rewriteInPlainWordsMessage(raw: string): string; /** * The next day at {@link DECISION_CONSTANTS.DEFAULT_DEADLINE_HOUR_LOCAL}:00 local. * * @param now - Clock * @returns Default deadline */ export declare function defaultDeadline(now: Date): Date; /** * Whether a question is too vague to put in front of the owner. * * @param question - One-line question * @returns True for "thoughts?", "OK?", "可以吗" and the like */ export declare function isVagueQuestion(question: string): boolean; /** * Parse the options: an array of `{label, detail?}` objects or of strings * (`"Label"` / `"Label — detail"`). * * @param raw - Input * @returns Options with keys a/b/c * @throws DecisionContractError */ export declare function parseOptions(raw: unknown): DecisionOption[]; /** * Resolve the default to an option key or `wait`. * * @param raw - Label, key (a/b/c), number (1–3) or `wait` * @param options - Parsed options * @returns Option key or `wait` * @throws DecisionContractError */ export declare function resolveDefault(raw: unknown, options: DecisionOption[]): string; /** * Find the option a label, key (a/b/c) or number (1–3) names. * * @param text - What was given * @param options - Options * @returns The option, or null */ export declare function matchOption(text: string, options: DecisionOption[]): DecisionOption | null; /** * Parse the deadline. * * @param raw - ISO / date-time string, or empty for the default * @param now - Clock * @returns The deadline * @throws DecisionContractError when unreadable or not in the future */ export declare function parseDeadline(raw: unknown, now: Date): Date; /** * Parse the sensitive kind. * * @param raw - `email` | `publish` | `deploy` | `spend`, or empty * @returns The kind, or undefined * @throws DecisionContractError on anything else */ export declare function parseSensitive(raw: unknown): DecisionSensitiveKind | undefined; /** * Validate a whole ask. * * @param input - Raw input (skill / API body) * @param now - Clock * @returns The validated ask * @throws DecisionContractError with a fix-it message */ export declare function validateAskOwner(input: AskOwnerInput, now?: Date): ValidatedAsk; /** * Whether a card's options are a plain yes/no pair. * * @param options - Parsed options * @returns True for exactly two options that are both yes/no words */ export declare function isYesNoOptions(options: Array>): boolean; /** * Whether two questions asked back to back are really one either/or: * the second starts with 还是 / 或者 / "or ", or the first ends in an * either/or clause ("A, or B?"). * * @param first - The earlier question * @param second - The later question * @returns True when the pair reads as alternatives */ export declare function readsAsEitherOr(first: string, second: string): boolean; /** * The fix-it message for a second yes/no ask that is the other half of an either/or. * * @param earlierId - Id of the earlier decision * @returns Error text */ export declare function eitherOrMessage(earlierId: string): string; /** * Make a ticket's question say what is being decided: a short question * ("这版可以吗?") gets the ticket title in front of it. Longer ones are * left alone. * * @param question - One-line question * @param title - The ticket's title * @returns The question the card shows (never longer than the maximum) */ export declare function withTicketContext(question: string, title: string | undefined): string; /** * Fit a validated ask to the owner's language (crewly#1367): a Chinese owner * gets a Chinese question (else the ask is refused with what to fix) and * generic English option labels in Chinese ("Not now" → 先不, on a merge * card "Yes, merge" → 合并). An English or unknown owner gets the ask as is. * * @param ask - The validated ask * @param lang - The owner's language, when known * @returns The ask with localized options * @throws DecisionContractError when the question or a button is not in the owner's language */ export declare function fitAskToOwnerLanguage(ask: ValidatedAsk, lang: DecisionLanguage | null | undefined): ValidatedAsk; //# sourceMappingURL=decision-contract.d.ts.map