diff --git a/src/commands/migrate/apply.test.ts b/src/commands/migrate/apply.test.ts new file mode 100644 index 00000000000..55d269460f9 --- /dev/null +++ b/src/commands/migrate/apply.test.ts @@ -0,0 +1,75 @@ +import { mkdtempSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { describe, expect, it, vi } from "vitest"; +import type { MigrationPlan, MigrationProviderPlugin } from "../../plugins/types.js"; +import { createNonExitingRuntime } from "../../runtime.js"; +import { runMigrationApply } from "./apply.js"; + +const stateDir = mkdtempSync(path.join(tmpdir(), "openclaw-migrate-apply-")); + +vi.mock("../../config/paths.js", () => ({ + resolveStateDir: () => stateDir, +})); + +function buildEmptyPlan(): MigrationPlan { + return { + providerId: "codex", + source: "/tmp/codex", + summary: { + total: 0, + planned: 0, + migrated: 0, + skipped: 0, + conflicts: 0, + errors: 0, + sensitive: 0, + }, + items: [], + }; +} + +describe("runMigrationApply", () => { + it("uses the resolved provider id when forwarding Codex options", async () => { + const plan = vi.fn(async () => buildEmptyPlan()); + const apply = vi.fn(async () => buildEmptyPlan()); + const provider: MigrationProviderPlugin = { + id: "codex", + label: "Codex", + plan, + apply, + }; + + await runMigrationApply({ + runtime: createNonExitingRuntime(), + opts: { + yes: true, + json: true, + noBackup: true, + configOverride: {}, + configPatchMode: "return", + verifyPluginApps: true, + }, + providerId: "codex", + provider, + }); + + expect(plan).toHaveBeenCalledWith( + expect.objectContaining({ + providerOptions: { + configPatchMode: "return", + verifyPluginApps: true, + }, + }), + ); + expect(apply).toHaveBeenCalledWith( + expect.objectContaining({ + providerOptions: { + configPatchMode: "return", + verifyPluginApps: true, + }, + }), + expect.anything(), + ); + }); +}); diff --git a/src/commands/migrate/apply.ts b/src/commands/migrate/apply.ts index 8de8f854ccb..8bbd6bb10fb 100644 --- a/src/commands/migrate/apply.ts +++ b/src/commands/migrate/apply.ts @@ -69,7 +69,7 @@ export async function runMigrationApply(params: { includeSecrets: params.opts.includeSecrets, overwrite: params.opts.overwrite, configOverride: params.opts.configOverride, - providerOptions: buildMigrationProviderOptions(params.opts), + providerOptions: buildMigrationProviderOptions(params.opts, params.providerId), runtime: params.runtime, json: params.opts.json, }), @@ -99,7 +99,7 @@ export async function runMigrationApply(params: { includeSecrets: params.opts.includeSecrets, overwrite: params.opts.overwrite, configOverride: params.opts.configOverride, - providerOptions: buildMigrationProviderOptions(params.opts), + providerOptions: buildMigrationProviderOptions(params.opts, params.providerId), runtime: params.runtime, backupPath, reportDir, diff --git a/src/commands/migrate/providers.test.ts b/src/commands/migrate/providers.test.ts new file mode 100644 index 00000000000..d202f89601d --- /dev/null +++ b/src/commands/migrate/providers.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vitest"; +import { buildMigrationProviderOptions } from "./providers.js"; + +describe("buildMigrationProviderOptions", () => { + it("uses the resolved provider id for Codex options", () => { + expect( + buildMigrationProviderOptions( + { + configPatchMode: "return", + verifyPluginApps: true, + }, + "codex", + ), + ).toEqual({ + configPatchMode: "return", + verifyPluginApps: true, + }); + }); + + it("omits Codex-only options for other providers", () => { + expect( + buildMigrationProviderOptions( + { + configPatchMode: "return", + provider: "other", + verifyPluginApps: true, + }, + "other", + ), + ).toBeUndefined(); + }); +}); diff --git a/src/commands/migrate/providers.ts b/src/commands/migrate/providers.ts index 3f9e937b7af..bff345d2560 100644 --- a/src/commands/migrate/providers.ts +++ b/src/commands/migrate/providers.ts @@ -28,12 +28,13 @@ export function resolveMigrationProvider( export function buildMigrationProviderOptions( opts: MigrateCommonOptions, + providerId = opts.provider, ): Record | undefined { const options: Record = {}; - if (opts.provider === "codex" && opts.verifyPluginApps === true) { + if (providerId === "codex" && opts.verifyPluginApps === true) { options.verifyPluginApps = true; } - if (opts.provider === "codex" && opts.configPatchMode) { + if (providerId === "codex" && opts.configPatchMode) { options.configPatchMode = opts.configPatchMode; } return Object.keys(options).length > 0 ? options : undefined;