import { type AutoUpdateCheckNowResult, type AutoUpdateConfig, type AutoUpdateSnapshot } from "./types.js"; import { type VersionSource } from "./version-source.js"; import { type EventName } from "../../utils/event-catalog.js"; import type { EventOptions, LogLevel } from "../../utils/logger.js"; /** * Minimal logger contract so the coordinator does not depend on a concrete logger. `event` mirrors * `Logger.event` (see `utils/logger.ts`) so the coordinator can emit first-class `auto_update.*` * telemetry through the same catalog every other subsystem uses, without pulling in the full * `Logger` interface (which also carries `debug`, not needed here). */ interface LoggerLike { info(...args: unknown[]): void; warn(...args: unknown[]): void; error(...args: unknown[]): void; event(name: N, level: LogLevel, opts: EventOptions): void; } /** Construction-time options for {@link AutoUpdateCoordinator}. */ export interface AutoUpdateCoordinatorOptions { enabled: boolean; config: AutoUpdateConfig; packageName: string; currentVersion: string; stateDir: string; logger: LoggerLike; runUpdateCommand?: (packageName: string) => Promise; canUpdatePlugin?: boolean; versionSource?: VersionSource; configFromApi?: unknown; loadConfig?: () => Promise; writeConfigFile?: (config: unknown) => Promise; pluginId: string; /** * Optional callback fired after each tick completes, before the next one is * scheduled. Invoked on **both** success and failure paths so downstream * subscribers don't get starved by a transient npm registry hiccup. Errors * from this hook are caught + logged at `warn` and never propagated — the * auto-update coordinator's own scheduling is never disturbed. * * Used to drive skills-manager off the same poll cadence as the plugin * package update check (see `src/index.ts` wiring + `src/skills-manager/`). * Intentionally a thin contract (no payload) so additional subscribers can * be added without changing the auto-update internals. */ onTickComplete?: () => Promise; } /** * Central lifecycle manager for the plugin auto-update feature. * * Polls the npm registry on a configurable interval, classifies the * version delta, and either notifies the user or applies the update * automatically depending on the resolved {@link AutoUpdateMode}. * * After a successful package install, the coordinator evaluates whether the * OpenClaw gateway can be restarted via a config-file bump. Runtimes are * stopped only when that automatic restart path is available; otherwise they * keep running until the user restarts the gateway manually. * * Thread-safety is enforced via a `runToken` / `stopped` flag pair * so that `stop()` reliably prevents any in-flight tick from * rescheduling. */ export declare class AutoUpdateCoordinator { private readonly options; private readonly store; private readonly versionSource; private readonly runUpdateCommand; private timer; private running; private stopped; private runToken; private state; private snapshot; private preflightReasons; constructor(options: AutoUpdateCoordinatorOptions); /** Run preflight checks, load persisted state, and schedule the first version poll. */ start(): Promise; /** Cancel the next scheduled poll and prevent in-flight ticks from rescheduling. */ stop(): Promise; /** Return the latest point-in-time snapshot for health/state gateway RPCs. */ getSnapshot(): AutoUpdateSnapshot; /** * Run one version check immediately instead of waiting for the poll timer. * * The check goes through the ordinary {@link tick}, so it takes the same * success, failure and backoff paths as a scheduled check. That also covers * rescheduling: `tick`'s `finally` calls `scheduleNext`, which clears the * pending timer first, so the check that was already queued is dropped and * the next one lands one interval after this run. A forced check therefore * shifts the cadence rather than adding a run on top of it. * * `runToken` is passed through unchanged, so `stop()` keeps its ability to * cancel the forced run's own reschedule. */ checkNow(): Promise; /** Schedule the next `tick` after `delayMs`, guarded by stop/token checks. */ private scheduleNext; /** Single poll cycle: run the check, persist state, and schedule the next cycle. */ private tick; /** * Emit a catalogued `auto_update.*` event, guarded so neither a throwing sink nor a bad * attribute shape can disturb the tick — telemetry must never break auto-update itself. */ private emitEvent; /** Core update logic: fetch latest version, classify, and take action. */ private runTick; /** * `currentVersion` is a compile-time constant frozen for the life of the * process, so it cannot reflect an install that already happened this * process. Once `runUpdateTransaction` has installed `latest` and requested * a restart, every tick before the restart actually replaces the process * would otherwise re-classify the same `latest` as an update and re-run * the whole transaction. Consulting the persisted `lastAppliedVersion` * bounds that to a single apply per version: once the restart lands, * `currentVersion` becomes `latest` and `classifyUpdate` returns `none`, * so this branch stops being reached on its own. */ private handleAlreadyAppliedAwaitingRestart; private isAllowedByPolicy; private handleMajorAvailable; private logUpdateAvailable; /** * Install the update, evaluate restart capability, then either trigger a * gateway restart or log that a manual restart is needed. * * Runtimes are never torn down here. Already-imported modules stay resolved to * the old bundle, so trading continues uninterrupted until the gateway tears * the plugin down through its own `stop()` lifecycle hook, which drains the * HTTP API before stopping launchers and runtime handles. * * Execution order is critical: * 1. Run `openclaw plugins update` — writes new files to disk. * If this step fails the transaction is aborted and the failure is logged; * `lastAppliedVersion` is NOT advanced. * 2. Record success for observability (`lastAppliedVersion` / `lastSuccessAt`). * 3. Evaluate gateway restart capability. If automatic restart is not * possible, log that a manual restart is needed and return. * 4. When capable: trigger the config-file bump for gateway restart. */ private runUpdateTransaction; /** Assemble a read-only snapshot from current state for external consumers. */ private buildSnapshot; private persistState; } export {}; //# sourceMappingURL=coordinator.d.ts.map