import type { ScheduledTask, ParsedSchedule, ScheduleExecutionPosition } from '../types.js'; /** * Raised by `createTask` when an `id` is supplied but a task already exists * with that id AND its canonical input differs from the incoming params. * * Workflow runtime uses this to detect "same attempt asked to create a * different schedule" — a sign the attempt is being mutated (forbidden by * attempt-immutability rule, events doc §4.2). */ export declare class IdempotencyConflictError extends Error { readonly taskId: string; readonly existingInputHash: string; readonly incomingInputHash: string; constructor(detail: { taskId: string; existingInputHash: string; incomingInputHash: string; }); } /** * Canonical schedule input used for create-or-return-identical comparison. * * Includes only the fields that callers control as task **input** (events * doc v0.1.2 §3.5 ScheduleCanonicalInput). Excludes: * - `creator*` (audit metadata, not input) * - `enabled`, `nextRunAt`, `lastRunAt`, `lastStatus`, `lastError`, * `lastDeliveryError` (runtime state, mutates over task lifetime) * - `createdAt` (metadata) * - `repeat.completed` (counter, mutates per run) * - `parsed.display` (UI-facing string, redundant given `expr`/`runAt`) * * Codex round 4 finding 4: `parsed` is NOT purely derived for one-shot or * relative schedules. `30m`/`2h`/`明天9:00`/`5分钟后` etc compute a * concrete `runAt` at parse time using "now"; if a workflow retry re- * parses the same raw `schedule`, it gets a different `runAt`. So the * canonical input freezes the resolved schedule shape (`parsed.kind` and * whichever of `parsed.runAt`/`parsed.minutes`/`parsed.expr` applies). */ export declare function canonicalScheduleInput(t: { name: string; schedule: string; parsed?: ParsedSchedule; prompt: string; workingDir: string; chatId: string; chatType?: 'group' | 'p2p' | 'topic_group'; rootMessageId?: string; scope?: 'thread' | 'chat'; executionPosition?: ScheduleExecutionPosition; topicTitle?: string; larkAppId?: string; repeat?: { times: number | null; completed?: number; }; deliver?: 'origin' | 'local' | 'new-topic'; silent?: boolean; }): unknown; /** Bind the store's default file to one bot. Daemon: own bot at startup. * CLI: the session's bot / explicit --lark-app-id before any store call. */ export declare function setScheduleScope(appId: string): void; export declare function getScheduleScope(): string | null; /** The per-bot schedules file: `/bots//schedules.json`. */ export declare function scheduleFilePathFor(appId: string): string; export declare function getTaskOutputDir(taskId: string): string; export declare function __setScheduleStoreBeforeRenameTestHook(hook?: () => void): void; /** * Create a scheduled task — or return the existing one with the same input * when called with a workflow-supplied `id` that already exists. * * Behaviour matrix (events doc v0.1.2 §2.2 Option A): * * | scenario | result | * |--------------------------------------------|------------------------------| * | no `id` | randomUUID(8) — legacy path | * | `id` not in store | create with the given id | * | `id` in store + canonical input matches | return existing (no mutation)| * | `id` in store + canonical input differs | IdempotencyConflictError | * * Use `wf_` prefixed ids when called from workflow runtime to * avoid collisions with the 8-char randomUUID legacy namespace. */ export declare function createTask(params: { id?: string; name: string; schedule: string; parsed: ParsedSchedule; prompt: string; workingDir: string; chatId: string; rootMessageId?: string; scope?: 'thread' | 'chat'; executionPosition?: ScheduleExecutionPosition; topicTitle?: string; chatType?: 'group' | 'p2p' | 'topic_group'; larkAppId?: string; creatorChatId?: string; creatorRootMessageId?: string; creatorLarkAppId?: string; nextRunAt?: string; repeat?: { times: number | null; completed: number; }; deliver?: 'origin' | 'local' | 'new-topic'; silent?: boolean; }): ScheduledTask; export declare function getTask(id: string, appId?: string): ScheduledTask | undefined; export declare function removeTask(id: string, appId?: string): boolean; export declare function updateTask(id: string, updates: Partial>, appId?: string): void; /** * Record a run outcome and auto-manage repeat counter. If the task has a * finite repeat count and we've hit it, the task is removed. */ export declare function markRun(id: string, success: boolean, error?: string, deliveryError?: string): void; export declare function listTasks(appId?: string): ScheduledTask[]; /** Aggregate view across several bots' stores (unsandboxed admin CLI). Bots * whose store cannot be read (sandbox deny / missing BOT_HOME) are skipped — * callers inside a sandbox naturally collapse to their own bot. */ export declare function listTasksForBots(appIds: readonly string[]): Array; /** Bulk-insert raw task entries into one bot's store (startup split * migration). Runs the same in-file legacy normalization as a disk read; * an id already present in the destination wins (the per-bot store is newer * by definition) and the collision is logged. */ export declare function importTasks(appId: string, entries: ReadonlyArray<[string, unknown]>): void; /** Locate a task id across several bots' stores. First hit wins (ids are * UUID-derived; a cross-store collision is negligible and would only make an * id-addressed command pick the first store). */ export declare function findTaskAcrossBots(id: string, appIds: readonly string[]): { task: ScheduledTask; appId: string; } | undefined; /** Ensure per-task output dir exists and return path to today's run log. */ export declare function appendOutputLog(taskId: string, content: string): string; export declare function startExternalWriteWatcher(): void; //# sourceMappingURL=schedule-store.d.ts.map