@danypops/pi-packed 0.28.1 → 0.28.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/pi-packed",
3
- "version": "0.28.1",
3
+ "version": "0.28.2",
4
4
  "description": "Pi package lifecycle, validation, daemon, tools, profiles, and TUI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,7 +42,8 @@
42
42
  "@danypops/pi-tui-harness": "^0.0.1",
43
43
  "@danypops/vehicle-client-pi": "^0.43.1",
44
44
  "@danypops/vehicle-conformance": "^0.4.0",
45
- "@types/semver": "^7.7.1"
45
+ "@types/semver": "^7.7.1",
46
+ "follow-redirects": "^1.16.0"
46
47
  },
47
48
  "peerDependencies": {
48
49
  "@danypops/vehicle-client-pi": "^0.43.1",
@@ -99,7 +99,16 @@ async function main(): Promise<void> {
99
99
  const extensionPath = process.argv[2];
100
100
  if (!extensionPath) throw new Error("extension path is required");
101
101
  try {
102
- const jiti = createJiti(import.meta.url, { interopDefault: true, tryNative: false });
102
+ // tryNative matches loader.ts's own real, non-Bun-binary Pi extension loading convention:
103
+ // prefer Bun's native TS/ESM transform, falling back to jiti's own Babel transform only for
104
+ // what native genuinely can't handle. Confirmed live: tryNative:false forced EVERY
105
+ // transitive dependency (including plain CJS libraries that never needed a Babel transform,
106
+ // e.g. follow-redirects) through jiti's Babel path -- which has its own real, reproducible
107
+ // bug interacting with a library that calls Error.captureStackTrace on a not-yet-initialized
108
+ // Error instance during module-level prototype setup (confirmed outside this sandbox too,
109
+ // given a cold jiti transform cache), surfacing as an opaque "First argument must be an
110
+ // Error object" crash unrelated to the extension's own code.
111
+ const jiti = createJiti(import.meta.url, { interopDefault: true, tryNative: true });
103
112
  const factory = (await jiti.import(extensionPath, { default: true })) as unknown;
104
113
  if (typeof factory !== "function") throw new Error("extension has no default factory export");
105
114
  await factory(api);
@@ -1,8 +1,9 @@
1
1
  import { afterEach, describe, expect, it } from "bun:test";
2
2
  import { spawnSync } from "node:child_process";
3
- import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
3
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { tmpdir } from "node:os";
5
- import { join } from "node:path";
5
+ import { dirname, join } from "node:path";
6
+ import { createRequire } from "node:module";
6
7
  import { checkPackage } from "../src/adoption/check.ts";
7
8
  import { resolveDependencyModulesDir, runExtensionSmoke } from "../src/adoption/smoke.ts";
8
9
 
@@ -180,6 +181,38 @@ describeIfSandboxed("isolated extension smoke runner", () => {
180
181
  expect(result.registrations.commands).toEqual(["hoisted-sibling"]);
181
182
  });
182
183
 
184
+ it("never routes a plain CJS dependency through jiti's own Babel transform path -- confirmed live: forcing every transitive dependency through Babel (tryNative:false) hit a real, reproducible upstream bug in jiti's own Babel-installed Error.prepareStackTrace hook, triggered by follow-redirects' own module-level Error.captureStackTrace call during its chained error-type prototype setup, surfacing as an opaque 'First argument must be an Error object' crash unrelated to the scanned extension's own code -- reproduces with a cold jiti transform cache regardless of this sandbox specifically, so a real npm package (not a synthetic fixture) is the only faithful way to prove it stays fixed", async () => {
185
+ const require = createRequire(import.meta.url);
186
+ const followRedirectsDir = dirname(require.resolve("follow-redirects/package.json"));
187
+
188
+ const workspaceRoot = mkdtempSync(join(tmpdir(), "packed-smoke-follow-redirects-"));
189
+ roots.push(workspaceRoot);
190
+ const sharedNodeModules = join(workspaceRoot, "node_modules");
191
+ cpSync(followRedirectsDir, join(sharedNodeModules, "follow-redirects"), { recursive: true });
192
+ const packageDir = join(sharedNodeModules, "@fixture", "pi-smoke-follow-redirects");
193
+ mkdirSync(join(packageDir, "extension"), { recursive: true });
194
+ const extensionPath = join(packageDir, "extension", "index.ts");
195
+ writeFileSync(
196
+ extensionPath,
197
+ 'import { http } from "follow-redirects";\nexport default function (pi: any) { pi.registerCommand(String(typeof http), { handler() {} }); }\n',
198
+ );
199
+ writeFileSync(
200
+ join(packageDir, "package.json"),
201
+ JSON.stringify({
202
+ name: "@fixture/pi-smoke-follow-redirects",
203
+ version: "1.0.0",
204
+ keywords: ["pi-package"],
205
+ files: ["extension"],
206
+ pi: { extensions: ["extension/index.ts"] },
207
+ }),
208
+ );
209
+
210
+ const result = await runExtensionSmoke(packageDir, extensionPath);
211
+
212
+ expect(result.status).toBe("ok");
213
+ expect(result.registrations.commands).toEqual(["object"]);
214
+ });
215
+
183
216
  it("keeps default package checks static and adds smoke results only when requested", async () => {
184
217
  const fixture = extension(
185
218
  'import { writeFileSync } from "node:fs"; export default function (pi: any) { writeFileSync("executed", "yes"); pi.registerCommand("x", { handler() {} }); }',