import { inspectDrift, readManifest, tildify } from "@designpaca/core"; import { getVersion } from "../skill.ts"; import { runInstall, printOutcomes } from "./install.ts"; import { dim, heading, info, ok, warn } from "../ui.ts"; /** * 설치 기록을 그대로 따라가며 재설치한다. * 사용자가 고친 파일은 기본적으로 보존된다(applyPlan 이 판단) — 강제로 맞추려면 --force. */ export async function runUpdate(opts: { force?: boolean } = {}): Promise { const version = await getVersion(); const manifest = await readManifest(); if (manifest.installs.length === 0) { console.log(warn("설치 기록이 없다. `npx designpaca install` 을 먼저 실행해라.")); return 1; } console.log(heading(`업데이트 → v${version}`)); const stale = manifest.installs.filter((i) => i.version !== version); if (stale.length === 0) { console.log(ok("모든 설치가 이미 최신이다")); // 버전이 같아도 파일이 사라졌거나 수정됐을 수 있다. 조용히 넘기면 사용자가 모른다. let broken = 0; for (const rec of manifest.installs) { const drift = await inspectDrift(rec); const missing = drift.files.filter((f) => f.status === "missing"); if (missing.length > 0) { broken += missing.length; console.log(warn(`${rec.target}: 파일 ${missing.length}개가 사라졌다 ${dim(tildify(rec.root))}`)); } if (drift.modified.length > 0) { console.log(info(`${rec.target}: 직접 수정한 파일 ${drift.modified.length}개는 그대로 둔다`)); } } if (!opts.force) { console.log(dim(broken > 0 ? " 사라진 파일을 복구하려면 --force" : " 강제로 다시 쓰려면 --force")); return broken > 0 ? 1 : 0; } } for (const rec of manifest.installs) { console.log(info(`${rec.target} (${rec.scope}) ${dim(tildify(rec.root))} — ${rec.version} → ${version}`)); const outcomes = await runInstall({ targets: [rec.target], scope: rec.scope, force: opts.force, }); printOutcomes(outcomes); } return 0; }