@bobfrankston/npmglobalize 1.0.155 → 1.0.157
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/lib.d.ts +12 -3
- package/lib.js +70 -7
- package/package.json +1 -1
package/lib.d.ts
CHANGED
|
@@ -244,9 +244,9 @@ export declare function compareVersions(a: number[], b: number[]): number;
|
|
|
244
244
|
/** Fix version/tag mismatches */
|
|
245
245
|
export declare function fixVersionTagMismatch(cwd: string, pkg: any, verbose?: boolean): boolean;
|
|
246
246
|
/** Walk `file:` deps transitively and run `npm install` in any target whose
|
|
247
|
-
* package.json declares deps but has no `node_modules/`.
|
|
248
|
-
*
|
|
249
|
-
* upcoming build/pack
|
|
247
|
+
* package.json declares deps but has no `node_modules/`. Also covers `cwd`
|
|
248
|
+
* itself on the first call, so a fresh clone with no `node_modules/` gets
|
|
249
|
+
* installed before the upcoming build/pack tries to resolve imports.
|
|
250
250
|
* Cycle-safe via the shared `visited` set. */
|
|
251
251
|
export declare function ensureFileDepModules(cwd: string, verbose?: boolean, visited?: Set<string>): void;
|
|
252
252
|
/** Run a command and return success status */
|
|
@@ -260,6 +260,15 @@ export declare function runCommand(cmd: string, args: string[], options?: {
|
|
|
260
260
|
output: string;
|
|
261
261
|
stderr: string;
|
|
262
262
|
};
|
|
263
|
+
/** Install a package globally in WSL, auto-fixing the root-owned /usr/local/lib/node_modules
|
|
264
|
+
* EACCES case by switching npm to a user prefix (~/.npm-global) and retrying once.
|
|
265
|
+
* Output is captured (so we can scan for the error) and then mirrored to the terminal. */
|
|
266
|
+
export declare function installInWsl(wslArgs: string[], opts?: {
|
|
267
|
+
cwd?: string;
|
|
268
|
+
}): {
|
|
269
|
+
success: boolean;
|
|
270
|
+
fixed: boolean;
|
|
271
|
+
};
|
|
263
272
|
/** Run a command and throw on failure */
|
|
264
273
|
export declare function runCommandOrThrow(cmd: string, args: string[], options?: {
|
|
265
274
|
silent?: boolean;
|
package/lib.js
CHANGED
|
@@ -1323,9 +1323,9 @@ function restoreNestedDepModules(stashed, verbose) {
|
|
|
1323
1323
|
}
|
|
1324
1324
|
}
|
|
1325
1325
|
/** Walk `file:` deps transitively and run `npm install` in any target whose
|
|
1326
|
-
* package.json declares deps but has no `node_modules/`.
|
|
1327
|
-
*
|
|
1328
|
-
* upcoming build/pack
|
|
1326
|
+
* package.json declares deps but has no `node_modules/`. Also covers `cwd`
|
|
1327
|
+
* itself on the first call, so a fresh clone with no `node_modules/` gets
|
|
1328
|
+
* installed before the upcoming build/pack tries to resolve imports.
|
|
1329
1329
|
* Cycle-safe via the shared `visited` set. */
|
|
1330
1330
|
export function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
|
|
1331
1331
|
const abs = path.resolve(cwd);
|
|
@@ -1339,6 +1339,26 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1339
1339
|
catch {
|
|
1340
1340
|
return;
|
|
1341
1341
|
}
|
|
1342
|
+
const cwdHasDeps = (pkg?.dependencies && Object.keys(pkg.dependencies).length > 0) ||
|
|
1343
|
+
(pkg?.devDependencies && Object.keys(pkg.devDependencies).length > 0);
|
|
1344
|
+
if (cwdHasDeps && !fs.existsSync(path.join(abs, 'node_modules'))) {
|
|
1345
|
+
const lock = path.join(abs, 'package-lock.json');
|
|
1346
|
+
if (fs.existsSync(lock)) {
|
|
1347
|
+
if (verbose)
|
|
1348
|
+
console.log(colors.dim(` removing stale ${lock}`));
|
|
1349
|
+
try {
|
|
1350
|
+
fs.rmSync(lock, { force: true });
|
|
1351
|
+
}
|
|
1352
|
+
catch { /* best-effort */ }
|
|
1353
|
+
}
|
|
1354
|
+
console.log(colors.yellow(`↻ installing node_modules in ${pkg?.name || abs}`));
|
|
1355
|
+
const r = runCommand('npm', ['install'], { cwd: abs, silent: !verbose });
|
|
1356
|
+
if (!r.success) {
|
|
1357
|
+
console.error(colors.red(` ✗ npm install failed in ${abs}`));
|
|
1358
|
+
if (r.stderr)
|
|
1359
|
+
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1342
1362
|
for (const key of ['dependencies', 'devDependencies']) {
|
|
1343
1363
|
const deps = pkg?.[key];
|
|
1344
1364
|
if (!deps || typeof deps !== 'object')
|
|
@@ -1360,6 +1380,15 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1360
1380
|
(targetPkg?.devDependencies && Object.keys(targetPkg.devDependencies).length > 0);
|
|
1361
1381
|
const nm = path.join(target, 'node_modules');
|
|
1362
1382
|
if (hasDeps && !fs.existsSync(nm)) {
|
|
1383
|
+
const lock = path.join(target, 'package-lock.json');
|
|
1384
|
+
if (fs.existsSync(lock)) {
|
|
1385
|
+
if (verbose)
|
|
1386
|
+
console.log(colors.dim(` removing stale ${lock}`));
|
|
1387
|
+
try {
|
|
1388
|
+
fs.rmSync(lock, { force: true });
|
|
1389
|
+
}
|
|
1390
|
+
catch { /* best-effort */ }
|
|
1391
|
+
}
|
|
1363
1392
|
console.log(colors.yellow(`↻ restoring node_modules in ${name} (${target})`));
|
|
1364
1393
|
const r = runCommand('npm', ['install'], { cwd: target, silent: !verbose });
|
|
1365
1394
|
if (!r.success) {
|
|
@@ -1420,6 +1449,40 @@ export function runCommand(cmd, args, options = {}) {
|
|
|
1420
1449
|
return { success: false, output: '', stderr: error.message };
|
|
1421
1450
|
}
|
|
1422
1451
|
}
|
|
1452
|
+
/** Install a package globally in WSL, auto-fixing the root-owned /usr/local/lib/node_modules
|
|
1453
|
+
* EACCES case by switching npm to a user prefix (~/.npm-global) and retrying once.
|
|
1454
|
+
* Output is captured (so we can scan for the error) and then mirrored to the terminal. */
|
|
1455
|
+
export function installInWsl(wslArgs, opts = {}) {
|
|
1456
|
+
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1457
|
+
let result = runCommand('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1458
|
+
if (result.output)
|
|
1459
|
+
process.stdout.write(result.output);
|
|
1460
|
+
if (result.stderr)
|
|
1461
|
+
process.stderr.write(result.stderr);
|
|
1462
|
+
if (result.success)
|
|
1463
|
+
return { success: true, fixed: false };
|
|
1464
|
+
const combined = (result.output || '') + '\n' + (result.stderr || '');
|
|
1465
|
+
const permIssue = /EACCES/.test(combined) && /\/usr\/(?:local\/)?lib\/node_modules/.test(combined);
|
|
1466
|
+
if (!permIssue)
|
|
1467
|
+
return { success: false, fixed: false };
|
|
1468
|
+
console.log(colors.yellow('Detected root-owned npm prefix in WSL — switching to ~/.npm-global and retrying...'));
|
|
1469
|
+
const fix = `set -e; npm config set prefix "$HOME/.npm-global"; mkdir -p "$HOME/.npm-global/bin"; if ! grep -q '\\.npm-global/bin' "$HOME/.bashrc" 2>/dev/null; then printf '\\n# npm user-prefix bin (added by npmglobalize)\\nexport PATH="$HOME/.npm-global/bin:$PATH"\\n' >> "$HOME/.bashrc"; fi`;
|
|
1470
|
+
const fixResult = runCommand('wsl', ['bash', '-lc', fix], { silent: true });
|
|
1471
|
+
if (!fixResult.success) {
|
|
1472
|
+
console.error(colors.red('Failed to apply WSL npm prefix fix:'));
|
|
1473
|
+
if (fixResult.stderr)
|
|
1474
|
+
process.stderr.write(fixResult.stderr);
|
|
1475
|
+
return { success: false, fixed: false };
|
|
1476
|
+
}
|
|
1477
|
+
console.log(colors.green('✓ WSL npm prefix set to ~/.npm-global; PATH appended to ~/.bashrc'));
|
|
1478
|
+
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1479
|
+
result = runCommand('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1480
|
+
if (result.output)
|
|
1481
|
+
process.stdout.write(result.output);
|
|
1482
|
+
if (result.stderr)
|
|
1483
|
+
process.stderr.write(result.stderr);
|
|
1484
|
+
return { success: result.success, fixed: result.success };
|
|
1485
|
+
}
|
|
1423
1486
|
/** Diagnose common build/version failure patterns and print actionable hints.
|
|
1424
1487
|
* Returns true if a diagnosis was printed. */
|
|
1425
1488
|
function diagnoseBuildFailure(errorText, cwd) {
|
|
@@ -4672,10 +4735,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4672
4735
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
4673
4736
|
console.log(`Installing in WSL${useLocalWsl ? ' (local)' : ' from registry'}: ${pkgName}@${pkgVersion}...`);
|
|
4674
4737
|
if (!dryRun) {
|
|
4675
|
-
const wslResult =
|
|
4738
|
+
const wslResult = installInWsl(wslArgs, { cwd });
|
|
4676
4739
|
if (wslResult.success) {
|
|
4677
4740
|
wslInstallOk = true;
|
|
4678
|
-
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
4741
|
+
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
4679
4742
|
}
|
|
4680
4743
|
else {
|
|
4681
4744
|
console.error(colors.yellow('✗ WSL install failed (is npm installed in WSL?)'));
|
|
@@ -5076,9 +5139,9 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5076
5139
|
if (wsl) {
|
|
5077
5140
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
5078
5141
|
if (!dryRun) {
|
|
5079
|
-
const wslResult =
|
|
5142
|
+
const wslResult = installInWsl(['npm', 'install', '-g', '.'], { cwd: rootDir });
|
|
5080
5143
|
if (wslResult.success) {
|
|
5081
|
-
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
5144
|
+
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
5082
5145
|
}
|
|
5083
5146
|
else {
|
|
5084
5147
|
console.error(colors.yellow('✗ WSL install failed (is npm installed in WSL?)'));
|