pi-crew 0.9.52 → 0.9.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/index.ts +39 -10
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  > **Note:** `atomic-write-v2.ts` / `AtomicWriter` mentioned in historical entries below was consolidated into `atomic-write.ts` as of v0.9.42. This changelog is preserved as historical record — the migration was completed (the v2 class was never adopted; v1 won on simplicity + symlink-safety + link+unlink atomicity). See `docs/migration/atomic-write-v2-migration.md` for the decision rationale.
4
4
 
5
5
 
6
+ ## [0.9.53] — HOTFIX: extension-load regression in published npm installs (2026-07-29)
7
+
8
+ **Fixes the v0.9.52 regression** where every fresh `npm install pi-crew` failed at extension load with `Cannot find module './src/extension/register.ts'`. Affected all platforms.
9
+
10
+ ### Root cause
11
+ v0.9.52's PKG-2 (Sprint 6) excluded `src/` from the npm tarball to slim it (16→4.8MB), but `index.ts` — the extension entry Pi loads via strip-types — still had **top-level static imports** from `./src/extension/register.ts` and `./src/runtime/run-tracker.ts`. The module loader resolves static imports BEFORE any code in the file runs, so the load failed before the shipped, self-contained `dist/index.mjs` bundle was ever tried. Pre-0.9.52 this was masked because `src/` was shipped alongside.
12
+
13
+ CI missed it because the `test:bundle` step loads `dist/index.mjs` directly (with repo peerDeps), and the CI-5 smoke test used `node --check` (syntax only — does not resolve imports).
14
+
15
+ ### Fix (`index.ts`)
16
+ The src/ imports are now **dynamic `import()`** inside the fallback path only. The self-contained `dist/index.mjs` bundle (always shipped in the tarball) is the default and loads without `src/`. The src/ fallback is reached only when the bundle is absent — i.e. dev clones without a built `dist/`. Published installs never touch `src/`. No behavior change for bundle users; the fallback semantics (`PI_CREW_USE_BUNDLE=0` opt-out) are preserved.
17
+
18
+ ### Regression guard
19
+ New `test/unit/extension-entry-load.test.ts` asserts `index.ts` has no static top-level `./src/` value imports (and that the dynamic src/ fallback imports still exist). Would have caught v0.9.52. Runs in CI's Test step on all platforms.
20
+
21
+ ### Note on v0.9.52
22
+ v0.9.52 is **deprecated** on npm — upgrade to 0.9.53. If you installed 0.9.52, run `npm install pi-crew@latest` (or `npx pi install npm:pi-crew`).
23
+
6
24
  ## [0.9.52] — Sprint 1-6: security hardening, durability, god-module refactor, tarball slim (2026-07-28)
7
25
 
8
26
  A full audit-driven upgrade pass — 6 sprints, ~60 findings from `REVIEW-UPGRADE-2026-07-27.md`, independently verified in `VERIFY-2026-07-27.md` (~22% of the original report's claims corrected: 4 false positives, count inflations, stale line refs). Test suite 6446 unit + 191 integration, 0 fail. CI green on ubuntu/macos/windows.
package/index.ts CHANGED
@@ -47,18 +47,29 @@
47
47
  * avoid recursion), the bundle flip risk is acceptable.
48
48
  */
49
49
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
50
- import { registerPiTeams as registerPiTeamsFromSrc } from "./src/extension/register.ts";
51
- import { waitForRun as waitForRunFromSrc } from "./src/runtime/run-tracker.ts";
52
50
  import { accessSync } from "node:fs";
53
51
  import { fileURLToPath } from "node:url";
54
52
  import { dirname, resolve } from "node:path";
55
53
 
56
- // Minimal bundle shape — we only use a few named exports. Keep this loose
57
- // because dist/index.mjs has no .d.ts (it's a build artifact, not source).
54
+ // IMPORTANT: src/ imports here MUST be dynamic (lazy `import()`), never
55
+ // top-level static imports. Published npm packages ship only dist/index.mjs
56
+ // in the tarball (src/ is excluded by the package.json "files" field — keeps
57
+ // the package ~5MB instead of ~16MB). A top-level static
58
+ // `import { x } from "./src/..."` is resolved by the module loader BEFORE
59
+ // this file's code runs, so it would break every fresh `npm install`
60
+ // (Cannot find module './src/...'). Dynamic import() defers src/ resolution
61
+ // to the fallback path below, which only executes when the bundle is
62
+ // unavailable — i.e. dev clones that still have src/. Published installs
63
+ // always ship + load the bundle, so src/ is never touched there.
64
+
65
+ // Minimal bundle shape — loose types because dist/index.mjs has no .d.ts
66
+ // (it's a build artifact, not source). The src fallback types use
67
+ // `typeof import(...)` type queries, which are type-only constructs erased
68
+ // at runtime (no module load) — they stay in sync with the real modules.
58
69
  type BundleModule = {
59
70
  default?: (pi: ExtensionAPI) => void;
60
- waitForRun?: typeof waitForRunFromSrc;
61
- registerPiTeams?: (pi: ExtensionAPI) => void;
71
+ waitForRun?: typeof import("./src/runtime/run-tracker.ts").waitForRun;
72
+ registerPiTeams?: typeof import("./src/extension/register.ts").registerPiTeams;
62
73
  };
63
74
 
64
75
  const OPT_OUT = new Set(["0", "false", "no", "off"]);
@@ -91,8 +102,26 @@ if (!envForceOff) {
91
102
  }
92
103
  }
93
104
 
94
- export const waitForRun = bundleModule?.waitForRun ?? waitForRunFromSrc;
95
- export const registerPiTeams: (pi: ExtensionAPI) => void =
96
- bundleModule?.registerPiTeams ?? registerPiTeamsFromSrc;
105
+ // Lazy src/ fallback — only resolved when the bundle is unavailable
106
+ // (dev clones without a built dist/). NEVER imported in published
107
+ // installs, where the bundle always ships + loads above. This dynamic
108
+ // import() is what lets us exclude src/ from the npm tarball.
109
+ let srcRegister:
110
+ | typeof import("./src/extension/register.ts").registerPiTeams
111
+ | undefined;
112
+ let srcWaitForRun:
113
+ | typeof import("./src/runtime/run-tracker.ts").waitForRun
114
+ | undefined;
115
+ if (!bundleModule) {
116
+ ({ registerPiTeams: srcRegister } = await import(
117
+ "./src/extension/register.ts",
118
+ ));
119
+ ({ waitForRun: srcWaitForRun } = await import(
120
+ "./src/runtime/run-tracker.ts",
121
+ ));
122
+ }
97
123
 
98
- export default bundleModule?.default ?? ((pi: ExtensionAPI) => registerPiTeamsFromSrc(pi));
124
+ export const waitForRun = bundleModule?.waitForRun ?? srcWaitForRun!;
125
+ export const registerPiTeams: (pi: ExtensionAPI) => void =
126
+ bundleModule?.registerPiTeams ?? srcRegister!;
127
+ export default bundleModule?.default ?? ((pi: ExtensionAPI) => srcRegister!(pi));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-crew",
3
- "version": "0.9.52",
3
+ "version": "0.9.53",
4
4
  "description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
5
5
  "author": "baphuongna",
6
6
  "license": "MIT",