{"version":3,"file":"upgrade-migration.mjs","names":[],"sources":["../../../src/services/scaffold/upgrade-migration.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { MISSING_CONFIG_MESSAGE, readAuthoredConfigInput } from \"../../config\";\nimport type { PhaseTiming, UpgradeOptions, UpgradeResult } from \"../../contract\";\nimport { formatUnknownError } from \"../../utils/errors\";\nimport { saveBosConfig } from \"../../utils/save-config\";\nimport { timePhase } from \"../../utils/timing\";\nimport { openResolution } from \"../resolution/session\";\nimport { syncResolvedSharedDeps } from \"../workspace/shared-deps\";\nimport { runTypesGen } from \"./init\";\nimport { syncTemplate } from \"./sync\";\nimport { migrateChildRootPackageJson } from \"./upgrade-packages\";\nimport { buildChangelogUrl, type ExtendedRootSource } from \"./upgrade-source\";\n\n/** Migration-phase scope (ADR 0032): template reconciliation rides the\n * framework version delta — with no delta nothing touches the tree. */\nexport interface MigrationScope {\n  /** true when the upgrade moves framework versions (or `--from` says so) */\n  versionDelta: boolean;\n}\n\n/**\n * Surgical platform-pin edit on the authored `bos.app.ts` source: rewrites\n * only the `platform: \"…\"` line (or inserts one after `extends`), leaving\n * every other byte — formatting, comments, attachments — untouched. Throws\n * with the version to set by hand when no safe anchor exists; the authored\n * file is never re-serialized.\n */\nexport function stampPlatformPin(source: string, version: string): string {\n  const platformLineRe = /^([ \\t]*)(platform|\"platform\")[ \\t]*:[ \\t]*\"([^\"]*)\"(,?)[ \\t]*$/;\n  const extendsLineRe = /^([ \\t]*)(extends|\"extends\")[ \\t]*:[ \\t]*(\"[^\"]*\")(,?)[ \\t]*$/;\n  const lines = source.split(\"\\n\");\n\n  for (let i = 0; i < lines.length; i++) {\n    const match = lines[i].match(platformLineRe);\n    if (match) {\n      lines[i] = `${match[1]}platform: \"${version}\"${match[4]}`;\n      return lines.join(\"\\n\");\n    }\n  }\n\n  for (let i = 0; i < lines.length; i++) {\n    const match = lines[i].match(extendsLineRe);\n    if (match) {\n      lines[i] = `${match[1]}${match[2]}: ${match[3]},`;\n      lines.splice(i + 1, 0, `${match[1]}platform: \"${version}\",`);\n      return lines.join(\"\\n\");\n    }\n  }\n\n  throw new Error(\n    `could not stamp the platform pin surgically — no platform or extends ` +\n      `property found in the authored config; set platform: \"${version}\" ` +\n      `in bos.app.ts manually and re-run`,\n  );\n}\n\n/**\n * Stamp the resolved framework version into the authored config's `platform`\n * pin (ADR 0034). Runs at the top of the migration phase on both the inline\n * and re-exec'd paths, so everyday resolution (sync, init, runtime) always\n * freezes to the release this upgrade just landed from — whether or not the\n * package versions actually moved. The authored `bos.app.ts` is edited\n * surgically (the pin line only) — never re-serialized.\n */\nexport async function applyPlatformPin(\n  projectDir: string,\n  parentSource: ExtendedRootSource,\n): Promise<string | undefined> {\n  const version = parentSource.platform.manifest.frameworkVersion;\n  const config = (await readAuthoredConfigInput(projectDir)) as Record<string, unknown> | null;\n  if (!config) return undefined;\n  if (config.platform === version) return undefined;\n\n  const appConfigPath = join(projectDir, \"bos.app.ts\");\n  if (existsSync(appConfigPath)) {\n    const source = readFileSync(appConfigPath, \"utf-8\");\n    writeFileSync(appConfigPath, stampPlatformPin(source, version));\n    return \"bos.app.ts\";\n  }\n\n  config.platform = version;\n  await saveBosConfig(projectDir, config);\n  return \"bos.config.json\";\n}\n\n/**\n * The re-exec'd migration child runs `--json`, so its stdout is the structured\n * result — a failed run carries the real failure in its `error` field, which\n * raw stderr/stdout concatenation hides behind `[CLI] [object Object]`.\n */\nexport function describeMigrationFailure(\n  stdout: string | undefined,\n  stderr: string | undefined,\n): string {\n  if (stdout) {\n    try {\n      const parsed = JSON.parse(stdout) as { error?: unknown };\n      if (parsed && typeof parsed === \"object\" && parsed.error != null) {\n        return formatUnknownError(parsed.error);\n      }\n    } catch {\n      // not JSON — fall through to the raw streams\n    }\n  }\n  const raw = (stderr || stdout || \"\").trim();\n  return raw.length > 0 ? raw : \"Unknown error\";\n}\n\nexport async function runMigrationPhase(\n  projectDir: string,\n  options: UpgradeOptions,\n  parentSource: ExtendedRootSource,\n  scope: MigrationScope,\n): Promise<UpgradeResult> {\n  const timings: PhaseTiming[] = [];\n\n  const platformPinned = await timePhase(timings, \"stamp platform pin\", () =>\n    applyPlatformPin(projectDir, parentSource),\n  );\n\n  const migratedRootPackageJson = await timePhase(timings, \"migrate root package\", () =>\n    migrateChildRootPackageJson(projectDir),\n  );\n\n  let syncResult: UpgradeResult[\"sync\"];\n  // Same-version upgrades never touch framework-owned files (ADR 0032).\n  // `--no-sync` opts out of a version-change sync.\n  if (scope.versionDelta && !options.noSync) {\n    syncResult = await timePhase(timings, \"sync template\", () =>\n      syncTemplate(projectDir, {\n        dryRun: false,\n        noInstall: true,\n        force: options.force,\n      }),\n    );\n    if (syncResult?.status === \"conflicted\") {\n      throw new Error(syncResult.error ?? \"Template sync hit unresolvable local conflicts\");\n    }\n  }\n\n  await timePhase(timings, \"sync shared deps\", async () => {\n    const configSession = await openResolution({ cwd: projectDir });\n    if (!configSession?.config) {\n      throw new Error(`${MISSING_CONFIG_MESSAGE} in current directory`);\n    }\n\n    return syncResolvedSharedDeps({\n      configDir: projectDir,\n      hostMode: \"local\",\n      bosConfig: configSession.config,\n    });\n  });\n\n  if (!options.noInstall) {\n    await timePhase(timings, \"generate types\", () => runTypesGen(projectDir));\n  }\n\n  const migratedFiles = [\n    ...(platformPinned ? [platformPinned] : []),\n    ...(migratedRootPackageJson ? [\"package.json\"] : []),\n  ];\n\n  const mainPkg = parentSource.catalog[\"everything-dev\"];\n  const changelogUrl = mainPkg\n    ? buildChangelogUrl(undefined, mainPkg, parentSource.repository)\n    : undefined;\n\n  return {\n    status: \"upgraded\",\n    packages: [],\n    sync: syncResult,\n    migrated: migratedFiles.length > 0 ? migratedFiles : undefined,\n    timings,\n    changelogUrl,\n  };\n}\n"],"mappings":"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"}