import { listChannelPlugins } from "../../channels/plugins/index.js"; import { parseAbsoluteTimeMs } from "../../cron/parse.js"; import { resolveCronStaggerMs } from "../../cron/stagger.js"; import type { CronDeliveryPreview, CronJob, CronSchedule } from "../../cron/types.js"; import { danger } from "../../globals.js"; import { formatDurationHuman } from "../../infra/format-time/format-duration.ts"; import {
isOffsetlessIsoDateTime,
parseOffsetlessIsoDateTimeInTimeZone,
} from "../../infra/format-time/parse-offsetless-zoned-datetime.js"; import { defaultRuntime, type RuntimeEnv } from "../../runtime.js"; import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalString,
} from "../../shared/string-coerce.js"; import { colorize, isRich, theme } from "../../terminal/theme.js"; import type { GatewayRpcOpts } from "../gateway-rpc.js"; import { callGatewayFromCli } from "../gateway-rpc.js";
export const getCronChannelOptions = () => { // Keep help truthful even before the plugin registry is bootstrapped. const pluginIds = listChannelPlugins()
.map((plugin) => plugin.id)
.filter(Boolean); return pluginIds.length > 0 ? ["last", ...pluginIds].join("|") : "last|<channel-id>";
};
export function printCronJson(value: unknown) {
defaultRuntime.writeJson(value);
}
export function handleCronCliError(err: unknown) {
defaultRuntime.error(danger(String(err)));
defaultRuntime.exit(1);
}
export async function warnIfCronSchedulerDisabled(opts: GatewayRpcOpts) { try { const res = (await callGatewayFromCli("cron.status", opts, {})) as {
enabled?: boolean;
storePath?: string;
}; if (res?.enabled === true) { return;
} const store = typeof res?.storePath === "string" ? res.storePath : "";
defaultRuntime.error(
[ "warning: cron scheduler is disabled in the Gateway; jobs are saved but will not run automatically.", "Re-enable with `cron.enabled: true` (or remove `cron.enabled: false`) and restart the Gateway.",
store ? `store: ${store}` : "",
]
.filter(Boolean)
.join("\n"),
);
} catch { // Ignore status failures (older gateway, offline, etc.)
}
}
export function parseDurationMs(input: string): number | null { const raw = input.trim(); if (!raw) { returnnull;
} const match = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i); if (!match) { returnnull;
} const n = Number.parseFloat(match[1] ?? ""); if (!Number.isFinite(n) || n <= 0) { returnnull;
} const unit = normalizeLowercaseStringOrEmpty(match[2] ?? ""); const factor =
unit === "ms"
? 1
: unit === "s"
? 1000
: unit === "m"
? 60_000
: unit === "h"
? 3_600_000
: 86_400_000; return Math.floor(n * factor);
}
export function parseCronStaggerMs(params: {
staggerRaw: string;
useExact: boolean;
}): number | undefined { if (params.useExact) { return0;
} if (!params.staggerRaw) { return undefined;
} const parsed = parseDurationMs(params.staggerRaw); if (!parsed) { thrownew Error("Invalid --stagger; use e.g. 30s, 1m, 5m");
} return parsed;
}
/** *Parseaone-shot`--at`valueintoanISOstring(UTC). * *When`tz`isprovidedandtheinputisanoffset-lessdatetime *(e.g.`2026-03-23T23:00:00`),thedatetimeisinterpretedin *thatIANAtimezoneinsteadofUTC.
*/
export function parseAt(input: string, tz?: string): string | null { const raw = input.trim(); if (!raw) { returnnull;
}
// If a timezone is provided and the input looks like an offset-less ISO datetime, // resolve it in the given IANA timezone so users get the time they expect. if (tz && isOffsetlessIsoDateTime(raw)) { return parseOffsetlessIsoDateTimeInTimeZone(raw, tz);
}
[Diese Firma untersucht Systeme, entwickelt Software und berät
Organisationen zu Themen der Informationstechnolgie. Dabei wird Wert auf anerkannte Normen und Standards gelegt.
Die Qualität eigener und fremder Produkte ist Leitlinie und Ziel zugleich.
Unter bestimmten Bedingungen finden Sie hier weiterführende Anregungen.0.17Die F&E-Firma in NorddeutschlandÜbersetzung europäischer Sprachen durch Browser2026-06-10]