// Plan §3.S2 / spec §1 / §10 / §20.3 / §21.3.2 — code-migration pipeline e2e. // // Exercises every Phase 6/7/8 atom impl in sequence on a Next.js // fixture repo: // // code-import → code/index.json // design-extract → code/tokens.json // token-map → token-map/{colors,...}.json + unmatched.json // rewrite-plan → plan/{plan.md, ownership.json, steps.json, meta.json} // patch-edit → mutates Button.tsx via a unified diff + // plan/receipts/step-rewrite-button.json // build-test → critique/build-test.json (skipped commands; passes) // diff-review → review/{diff.patch, summary.md, decision.json, meta.json} // handoff → ArtifactManifest with handoffKind='patch' // // The test does NOT run an actual `pnpm typecheck` / `pnpm test` — // we pass `'true'` as the build/test command so the runner just // records the no-op exit-0 receipt. The point is the pipe shape: // every atom reads what the previous atom wrote, the audit trail // chains through. import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import type { ArtifactManifest } from '@open-design/contracts'; import { runCodeImport } from '../src/plugins/atoms/code-import.js'; import { runDesignExtract } from '../src/plugins/atoms/design-extract.js'; import { runTokenMap, type DesignSystemTokenBag } from '../src/plugins/atoms/token-map.js'; import { runRewritePlan } from '../src/plugins/atoms/rewrite-plan.js'; import { applyPatchForStep } from '../src/plugins/atoms/patch-edit.js'; import { runBuildTest, writeBuildTestReport } from '../src/plugins/atoms/build-test.js'; import { runDiffReview } from '../src/plugins/atoms/diff-review.js'; import { runHandoffAtom } from '../src/plugins/atoms/handoff.js'; let repo: string; let cwd: string; const designSystem: DesignSystemTokenBag = { id: 'fixture-ds', tokens: [ { name: '--ds-color-primary', value: '#5b8def', kind: 'color' }, { name: '--ds-spacing-2', value: '16px', kind: 'spacing' }, ], }; beforeEach(async () => { const tmp = await mkdtemp(path.join(os.tmpdir(), 'od-pipeline-e2e-')); repo = path.join(tmp, 'repo'); cwd = path.join(tmp, 'cwd'); await mkdir(repo, { recursive: true }); await mkdir(cwd, { recursive: true }); // Tiny Next.js fixture: one leaf component carrying inline tokens. await writeFile(path.join(repo, 'package.json'), JSON.stringify({ name: 'fixture', dependencies: { next: '15', react: '18' }, devDependencies: { tailwindcss: '4', typescript: '5' }, })); await writeFile(path.join(repo, 'pnpm-lock.yaml'), ''); await mkdir(path.join(repo, 'app'), { recursive: true }); await mkdir(path.join(repo, 'components'),{ recursive: true }); await writeFile(path.join(repo, 'app', 'page.tsx'), `import Button from '@/components/Button';\nexport default function Page(){ return