UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

140 lines (139 loc) • 5.95 kB
import { p as shortenHomePath } from "./utils-CitNzLyF.mjs"; import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs"; import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs"; import { t as GatewayScheduler } from "./gateway-scheduler-B6bteUrw.mjs"; import { C as tryResolveAmbientOwnerAgentId } from "./agent-scope-config-BEk6-ThS.mjs"; import { t as formatDurationCompact } from "./format-duration-CyyGVUjR.mjs"; import { t as note } from "./note-Bi0VsI6R.mjs"; import { n as resolveCronJobsStorePathFromConfig } from "./paths-Dqy-ZJ8r.mjs"; import "./store-l4f-3zyW.mjs"; import { n as loadCronJobsStoreWithConfigJobsReadOnly } from "./read-only-HKCt5rQZ.mjs"; import { t as CronService } from "./service-DnmPiLd1.mjs"; import { a as resolveHeartbeatSchedulerSeed, i as resolveHeartbeatMonitorPlan, n as heartbeatMonitorAddOptions, t as applyHeartbeatMonitorJobs } from "./heartbeat-monitor-Dred-8sc.mjs"; //#region src/commands/doctor-heartbeat-cadence-migration.ts /** Doctor-owned materialization of heartbeat cadence config into cron monitor rows. */ const HEARTBEAT_CADENCE_MIGRATION_CHECK_ID = "core/doctor/heartbeat-cadence-migration"; async function withDoctorCronService(storePath, cfg, run) { const scheduler = new GatewayScheduler(); const noop = () => {}; const log = { debug: noop, info: noop, warn: noop, error: noop }; const cron = new CronService({ scheduler, storePath, cronEnabled: false, cronConfig: cfg.cron, resolveDefaultAgentId: () => tryResolveAmbientOwnerAgentId(cfg), log, enqueueSystemEvent: () => false, requestHeartbeat: noop, runIsolatedAgentJob: async () => ({ status: "skipped", error: "doctor does not execute automations" }) }); try { return await run(cron); } finally { cron.stop(); await scheduler.stop(); } } async function loadHeartbeatMonitorPlanReadOnly(cfg, storePath, env) { const loaded = await loadCronJobsStoreWithConfigJobsReadOnly(storePath, env); const schedulerSeed = resolveHeartbeatSchedulerSeed(void 0, { env, readOnly: true }); return resolveHeartbeatMonitorPlan(cfg, loaded.store.jobs, { schedulerSeed }); } function describePlannedChange(change) { if (change.kind === "remove") return `Remove stale heartbeat monitor for agent "${change.agentId}".`; const schedule = change.input.schedule; const cadence = schedule.kind === "every" ? formatDurationCompact(schedule.everyMs) : schedule.kind; const action = change.kind === "create" ? "Create" : "Update"; const state = change.input.enabled ? `at ${cadence}` : "as disabled"; return `${action} heartbeat monitor for agent "${change.agentId}" ${state}.`; } function noteWarnings(warnings, storePath) { if (warnings.length === 0) return; note(`${warnings.join("\n")}\nCron store: ${shortenHomePath(storePath)}`, "Doctor warnings"); } async function collectHeartbeatCadenceMigrationFindings(cfg, env = process.env) { const storePath = resolveCronJobsStorePathFromConfig(cfg, env); try { return (await loadHeartbeatMonitorPlanReadOnly(cfg, storePath, env)).changes.map((change) => ({ checkId: HEARTBEAT_CADENCE_MIGRATION_CHECK_ID, severity: "warning", message: describePlannedChange(change), path: storePath, target: change.agentId, requirement: `heartbeat-monitor-${change.kind}`, fixHint: `Run ${formatCliCommand("openclaw doctor --fix")} to materialize heartbeat cadence in cron.` })); } catch (error) { return [{ checkId: HEARTBEAT_CADENCE_MIGRATION_CHECK_ID, severity: "error", message: `Heartbeat cadence could not be inspected: ${formatErrorMessage(error)}`, path: storePath, requirement: "heartbeat-monitor-inspection", fixHint: `Run ${formatCliCommand("openclaw doctor --fix")} after resolving the cron store error.` }]; } } async function ensureHeartbeatMonitorJobs(cfg, storePath, env = process.env) { return await withDoctorCronService(storePath, cfg, async (cron) => { const jobs = await cron.list({ includeDisabled: true }); const schedulerSeed = resolveHeartbeatSchedulerSeed(void 0, { env }); const { specs } = resolveHeartbeatMonitorPlan(cfg, jobs, { schedulerSeed }); const monitors = /* @__PURE__ */ new Map(); for (const spec of specs) { const result = await cron.add(spec.input, heartbeatMonitorAddOptions(spec.agentId)); const job = "job" in result ? result.job : result; monitors.set(spec.agentId, job); } return monitors; }); } async function maybeMigrateHeartbeatCadenceToCron(params) { const env = params.env ?? process.env; const storePath = resolveCronJobsStorePathFromConfig(params.cfg, env); const changes = []; const warnings = []; if (!params.shouldRepair) { try { const plan = await loadHeartbeatMonitorPlanReadOnly(params.cfg, storePath, env); if (plan.changes.length > 0) note(plan.changes.map(describePlannedChange).join("\n"), "Heartbeat cadence migration preview"); } catch (error) { warnings.push(`Could not inspect heartbeat monitor jobs: ${formatErrorMessage(error)}`); } noteWarnings(warnings, storePath); return { changes, warnings }; } await withDoctorCronService(storePath, params.cfg, async (cron) => { const schedulerSeed = resolveHeartbeatSchedulerSeed(void 0, { env }); const result = await applyHeartbeatMonitorJobs({ cron, cfg: params.cfg, schedulerSeed }); changes.push(...result.applied.map(describePlannedChange)); for (const failure of result.failures) warnings.push(failure.change ? `Heartbeat monitor for agent "${failure.change.agentId}" was not migrated: ${formatErrorMessage(failure.error)}` : `Could not inspect heartbeat monitor jobs: ${formatErrorMessage(failure.error)}`); }); if (changes.length > 0) note(changes.join("\n"), "Doctor changes"); noteWarnings(warnings, storePath); return { changes, warnings }; } //#endregion export { ensureHeartbeatMonitorJobs as n, maybeMigrateHeartbeatCadenceToCron as r, collectHeartbeatCadenceMigrationFindings as t };