import { type CliLang } from './i18n.js'; /** 严格按 SemVer 2.0 precedence 判断 `a > b`(只覆盖本仓库实际使用的形态: * MAJOR.MINOR.PATCH 可选 `-prerelease`)。非法字符串直接返回 false,update-check * fail-safe 不提示。 * - release > prerelease(同 MAJOR.MINOR.PATCH) * - prerelease 之间按 dot-separated identifier 比较(数字段当数字,字母段当字符串) */ export declare function isSemverGt(a: string, b: string): boolean; /** 落盘缓存。展示只读它(热路径零网络);registry 抓取在后台写它,供下次运行用。 */ export interface UpdateCache { /** 上次抓到的 registry latest 版本。后台抓取成功才有;只发起过、还没成功时缺位。 */ latestVersion?: string; /** 上次「发起检查」的时间(ISO)—— 成功失败都更新,是 20h 重抓节流的锚点。 * 父进程在 spawn 刷新前就写它,这样 registry 不通时也不会每条命令都重新拉起后台检查。 */ lastCheckedAt: string; /** 上次提示过的版本,用于「同版本 20h 内不重复提示」。 */ lastNotifiedVersion?: string; /** 上次提示时间(ISO)。 */ lastNotifiedAt?: string; } interface BoxParts { current: string; latest: string; upgradeCmd: string; silenceHint: string; } /** 缓存落盘走仓库既有约定 `~/.oh-my-knowledge/<...>`(见 src/eval-core/cache.ts、 * src/server/job-store.ts)。home 可注入,方便测试传 tmp 目录。 */ export declare function defaultCachePath(home?: string): string; /** 读缓存。缺失 / 损坏 / 非对象 / 缺时间锚点一律返回 null,调用方按「无缓存」处理。 * lastCheckedAt(节流锚点)必须有;latestVersion 可缺(只发起过、还没抓成功的记录)。 */ export declare function readCache(path: string): UpdateCache | null; /** 原子写(temp + rename),避免两个 omk 进程并发写出半截 JSON。homedir 不可写时 * 整体静默失败 — 退化为「每次后台重抓」,不崩。 */ export declare function writeCache(path: string, data: UpdateCache): void; /** 是否该提示:有缓存的 latest 严格高于当前版本,且(没提示过这个版本 / 距上次提示超 20h)。 * 纯函数,now 外部注入,便于确定性测试。 */ export declare function shouldNotify(cache: UpdateCache | null, currentVersion: string, now: Date, throttleMs?: number): boolean; /** 缓存是否过期(需后台重抓):无缓存 / 时间戳缺失或不可解析 / 超 ttl。 */ export declare function isStale(cache: UpdateCache | null, now: Date, ttlMs?: number): boolean; /** 一次运行该做什么(纯函数,now 注入,便于确定性测试): * - notify:是否展示提示(仅凭缓存,无网络)。 * - refresh:是否发起后台刷新。 * - nextCache:需要落盘的新缓存,null 表示无需写。 * * 关键:refresh 为真时,nextCache 一定带上 `lastCheckedAt = now` —— 即「发起检查」这件事本身 * 会立即落盘,所以 registry 持续不通时,下一次运行看到新鲜的 lastCheckedAt 就不再重复 spawn, * 20h 节流对离线/失败同样生效(不退化成每条命令拉起后台检查)。 */ export declare function planUpdateActions(cache: UpdateCache | null, currentVersion: string, now: Date): { notify: boolean; refresh: boolean; nextCache: UpdateCache | null; }; /** 终端可视宽度:全角 / CJK codepoint 计 2,其余计 1。用 [...str] 逐 codepoint * 迭代以正确处理代理对。框内只用 width-1 的 ↑(U+2191)/→(U+2192),不放 emoji, * 避免 emoji 宽度歧义破坏右边框对齐。 */ export declare function visualWidth(str: string): number; /** 右补空格到目标可视宽度(已超宽则原样返回)。 */ export declare function padToWidth(str: string, target: number): string; /** 渲染多行高亮边框(纯函数,可快照测试)。内宽取各行最大可视宽度,逐行用 * padToWidth 对齐后画 ┌┐└┘─│ 框,返回前后留白、以 \n 结尾的整串。 */ export declare function renderUpdateBox(parts: BoxParts, lang: CliLang): string; /** 选染提示文案:TTY 下多行高亮框,管道 / 非 TTY 退回单行(不污染输出)。纯函数, * isTty 注入便于测试两条分支。 */ export declare function renderNotice(parts: BoxParts, pkgName: string, lang: CliLang, isTty: boolean): string; /** spawn 一个 detached + unref 的子进程跑 worker。子进程启动失败(ENOENT / EACCES / * EAGAIN)是异步 `error` 事件 —— 不挂 listener 的话 Node 会当 uncaught exception 抛出、 * 反过来拖垮主命令,所以必须挂个空 handler 吞掉,维持升级检查全程 fail-silent。 */ export declare function spawnDetached(scriptPath: string, args: string[]): void; /** 升级提示:展示与抓取解耦。本次运行只读缓存即时决定是否提示(热路径零网络); * 缓存过期时后台抓一次写回,供下次用。首次运行(无缓存)不提示。全程 fail-silent, * 由 index.ts 在非短路径下 fire-and-forget 调用。 */ export declare function checkUpdate(lang: CliLang): Promise; export {};