openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
109 lines (108 loc) • 6.32 kB
JavaScript
import { p as shortenHomePath } from "./utils-DgZn2dLu.mjs";
import { i as executeGitCommand } from "./git-exec-DXEiUR5e.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import { m as resolveConfiguredAgentId } from "./agent-scope-config-CDYpzA0r.mjs";
import "./session-key-C09ow4h0.mjs";
import { t as parseDurationMs } from "./parse-duration-C4JaJvt9.mjs";
import { r as getRuntimeConfig } from "./io.runtime-BsUXSsD4.mjs";
import "./config-DLycWFvB.mjs";
import { a as isImplicitLocalGatewayTargetFromCli, n as callGatewayFromCli } from "./gateway-rpc-0aouJxQt.mjs";
import { r as listCronJobsFromGateway } from "./list-jobs-BIQY6N_D.mjs";
import { u as resolveRequiredBackupPath } from "./backup-shared-D8dux81d.mjs";
import { i as resolveBackupNamespace, n as normalizeBackupRetention } from "./backup-retention-D0JLSuDB.mjs";
import { t as GIT_BACKUP_PUSH_CREDENTIAL_WARNING } from "./backup-git-3w3cjFyp.mjs";
import { n as buildBackupScheduleJob, t as backupScheduleModeForDeclaration } from "./backup-command-DM-EcqY5.mjs";
//#region src/commands/backup-schedule.ts
const LOCAL_GATEWAY_REQUIRED_ERROR = "backup enable manages backups on the Gateway host and currently requires a local Gateway. Create the cron job manually with openclaw cron add for remote Gateways.";
/**
* Unattended pushed schedules make credential retention durable in remote
* history, so they redact by default; --include-secrets is the explicit
* full-fidelity override. Local (non-push) schedules keep full fidelity for
* complete restores.
*/
function resolveScheduledRedaction(options) {
if (options.excludeSecrets && options.includeSecrets) throw new Error("Use either --exclude-secrets or --include-secrets, not both.");
if (!options.push) return options.excludeSecrets === true;
return options.includeSecrets !== true;
}
function resolveScheduleSpec(options, everyMs) {
if (options.to !== void 0) {
if (options.repository !== void 0 || options.push || options.excludeSecrets || options.includeSecrets || options.globalOnly || options.agent !== void 0) throw new Error("--to cannot be combined with Git backup options (--repository, --push, --exclude-secrets, --include-secrets, --global-only, --agent).");
const location = options.to.trim();
if (!location) throw new Error("--to must name a configured storage location.");
if (!getRuntimeConfig({ skipPluginValidation: true }).storage?.locations?.[location]) throw new Error(`Storage location "${location}" is not configured. Run openclaw storage list.`);
return {
mode: "offsite",
everyMs,
location,
namespace: resolveBackupNamespace(options.namespace),
claimNamespace: options.claimNamespace === true,
includeWorkspace: options.includeWorkspace !== false,
...normalizeBackupRetention(options)
};
}
if (options.namespace !== void 0 || options.claimNamespace || options.includeWorkspace === false || options.keepDaily !== void 0 || options.keepWeekly !== void 0 || options.keepMonthly !== void 0) throw new Error("--namespace, --claim-namespace, --no-include-workspace, and --keep-* require --to <location>.");
const repository = resolveRequiredBackupPath(options.repository, "--repository");
const agent = options.agent?.trim();
if (options.agent !== void 0 && !agent) throw new Error("--agent must not be blank");
if (options.globalOnly && agent) throw new Error("Use either --global-only or --agent <id>, not both.");
const agentId = agent ? resolveConfiguredAgentId(getRuntimeConfig({ skipPluginValidation: true }), normalizeAgentId(agent)) : void 0;
return {
mode: "git",
everyMs,
repository,
scope: options.globalOnly ? { kind: "global" } : agentId ? {
kind: "agent",
agentId
} : { kind: "all" },
push: options.push === true,
excludeSecrets: resolveScheduledRedaction(options)
};
}
async function assertLocalGatewayScheduleTarget(options) {
if (!await isImplicitLocalGatewayTargetFromCli(options)) throw new Error(LOCAL_GATEWAY_REQUIRED_ERROR);
}
async function backupEnableCommand(runtime, options) {
await assertLocalGatewayScheduleTarget(options);
const every = options.every?.trim() ?? "24h";
const everyMs = parseDurationMs(every, { defaultUnit: "ms" });
if (!Number.isSafeInteger(everyMs) || everyMs <= 0) throw new Error("--every must be a positive duration such as 6h or 24h.");
const spec = resolveScheduleSpec(options, everyMs);
if (spec.mode === "git" && spec.push) {
if ((await executeGitCommand(spec.repository, [
"remote",
"get-url",
"origin"
])).code !== 0) throw new Error(`--push requires an origin remote. Run: openclaw backup git init --repository ${shortenHomePath(spec.repository)} --remote <url>`);
if (!spec.excludeSecrets) runtime.error(GIT_BACKUP_PUSH_CREDENTIAL_WARNING);
}
const result = await callGatewayFromCli("cron.add", options, buildBackupScheduleJob(spec));
const id = result.job?.id;
if (!id) throw new Error("cron.add returned no scheduled backup job id.");
const updated = result.created === false;
runtime.log(`Scheduled ${spec.mode === "git" ? "Git" : "offsite"} backups ${updated ? "updated" : "enabled"}: every ${every} to ${spec.mode === "git" ? shortenHomePath(spec.repository) : spec.location}`);
return {
id,
updated
};
}
async function backupDisableCommand(runtime, options) {
await assertLocalGatewayScheduleTarget(options);
if (options.git && options.offsite) throw new Error("Use either --git or --offsite, or omit both to disable all backup schedules.");
const { jobs } = await listCronJobsFromGateway(options, { includeDisabled: true });
const selectedMode = options.git ? "git" : options.offsite ? "offsite" : void 0;
const existing = jobs.filter((job) => {
const mode = backupScheduleModeForDeclaration(job.declarationKey);
return mode !== void 0 && (selectedMode === void 0 || mode === selectedMode);
});
const label = selectedMode === "git" ? "Scheduled Git backups" : selectedMode === "offsite" ? "Scheduled offsite backups" : "Scheduled backups";
if (existing.length === 0) {
runtime.log(`${label} are already disabled.`);
return { removed: false };
}
for (const job of existing) await callGatewayFromCli("cron.remove", options, { id: job.id });
runtime.log(`${label} disabled.`);
return { removed: true };
}
//#endregion
export { backupDisableCommand, backupEnableCommand };