Skip to content

fix(web): hand resolved pi-coding-agent entry to the /web child process - #355

Open
FHMinyi wants to merge 1 commit into
openpi-dev:mainfrom
FHMinyi:fix/web-peer-resolution
Open

fix(web): hand resolved pi-coding-agent entry to the /web child process#355
FHMinyi wants to merge 1 commit into
openpi-dev:mainfrom
FHMinyi:fix/web-peer-resolution

Conversation

@FHMinyi

@FHMinyi FHMinyi commented Sep 2, 2026

Copy link
Copy Markdown

Problem

Closes #341.

Users who install via pi install npm:@tt-a1i/openpi (the documented install path) cannot start the Web Workbench: /web reports OpenPI Web Workbench exited with code 1. and the real error is swallowed when the TUI resumes. The spawned standalone node process fails with Cannot find module '@earendil-works/pi-coding-agent' because the package is a peerDependency, which pi install npm: does not install. Dev checkouts never see this because the same-name devDependency resolves.

Value

Makes /web and openpi web work for every npm-installed user — currently the feature is broken for 100% of that install base. No behavior change for dev checkouts or for environments where resolution fails.

Approach

The parent extension runs inside the Pi process, where the loader resolves the peer package. It resolves the entry path and hands it to the child through OPENPI_PI_CODING_AGENT_ENTRY; the child (bin/openpi.js) maps the bare specifier to that absolute path via a jiti alias.

Why walk-up instead of import.meta.resolve / createRequire (verified with a probe extension inside a real Pi process, fnm + node 24):

  • Pi's extension loader (pi-coding-agent/dist/core/extensions/loader.js) jiti-aliases the specifier to <pkg>/dist/index.js, so dynamic import() works, but import.meta.resolve and createRequire(import.meta.url) are not intercepted and fail from the extension's location.
  • createRequire(process.argv[1]) fails because argv[1] is a version-manager shim symlink (node does not realpath it); after realpathSync, CJS resolution is still rejected (exports has no require condition).
  • So: realpathSync(process.argv[1]) → walk up to the package.json named @earendil-works/pi-coding-agent → use <root>/dist/index.js (the exact path Pi's own loader aliases to), verified with existsSync.

Design choices:

  • Resolution is fail-soft: when no path is found the env var is unset, any inherited stale OPENPI_PI_CODING_AGENT_ENTRY is deleted, and the child behaves exactly as before.
  • Resolution capability is injected through the existing WebCommandDependencies seam so tests fake it without touching the filesystem.

Known limitation (not addressed here): bun/SEA compiled Pi binaries have no node_modules tree, so walk-up finds nothing and behavior is unchanged; the /web spawn via process.execPath already assumes a node runtime.

Validation

  • bun run test on main @ 72fbba5: 1243 pass / 0 fail / 1 skipped.
  • bun run check: config contract, discipline ledger, web syntax check, biome format + lint, tsc — all green.
  • New tests:
    • tests/extensions/web/index.test.ts: the launcher hands the resolved entry to the child env and drops a stale inherited value when resolution fails.
    • tests/web/cli.test.ts: end-to-end — a stub package layout without the peer dependency proves the jiti alias redirects the bare @earendil-works/pi-coding-agent import to the handed-over entry.
  • Real smoke: OPENPI_PI_CODING_AGENT_ENTRY=<global pi dist/index.js> node bin/openpi.js web --no-workspace --no-open — WebHost started on 127.0.0.1:53056, printed the authenticated ready screen, and released the host lease on shutdown.
  • Not run: the full interactive TUI /web path (the ctx.mode === "tui" gate cannot be automated here); the smoke exercised the identical child command the TUI spawns.

Impact

  • User-visible behavior: /web and openpi web now start for npm-installed users; unchanged otherwise.
  • Model-visible context/tools: none.
  • Runtime/lifecycle: one additional env var on the web child process; stale inherited values are removed when resolution fails.
  • Persisted config/data: none.
  • Compatibility/risk: dev checkouts and failure paths behave as before; bun/SEA compiled Pi installs remain a known limitation.

npm-installed users hit exit code 1 on /web: the standalone child
process cannot resolve the peer dependency @earendil-works/pi-coding-agent
from the npm package location.

The parent extension runs inside Pi, so resolve the package entry there:
walk up from realpathSync(process.argv[1]) to the pi-coding-agent package
root and hand dist/index.js to the child via OPENPI_PI_CODING_AGENT_ENTRY.
The child maps the bare specifier to that absolute path through a jiti
alias. Resolution is fail-soft and any inherited stale env value is
dropped, preserving the previous behavior when no path is found.

Closes openpi-dev#341
@FHMinyi

FHMinyi commented Sep 3, 2026

Copy link
Copy Markdown
Author

@tt-a1i 佬 review 下🥺

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(web): npm 安装后 /web 与 openpi web 因子进程无法解析 peer 依赖 @earendil-works/pi-coding-agent 而退出(exit 1)

1 participant