mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 13:34:49 +00:00
* feat: add migration providers * feat: offer Hermes migration during onboarding * feat(hermes): map imported config surfaces * feat(onboard): require fresh migration imports * docs(cli): clarify Hermes import coverage * chore(migrations): rename Hermes importer package * chore(migrations): rewire Hermes importer id * fix(migrations): redact migration JSON details * fix(hermes): use provider runtime for config imports * test(hermes): cover missing source planning --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
118 lines
4.8 KiB
TypeScript
118 lines
4.8 KiB
TypeScript
import type { Command } from "commander";
|
|
import {
|
|
migrateApplyCommand,
|
|
migrateDefaultCommand,
|
|
migrateListCommand,
|
|
migratePlanCommand,
|
|
} from "../../commands/migrate.js";
|
|
import { defaultRuntime } from "../../runtime.js";
|
|
import { theme } from "../../terminal/theme.js";
|
|
import { runCommandWithRuntime } from "../cli-utils.js";
|
|
import { formatHelpExamples } from "../help-format.js";
|
|
|
|
function addMigrationOptions(command: Command): Command {
|
|
return command
|
|
.option("--from <path>", "Source directory to migrate from")
|
|
.option("--include-secrets", "Import supported credentials and secrets", false)
|
|
.option("--overwrite", "Overwrite conflicting target files after item-level backups", false)
|
|
.option("--json", "Output JSON", false);
|
|
}
|
|
|
|
export function registerMigrateCommand(program: Command) {
|
|
const migrate = program
|
|
.command("migrate")
|
|
.description("Import state from another agent system")
|
|
.argument("[provider]", "Migration provider id, for example hermes")
|
|
.option("--from <path>", "Source directory to migrate from")
|
|
.option("--include-secrets", "Import supported credentials and secrets", false)
|
|
.option("--overwrite", "Overwrite conflicting target files after item-level backups", false)
|
|
.option("--dry-run", "Preview only; do not apply changes", false)
|
|
.option("--yes", "Apply without prompting after preview", false)
|
|
.option("--backup-output <path>", "Pre-migration backup archive path or directory")
|
|
.option("--no-backup", "Skip the pre-migration OpenClaw backup")
|
|
.option("--force", "Allow dangerous options such as --no-backup", false)
|
|
.option("--json", "Output JSON", false)
|
|
.addHelpText(
|
|
"after",
|
|
() =>
|
|
`\n${theme.heading("Examples:")}\n${formatHelpExamples([
|
|
["openclaw migrate list", "Show available migration providers."],
|
|
["openclaw migrate hermes", "Preview Hermes migration, then prompt before applying."],
|
|
["openclaw migrate hermes --dry-run", "Preview Hermes migration only."],
|
|
[
|
|
"openclaw migrate apply hermes --yes",
|
|
"Apply Hermes migration non-interactively after writing a verified backup.",
|
|
],
|
|
[
|
|
"openclaw migrate apply hermes --include-secrets --yes",
|
|
"Include supported credentials in the migration.",
|
|
],
|
|
])}`,
|
|
)
|
|
.action(async (provider, opts) => {
|
|
await runCommandWithRuntime(defaultRuntime, async () => {
|
|
await migrateDefaultCommand(defaultRuntime, {
|
|
provider: provider as string | undefined,
|
|
source: opts.from as string | undefined,
|
|
includeSecrets: Boolean(opts.includeSecrets),
|
|
overwrite: Boolean(opts.overwrite),
|
|
dryRun: Boolean(opts.dryRun),
|
|
yes: Boolean(opts.yes),
|
|
backupOutput: opts.backupOutput as string | undefined,
|
|
noBackup: opts.backup === false,
|
|
force: Boolean(opts.force),
|
|
json: Boolean(opts.json),
|
|
});
|
|
});
|
|
});
|
|
|
|
migrate
|
|
.command("list")
|
|
.description("List migration providers")
|
|
.option("--json", "Output JSON", false)
|
|
.action(async (opts) => {
|
|
await runCommandWithRuntime(defaultRuntime, async () => {
|
|
await migrateListCommand(defaultRuntime, { json: Boolean(opts.json) });
|
|
});
|
|
});
|
|
|
|
addMigrationOptions(
|
|
migrate
|
|
.command("plan <provider>")
|
|
.description("Preview a migration without changing OpenClaw state"),
|
|
).action(async (provider, opts) => {
|
|
await runCommandWithRuntime(defaultRuntime, async () => {
|
|
await migratePlanCommand(defaultRuntime, {
|
|
provider: provider as string,
|
|
source: opts.from as string | undefined,
|
|
includeSecrets: Boolean(opts.includeSecrets),
|
|
overwrite: Boolean(opts.overwrite),
|
|
json: Boolean(opts.json),
|
|
});
|
|
});
|
|
});
|
|
|
|
addMigrationOptions(
|
|
migrate.command("apply <provider>").description("Apply a migration after a verified backup"),
|
|
)
|
|
.option("--yes", "Apply without prompting", false)
|
|
.option("--backup-output <path>", "Pre-migration backup archive path or directory")
|
|
.option("--no-backup", "Skip the pre-migration OpenClaw backup")
|
|
.option("--force", "Allow dangerous options such as --no-backup", false)
|
|
.action(async (provider, opts) => {
|
|
await runCommandWithRuntime(defaultRuntime, async () => {
|
|
await migrateApplyCommand(defaultRuntime, {
|
|
provider: provider as string,
|
|
source: opts.from as string | undefined,
|
|
includeSecrets: Boolean(opts.includeSecrets),
|
|
overwrite: Boolean(opts.overwrite),
|
|
yes: Boolean(opts.yes),
|
|
backupOutput: opts.backupOutput as string | undefined,
|
|
noBackup: opts.backup === false,
|
|
force: Boolean(opts.force),
|
|
json: Boolean(opts.json),
|
|
});
|
|
});
|
|
});
|
|
}
|