fix(pi-ext): stop importing @earendil-works/pi-ai at runtime #105

Merged
michal merged 1 commits from fix/pi-ext-module-resolution into main 2026-08-09 23:15:31 +00:00
Owner

The pi extension failed to load outright on older pi installs:

Failed to load extension ".../mcpctl-pi.ts": Cannot find module '@earendil-works/pi-ai'

Root cause

pi doesn't resolve an extension's bare specifiers the ordinary way — it hands jiti a hard-coded alias table built from its own dependencies, and that table differs between pi distributions:

install aliases
@earendil-works/pi-coding-agent 0.84.1 @earendil-works/* and legacy @mariozechner/*
@mariozechner/pi-coding-agent 0.73.1 @mariozechner/* only

Neither resolves the other's namespace, so one import outside the intersection takes the whole extension down — every tool, the /mcpctl command, the status line.

Fix

The only thing we used from pi-ai was StringEnum, a six-line wrapper over Type.Unsafe. Inlined as a local stringEnum with byte-identical output, so typebox — aliased by every published pi — is now the sole bare runtime import. The call site also passes description through, which the pi-ai version was silently dropping.

Guarded in tests/config/pi-extension-embed.test.ts: any runtime import in the embedded sources that isn't node:, relative, or typebox now fails the build. Confirmed the guard flags the old source.

Verification

Same active project, both installs:

  • 0.73.1 — reproduced the error verbatim before, loads clean after, registers mc_sre_begin_session
  • 0.84.1 — unchanged, still registers mc_sre_begin_session
  • stringEnum output compared against pi-ai's StringEnum: identical JSON, with and without a description
  • typecheck:pi-ext clean; 700 CLI tests pass; lint unchanged from the main baseline

Docs updated with the constraint and a type -a pi pointer for the two-installs-on-PATH case.

🤖 Generated with Claude Code

https://claude.ai/code/session_014tsRTqhEC7YYYYaP3cBqo8

The pi extension failed to load outright on older pi installs: ``` Failed to load extension ".../mcpctl-pi.ts": Cannot find module '@earendil-works/pi-ai' ``` ## Root cause pi doesn't resolve an extension's bare specifiers the ordinary way — it hands jiti a **hard-coded alias table** built from its own dependencies, and that table differs between pi distributions: | install | aliases | |---|---| | `@earendil-works/pi-coding-agent` 0.84.1 | `@earendil-works/*` **and** legacy `@mariozechner/*` | | `@mariozechner/pi-coding-agent` 0.73.1 | `@mariozechner/*` only | Neither resolves the other's namespace, so one import outside the intersection takes the **whole extension** down — every tool, the `/mcpctl` command, the status line. ## Fix The only thing we used from pi-ai was `StringEnum`, a six-line wrapper over `Type.Unsafe`. Inlined as a local `stringEnum` with byte-identical output, so `typebox` — aliased by every published pi — is now the sole bare runtime import. The call site also passes `description` through, which the pi-ai version was silently dropping. Guarded in `tests/config/pi-extension-embed.test.ts`: any runtime import in the embedded sources that isn't `node:`, relative, or typebox now fails the build. Confirmed the guard flags the old source. ## Verification Same active project, both installs: - **0.73.1** — reproduced the error verbatim before, loads clean after, registers `mc_sre_begin_session` - **0.84.1** — unchanged, still registers `mc_sre_begin_session` - `stringEnum` output compared against pi-ai's `StringEnum`: identical JSON, with and without a description - `typecheck:pi-ext` clean; 700 CLI tests pass; lint unchanged from the `main` baseline Docs updated with the constraint and a `type -a pi` pointer for the two-installs-on-PATH case. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_014tsRTqhEC7YYYYaP3cBqo8
michal added 1 commit 2026-08-09 23:15:24 +00:00
fix(pi-ext): stop importing @earendil-works/pi-ai at runtime
Some checks failed
CI/CD / typecheck (pull_request) Successful in 1m19s
CI/CD / test (pull_request) Successful in 1m23s
CI/CD / lint (pull_request) Successful in 3m10s
CI/CD / smoke (pull_request) Failing after 10m42s
CI/CD / build (pull_request) Failing after 13m32s
CI/CD / publish (pull_request) Has been skipped
be7fabd467
The extension failed to load outright on older pi installs:

  Failed to load extension ".../mcpctl-pi.ts":
  Cannot find module '@earendil-works/pi-ai'

pi doesn't resolve an extension's bare specifiers the ordinary way — it
hands jiti a hard-coded alias table built from its own dependencies, and
that table differs between pi distributions. `@earendil-works/pi-coding-
agent` (0.84.1) aliases both the `@earendil-works/*` and legacy
`@mariozechner/*` names; `@mariozechner/pi-coding-agent` (0.73.1) aliases
only the old ones. Neither resolves the other's namespace, so a single
import outside the intersection takes the whole extension down: every
tool, the /mcpctl command, and the status line, all gone.

The only thing we used from pi-ai was `StringEnum`, a six-line wrapper
over `Type.Unsafe`. Inlined as a local `stringEnum` with byte-identical
output, so `typebox` — aliased by every published pi — is now the sole
bare runtime import. The call site also passes `description` through,
which the pi-ai version was silently dropping.

Guarded in tests/config/pi-extension-embed.test.ts: any runtime import in
the embedded sources that isn't `node:`, relative, or typebox now fails.

Verified against both installs with the same active project: 0.73.1
reproduced the error verbatim before the change and loads cleanly after,
and 0.84.1 keeps registering the gate tool exactly as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014tsRTqhEC7YYYYaP3cBqo8
michal merged commit 2b87cfdbf1 into main 2026-08-09 23:15:31 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#105