fix(cron): migrate legacy string schedule and command jobs
This commit is contained in:
committed by
Peter Steinberger
parent
c424836fbe
commit
4cd04e4652
@@ -178,4 +178,47 @@ describe("cron store migration", () => {
|
||||
expect(schedule.kind).toBe("cron");
|
||||
expect(schedule.staggerMs).toBeUndefined();
|
||||
});
|
||||
|
||||
it("migrates legacy string schedules and command-only payloads (#18445)", async () => {
|
||||
const store = await makeStorePath();
|
||||
try {
|
||||
await writeLegacyStore(store.storePath, {
|
||||
id: "imessage-refresh",
|
||||
name: "iMessage Refresh",
|
||||
enabled: true,
|
||||
createdAtMs: 1_700_000_000_000,
|
||||
updatedAtMs: 1_700_000_000_000,
|
||||
schedule: "0 */2 * * *",
|
||||
command: "bash /tmp/imessage-refresh.sh",
|
||||
timeout: 120,
|
||||
state: {},
|
||||
});
|
||||
|
||||
await migrateAndLoadFirstJob(store.storePath);
|
||||
const loaded = await loadCronStore(store.storePath);
|
||||
const migrated = loaded.jobs[0] as Record<string, unknown>;
|
||||
|
||||
expect(migrated.schedule).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: "cron",
|
||||
expr: "0 */2 * * *",
|
||||
}),
|
||||
);
|
||||
expect(migrated.sessionTarget).toBe("main");
|
||||
expect(migrated.wakeMode).toBe("now");
|
||||
expect(migrated.payload).toEqual({
|
||||
kind: "systemEvent",
|
||||
text: "bash /tmp/imessage-refresh.sh",
|
||||
});
|
||||
expect("command" in migrated).toBe(false);
|
||||
expect("timeout" in migrated).toBe(false);
|
||||
|
||||
const scheduleWarn = noopLogger.warn.mock.calls.find((args) =>
|
||||
String(args[1] ?? "").includes("failed to compute next run for job (skipping)"),
|
||||
);
|
||||
expect(scheduleWarn).toBeUndefined();
|
||||
} finally {
|
||||
await store.cleanup();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,6 +92,7 @@ function normalizePayloadKind(payload: Record<string, unknown>) {
|
||||
function inferPayloadIfMissing(raw: Record<string, unknown>) {
|
||||
const message = typeof raw.message === "string" ? raw.message.trim() : "";
|
||||
const text = typeof raw.text === "string" ? raw.text.trim() : "";
|
||||
const command = typeof raw.command === "string" ? raw.command.trim() : "";
|
||||
if (message) {
|
||||
raw.payload = { kind: "agentTurn", message };
|
||||
return true;
|
||||
@@ -100,6 +101,10 @@ function inferPayloadIfMissing(raw: Record<string, unknown>) {
|
||||
raw.payload = { kind: "systemEvent", text };
|
||||
return true;
|
||||
}
|
||||
if (command) {
|
||||
raw.payload = { kind: "systemEvent", text: command };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -209,6 +214,12 @@ function stripLegacyTopLevelFields(raw: Record<string, unknown>) {
|
||||
if ("provider" in raw) {
|
||||
delete raw.provider;
|
||||
}
|
||||
if ("command" in raw) {
|
||||
delete raw.command;
|
||||
}
|
||||
if ("timeout" in raw) {
|
||||
delete raw.timeout;
|
||||
}
|
||||
}
|
||||
|
||||
async function getFileMtimeMs(path: string): Promise<number | null> {
|
||||
@@ -262,6 +273,12 @@ export async function ensureLoaded(
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
if (typeof raw.schedule === "string") {
|
||||
const expr = raw.schedule.trim();
|
||||
raw.schedule = { kind: "cron", expr };
|
||||
mutated = true;
|
||||
}
|
||||
|
||||
const nameRaw = raw.name;
|
||||
if (typeof nameRaw !== "string" || nameRaw.trim().length === 0) {
|
||||
raw.name = inferLegacyName({
|
||||
@@ -353,7 +370,9 @@ export async function ensureLoaded(
|
||||
"channel" in raw ||
|
||||
"to" in raw ||
|
||||
"bestEffortDeliver" in raw ||
|
||||
"provider" in raw;
|
||||
"provider" in raw ||
|
||||
"command" in raw ||
|
||||
"timeout" in raw;
|
||||
if (hadLegacyTopLevelFields) {
|
||||
stripLegacyTopLevelFields(raw);
|
||||
mutated = true;
|
||||
@@ -469,6 +488,21 @@ export async function ensureLoaded(
|
||||
|
||||
const payloadKind =
|
||||
payloadRecord && typeof payloadRecord.kind === "string" ? payloadRecord.kind : "";
|
||||
const normalizedSessionTarget =
|
||||
typeof raw.sessionTarget === "string" ? raw.sessionTarget.trim().toLowerCase() : "";
|
||||
if (normalizedSessionTarget === "main" || normalizedSessionTarget === "isolated") {
|
||||
if (raw.sessionTarget !== normalizedSessionTarget) {
|
||||
raw.sessionTarget = normalizedSessionTarget;
|
||||
mutated = true;
|
||||
}
|
||||
} else {
|
||||
const inferredSessionTarget = payloadKind === "agentTurn" ? "isolated" : "main";
|
||||
if (raw.sessionTarget !== inferredSessionTarget) {
|
||||
raw.sessionTarget = inferredSessionTarget;
|
||||
mutated = true;
|
||||
}
|
||||
}
|
||||
|
||||
const sessionTarget =
|
||||
typeof raw.sessionTarget === "string" ? raw.sessionTarget.trim().toLowerCase() : "";
|
||||
const isIsolatedAgentTurn =
|
||||
|
||||
Reference in New Issue
Block a user