Skip to content

Commit b3d6588

Browse files
committed
fix: remove npm global prefix workaround
1 parent bd6164d commit b3d6588

7 files changed

Lines changed: 79 additions & 488 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@link-assistant/hive-mind": patch
3+
---
4+
5+
Remove Hive Mind's npm global prefix workaround now that use-m handles non-writable npm global roots upstream.

.gitkeep

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
# .gitkeep file auto-generated at 2026-06-11T13:26:22.528Z for PR creation at branch issue-1903-1bd05d5aade7 for issue https://github.com/link-assistant/hive-mind/issues/1903
2-
# Updated: 2026-06-12T21:23:19.753Z
1+
# .gitkeep file auto-generated at 2026-06-11T13:26:22.528Z for PR creation at branch issue-1903-1bd05d5aade7 for issue https://github.com/link-assistant/hive-mind/issues/1903

docs/case-studies/issue-1897/README.md

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- Issue: [link-assistant/hive-mind#1897](https://github.com/link-assistant/hive-mind/issues/1897)
44
- Pull request: [link-assistant/hive-mind#1898](https://github.com/link-assistant/hive-mind/pull/1898)
5+
- Cleanup pull request: [link-assistant/hive-mind#1911](https://github.com/link-assistant/hive-mind/pull/1911)
56
- Upstream package: [link-foundation/use-m](https://github.com/link-foundation/use-m)
67
- Upstream issue: https://github.com/link-foundation/use-m/issues/54
78
- Follow-up cleanup issue: https://github.com/link-assistant/hive-mind/issues/1910
@@ -24,11 +25,12 @@ the process ran under a system Node whose npm global root was
2425
`/opt/node-v24.16.0-linux-x64/lib/node_modules`. The first `use()` call therefore
2526
crashed with `Error: Failed to install command-stream@latest globally.`
2627

27-
PR #1898 keeps users unblocked by routing all real Hive Mind `use-m` bootstraps
28-
through `src/use-m-bootstrap.lib.mjs`, which runs the temporary npm-prefix
29-
workaround before `use-m` can run its npm resolver. The upstream issue tracks the
30-
proper fix in `link-foundation/use-m`, and the Hive Mind follow-up issue tracks
31-
removing this workaround once upstream handles non-writable global roots.
28+
PR #1898 kept users unblocked by routing all real Hive Mind `use-m` bootstraps
29+
through `src/use-m-bootstrap.lib.mjs`, which ran a temporary npm-prefix
30+
workaround before `use-m` could run its npm resolver. After upstream
31+
`use-m@8.13.8` added its own non-writable npm global-root fallback, PR #1911
32+
removed the downstream preflight so Hive Mind no longer duplicates resolver
33+
policy.
3234

3335
## Requirements inventory
3436

@@ -43,7 +45,7 @@ From the PR discussion:
4345
1. Treat `link-foundation/use-m` as the likely long-term owner.
4446
2. Report the issue upstream with evidence, a workaround, and a proposed
4547
use-m-side solution.
46-
3. Keep the downstream workaround for now.
48+
3. Keep the downstream workaround until upstream `use-m` owns the behavior.
4749
4. Create a Hive Mind follow-up issue to remove the workaround after upstream is
4850
resolved.
4951
5. Double-check that the workaround does not break previously working startup
@@ -75,17 +77,17 @@ controls global folder placement.
7577

7678
## Solution options
7779

78-
| Option | Owner | Plan | Pros | Cons | Decision |
79-
| -------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------ |
80-
| Downstream preflight in Hive Mind | Hive Mind | Detect non-writable npm global root before `use-m`, set `npm_config_prefix=~/.npm-global`, prepend `~/.npm-global/bin`. | Fixes users immediately; can be tested locally with injected fs/npm mocks. | Duplicates policy that belongs in use-m. | Implemented as temporary workaround. |
81-
| Writable cache/prefix in use-m | use-m | Before `npm install -g`, test `npm root -g`; if unwritable, use a use-m-owned user prefix/cache for alias installs. | Fixes all downstream packages and keeps resolver logic in one place. | Requires upstream release and migration decision. | Recommended upstream solution. |
82-
| Clear upstream error only | use-m | Detect unwritable global root and throw an actionable error before raw npm EACCES. | Smallest upstream change. | Users still need manual remediation; downstream CLIs still fail. | Acceptable fallback, not preferred. |
83-
| Replace use-m global npm installs with project-local dynamic imports | use-m or Hive Mind | Avoid `npm install -g`; install/cache packages under an app/user cache and import from there. | Avoids global npm prefix entirely. | Larger resolver redesign; more cache invalidation and security review. | Long-term alternative. |
84-
| Vendor all dynamic dependencies | Hive Mind | Replace `use-m` bootstraps with package dependencies/imports. | Removes this class of startup failure for Hive Mind. | Large architectural change; loses current cross-runtime dynamic-loading pattern. | Out of scope for this bug. |
80+
| Option | Owner | Plan | Pros | Cons | Decision |
81+
| -------------------------------------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------- |
82+
| Downstream preflight in Hive Mind | Hive Mind | Detect non-writable npm global root before `use-m`, set `npm_config_prefix=~/.npm-global`, prepend `~/.npm-global/bin`. | Fixes users immediately; can be tested locally with injected fs/npm mocks. | Duplicates policy that belongs in use-m. | Implemented temporarily, removed by PR #1911. |
83+
| Writable cache/prefix in use-m | use-m | Before `npm install -g`, test `npm root -g`; if unwritable, use a use-m-owned user prefix/cache for alias installs. | Fixes all downstream packages and keeps resolver logic in one place. | Requires upstream release and migration decision. | Recommended upstream solution. |
84+
| Clear upstream error only | use-m | Detect unwritable global root and throw an actionable error before raw npm EACCES. | Smallest upstream change. | Users still need manual remediation; downstream CLIs still fail. | Acceptable fallback, not preferred. |
85+
| Replace use-m global npm installs with project-local dynamic imports | use-m or Hive Mind | Avoid `npm install -g`; install/cache packages under an app/user cache and import from there. | Avoids global npm prefix entirely. | Larger resolver redesign; more cache invalidation and security review. | Long-term alternative. |
86+
| Vendor all dynamic dependencies | Hive Mind | Replace `use-m` bootstraps with package dependencies/imports. | Removes this class of startup failure for Hive Mind. | Large architectural change; loses current cross-runtime dynamic-loading pattern. | Out of scope for this bug. |
8587

86-
## Implemented coverage
88+
## Temporary downstream coverage
8789

88-
The workaround is now centralized:
90+
PR #1898 centralized the workaround while upstream support was pending:
8991

9092
- `src/npm-global-prefix.lib.mjs` detects writable/non-writable global npm roots
9193
and redirects only when needed.
@@ -103,6 +105,18 @@ The source-level regression test prevents reintroducing direct
103105
`eval(await fetch('https://unpkg.com/use-m/use.js'))` bootstraps outside the
104106
shared helper.
105107

108+
## Cleanup coverage
109+
110+
PR #1911 removed Hive Mind's local npm-prefix preflight after verifying
111+
`use-m@8.13.8` includes equivalent upstream handling:
112+
113+
- `src/npm-global-prefix.lib.mjs` was deleted.
114+
- `src/use-m-bootstrap.lib.mjs` now only loads the shared upstream `use-m`
115+
bootstrap.
116+
- `tests/test-npm-global-prefix.mjs` was replaced with
117+
`tests/test-use-m-bootstrap-no-npm-prefix-workaround.mjs`, which guards
118+
against reintroducing project-local npm prefix policy.
119+
106120
## Existing components and libraries considered
107121

108122
- npm global prefix configuration: relevant and used. It is the documented
@@ -130,6 +144,14 @@ Still required after push:
130144

131145
- fresh PR CI after push
132146

147+
Implemented and run locally for PR #1911:
148+
149+
- `node tests/test-use-m-bootstrap-no-npm-prefix-workaround.mjs`
150+
- `npm run lint`
151+
- `npm run format:check`
152+
- `npm test`
153+
- `git diff --check`
154+
133155
## Source data
134156

135157
- Original attachment: https://github.com/user-attachments/files/28828561/d8b3067e-6d6c-4907-b4a6-78f42b41ea3b.log

src/npm-global-prefix.lib.mjs

Lines changed: 0 additions & 160 deletions
This file was deleted.

src/use-m-bootstrap.lib.mjs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
#!/usr/bin/env node
22

3-
import { ensureWritableNpmGlobalPrefix } from './npm-global-prefix.lib.mjs';
4-
53
const defaultFetchUseMCode = async () => (await fetch('https://unpkg.com/use-m/use.js')).text();
64

75
/**
8-
* Load the use-m bootstrap after npm's global prefix has been made safe for
9-
* use-m's Node resolver.
6+
* Load the shared use-m bootstrap.
107
*
118
* @param {object} [options]
12-
* @param {(message: string) => void} [options.log]
139
* @param {() => Promise<string>} [options.fetchUseMCode]
1410
* @returns {Promise<Function>} The global use-m `use` function.
1511
*/
1612
export const ensureUseM = async (options = {}) => {
17-
const { log = message => console.log(message), fetchUseMCode = defaultFetchUseMCode } = options;
18-
await ensureWritableNpmGlobalPrefix({ log });
13+
const { fetchUseMCode = defaultFetchUseMCode } = options;
1914
if (typeof globalThis.use === 'undefined') {
2015
globalThis.use = (await eval(await fetchUseMCode())).use;
2116
}

0 commit comments

Comments
 (0)