import type { ToolSpec } from "../core/types.js";
/**
 * design/119 (CC 2.1.198 parity) — the structured task-list tool family: `TaskCreate` / `TaskGet` /
 * `TaskUpdate` / `TaskList`. CC 198's upgrade path over TodoWrite: individual tasks with stable ids,
 * status transitions, dependencies (blocks/blockedBy), an optional owner, and free metadata — instead
 * of TodoWrite's replace-the-whole-list. CC209 对齐批B B3: the two families are MUTUALLY EXCLUSIVE and
 * this one is the DEFAULT — TodoWrite mounts only when the task list is explicitly off (the CC 209
 * shape: TodoWrite isEnabled = !taskList; see `scenarios/full-body.ts`).
 *
 * State default: like TodoWrite, the default store lives in this factory's closure — FRESH per task
 * and torn down with it; nothing durable, no deps, no egress (the model's own scratch, projected to
 * observers only through each call's tool result / `details`). Descriptions follow CC 2.1.198
 * (product-specific lines — teammate assignment, spinner/UI wording — trimmed or generalized).
 *
 * design/147 §6 D2 (CC 2.1.216 shared team task list): pass a {@link TaskListStore} to share ONE
 * task list across several agents — CC 216's team coordination artifact ("Check the task list
 * periodically. Create new tasks when work should be divided. Mark tasks resolved when complete.")
 * is a task-list file under the team directory; the sema equivalent is this storage seam. A
 * deployment mounts the SAME store instance into each teammate's tool bundle (same session = same
 * trust domain — the list is model scratch either way, sharing adds no egress). The `owner` field's
 * teammate-assignment semantics (trimmed in the 198 port) come back through this seam.
 */
export interface TaskListItem {
    id: string;
    subject: string;
    description: string;
    activeForm?: string;
    owner?: string;
    status: "pending" | "in_progress" | "completed";
    blocks: string[];
    blockedBy: string[];
    metadata?: Record<string, unknown>;
}
/**
 * design/147 §6 D2 — the task-list persistence seam (storage-tier abstraction, same family as
 * `RosterStore`/checkpoint store: core bundles a memory implementation; a deployment plugs pg/file
 * behind the same interface and hands ONE instance to every teammate's tool bundle).
 *
 * Contract:
 * - Methods MAY be async (a pg-backed store is); the bundled memory store is synchronous.
 * - Each single method call must be atomic in the store. Multi-step read-modify-write sequences
 *   (update, delete-with-pruning) are serialized PER STORE by the tools themselves within this
 *   process ({@link createTaskListTools} keeps a per-store promise chain) — a store shared across
 *   PROCESSES additionally needs its own transactional guarantees for those sequences, which is the
 *   deployment's half (documented, not solved here; CC's file-backed team list has the same window).
 * - `allocateId` is store-owned so concurrent teammates never mint colliding ids, and the
 *   high-water mark is MONOTONIC ACROSS REOPENS for any backend that outlives one wrapper
 *   instance: a restart/reconnect must never re-mint an id the backend has already handed out
 *   (the conformance suite's durable tier pins exactly this — a counter that resets while the
 *   rows survive makes every receipt lie and every subsequent update miss).
 * - Value semantics: `get`/`list` return detached copies; `set` stores a detached copy. Callers
 *   mutate their copy and write it back — a live-reference store would alias already-emitted events.
 * - RB-274: `list` is ordered by ID (numeric ascending), not by write order. The tool lane always
 *   allocates before it sets, so the two coincide there — but a store shared with an OUTSIDE writer
 *   (a real CC instance on the same directory) can set an id out of order, and then the backends
 *   disagreed: memory replayed its Map's insertion order while file/cc read the id order back off
 *   disk. Ordering is part of the contract, not each backend's incidental iteration order.
 *
 * @contract task_list.partition_is_root_session — a deployment that mounts a TaskListStore per session keys it by the
 * delegation tree's ROOT session: every child of the tree (spawned live, or revived by a host verb after a durable park)
 * reads the one list the leader reads; in-engine children share by construction, a per-call or per-reviver store is the divergence.
 */
export interface TaskListStore {
    get(id: string): TaskListItem | undefined | Promise<TaskListItem | undefined>;
    set(id: string, item: TaskListItem): void | Promise<void>;
    delete(id: string): boolean | Promise<boolean>;
    list(): TaskListItem[] | Promise<TaskListItem[]>;
    allocateId(): string | Promise<string>;
    /** the transaction boundary for adapters whose backend outlives one wrapper
     *  instance (pg, shared files): when present, the tools run EVERY read-modify-write sequence
     *  inside `mutate` and the adapter supplies sequence-level atomicity (a DB transaction, an
     *  advisory lock keyed on the backend — not on this object). Absent ⇒ the tools fall back to the
     *  in-process per-store promise chain, which is exactly right for the bundled memory store (its
     *  backend IS this object) and wrong for anything shared wider — implement `mutate` there. */
    mutate?<T>(fn: (tx: TaskListStore) => Promise<T>): Promise<T>;
}
/** the clone policy behind the detached-copy contract: metadata must be JSON-shaped
 *  (structuredClone would accept — and SHARE — SharedArrayBuffer backing memory, and throws opaquely
 *  on functions/proxies; the tool lane is always JSON, so this guards DIRECT store users). */
/**
 * RB-168 — the dependency arrays are STRUCTURAL, and a store must refuse a row that lacks them.
 *
 * The in-memory store rejected such a row incidentally: its snapshot helper spreads `t.blocks`, so a
 * missing array threw "blocks is not iterable" at write. The file store had no such accident and wrote the
 * row to disk, where it survived until `TaskUpdate` reached `t.blocks.includes(...)` — a contaminated row that
 * passes the write and detonates at an unrelated later call, in a different session, with no trace of where
 * it came from. Two backends disagreeing about what a valid row is means a test written against one has
 * different semantics on the other.
 *
 * NORMALIZE rather than reject: the harm is a stored row that EXPLODES AT READ, not an incomplete one.
 * Defaulting the arrays removes the harm without inventing a new failure mode for callers that legitimately
 * write a partial row (a task with no dependencies has empty arrays — that is what the absence meant).
 * Rejecting instead would have been a behaviour change dressed as a fix: the first attempt did exactly that
 * and broke an in-tree test whose subject was id allocation, not row shape.
 */
export declare function normalizeTaskShape<T>(item: T): T;
export declare function assertJsonMetadata(value: unknown, path?: string): void;
/**
 * RB-274 — the contract's `list` order, mirroring the CC-compat backend's `orderIds`
 * (`stores/cc/task-list-store.ts`): numeric ids ascending (CC's own task order), any non-numeric id
 * after them, lexicographically. Ties broken lexicographically so the comparator is total (and the
 * order therefore stable across repeated calls, which the contract also requires).
 */
export declare function compareTaskIds(a: string, b: string): number;
/** The bundled in-memory {@link TaskListStore} — detached copies both ways (see interface contract). */
export declare function createMemoryTaskListStore(): TaskListStore;
/** Build the four task-list tools sharing one task list. Mount all four together.
 *  No `store` ⇒ a fresh private in-memory list (the design/119 per-run scratch shape, unchanged).
 *  With `store` ⇒ the shared team task list (design/147 §6 D2) — mount the same instance everywhere. */
export declare function createTaskListTools(store?: TaskListStore): ToolSpec[];
