glubean 0.2.3 → 0.3.0

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 (2) hide show
  1. package/bin/glubean.js +63 -1
  2. package/package.json +2 -2
package/bin/glubean.js CHANGED
@@ -1,2 +1,64 @@
1
1
  #!/usr/bin/env node
2
- import "@glubean/cli";
2
+ // Local-bin delegation (defense in depth for version-skew).
3
+ //
4
+ // When a project has its own `glubean` install in `node_modules/.bin/`, npm /
5
+ // pnpm / yarn run it directly via PATH and the local copy executes. But when
6
+ // a user runs the global `glubean` from a project root that ALSO has a local
7
+ // install — e.g. they typed `glubean ...` directly instead of via `npm test`
8
+ // — the global binary executes against the project's `@glubean/sdk`, which
9
+ // may be a different version. Some non-spawn CLI commands (`glubean scan`,
10
+ // `glubean init`, `glubean contracts`, `glubean validate-metadata`,
11
+ // `glubean migrate`) don't go through `TestExecutor.run()`'s project-local
12
+ // runner resolution, so they would silently use the global's bundled SDK and
13
+ // drift from the project's pinned version.
14
+ //
15
+ // Fix: if a project-local `glubean` is reachable from `process.cwd()`, exec it
16
+ // and exit. Otherwise fall through to the global. Standard pattern used by
17
+ // jest, vitest, eslint, pnpm.
18
+ //
19
+ // Escape hatches:
20
+ // * GLUBEAN_NO_LOCAL_BIN_DELEGATE=1 — skip delegation for unusual setups
21
+ // * --inspect / --inspect-brk (via execArgv or NODE_OPTIONS) — skip
22
+ // delegation so the inspector socket isn't lost in the spawned child
23
+
24
+ import { realpathSync } from "node:fs";
25
+ import { createRequire } from "node:module";
26
+ import { fileURLToPath } from "node:url";
27
+ import { spawnSync } from "node:child_process";
28
+
29
+ const selfPath = realpathSync(fileURLToPath(import.meta.url));
30
+ const projectCwd = process.cwd();
31
+
32
+ const optOut = process.env["GLUBEAN_NO_LOCAL_BIN_DELEGATE"] === "1";
33
+
34
+ // Inspector guard: re-exec drops the debug socket. Both execArgv and
35
+ // NODE_OPTIONS can carry --inspect / --inspect-brk (with optional =port).
36
+ const inspectorPattern = /--inspect(-brk)?(?=\s|=|$)/;
37
+ const debugging =
38
+ process.execArgv.some((a) => inspectorPattern.test(a)) ||
39
+ inspectorPattern.test(process.env["NODE_OPTIONS"] ?? "");
40
+
41
+ let localBinPath;
42
+ if (!optOut && !debugging) {
43
+ try {
44
+ // Root the require at a stub inside projectCwd — NOT at import.meta.url
45
+ // (which is the global install location). With cwd-rooted resolution we
46
+ // walk the project's node_modules chain and avoid resolving back to the
47
+ // global install via self-reference.
48
+ const req = createRequire(`${projectCwd}/__glubean_local_bin_stub__.js`);
49
+ localBinPath = realpathSync(req.resolve("glubean/bin/glubean.js"));
50
+ } catch {
51
+ // No local install — fall through to global.
52
+ }
53
+ }
54
+
55
+ if (localBinPath && localBinPath !== selfPath) {
56
+ const result = spawnSync(
57
+ process.execPath,
58
+ [localBinPath, ...process.argv.slice(2)],
59
+ { stdio: "inherit", env: process.env },
60
+ );
61
+ process.exit(result.status ?? 1);
62
+ }
63
+
64
+ await import("@glubean/cli");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glubean",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Glubean CLI — test automation for APIs, browsers, and more",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "access": "public"
14
14
  },
15
15
  "dependencies": {
16
- "@glubean/cli": "0.2.3"
16
+ "@glubean/cli": "0.3.0"
17
17
  },
18
18
  "repository": {
19
19
  "type": "git",