/**
 * design/105 — Scheduler seam（自唤醒/自调度）。「手」腿（`ExecutionEnv`）的**跨-task** 未来意图能力：一个 run 里的模型
 * 把「未来要做的活」（cron 排程 / 延迟唤醒）持久化交给一个**常驻 backend**（TOC = shell daemon），由它在未来重起一个
 * **新** task。
 *
 * 🔴 与 {@link import("./background-shell.js").BackgroundShellCapability} 的根本区别（design/105 §3.1 D1）：
 * background-shell 的进程 ⊆ task（在每条退出路径 dispose，不跨 suspend）；scheduler 的意图必须 **SURVIVE task 结束**
 * （schedule 的全部意义就是当前 task 结束后 daemon 还能重起）——镜像反转，**绝不 dispose-on-exit**。
 *
 * core 薄壳裁定：core 只出接口 + 工具壳 + `hasScheduler` 门控；**持久化存储 / cron 时钟 / idle 触发 / 起新 task 全在
 * backend（daemon）**——core 是 request-driven 不常驻，绝不假装调度器。NodeExecutionEnv 不自带 daemon（不同于
 * background-shell 自带 spawn），而是**委托一个注入的 backend**（由一个 shell daemon 实现本接口）。
 */
import type { ExecutionEnv, Result } from "../internal/harness-types.js";
/** 一个已排未来意图的句柄。**backend-local、durable（daemon 持久化、重启存活）、对调用方不透明** —— 绝不暴露可枚举的 raw id。 */
export type ScheduledTaskId = string & {
    readonly __brand: "ScheduledTaskId";
};
/**
 * 类型化错误码（对齐 background-shell 风格）。方法 MUST NOT throw（返回 {@link Result}）。
 */
export type SchedulerErrorCode = "unsupported" | "not_found" | "limit_exceeded" | "invalid_schedule" | "io";
/** scheduler 操作的类型化错误。`code` 给程序分类，`message` 给模型自纠。 */
export declare class SchedulerError extends Error {
    readonly code: SchedulerErrorCode;
    readonly cause?: unknown | undefined;
    constructor(code: SchedulerErrorCode, message: string, cause?: unknown | undefined);
}
/**
 * 🔴 **模型可控面（不可信）**：纯意图，**无任何身份字段** —— 防模型经自排 prompt 权限抬升（design/62 同款红线：身份是
 * Runner-held，非工具参数）。`prompt` = 未来 task 的不可信 `objective`（daemon 起 task 时经完整 prepare-task gate）。
 */
export interface ScheduledIntent {
    /** 未来要跑的 prompt（agent 自排）。daemon 起新 task 时作 `objective`。 */
    prompt: string;
    /** 何时触发。`cron`=重复（受 minCronIntervalSec 约束）；`at`=一次性绝对时刻；`delay`=相对延迟（一次性 self re-wake 用）。 */
    when: {
        kind: "cron";
        expr: string;
    } | {
        kind: "at";
        atMs: number;
    } | {
        kind: "delay";
        delaySec: number;
    };
    /** 可选短标签；与 `(scope, when)` 一起做 upsert 去重键（防工具重试产生重复 intent）。 */
    label?: string;
    /**
     * [c209-D2] 生存期维度（durable 分层激活批 2026-07-16；缺省 `"durable"` = 既有行为，零破坏）。
     * - `"durable"`：daemon 持久化、重启存活、跨会话继续触发——本 seam 的历史唯一语义（intent 不带本字段
     *   即此义，老 backend 零迁移）。
     * - `"session"`：会话级易失体（上游同名工具的缺省语义——「会话内过会儿跑一下」，不该活成永生任务）。
     *   🔴 消费契约（daemon 半场，shell 仓实现）：session intent MUST 随带 `sessionId` 的
     *   {@link SchedulerContext} 排入（工具壳保证）；该会话终结（正常收束 / 超时 reap / 显式关闭）时 daemon
     *   MUST 一并 reap 本 intent——绝不让它在会话死后继续触发。不支持本维度的 backend 不会收到 session
     *   intent：工具壳按 {@link SchedulerCapability} 的 `supportsSessionLifetime` 能力位门控，不支持时对
     *   session 语义调用诚实拒绝并引导 `durable: true`——**绝不静默升级为永生任务**（本案的整个意义）。
     */
    lifetime?: "durable" | "session";
    /**
     * [c209-D2] `when.kind === "cron"` 专用：`false` = 命中一次即删（上游 recurring:false 语义——触发一次后
     * 等价一次性 at）；缺省 `true` = 每次 cron 匹配都触发（既有行为，intent 不带本字段即此义）。
     * 🔴 消费契约（daemon 半场，shell 仓实现）：recurring:false 的 cron intent 首次触发后 daemon MUST 删除
     * 该 intent，不再排下次。core 侧只把字段进 seam；delay/at kind 与 recurring 同给在工具层 fail-closed 拒
     * （recurring 只属 cron），故 daemon 只会在 cron intent 上见到本字段。
     */
    recurring?: boolean;
    /**
     * 执行形态（CC ScheduleWakeup 对齐批 2026-07-11；缺省 `"task"` = 既有行为，全向后兼容）。
     * - `"task"`：daemon 起一个**无上下文新 task**（`prompt` 作 objective，经完整 prepare-task gate）——CronCreate 语义。
     * - `"session-wakeup"`：daemon **续 `ctx.sessionId` 指定的同一会话**（`prompt` 作该会话下一轮输入；同上下文、
     *   同 prompt cache）——CC ScheduleWakeup 的 /loop dynamic 语义。🔴 契约：`mode:"session-wakeup"` 的 intent
     *   MUST 随一个带 `sessionId` 的 {@link SchedulerContext} 排入（工具壳保证）；daemon 触发时 MUST resume 该
     *   session 而非起新 task，且 principal 原样（不升权）。不支持续会话的 daemon MUST 拒（`invalid_schedule`），
     *   绝不静默降级成新 task（丢上下文=静默换语义）。
     */
    mode?: "task" | "session-wakeup";
}
/**
 * 🔴 **Runner-held 可信面**（工具工厂闭包捕获，模型无法触及）。镜像 subagent 经 `ctx.principal` 继承的代码层强制
 * （`agents/subagent.ts`）。`schedule` 的实现 MUST 把 `principal` 钉死进持久化 intent；daemon 触发时原样传
 * `runTask({ principal })` —— **不升权、不省略**。
 */
export interface SchedulerContext {
    /**
     * 越界隔离键（cancel/list 只能操作同 scope 排的）。由 Runner 填，且**按被操作 intent 的 lifetime 分叉**
     * （ruled 2026-08-03）：`lifetime:"session"` 的意图用会话链（sessionId ?? principal ?? taskId ?? "default"）；
     * durable 意图用跨会话稳定身份（principal ?? "default"）——否则 durable job 会被钉死在排它的那个会话里，
     * 后续会话 cancel/list 一律 `not_found`（任务照常触发却再也删不掉）。backend 侧无需分辨腿别：照旧只按
     * 收到的 `scope` 隔离即可；**同一 daemon 上两类键共存**，一次 `list` 只回本 scope 的行（工具壳自己并两腿）。
     * ⚠️ 部署面：本分叉之前写下的 durable 行仍带旧的会话键，一次性重铸键归 backend 半场，engine 不做迁移。
     */
    scope: string;
    /** 排程者身份；daemon 触发时原样传给 runTask（防权限抬升）。 */
    principal?: string;
    /** 可选：daemon 触发新 task 时复用的 session（chat-continuity；缺省=fresh-session）。⚠️ 复用需 durable sessionStore（design/105 §3.4）。 */
    sessionId?: string;
    /**
     * 可选 opaque 起-task 配置（model/policy 提示）。v1 daemon 可忽略、用部署默认模板起 task（intent.prompt + 继承的
     * principal 已足）；未来精细化时由 daemon 解释。core 不定其 schema（最薄）。**不可由模型提供**（Runner-held）。
     */
    taskConfig?: unknown;
}
/** {@link SchedulerCapability.list} 的条目：足够 self-discovery + 防重复排，不含完整意图。 */
export interface ScheduledTaskSummary {
    id: ScheduledTaskId;
    /** 渲染用：cron expr / at 时刻 / delay 秒 的人读摘要。 */
    when: string;
    label?: string;
    /** 下次触发的 epoch ms（cron/at 可算；daemon 提供）。 */
    nextRunMs?: number;
    /** 执行形态回显（{@link ScheduledIntent.mode}）。ScheduleWakeup 的 stop:true 靠它定位要取消的 pending
     *  wakeup（cron/task 意图不受 stop 影响——CC 206 D9 语义）。老 backend 不回 = undefined（工具壳以
     *  label 兜底过滤）。 */
    mode?: "task" | "session-wakeup";
    /** [c209-D2]：生命周期层级回显（{@link ScheduledIntent.lifetime}）——缺了它，任务创建后就再无
     *  公开面能辨认自己是会话级还是持久级（CronCreate 的即时 details 是唯一一瞥）。老 backend 不回 =
     *  undefined（层级未知，按既有 durable 直觉读）。 */
    lifetime?: "durable" | "session";
    /** [c209-D2]：one-shot cron 回显（{@link ScheduledIntent.recurring}）；undefined = 老 backend
     *  或非 cron 意图。 */
    recurring?: boolean;
}
/**
 * 「手」腿的跨-task 调度能力。一个具体 `ExecutionEnv` 可选附加它（交叉类型），经 {@link hasScheduler} 检测。不支持的
 * env（无注入 daemon backend）= `schedulerCapabilities.supported=false`，四个 scheduler 工具自动不挂（INERT）。
 */
export interface SchedulerCapability {
    /** 显式声明能力（像 background-shell 一样不猜）。`supported:false` → 工具不挂（design/105 §3.9 TOB / 无 daemon）。 */
    readonly schedulerCapabilities: {
        readonly supported: boolean;
        /** 单 scope 存量 intent 上限（防自排炸弹；超限 `limit_exceeded`）。 */
        readonly maxScheduledPerScope: number;
        /** delay/at 最小延迟秒（防 busy 自醒）。 */
        readonly minDelaySec: number;
        /** cron 解析后实际触发间隔下限秒（`* * * * *` 占 1 slot 但无限触发 → 须有下限）。 */
        readonly minCronIntervalSec: number;
        /** 最远排程地平线秒（fail-closed 有界，绝不无限未来）。 */
        readonly maxScheduledHorizonSec: number;
        /**
         * [c209-D2] backend 是否支持 {@link ScheduledIntent.lifetime} `"session"`（intent 随排入会话终结被
         * reap）。缺省 undefined/false = 不支持：工具壳收到 session 语义调用（CC 形 `durable` 缺省 false）时
         * 诚实拒绝并引导 `durable: true`——**绝不静默落成永生任务**。声明 `true` 的 backend MUST 实现 session
         * intent 的 reap 消费契约（见 {@link ScheduledIntent.lifetime} 注释）。
         * 🔴（TOCTOU 契约条款）：本能力位 MUST 在 backend **实例生命周期内不可变**（`readonly` 快照，
         * 不得热翻）——工具壳的门控读与 `schedule()` 是两次操作，中途翻位会让 session intent 落到不会 reap 的
         * backend 上。防线双置：声明面不可变 + `schedule()` 实现 MUST 自行拒绝它无法履行 reap 契约的
         * `lifetime:"session"` intent（fail-closed 兜底，不依赖工具壳的先行探测）。
         *
         * 「诚实拒绝」条款的适用边界：它约束**携带 session 语义字段的调用**（CronCreate 的 `durable` 形）。
         * 一个没有 durable 逃生口的工具（ScheduleWakeup 形）对不支持位的 backend 走的是另一臂——发送
         * 历史 durable intent 并在回执与工具描述上**披露**该 wakeup 不随会话终结（披露≠静默；拒绝会在
         * 零收益下拿掉该宿主的整只工具）。该臂为既裁形（capability 位 opt-out 裁定），非本条款的违例。
         */
        readonly supportsSessionLifetime?: boolean;
        /**
         * TB 裁决 — 宿主是否有会兑现 `mode:"session-wakeup"` intent 的常驻唤醒腿。
         * **opt-out 方向(与 supportsSessionLifetime 的 fail-closed 缺省相反,有意)**:session-wakeup
         * 是既有工作语义(daemon 宿主已在兑现),缺省关断=误伤现网——缺省/undefined=支持;headless 单发
         * 宿主(如 `-p` print 路径:零 daemon,进程终答即退)**显式声明 false** ⇒ 工具壳对 ScheduleWakeup
         * 诚实拒绝(排入即失约=静默尸体,比拒绝更糟)。不可变纪律同 supportsSessionLifetime。
         */
        readonly supportsSessionWakeup?: boolean;
    };
    /**
     * 持久化一个未来意图。`intent` = 模型可控（无身份）；`ctx` = Runner-held 可信上下文（principal/scope/...）。返回不透明
     * 句柄。🔴 实现 MUST 把 `ctx.principal` 钉死进持久化 intent（daemon 触发原样传 runTask，不升权）；MUST 用 cron 库
     * 解析 `when.expr` **禁 shell-exec**（RCE 红线）；MUST 持久化（durable，daemon 重启存活）。upsert：同
     * `(scope, when, label, lifetime)` 覆盖（幂等）——**lifetime 是身份的一部分**（RB-12/server 1.215 F1 案：
     * session 级与 durable 级、或不同会话的 session 级 job 撞 (when,label) 是正常用法,MUST NOT 互相覆盖;
     * session 级的身份还含 sessionId）。
     */
    schedule(intent: ScheduledIntent, ctx: SchedulerContext): Promise<Result<{
        id: ScheduledTaskId;
    }, SchedulerError>>;
    /** 取消一个已排意图（幂等：取消不存在的是 ok no-op）。🔴 越界：`id` MUST 属本 scope；非本 scope 一律 `not_found`，不越界存在性。 */
    cancel(id: ScheduledTaskId, ctx: SchedulerContext): Promise<Result<void, SchedulerError>>;
    /** 列**本 scope** 已排意图（self-discovery + 防重复排）。范围 = `ctx.scope`，非全局。 */
    list(ctx: SchedulerContext): Promise<Result<ScheduledTaskSummary[], SchedulerError>>;
}
/**
 * 结构 + 语义检测：`env` 是否暴露 scheduler 能力且声明 `supported:true`。挂载门控用此（对齐 `hasBackgroundShell`）。
 */
export declare function hasScheduler(env: ExecutionEnv): env is ExecutionEnv & SchedulerCapability;
export declare function isValidCronExpr(expr: string): boolean;
