6d16e93b86
The asset-emission assertion was the false positive flagged in
tab-supervisor.ts: the new pattern intentionally does not bundle the
worker as an asset of the supervisor — it is added as a separate
`--compile` entrypoint in build-binary.ts, and runtime is covered by
`omp --smoke-test` (sync worker).
Replaces it with two cheap static checks that defend the two halves
that actually make the worker survive `bun build --compile`:
1. tab-supervisor.ts branches on `isCompiledBinary()` and uses the
exact `--root`-relative literal at the `new Worker(...)` site
that Bun's `--compile` analyzer can discover, while keeping the
`new URL("./tab-worker-entry.ts", import.meta.url)` branch for
dev/source spawns.
2. scripts/build-binary.ts lists the same worker as an explicit
additional `--compile` entrypoint so Bun emits it into bunfs.
79 lines
3.9 KiB
TypeScript
79 lines
3.9 KiB
TypeScript
import { describe, expect, it } from "bun:test";
|
|
import * as path from "node:path";
|
|
|
|
/**
|
|
* Regression for https://github.com/can1357/oh-my-pi/issues/1011
|
|
*
|
|
* In v14.5.13 `spawnTabWorker` (in `src/tools/browser/tab-supervisor.ts`)
|
|
* resolved the worker entry as `new URL("./tab-worker-entry.ts", import.meta.url)`
|
|
* and passed `.href` to `new Worker(...)`. Bun's `--compile` static analyzer
|
|
* cannot discover that pattern, so the entry was never embedded in the
|
|
* single-file binary and the runtime symptom was "Timed out initializing
|
|
* browser tab worker".
|
|
*
|
|
* The original fix used an `import "./worker.ts" with { type: "file" }`
|
|
* trick. That copied the entry as a raw asset but could not resolve its
|
|
* relative imports inside the compiled binary, so the worker still failed
|
|
* to load (issue #1027 was the same root cause, retriggered).
|
|
*
|
|
* The working pattern documented in AGENTS.md is a two-part contract:
|
|
*
|
|
* 1. `spawnTabWorker` branches on `isCompiledBinary()` and uses a literal
|
|
* string path under `--compile`. Bun's `--compile` analyzer discovers
|
|
* that literal at the `new Worker("...", ...)` call site. The path is
|
|
* `--root`-relative (`./packages/coding-agent/src/...`) because the
|
|
* build script passes `--root ../..`.
|
|
* 2. `scripts/build-binary.ts` lists the worker as an explicit additional
|
|
* `--compile` entrypoint. Without this, Bun sees the literal at the
|
|
* spawn site but never emits the worker module into bunfs.
|
|
*
|
|
* Either half alone is insufficient — both must agree on the exact path.
|
|
* Runtime end-to-end coverage lives in `omp --smoke-test` (via the stats
|
|
* sync worker). This test is the cheap static contract that catches an
|
|
* accidental regression of either half in code review / CI.
|
|
*/
|
|
describe("issue #1011 — tab worker entry must survive `bun build --compile`", () => {
|
|
const packageDir = path.resolve(import.meta.dir, "..");
|
|
const supervisorPath = path.join(packageDir, "src/tools/browser/tab-supervisor.ts");
|
|
const buildBinaryPath = path.join(packageDir, "scripts/build-binary.ts");
|
|
// `--root` is `../..` from packages/coding-agent, so the literal that
|
|
// matches at runtime inside the compiled bunfs is repo-relative.
|
|
const compiledLiteral = "./packages/coding-agent/src/tools/browser/tab-worker-entry.ts";
|
|
// The build script's cwd is packages/coding-agent, so its entrypoint
|
|
// path is package-relative.
|
|
const buildEntrypoint = "./src/tools/browser/tab-worker-entry.ts";
|
|
|
|
it("tab-supervisor uses the isCompiledBinary() hybrid spawn pattern with a static literal", async () => {
|
|
const source = await Bun.file(supervisorPath).text();
|
|
|
|
// The exact literal at the `new Worker(...)` call must be present
|
|
// and discoverable to Bun's `--compile` static analyzer.
|
|
expect(
|
|
source.includes(`new Worker("${compiledLiteral}"`),
|
|
`tab-supervisor.ts must spawn the worker with the literal "${compiledLiteral}" so Bun's --compile analyzer can embed it`,
|
|
).toBe(true);
|
|
|
|
// And the dev-mode branch should keep the portable import.meta.url
|
|
// form so spawns work outside of compiled binaries too.
|
|
expect(
|
|
/new Worker\(\s*new URL\("\.\/tab-worker-entry\.ts",\s*import\.meta\.url\)/.test(source),
|
|
"tab-supervisor.ts must keep a `new URL('./tab-worker-entry.ts', import.meta.url)` branch for dev/source spawns",
|
|
).toBe(true);
|
|
|
|
// And the branching must come from `isCompiledBinary()` — not, say,
|
|
// a hard-coded check, an env var, or a renamed helper.
|
|
expect(
|
|
source.includes("isCompiledBinary()"),
|
|
"tab-supervisor.ts must select the spawn pattern via isCompiledBinary()",
|
|
).toBe(true);
|
|
});
|
|
|
|
it("build-binary.ts lists tab-worker-entry as an explicit --compile entrypoint", async () => {
|
|
const source = await Bun.file(buildBinaryPath).text();
|
|
expect(
|
|
source.includes(`"${buildEntrypoint}"`),
|
|
`scripts/build-binary.ts must include "${buildEntrypoint}" as an explicit --compile entrypoint so Bun emits the worker into bunfs`,
|
|
).toBe(true);
|
|
});
|
|
});
|