diff --git a/src/cron/session-reaper.ts b/src/cron/session-reaper.ts index ceb347fc1314..f98549e23edd 100644 --- a/src/cron/session-reaper.ts +++ b/src/cron/session-reaper.ts @@ -1,3 +1,4 @@ +/** Prunes expired per-run cron sessions and archives unreferenced transcripts. */ import { parseDurationMs } from "../cli/parse-duration.js"; import { loadSessionStore } from "../config/sessions/store-load.js"; import { archiveRemovedSessionTranscripts, updateSessionStore } from "../config/sessions/store.js"; diff --git a/src/cron/session-target.ts b/src/cron/session-target.ts index 22db8847e9b6..9209edd8fc0d 100644 --- a/src/cron/session-target.ts +++ b/src/cron/session-target.ts @@ -1,3 +1,4 @@ +/** Resolves and validates session-target keys used by cron jobs and delivery. */ const INVALID_CRON_SESSION_TARGET_ID_ERROR = "invalid cron sessionTarget session id"; /** Returns whether an error came from cron session target id validation. */ diff --git a/src/cron/stagger.ts b/src/cron/stagger.ts index 00087e789f7f..e2e79a969ac4 100644 --- a/src/cron/stagger.ts +++ b/src/cron/stagger.ts @@ -1,3 +1,4 @@ +/** Resolves deterministic cron stagger windows for recurring schedules. */ import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js"; import type { CronSchedule } from "./types.js"; diff --git a/src/cron/store.ts b/src/cron/store.ts index d43d4d93a350..d48d52948798 100644 --- a/src/cron/store.ts +++ b/src/cron/store.ts @@ -1,3 +1,4 @@ +/** Public cron store load/save API backed by SQLite plus quarantine sidecars. */ import fs from "node:fs"; import path from "node:path"; import { isRecord } from "@openclaw/normalization-core/record-coerce"; @@ -119,6 +120,8 @@ export async function saveCronJobsStore( const resolvedStorePath = path.resolve(storePath); const storeKey = cronStoreKey(resolvedStorePath); if (opts?.stateOnly) { + // Hot-path timer updates only mutate runtime columns; full config JSON stays + // untouched so user-authored cron definitions do not churn. runOpenClawStateWriteTransaction(({ db }) => { updateCronRuntimeRows(db, storeKey, store); }); diff --git a/src/cron/store/delivery-codec.ts b/src/cron/store/delivery-codec.ts index 9c0592fc8258..518001cb10bf 100644 --- a/src/cron/store/delivery-codec.ts +++ b/src/cron/store/delivery-codec.ts @@ -1,3 +1,4 @@ +/** SQLite column codec for cron delivery configuration. */ import type { CronDelivery } from "../types.js"; import { booleanToInteger, integerToBoolean } from "./scalar-codec.js"; import type { CronJobInsert, CronJobRow } from "./schema.js"; diff --git a/src/cron/store/failure-alert-codec.ts b/src/cron/store/failure-alert-codec.ts index c829d0a74b2a..37eaffba98c8 100644 --- a/src/cron/store/failure-alert-codec.ts +++ b/src/cron/store/failure-alert-codec.ts @@ -1,3 +1,4 @@ +/** SQLite column codec for cron failure-alert configuration. */ import type { CronFailureAlert } from "../types.js"; import { booleanToInteger, integerToBoolean, normalizeNumber } from "./scalar-codec.js"; import type { CronJobInsert, CronJobRow } from "./schema.js"; diff --git a/src/cron/store/key.ts b/src/cron/store/key.ts index 26127cf0b59b..91d44360b00b 100644 --- a/src/cron/store/key.ts +++ b/src/cron/store/key.ts @@ -1,3 +1,4 @@ +/** Cron store key normalization for SQLite partitions. */ import path from "node:path"; /** Returns the canonical per-file SQLite partition key for cron store rows. */ diff --git a/src/cron/store/payload-codec.ts b/src/cron/store/payload-codec.ts index 873704c4f4a9..f9590bbbca2b 100644 --- a/src/cron/store/payload-codec.ts +++ b/src/cron/store/payload-codec.ts @@ -1,3 +1,4 @@ +/** SQLite column codec for cron payload variants. */ import type { CronPayload } from "../types.js"; import { booleanToInteger, diff --git a/src/cron/store/row-codec.ts b/src/cron/store/row-codec.ts index c80b96dbf03c..7a03b0e0be4d 100644 --- a/src/cron/store/row-codec.ts +++ b/src/cron/store/row-codec.ts @@ -1,3 +1,4 @@ +/** Converts cron jobs between public store shape and normalized SQLite rows. */ import type { DatabaseSync } from "node:sqlite"; import { isRecord } from "@openclaw/normalization-core/record-coerce"; import { executeSqliteQuerySync } from "../../infra/kysely-sync.js"; @@ -61,6 +62,8 @@ function bindScheduleColumns( function stripJobRuntimeFields(job: CronStoreFile["jobs"][number]): Record { const { state: _state, updatedAtMs: _updatedAtMs, ...rest } = job; + // job_json stores config shape only; runtime state lives in split columns and + // state_json so state-only writes never rewrite public job config. return { ...rest, state: {} }; } @@ -72,6 +75,8 @@ function mergeFailureDestinationProjection( if (!failureDestination) { return configJob; } + // Empty SQLite sentinels preserve explicit undefined fields for failure + // destination overrides; project them back into the config sidecar shape. const delivery: Record = isRecord(configJob.delivery) && !Array.isArray(configJob.delivery) ? { ...configJob.delivery } diff --git a/src/cron/store/schema.ts b/src/cron/store/schema.ts index 41bde95f8af0..af6b86bbbc7e 100644 --- a/src/cron/store/schema.ts +++ b/src/cron/store/schema.ts @@ -1,3 +1,4 @@ +/** Kysely row types and table facade for the cron_jobs SQLite table. */ import type { DatabaseSync } from "node:sqlite"; import type { Insertable, Selectable } from "kysely"; import { getNodeSqliteKysely } from "../../infra/kysely-sync.js"; diff --git a/src/cron/store/state-codec.ts b/src/cron/store/state-codec.ts index 9ff56b080739..77e40cb98966 100644 --- a/src/cron/store/state-codec.ts +++ b/src/cron/store/state-codec.ts @@ -1,3 +1,4 @@ +/** SQLite column codec for mutable cron runtime state. */ import type { CronJobState } from "../types.js"; import { booleanToInteger, diff --git a/src/cron/store/types.ts b/src/cron/store/types.ts index 0b744cffa387..5da7cda2ec68 100644 --- a/src/cron/store/types.ts +++ b/src/cron/store/types.ts @@ -1,3 +1,4 @@ +/** Shared cron store sidecar and quarantine types. */ import type { CronStoreFile } from "../types.js"; /** Invalid config-backed cron job captured for quarantine instead of runtime load. */ diff --git a/src/cron/types.ts b/src/cron/types.ts index 8251937c07d4..069e3b279e9d 100644 --- a/src/cron/types.ts +++ b/src/cron/types.ts @@ -1,3 +1,4 @@ +/** Cron scheduling, delivery, diagnostics, and store data contracts. */ import type { FailoverReason } from "../agents/embedded-agent-helpers/types.js"; import type { EmbeddedAgentExecutionPhase } from "../agents/embedded-agent-runner/execution-phase.js"; import type { ChannelId } from "../channels/plugins/types.public.js"; diff --git a/src/cron/validate-timestamp.ts b/src/cron/validate-timestamp.ts index 1cd00a1eb8b9..57baa9117121 100644 --- a/src/cron/validate-timestamp.ts +++ b/src/cron/validate-timestamp.ts @@ -1,3 +1,4 @@ +/** Validates user-supplied one-shot cron timestamps before scheduling. */ import { asDateTimestampMs, resolveTimestampMsToIsoString, diff --git a/src/cron/webhook-url.ts b/src/cron/webhook-url.ts index 032f49be61a0..35a0b2f49bee 100644 --- a/src/cron/webhook-url.ts +++ b/src/cron/webhook-url.ts @@ -1,3 +1,4 @@ +/** Normalizes cron webhook destination URLs. */ function isAllowedWebhookProtocol(protocol: string) { return protocol === "http:" || protocol === "https:"; }