pi-usereq 0.47.0 → 0.48.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.48.0](https://github.com/Ogekuri/PI-useReq/compare/v0.47.0..v0.48.0) - 2026-07-13
4
+ ### 🐛 Bug Fixes
5
+ - approve scripts at correct install root [useReq] *(install-static-checkers)*
6
+ - getConsumerInstallRoot preferred INIT_CWD over npm_config_local_prefix.
7
+ - pi runs 'npm install --prefix <root>' from its own cwd, so INIT_CWD is the
8
+ - caller cwd, not the install root; the allowScripts approval was written to
9
+ - the wrong project (or nowhere) and 'npm warn allow-scripts' persisted on
10
+ - every 'pi update --extensions'.
11
+ - Swap priority to prefer npm_config_local_prefix (the real install root in
12
+ - both --prefix and plain installs), falling back to INIT_CWD.
13
+ - Add reproducer unit test; update WORKFLOW.md call-trace description.
14
+ - Satisfies DES-020, REQ-352.
15
+
3
16
  ## [0.47.0](https://github.com/Ogekuri/PI-useReq/compare/v0.46.0..v0.47.0) - 2026-07-13
4
17
  ### 🐛 Bug Fixes
5
18
  - Fix packages file.
@@ -636,6 +649,7 @@
636
649
  - \[0.45.0\]: https://github.com/Ogekuri/PI-useReq/releases/tag/v0.45.0
637
650
  - \[0.46.0\]: https://github.com/Ogekuri/PI-useReq/releases/tag/v0.46.0
638
651
  - \[0.47.0\]: https://github.com/Ogekuri/PI-useReq/releases/tag/v0.47.0
652
+ - \[0.48.0\]: https://github.com/Ogekuri/PI-useReq/releases/tag/v0.48.0
639
653
 
640
654
  [0.1.0]: https://github.com/Ogekuri/PI-useReq/releases/tag/v0.1.0
641
655
  [0.2.0]: https://github.com/Ogekuri/PI-useReq/compare/v0.1.0..v0.2.0
@@ -682,3 +696,4 @@
682
696
  [0.45.0]: https://github.com/Ogekuri/PI-useReq/compare/v0.44.0..v0.45.0
683
697
  [0.46.0]: https://github.com/Ogekuri/PI-useReq/compare/v0.45.0..v0.46.0
684
698
  [0.47.0]: https://github.com/Ogekuri/PI-useReq/compare/v0.46.0..v0.47.0
699
+ [0.48.0]: https://github.com/Ogekuri/PI-useReq/compare/v0.47.0..v0.48.0
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # PI-useReq/pi-usereq (0.47.0)
1
+ # PI-useReq/pi-usereq (0.48.0)
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python 3.11+">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-usereq",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Ogekuri/PI-useReq.git"
@@ -1309,7 +1309,7 @@
1309
1309
  - Internal Call-Trace Tree:
1310
1310
  - `main(...)`: when invoked as the npm `postinstall` lifecycle, best-effort write consumer-root name-only `allowScripts` approvals, then probe each bundled npm checker, attempt best-effort install on miss, print native-checker guidance, and return `0` [`scripts/install-static-checkers.ts`]
1311
1311
  - `approvePendingInstallScripts(...)`: best-effort write name-only `allowScripts` approvals into the consumer-root `package.json` for installed packages declaring install lifecycle scripts before probing [`scripts/install-static-checkers.ts`]
1312
- - `getConsumerInstallRoot(...)`: resolve the consumer install root from the npm `INIT_CWD` or `npm_config_local_prefix` lifecycle environment [`scripts/install-static-checkers.ts`]
1312
+ - `getConsumerInstallRoot(...)`: resolve the consumer install root preferring the npm `npm_config_local_prefix` install root (correct under pi `npm install --prefix <root>` flows) over the `INIT_CWD` caller-cwd fallback [`scripts/install-static-checkers.ts`]
1313
1313
  - `collectNodeModulesPackages(...)`: scan consumer-root `node_modules` and parse each readable package manifest [`scripts/install-static-checkers.ts`]
1314
1314
  - `selectInstallScriptPackageNames(...)`: select package names declaring `preinstall`, `install`, or `postinstall` scripts [`scripts/install-static-checkers.ts`]
1315
1315
  - `mergeAllowScriptsEntries(...)`: merge name-only approvals into the existing `allowScripts` map while preserving prior entries and explicit denials [`scripts/install-static-checkers.ts`]
@@ -71,12 +71,13 @@ export interface InstallScriptApprovalDeps {
71
71
 
72
72
  /**
73
73
  * @brief Resolves the consumer install root that owns the active npm install transaction.
74
- * @details During an npm lifecycle script npm sets `INIT_CWD` to the invocation directory and `npm_config_local_prefix` to the resolved project prefix; both point at the true consumer root instead of the installed package directory that is the postinstall `process.cwd()`. Returns the first available value so the approval flow writes the consumer-root `package.json` allowScripts map instead of the nested `node_modules/<pkg>` directory. Runtime is O(1). No external state is mutated.
74
+ * @details During an npm lifecycle script npm sets `npm_config_local_prefix` to the resolved project prefix (the directory holding the `package.json` npm operates on) and `INIT_CWD` to the npm invocation directory. The pi extension host drives installs with `npm install <pkg> --prefix <installRoot>` from its own caller cwd, so in that flow `INIT_CWD` is the host caller cwd, NOT the install root, while `npm_config_local_prefix` equals the install root in both `--prefix` and plain `cd <root> && npm install` flows. Therefore `npm_config_local_prefix` MUST be selected first; `INIT_CWD` is retained only as a fallback for npm versions or flows that leave the prefix unset. Selecting `INIT_CWD` first would resolve the caller project (or a nonexistent path), so the `allowScripts` approval would be written to the wrong `package.json` (or nowhere) and the `npm warn allow-scripts` warning would persist on every extension update. Runtime is O(1). No external state is mutated.
75
75
  * @param[in] env {NodeJS.ProcessEnv} Environment map read for npm lifecycle path variables.
76
- * @return {string | undefined} Consumer install root, or `undefined` when not running inside an npm lifecycle.
76
+ * @return {string | undefined} Consumer install root, preferring `npm_config_local_prefix` then `INIT_CWD`, or `undefined` when not running inside an npm lifecycle.
77
+ * @satisfies DES-020, REQ-352
77
78
  */
78
79
  export function getConsumerInstallRoot(env: NodeJS.ProcessEnv = process.env): string | undefined {
79
- return env.INIT_CWD || env.npm_config_local_prefix || undefined;
80
+ return env.npm_config_local_prefix || env.INIT_CWD || undefined;
80
81
  }
81
82
 
82
83
  /**
@@ -153,6 +153,32 @@ test("getConsumerInstallRoot falls back to npm_config_local_prefix and then unde
153
153
  }
154
154
  });
155
155
 
156
+ test("getConsumerInstallRoot prefers npm_config_local_prefix over INIT_CWD for --prefix installs", () => {
157
+ // Reproducer for `pi update --extensions` `npm warn allow-scripts`: the pi host runs
158
+ // `npm install <pkg> --prefix <installRoot>` from its own caller cwd, so INIT_CWD is the
159
+ // caller cwd while npm_config_local_prefix is the real install root. Resolving INIT_CWD
160
+ // first writes the allowScripts approval to the wrong project (or nowhere) and the warning
161
+ // persists on every extension update.
162
+ const previousInitCwd = process.env.INIT_CWD;
163
+ const previousPrefix = process.env.npm_config_local_prefix;
164
+ try {
165
+ process.env.INIT_CWD = "/tmp/pi-usereq-caller-cwd";
166
+ process.env.npm_config_local_prefix = "/tmp/pi-usereq-install-root";
167
+ assert.equal(getConsumerInstallRoot(), "/tmp/pi-usereq-install-root");
168
+ } finally {
169
+ if (previousInitCwd === undefined) {
170
+ delete process.env.INIT_CWD;
171
+ } else {
172
+ process.env.INIT_CWD = previousInitCwd;
173
+ }
174
+ if (previousPrefix === undefined) {
175
+ delete process.env.npm_config_local_prefix;
176
+ } else {
177
+ process.env.npm_config_local_prefix = previousPrefix;
178
+ }
179
+ }
180
+ });
181
+
156
182
  test("selectInstallScriptPackageNames returns only packages with lifecycle scripts", () => {
157
183
  const packages: NodeModulesPackage[] = [
158
184
  { name: "has-postinstall", scripts: { postinstall: "node install.js" } },