(args: CliArgs)
| 762 | |
| 763 | |
| 764 | async function runCodeImport(args: CliArgs): Promise<StageResult> { |
| 765 | const t0 = Date.now(); |
| 766 | const root = repoRoot(); |
| 767 | if (!root) { |
| 768 | return { name: "code", ran: false, ok: true, duration_ms: 0, summary: "skipped (not in git repo)" }; |
| 769 | } |
| 770 | |
| 771 | const sourceId = deriveCodeSourceId(root); |
| 772 | |
| 773 | // dry-run preview always shows the would-do steps, regardless of local |
| 774 | // engine state. Useful for "what would /sync-gbrain do" without probing |
| 775 | // the engine. |
| 776 | if (args.mode === "dry-run") { |
| 777 | return { |
| 778 | name: "code", |
| 779 | ran: false, |
| 780 | ok: true, |
| 781 | duration_ms: 0, |
| 782 | summary: `would: gbrain sources add ${sourceId} --path ${root} --federated; gbrain sync --strategy code --source ${sourceId}; gbrain sources attach ${sourceId}`, |
| 783 | detail: { source_id: sourceId, source_path: root, status: "skipped" }, |
| 784 | }; |
| 785 | } |
| 786 | |
| 787 | // Split-engine pre-flight (per plan D12): when local engine is not ok, SKIP |
| 788 | // code stage cleanly. Brain-sync stage still runs because it doesn't depend |
| 789 | // on local engine. The /sync-gbrain Step 1.5 pre-flight surfaces the user |
| 790 | // remediation message; this skip just keeps the orchestrator from crashing |
| 791 | // when the local DB is dead. Skipped on --dry-run (above) since dry-run |
| 792 | // never actually probes anything. |
| 793 | const localStatus = localEngineStatus({ noCache: false }); |
| 794 | if (localStatus === "timeout") { |
| 795 | warnProbeTimeout("code"); // #1964: slow-but-healthy — proceed |
| 796 | } else if (localStatus !== "ok") { |
| 797 | return skipStageForLocalStatus("code", localStatus, t0); |
| 798 | } |
| 799 | |
| 800 | // Step 0a: Best-effort cleanup of pre-pathhash legacy source (v1.x form). |
| 801 | // Earlier /sync-gbrain versions registered `gstack-code-<slug>` (no path |
| 802 | // suffix). On a multi-worktree repo, those collapsed onto a single id |
| 803 | // with last-sync-wins. Federated search would return stale duplicate |
| 804 | // hits forever if we left the orphan in place. Remove the legacy id once |
| 805 | // here so users don't accumulate orphans. |
| 806 | // Failure is non-fatal — we still register the new id below. |
| 807 | // gbrainEnv seeds DATABASE_URL from gbrain's config so this stage works |
| 808 | // inside Next.js / Prisma / Rails projects with their own .env.local |
| 809 | // (codex review #7 — bug fix is wider than #1508 as filed). |
| 810 | const gbrainEnv = buildGbrainEnv({ announce: !args.quiet }); |
| 811 | const legacyId = deriveLegacyCodeSourceId(root); |
| 812 | let legacyRemoved = false; |
| 813 | if (legacyId !== sourceId) { |
| 814 | // #1734: route through the data-loss guards (autopilot + source-safety). |
| 815 | const rm = safeSourcesRemove(legacyId, gbrainEnv); |
| 816 | if (rm.skipped && !args.quiet) { |
| 817 | console.error(`[sync:code] legacy-source cleanup skipped: ${rm.reason}`); |
| 818 | } |
| 819 | if (rm.removed) legacyRemoved = true; |
| 820 | } |
| 821 |
no test coverage detected