@bobfrankston/npmglobalize 1.0.79 → 1.0.81

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 (4) hide show
  1. package/cli.js +79 -78
  2. package/lib.d.ts +5 -1
  3. package/lib.js +90 -29
  4. package/package.json +1 -1
package/cli.js CHANGED
@@ -2,44 +2,13 @@
2
2
  /**
3
3
  * npmglobalize CLI - Transform file: dependencies to npm versions for publishing
4
4
  */
5
- import { globalize, globalizeWorkspace, readConfig, readPackageJson, writePackageJson } from './lib.js';
5
+ import { globalize, globalizeWorkspace, readConfig, readPackageJson, writeConfig, writePackageJson } from './lib.js';
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
- import { fileURLToPath } from 'url';
9
8
  import { styleText } from 'util';
10
9
  import JSON5 from 'json5';
11
- // Check if JS files are up-to-date with TS files
12
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
- // Check all .ts files in the directory
14
- const tsFiles = ['lib.ts', 'cli.ts', 'index.ts'];
15
- const outOfSync = [];
16
- for (const tsFile of tsFiles) {
17
- const tsPath = path.join(__dirname, tsFile);
18
- const jsPath = path.join(__dirname, tsFile.replace('.ts', '.js'));
19
- if (fs.existsSync(tsPath) && fs.existsSync(jsPath)) {
20
- const tsStat = fs.statSync(tsPath);
21
- const jsStat = fs.statSync(jsPath);
22
- if (jsStat.mtime < tsStat.mtime) {
23
- outOfSync.push(tsFile);
24
- }
25
- }
26
- }
27
- if (outOfSync.length > 0 && !process.argv.includes('--force')) {
28
- console.error('\n' + styleText('red', '❌ Build check failed:'));
29
- console.error(styleText('red', ` ${outOfSync.length} file(s) need compilation in ${__dirname}:`));
30
- outOfSync.forEach(f => {
31
- const tsPath = path.join(__dirname, f);
32
- const jsPath = path.join(__dirname, f.replace('.ts', '.js'));
33
- const tsMtime = fs.statSync(tsPath).mtime;
34
- const jsMtime = fs.statSync(jsPath).mtime;
35
- const fmt = (d) => d.toLocaleString();
36
- console.error(styleText('red', ` - ${tsPath}`));
37
- console.error(styleText('red', ` .ts: ${fmt(tsMtime)} .js: ${fmt(jsMtime)}`));
38
- });
39
- console.error('\n' + styleText('yellow', ' Please run: tsc'));
40
- console.error(styleText('yellow', ' Or use --force to skip this check') + '\n');
41
- process.exit(1);
42
- }
10
+ // npmglobalize install directory (for --version)
11
+ const __dirname = import.meta.dirname;
43
12
  function printHelp() {
44
13
  console.log(`
45
14
  npmglobalize - Transform file: dependencies to npm versions for publishing
@@ -65,8 +34,10 @@ Dependency Options:
65
34
  --fix Run npm audit fix after transformation
66
35
 
67
36
  Install Options:
68
- --install, -i Global install after publish (Windows)
37
+ --install, -i Global install after publish (from registry)
38
+ --link Global install via symlink (npm install -g .)
69
39
  --wsl Also install globally in WSL
40
+ --once Don't persist flags to .globalize.json5
70
41
 
71
42
  Mode Options:
72
43
  --files Keep file: paths after publish (default)
@@ -108,7 +79,8 @@ Examples:
108
79
  npmglobalize -npd Skip auto-publishing file: deps (use with caution)
109
80
  npmglobalize --force-publish Force republish all file: dependencies
110
81
  npmglobalize --fix Fix security vulnerabilities
111
- npmglobalize --install --wsl Release + install on Windows and WSL
82
+ npmglobalize --install --wsl Release + install on Windows and WSL (from registry)
83
+ npmglobalize --link --wsl Release + link on Windows and WSL (symlink)
112
84
  npmglobalize -np Just transform, no publish
113
85
  npmglobalize --cleanup Restore original dependencies
114
86
  npmglobalize --init Initialize new git repo + release
@@ -126,7 +98,8 @@ function parseArgs(args) {
126
98
  const options = {
127
99
  help: false,
128
100
  version: false,
129
- error: ''
101
+ error: '',
102
+ explicitKeys: new Set()
130
103
  };
131
104
  const unrecognized = [];
132
105
  const positional = [];
@@ -161,25 +134,35 @@ function parseArgs(args) {
161
134
  case '--install':
162
135
  case '-i':
163
136
  options.install = true;
137
+ options.explicitKeys.add('install');
164
138
  break;
165
139
  case '--noinstall':
166
140
  case '-ni':
167
141
  options.install = false;
142
+ options.explicitKeys.add('install');
143
+ break;
144
+ case '--link':
145
+ options.link = true;
146
+ options.explicitKeys.add('link');
168
147
  break;
169
148
  case '--wsl':
170
149
  options.wsl = true;
150
+ options.explicitKeys.add('wsl');
171
151
  break;
172
152
  case '--nowsl':
173
153
  options.wsl = false;
154
+ options.explicitKeys.add('wsl');
174
155
  break;
175
156
  case '--force':
176
157
  options.force = true;
177
158
  break;
178
159
  case '--files':
179
160
  options.files = true;
161
+ options.explicitKeys.add('files');
180
162
  break;
181
163
  case '--nofiles':
182
164
  options.files = false;
165
+ options.explicitKeys.add('files');
183
166
  break;
184
167
  case '--dry-run':
185
168
  options.dryRun = true;
@@ -198,6 +181,7 @@ function parseArgs(args) {
198
181
  i++;
199
182
  if (args[i] === 'private' || args[i] === 'public') {
200
183
  options.gitVisibility = args[i];
184
+ options.explicitKeys.add('gitVisibility');
201
185
  }
202
186
  else {
203
187
  options.error = `--git requires 'private' or 'public', got: ${args[i]}`;
@@ -207,6 +191,7 @@ function parseArgs(args) {
207
191
  i++;
208
192
  if (args[i] === 'private' || args[i] === 'public') {
209
193
  options.npmVisibility = args[i];
194
+ options.explicitKeys.add('npmVisibility');
210
195
  }
211
196
  else {
212
197
  options.error = `--npm requires 'private' or 'public', got: ${args[i]}`;
@@ -257,9 +242,11 @@ function parseArgs(args) {
257
242
  break;
258
243
  case '--fix':
259
244
  options.fix = true;
245
+ options.explicitKeys.add('fix');
260
246
  break;
261
247
  case '--no-fix':
262
248
  options.fix = false;
249
+ options.explicitKeys.add('fix');
263
250
  break;
264
251
  case '--workspace':
265
252
  case '-w':
@@ -283,6 +270,9 @@ function parseArgs(args) {
283
270
  case '-pkg':
284
271
  options.package = true;
285
272
  break;
273
+ case '--once':
274
+ options.once = true;
275
+ break;
286
276
  default:
287
277
  if (arg.startsWith('-')) {
288
278
  unrecognized.push(arg);
@@ -312,52 +302,11 @@ export async function main() {
312
302
  process.exit(0);
313
303
  }
314
304
  if (cliOptions.version) {
315
- const __filename = fileURLToPath(import.meta.url);
316
- const __dirname = path.dirname(__filename);
317
305
  const pkgPath = path.join(__dirname, 'package.json');
318
306
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
319
307
  console.log(pkg.version);
320
308
  process.exit(0);
321
309
  }
322
- // Check if TypeScript files are compiled (unless --force or --help/--version)
323
- if (!cliOptions.force && !cliOptions.help && !cliOptions.version) {
324
- const __filename = fileURLToPath(import.meta.url);
325
- const __dirname = path.dirname(__filename);
326
- // Check for noEmit in tsconfig.json
327
- let noEmit = false;
328
- try {
329
- const tsconfigPath = path.join(__dirname, 'tsconfig.json');
330
- const content = fs.readFileSync(tsconfigPath, 'utf-8');
331
- const tsconfig = JSON5.parse(content);
332
- noEmit = tsconfig.compilerOptions?.noEmit === true;
333
- }
334
- catch (error) {
335
- // If we can't read tsconfig, assume we need to check
336
- }
337
- if (!noEmit) {
338
- // Check if this .js file is older than its .ts source
339
- const jsFile = __filename;
340
- const tsFile = jsFile.replace(/\.js$/, '.ts');
341
- if (fs.existsSync(tsFile)) {
342
- if (!fs.existsSync(jsFile)) {
343
- console.error('\n❌ Error: TypeScript files not compiled');
344
- console.error(`Missing: ${path.basename(jsFile)}`);
345
- console.error('\nPlease run: npm run build');
346
- console.error('Or use --force to skip this check\n');
347
- process.exit(1);
348
- }
349
- const tsStat = fs.statSync(tsFile);
350
- const jsStat = fs.statSync(jsFile);
351
- if (jsStat.mtime < tsStat.mtime) {
352
- console.error('\n❌ Error: TypeScript files not compiled');
353
- console.error(`${path.basename(jsFile)} is older than ${path.basename(tsFile)}`);
354
- console.error('\nPlease run: npm run build');
355
- console.error('Or use --force to skip this check\n');
356
- process.exit(1);
357
- }
358
- }
359
- }
360
- }
361
310
  if (cliOptions.error) {
362
311
  console.error(`Error: ${cliOptions.error}`);
363
312
  console.error('Run with --help for usage.');
@@ -376,6 +325,50 @@ export async function main() {
376
325
  process.exit(1);
377
326
  }
378
327
  }
328
+ // Check if TypeScript files in target project are compiled
329
+ if (!cliOptions.force) {
330
+ let noEmit = false;
331
+ try {
332
+ const tsconfigPath = path.join(cwd, 'tsconfig.json');
333
+ const content = fs.readFileSync(tsconfigPath, 'utf-8');
334
+ const tsconfig = JSON5.parse(content);
335
+ noEmit = tsconfig.compilerOptions?.noEmit === true;
336
+ }
337
+ catch (error) {
338
+ // No tsconfig or can't parse — skip check
339
+ noEmit = true;
340
+ }
341
+ if (!noEmit) {
342
+ const outOfSync = [];
343
+ const jsFiles = fs.readdirSync(cwd).filter(f => f.endsWith('.js') && !f.endsWith('.min.js'));
344
+ for (const jsFile of jsFiles) {
345
+ const tsFile = jsFile.replace(/\.js$/, '.ts');
346
+ const tsPath = path.join(cwd, tsFile);
347
+ const jsPath = path.join(cwd, jsFile);
348
+ if (fs.existsSync(tsPath)) {
349
+ const tsStat = fs.statSync(tsPath);
350
+ const jsStat = fs.statSync(jsPath);
351
+ if (jsStat.mtime < tsStat.mtime) {
352
+ outOfSync.push(tsFile);
353
+ }
354
+ }
355
+ }
356
+ if (outOfSync.length > 0) {
357
+ console.error('\n' + styleText('red', '❌ Build check failed:'));
358
+ console.error(styleText('red', ` ${outOfSync.length} file(s) need compilation in ${cwd}:`));
359
+ outOfSync.forEach(f => {
360
+ const tsPath = path.join(cwd, f);
361
+ const jsPath = path.join(cwd, f.replace('.ts', '.js'));
362
+ const fmt = (d) => d.toLocaleString();
363
+ console.error(styleText('red', ` - ${f}`));
364
+ console.error(styleText('red', ` .ts: ${fmt(fs.statSync(tsPath).mtime)} .js: ${fmt(fs.statSync(jsPath).mtime)}`));
365
+ });
366
+ console.error('\n' + styleText('yellow', ' Please run: tsc'));
367
+ console.error(styleText('yellow', ' Or use --force to skip this check') + '\n');
368
+ process.exit(1);
369
+ }
370
+ }
371
+ }
379
372
  // Handle --package: update scripts in target package.json
380
373
  if (cliOptions.package) {
381
374
  const pkg = readPackageJson(cwd);
@@ -401,6 +394,14 @@ export async function main() {
401
394
  // Load config file and merge with CLI options (CLI takes precedence)
402
395
  const configOptions = readConfig(cwd);
403
396
  const options = { ...configOptions, ...cliOptions };
397
+ // Persist explicitly set CLI flags to .globalize.json5
398
+ if (cliOptions.explicitKeys.size > 0 && !cliOptions.once) {
399
+ const persistable = { ...configOptions };
400
+ for (const key of cliOptions.explicitKeys) {
401
+ persistable[key] = options[key];
402
+ }
403
+ writeConfig(cwd, persistable, cliOptions.explicitKeys);
404
+ }
404
405
  try {
405
406
  // Auto-detect workspace root: private package with workspaces[] field
406
407
  if (!options.noWorkspace) {
package/lib.d.ts CHANGED
@@ -17,8 +17,10 @@ export interface GlobalizeOptions {
17
17
  noPublish?: boolean;
18
18
  /** Restore from .dependencies */
19
19
  cleanup?: boolean;
20
- /** Global install after publish */
20
+ /** Global install after publish (from registry) */
21
21
  install?: boolean;
22
+ /** Global install via symlink (npm install -g .) */
23
+ link?: boolean;
22
24
  /** Also install in WSL */
23
25
  wsl?: boolean;
24
26
  /** Continue despite git errors */
@@ -67,6 +69,8 @@ export interface GlobalizeOptions {
67
69
  continueOnError?: boolean;
68
70
  /** Update package.json scripts to use npmglobalize */
69
71
  package?: boolean;
72
+ /** Don't persist CLI flags to .globalize.json5 */
73
+ once?: boolean;
70
74
  /** Internal: signals this call is from workspace orchestrator */
71
75
  _fromWorkspace?: boolean;
72
76
  }
package/lib.js CHANGED
@@ -110,7 +110,7 @@ export function writeConfig(dir, config, explicitKeys) {
110
110
  const existing = readConfig(dir);
111
111
  // Filter out temporary flags and default values (unless explicitly set)
112
112
  const filtered = {};
113
- const omitKeys = new Set(['noPublish', 'cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish']);
113
+ const omitKeys = new Set(['noPublish', 'cleanup', 'init', 'dryRun', 'message', 'conform', 'asis', 'help', 'error', 'updateDeps', 'updateMajor', 'publishDeps', 'forcePublish', 'once']);
114
114
  for (const [key, value] of Object.entries(config)) {
115
115
  if (omitKeys.has(key))
116
116
  continue;
@@ -138,7 +138,9 @@ export function writeConfig(dir, config, explicitKeys) {
138
138
  // Add inline comment for clarity
139
139
  let comment = '';
140
140
  if (key === 'install')
141
- comment = ' // Auto-install globally after publish';
141
+ comment = ' // Auto-install globally after publish (from registry)';
142
+ else if (key === 'link')
143
+ comment = ' // Install globally via symlink (npm install -g .)';
142
144
  else if (key === 'wsl')
143
145
  comment = ' // Also install in WSL';
144
146
  else if (key === 'files')
@@ -164,7 +166,8 @@ export function writeConfig(dir, config, explicitKeys) {
164
166
  // Add commented reference for all options
165
167
  lines.push(' // Defaults (omitted above):');
166
168
  lines.push(' // "bump": "patch" // Version bump: patch, minor, major');
167
- lines.push(' // "install": false // Auto-install globally after publish');
169
+ lines.push(' // "install": false // Auto-install globally after publish (from registry)');
170
+ lines.push(' // "link": false // Install globally via symlink (npm install -g .)');
168
171
  lines.push(' // "wsl": false // Also install in WSL');
169
172
  lines.push(' // "files": true // Keep file: paths after publish');
170
173
  lines.push(' // "force": false // Continue despite git errors');
@@ -716,6 +719,27 @@ export function fixVersionTagMismatch(cwd, pkg, verbose = false) {
716
719
  }
717
720
  return deletedAny;
718
721
  }
722
+ /** Wait for a package version to appear on the npm registry */
723
+ function waitForNpmVersion(pkgName, version, maxWaitMs = 60000) {
724
+ const interval = 3000;
725
+ const maxAttempts = Math.ceil(maxWaitMs / interval);
726
+ process.stdout.write(`Waiting for ${pkgName}@${version} on npm registry`);
727
+ for (let i = 0; i < maxAttempts; i++) {
728
+ const result = spawnSync('npm', ['view', `${pkgName}@${version}`, 'version'], {
729
+ shell: process.platform === 'win32',
730
+ stdio: ['pipe', 'pipe', 'pipe'],
731
+ encoding: 'utf-8'
732
+ });
733
+ if (result.status === 0 && result.stdout?.trim() === version) {
734
+ process.stdout.write(' ready\n');
735
+ return true;
736
+ }
737
+ process.stdout.write('.');
738
+ spawnSync(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['/t', '3', '/nobreak'] : ['3'], { stdio: 'pipe', shell: process.platform === 'win32' });
739
+ }
740
+ process.stdout.write(' timed out\n');
741
+ return false;
742
+ }
719
743
  /** Run a command and return success status */
720
744
  export function runCommand(cmd, args, options = {}) {
721
745
  const { silent = false, cwd } = options;
@@ -1393,7 +1417,7 @@ export function getToolVersion() {
1393
1417
  }
1394
1418
  }
1395
1419
  export async function globalize(cwd, options = {}, configOptions = {}) {
1396
- const { bump = 'patch', noPublish = false, cleanup = false, install = false, wsl = false, force = false, files = true, dryRun = false, quiet = true, verbose = false, init = false, gitVisibility = 'private', npmVisibility = 'private', message, conform = false, asis = false, updateDeps = false, updateMajor = false, publishDeps = true, // Default to publishing deps for safety
1420
+ const { bump = 'patch', noPublish = false, cleanup = false, install = false, link = false, wsl = false, force = false, files = true, dryRun = false, quiet = true, verbose = false, init = false, gitVisibility = 'private', npmVisibility = 'private', message, conform = false, asis = false, updateDeps = false, updateMajor = false, publishDeps = true, // Default to publishing deps for safety
1397
1421
  forcePublish = false, fix = false, fixTags = false, rebase = false, show = false } = options;
1398
1422
  // Show tool version (skip when called from workspace orchestrator)
1399
1423
  const toolVersion = getToolVersion();
@@ -1405,6 +1429,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
1405
1429
  const settings = [];
1406
1430
  if (configOptions.install)
1407
1431
  settings.push('--install');
1432
+ if (configOptions.link)
1433
+ settings.push('--link');
1408
1434
  if (configOptions.npmVisibility)
1409
1435
  settings.push(`--npm-visibility ${configOptions.npmVisibility}`);
1410
1436
  if (configOptions.gitVisibility)
@@ -2023,40 +2049,54 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2023
2049
  if (!currentGitStatus.hasUncommitted && !message && !justInitialized && !isFirstPublish) {
2024
2050
  console.log('');
2025
2051
  console.log('No changes to commit and no custom message specified.');
2026
- // If install flag is set, install from local directory
2027
- if (install || wsl) {
2052
+ // If install/link flag is set, install globally
2053
+ if (install || link || wsl) {
2028
2054
  if (verbose) {
2029
2055
  console.log('');
2030
- console.log('Installing from local directory...');
2056
+ console.log(link ? 'Installing from local directory (link)...' : 'Installing from registry...');
2031
2057
  }
2032
2058
  const pkgName = pkg.name;
2033
- if (!pkg.bin && (install || wsl)) {
2059
+ const pkgVersion = pkg.version;
2060
+ if (!pkg.bin && (install || link || wsl)) {
2034
2061
  console.log(colors.yellow('Note: This is a library (no bin field), skipping global installation.'));
2035
2062
  console.log(colors.yellow('To use in projects: npm install ' + pkgName));
2036
2063
  }
2037
2064
  else {
2038
- if (install) {
2039
- console.log(`Installing ${pkgName} globally from local directory...`);
2065
+ if (link) {
2066
+ console.log(`Installing ${pkgName} globally from local directory (link)...`);
2040
2067
  const localInstallResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
2041
2068
  if (localInstallResult.success) {
2042
- const version = pkg.version;
2043
- console.log(colors.green(`✓ Installed globally: ${pkgName}@${version}`));
2069
+ console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
2044
2070
  }
2045
2071
  else {
2046
- console.error(colors.red(`✗ Global install failed`));
2072
+ console.error(colors.red(`✗ Global link install failed`));
2047
2073
  console.error(colors.yellow(' Try running manually: npm install -g .'));
2048
2074
  }
2049
2075
  }
2076
+ else if (install) {
2077
+ waitForNpmVersion(pkgName, pkgVersion);
2078
+ console.log(`Installing ${pkgName}@${pkgVersion} globally from registry...`);
2079
+ const registryInstallResult = runCommand('npm', ['install', '-g', `${pkgName}@${pkgVersion}`], { cwd, silent: false });
2080
+ if (registryInstallResult.success) {
2081
+ console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
2082
+ }
2083
+ else {
2084
+ console.error(colors.red(`✗ Global install failed`));
2085
+ console.error(colors.yellow(` Try running manually: npm install -g ${pkgName}@${pkgVersion}`));
2086
+ }
2087
+ }
2050
2088
  if (wsl) {
2051
- console.log(`Installing ${pkgName} in WSL from local directory...`);
2052
- const wslInstallResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false });
2089
+ const wslArgs = link ? ['npm', 'install', '-g', '.'] : ['npm', 'install', '-g', `${pkgName}@${pkgVersion}`];
2090
+ if (!link && !install)
2091
+ waitForNpmVersion(pkgName, pkgVersion);
2092
+ console.log(`Installing ${pkgName} in WSL${link ? ' (link)' : ' from registry'}...`);
2093
+ const wslInstallResult = runCommand('wsl', wslArgs, { cwd, silent: false });
2053
2094
  if (wslInstallResult.success) {
2054
- const version = pkg.version;
2055
- console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${version}`));
2095
+ console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
2056
2096
  }
2057
2097
  else {
2058
2098
  console.error(colors.red(`✗ WSL install failed`));
2059
- console.error(colors.yellow(' Try running manually in WSL: npm install -g .'));
2099
+ console.error(colors.yellow(' Try running manually in WSL: npm install -g ' + (link ? '.' : pkgName)));
2060
2100
  }
2061
2101
  }
2062
2102
  }
@@ -2470,21 +2510,20 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2470
2510
  const updatedPkg = readPackageJson(cwd); // Re-read to get updated version
2471
2511
  const pkgName = updatedPkg.name;
2472
2512
  const pkgVersion = updatedPkg.version;
2473
- if (!updatedPkg.bin && (install || wsl)) {
2513
+ if (!updatedPkg.bin && (install || link || wsl)) {
2474
2514
  console.log(colors.yellow('Note: This is a library (no bin field), skipping global installation.'));
2475
2515
  console.log(colors.yellow('To use in projects: npm install ' + pkgName));
2476
2516
  }
2477
2517
  else {
2478
- if (install) {
2479
- console.log(`Installing globally: ${pkgName}@${pkgVersion}...`);
2518
+ if (link) {
2519
+ console.log(`Linking globally: ${pkgName}@${pkgVersion}...`);
2480
2520
  if (!dryRun) {
2481
- // Install from local directory (faster and works immediately after publish)
2482
2521
  const installResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
2483
2522
  if (installResult.success) {
2484
- console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
2523
+ console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
2485
2524
  }
2486
2525
  else {
2487
- console.error(colors.red(`✗ Global install failed`));
2526
+ console.error(colors.red(`✗ Global link install failed`));
2488
2527
  console.error(colors.yellow(' Try running manually: npm install -g .'));
2489
2528
  }
2490
2529
  }
@@ -2492,11 +2531,30 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2492
2531
  console.log(` [dry-run] Would run: npm install -g .`);
2493
2532
  }
2494
2533
  }
2534
+ else if (install) {
2535
+ console.log(`Installing globally from registry: ${pkgName}@${pkgVersion}...`);
2536
+ if (!dryRun) {
2537
+ waitForNpmVersion(pkgName, pkgVersion);
2538
+ const installResult = runCommand('npm', ['install', '-g', `${pkgName}@${pkgVersion}`], { cwd, silent: false });
2539
+ if (installResult.success) {
2540
+ console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
2541
+ }
2542
+ else {
2543
+ console.error(colors.red(`✗ Global install failed`));
2544
+ console.error(colors.yellow(` Try running manually: npm install -g ${pkgName}@${pkgVersion}`));
2545
+ }
2546
+ }
2547
+ else {
2548
+ console.log(` [dry-run] Would run: npm install -g ${pkgName}@${pkgVersion}`);
2549
+ }
2550
+ }
2495
2551
  if (wsl) {
2496
- console.log(`Installing in WSL: ${pkgName}@${pkgVersion}...`);
2552
+ const wslArgs = link ? ['npm', 'install', '-g', '.'] : ['npm', 'install', '-g', `${pkgName}@${pkgVersion}`];
2553
+ if (!link && !install)
2554
+ waitForNpmVersion(pkgName, pkgVersion);
2555
+ console.log(`Installing in WSL${link ? ' (link)' : ' from registry'}: ${pkgName}@${pkgVersion}...`);
2497
2556
  if (!dryRun) {
2498
- // Install from local directory in WSL
2499
- const wslResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false });
2557
+ const wslResult = runCommand('wsl', wslArgs, { cwd, silent: false });
2500
2558
  if (wslResult.success) {
2501
2559
  console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
2502
2560
  }
@@ -2505,7 +2563,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2505
2563
  }
2506
2564
  }
2507
2565
  else {
2508
- console.log(` [dry-run] Would run: wsl npm install -g ${pkgName}`);
2566
+ console.log(` [dry-run] Would run: wsl npm install -g ${link ? '.' : pkgName}`);
2509
2567
  }
2510
2568
  }
2511
2569
  }
@@ -2545,7 +2603,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2545
2603
  console.log(` Version: ${colors.green('v' + finalPkg.version)}`);
2546
2604
  console.log(` Published: ${colors.green('✓')} (${accessLabel})`);
2547
2605
  console.log(` Git pushed: ${colors.green('✓')}`);
2548
- if (install) {
2606
+ if (link) {
2607
+ console.log(` Linked globally: ${colors.green('✓')}`);
2608
+ }
2609
+ else if (install) {
2549
2610
  console.log(` Installed globally: ${colors.green('✓')}`);
2550
2611
  }
2551
2612
  if (wsl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.79",
3
+ "version": "1.0.81",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",