feat(desktop): headless v1→v2 migrator core + first migration-ledger writers

Merged
KI
4mo ago
+1317-225

Summary

PR 1 of the v1→v2 auto-migration plan (SUPER-1534 / SUPER-1577, design doc plans/20260716-v1-to-v2-auto-migration.md): extract the V1ImportModal wizard's import logic into a shared headless module and give the dormant v1_migration_state ledger its first readers/writers.

  • New renderer/lib/v1-migration/ module: runV1Migration() orchestrator (projects → workspaces → presets, every outcome ledger-recorded, idempotent per boot) plus the extracted pure logic: decideProjectImport, planWorkspaceAdoptions, resolvePresetImport (keep-v2 preset collision policy), importV1Project, adoptV1Workspace (worktree-path NOT_FOUND fallback preserved).
  • Ledger live: migration.ledgerList / migration.ledgerRecord electron tRPC procedures (upsert on (org, v1Id, kind)); V1MigrationKind extended with settings + terminal for the follow-up PRs.
  • Wizard fixes: pages consume the shared module and record ledger outcomes; ImportWorkspacesPage dedups against host-local workspace.list instead of the stale cloud cloudList (post-local-first, newly adopted workspaces never appear in cloud, so the old "Imported" badge misreported); removed the now-moot cloud tiebreak in v1→v2 project mapping.

The boot trigger + flip gate land in a later PR — nothing runs automatically yet; the wizard behavior is unchanged apart from the badge fix.

Test Plan

  • bun test src/renderer/lib/v1-migration/ — 12 tests over the extracted decision logic (each mutation-verified to fail on a seeded regression)
  • bun run typecheck (desktop) and root bun run lint clean
  • Manual wizard pass on a machine with v1 data: import project + workspace + preset, confirm v1_migration_state rows land and re-running shows Imported/Linked

Summary by cubic

Built the headless v1→v2 migrator core and activated the migration ledger to prepare desktop for automated migration (SUPER-1534, SUPER-1577). Added per-stage ledger flushing and guarded UI callbacks; the wizard now uses the shared module with fixed workspace dedup. Nothing runs automatically yet.

  • New Features

    • Added renderer/lib/v1-migration/ with runV1Migration() (projects → workspaces → presets; idempotent; records outcomes).
    • Extracted pure logic: decideProjectImport, planWorkspaceAdoptions, resolvePresetImport, importV1Project, adoptV1Workspace.
    • Enabled migration.ledgerList and migration.ledgerRecord tRPC procedures; upsert on (org, v1Id, kind).
    • Extended V1MigrationKind with settings and terminal for follow-up migrations.
  • Bug Fixes

    • Flush ledger outcomes between stages and guard onProjectImported/onWorkspaceAdopted callbacks to avoid dropping committed results on later errors.
    • Wizard pages consume the shared module and record outcomes to the ledger; ImportWorkspacesPage dedups against host-local workspace.list, and ImportPresetsPage uses the shared resolver and writes ledger results.

Summary by CodeRabbit

  • New Features
    • Added resumable v1 → v2 migration support for projects, workspaces, and terminal presets, with ledger-based progress tracking to safely skip completed items and retry partial runs.
    • Introduced an idempotent, headless migration runner with clearer per-item results and an overall completion gate.
    • Updated the import screens to use the shared migration flow, improving project eligibility decisions, preset collision handling, and workspace adoption behavior.
  • Documentation
    • Added a seamless auto-migration plan and v1 sunset roadmap.
  • Tests
    • Added coverage for project, workspace, and preset migration decision logic.