From 8b683f8ccb4cbfee328eb4f8d3c98c828c8a0954 Mon Sep 17 00:00:00 2001 From: roboomp Date: Wed, 1 Jul 2026 00:25:24 +0000 Subject: [PATCH] fix(coding-agent): kept docs embed populated for bun pm pack gen:bundle previously ran gen:docs and gen:docs:reset around the build. Under prepack that reset ran before bun pm pack assembled the tarball, so the published src/ copy of docs-index.generated.txt was empty and consumers importing via subpath (e.g. @oh-my-pi/pi-coding-agent/internal-urls/docs-index) fell through to the missing repo docs/ tree. Restored gen:docs in prepack so postpack owns the reset (matching the original lifecycle), and made gen:bundle assert the embed is populated and fresh instead of touching it, so a direct gen:bundle outside prepack fails with an actionable message. Fixes #3934 --- packages/coding-agent/package.json | 2 +- packages/coding-agent/scripts/bundle-dist.ts | 30 ++++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 1cdaa0edf..4491e38c4 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -48,7 +48,7 @@ "gen:mupdf:reset": "bun scripts/embed-mupdf-wasm.ts --reset", "gen:native": "bun --cwd=../natives run gen:native", "gen:native:reset": "bun --cwd=../natives run gen:native:reset", - "prepack": "bun run gen:tool-views && bun run gen:bundle || ( bun run gen:docs:reset; exit 1 )", + "prepack": "bun run gen:docs && bun run gen:tool-views && bun run gen:bundle || ( bun run gen:docs:reset; exit 1 )", "postpack": "bun run gen:docs:reset", "bench:guard": "bun scripts/bench-guard.ts" }, diff --git a/packages/coding-agent/scripts/bundle-dist.ts b/packages/coding-agent/scripts/bundle-dist.ts index 9c64a9eb7..af8bb152b 100755 --- a/packages/coding-agent/scripts/bundle-dist.ts +++ b/packages/coding-agent/scripts/bundle-dist.ts @@ -3,6 +3,7 @@ import * as fs from "node:fs/promises"; import * as path from "node:path"; import { isEnoent } from "@oh-my-pi/pi-utils"; +import { assertDocsIndexFresh, buildDocsIndexPayload } from "./generate-docs-index"; const packageDir = path.join(import.meta.dir, ".."); const outDir = path.join(packageDir, "dist"); @@ -72,15 +73,33 @@ async function cleanBundleOutputs(): Promise { ); } +async function assertDocsEmbedPopulated(): Promise { + // bundle-dist runs from prepack (which calls `gen:docs` first) or directly. + // Direct invocations must fail — the tarball ships src/, and an empty embed + // would make src/internal-urls/docs-index.ts fall through to the missing + // repo `docs/` tree at runtime in published packages (codex review, PR #3941). + const embedPath = path.join(packageDir, "src/internal-urls/docs-index.generated.txt"); + const embed = await Bun.file(embedPath).text(); + if (embed.length === 0) { + throw new Error( + "docs-index embed is empty. Run `bun run gen:docs` before `bun run gen:bundle`, or use `bun pm pack` which runs the prepack chain.", + ); + } + const expected = await buildDocsIndexPayload(); + assertDocsIndexFresh(embed, expected); +} + async function main(): Promise { const start = Bun.nanoseconds(); await cleanBundleOutputs(); - // The npm bundle ships no repo docs tree or stats dashboard sources, so embed - // both generated assets before bundling. Reset afterwards to keep the - // checked-in placeholders empty. + await assertDocsEmbedPopulated(); + // The npm bundle ships no stats dashboard sources, so embed the dashboard + // archive the same way compiled binaries do (scripts/build-binary.ts). Reset + // afterwards to keep the checked-in placeholder empty. The docs embed stays + // populated on disk — postpack owns its reset so `bun pm pack` can pack a + // tarball whose src copy is still valid for subpath imports. + await runCommand(["bun", "--cwd=../stats", "run", "gen:stats"]); try { - await runCommand(["bun", "run", "gen:docs"]); - await runCommand(["bun", "--cwd=../stats", "run", "gen:stats"]); await runCommand([ "bun", "build", @@ -98,7 +117,6 @@ async function main(): Promise { ]); } finally { await runCommand(["bun", "--cwd=../stats", "run", "gen:stats:reset"]); - await runCommand(["bun", "run", "gen:docs:reset"]); } await ensureShebang(); const stat = await fs.stat(cliPath);