@bobfrankston/npmglobalize 1.0.108 → 1.0.110

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/cli.js CHANGED
@@ -40,6 +40,8 @@ Install Options:
40
40
  -link Global install via symlink (npm install -g .)
41
41
  -local Local install only — skip transform/publish, just npm install -g .
42
42
  -wsl Also install globally in WSL
43
+ -freeze Freeze node_modules (replace symlinks with real copies for network shares)
44
+ -nofreeze Disable freeze
43
45
  -once Don't persist flags to .globalize.json5
44
46
 
45
47
  Mode Options:
@@ -283,6 +285,14 @@ function parseArgs(args) {
283
285
  case '-pkg':
284
286
  options.package = true;
285
287
  break;
288
+ case '-freeze':
289
+ options.freeze = true;
290
+ options.explicitKeys.add('freeze');
291
+ break;
292
+ case '-nofreeze':
293
+ options.freeze = false;
294
+ options.explicitKeys.add('freeze');
295
+ break;
286
296
  case '-once':
287
297
  options.once = true;
288
298
  break;
@@ -20,7 +20,6 @@
20
20
  recommended: [
21
21
  "node_modules/",
22
22
  ".globalize.json5",
23
- ".globalize.jsonc",
24
23
  "*.log",
25
24
  ".DS_Store",
26
25
  "Thumbs.db"
package/lib.d.ts CHANGED
@@ -74,6 +74,8 @@ export interface GlobalizeOptions {
74
74
  once?: boolean;
75
75
  /** Local install only — skip transform/publish, just npm install -g . */
76
76
  local?: boolean;
77
+ /** Freeze node_modules: replace symlinks/junctions with real copies for network share use */
78
+ freeze?: boolean;
77
79
  /** Internal: signals this call is from workspace orchestrator */
78
80
  _fromWorkspace?: boolean;
79
81
  /** Internal: signals this call is from CLI (version already printed) */
package/lib.js CHANGED
@@ -13,6 +13,7 @@ import fs from 'fs';
13
13
  import path from 'path';
14
14
  import { execSync, spawnSync } from 'child_process';
15
15
  import { readConfig as readUserConfig, writeConfig as writeUserConfig, configDir } from '@bobfrankston/userconfig';
16
+ import { freezeDependencies } from '@bobfrankston/freezepak';
16
17
  /** Wrapper for spawnSync that avoids DEP0190 (args + shell: true).
17
18
  * When shell is true, joins cmd+args into a single command string. */
18
19
  function spawnSafe(cmd, args, options = {}) {
@@ -198,7 +199,8 @@ export function writeConfig(dir, config, explicitKeys) {
198
199
  install: false,
199
200
  wsl: false,
200
201
  force: false,
201
- verbose: false
202
+ verbose: false,
203
+ freeze: false
202
204
  };
203
205
  // Read existing config to preserve values
204
206
  const existing = readConfig(dir);
@@ -257,6 +259,8 @@ export function writeConfig(dir, config, explicitKeys) {
257
259
  comment = ' // Local install only (skip transform/publish)';
258
260
  else if (key === 'noPublish')
259
261
  comment = ' // Transform but don\'t publish';
262
+ else if (key === 'freeze')
263
+ comment = ' // Freeze node_modules (replace symlinks with real copies)';
260
264
  lines.push(` "${key}": ${jsonValue}${comma}${comment}`);
261
265
  });
262
266
  lines.push('');
@@ -276,6 +280,7 @@ export function writeConfig(dir, config, explicitKeys) {
276
280
  lines.push(' // "fix": false // Auto-run npm audit fix');
277
281
  lines.push(' // "local": false // Local install only (skip transform/publish)');
278
282
  lines.push(' // "noPublish": false // Transform but don\'t publish');
283
+ lines.push(' // "freeze": false // Freeze node_modules (replace symlinks with real copies)');
279
284
  lines.push('}');
280
285
  fs.writeFileSync(configPath, lines.join('\n') + '\n');
281
286
  }
@@ -1870,7 +1875,7 @@ async function doLocalInstall(cwd, options) {
1870
1875
  }
1871
1876
  export async function globalize(cwd, options = {}, configOptions = {}) {
1872
1877
  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
1873
- forcePublish = false, fix = false, fixTags = false, rebase = false, show = false, local = false } = options;
1878
+ forcePublish = false, fix = false, fixTags = false, rebase = false, show = false, local = false, freeze = false } = options;
1874
1879
  // Show tool version only for recursive dep calls (CLI already prints it at startup)
1875
1880
  const toolVersion = getToolVersion();
1876
1881
  if (!options._fromWorkspace && !options._fromCli) {
@@ -1927,6 +1932,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
1927
1932
  settings.push('--show');
1928
1933
  if (configOptions.local)
1929
1934
  settings.push('-local');
1935
+ if (configOptions.freeze)
1936
+ settings.push('-freeze');
1930
1937
  if (settings.length > 0) {
1931
1938
  console.log(colors.dim(`Settings from .globalize.json5: ${settings.join(', ')}`));
1932
1939
  }
@@ -2687,6 +2694,16 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2687
2694
  }
2688
2695
  if (noPublish) {
2689
2696
  console.log('Transform complete (--nopublish mode).');
2697
+ if (freeze && !dryRun) {
2698
+ console.log('Freezing node_modules (replacing symlinks with real copies)...');
2699
+ try {
2700
+ freezeDependencies(cwd);
2701
+ console.log(colors.green('✓ node_modules frozen'));
2702
+ }
2703
+ catch (error) {
2704
+ console.error(colors.red(`✗ Freeze failed: ${error.message}`));
2705
+ }
2706
+ }
2690
2707
  if (files && transformResult.transformed) {
2691
2708
  console.log('Restoring file: dependencies...');
2692
2709
  const finalPkg = readPackageJson(cwd);
@@ -2705,6 +2722,16 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2705
2722
  // Skip if private
2706
2723
  if (pkg.private) {
2707
2724
  console.log('Package is private - skipping npm publish.');
2725
+ if (freeze && !dryRun) {
2726
+ console.log('Freezing node_modules (replacing symlinks with real copies)...');
2727
+ try {
2728
+ freezeDependencies(cwd);
2729
+ console.log(colors.green('✓ node_modules frozen'));
2730
+ }
2731
+ catch (error) {
2732
+ console.error(colors.red(`✗ Freeze failed: ${error.message}`));
2733
+ }
2734
+ }
2708
2735
  if (files && transformResult.transformed) {
2709
2736
  console.log('Restoring file: dependencies...');
2710
2737
  const finalPkg = readPackageJson(cwd);
@@ -2870,6 +2897,19 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2870
2897
  console.log(' [dry-run] Would commit changes');
2871
2898
  }
2872
2899
  }
2900
+ // Pull latest from remote before version bump to avoid push rejection
2901
+ if (currentGitStatus.hasRemote && !dryRun) {
2902
+ const pullResult = runCommand('git', ['pull', '--rebase'], { cwd, silent: true });
2903
+ if (!pullResult.success) {
2904
+ console.error(colors.yellow('Warning: git pull --rebase failed before version bump'));
2905
+ if (verbose) {
2906
+ console.error(' ' + pullResult.stderr);
2907
+ }
2908
+ }
2909
+ else if (verbose) {
2910
+ console.log(' Pulled latest from remote');
2911
+ }
2912
+ }
2873
2913
  // Version bump
2874
2914
  console.log(`Bumping version (${bump})...`);
2875
2915
  if (!dryRun) {
@@ -2915,6 +2955,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2915
2955
  console.log(colors.green(`Version bumped to ${newVersion}`));
2916
2956
  }
2917
2957
  catch (error) {
2958
+ let autoFixed = false;
2918
2959
  console.error(colors.red('ERROR: Version bump failed:'), error.message);
2919
2960
  // Show additional error details if available
2920
2961
  if (error.stderr || error.stdout || error.code) {
@@ -2933,16 +2974,41 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
2933
2974
  const stderrLower = (error.stderr || '').toLowerCase();
2934
2975
  const stdoutLower = (error.stdout || '').toLowerCase();
2935
2976
  const combinedOutput = stderrLower + ' ' + stdoutLower;
2936
- if (combinedOutput.includes('non-fast-forward') || combinedOutput.includes('rejected') && combinedOutput.includes('behind')) {
2937
- console.error(colors.yellow('\nYour local branch is behind the remote.'));
2938
- console.error(colors.yellow('This usually means changes were pushed from another location.'));
2939
- console.error(colors.yellow('\nTo fix this:'));
2940
- console.error(' 1. Pull remote changes: git pull --rebase');
2941
- console.error(' 2. Then run npmglobalize again');
2942
- console.error(colors.yellow('\nOr to force push (use with caution):'));
2943
- console.error(' git push --force-with-lease');
2944
- if (!force) {
2945
- return false;
2977
+ if (combinedOutput.includes('non-fast-forward') || (combinedOutput.includes('rejected') && combinedOutput.includes('behind'))) {
2978
+ // Version bump + tag succeeded locally; only the push failed.
2979
+ // Auto-pull --rebase and retry the push.
2980
+ console.log(colors.yellow('\nLocal branch is behind remote — pulling with rebase...'));
2981
+ const pullResult = runCommand('git', ['pull', '--rebase'], { cwd });
2982
+ if (pullResult.success) {
2983
+ console.log(colors.green(' Rebased onto remote'));
2984
+ const pushResult = runCommand('git', ['push'], { cwd });
2985
+ if (pushResult.success) {
2986
+ const tagPush = runCommand('git', ['push', '--tags'], { cwd, silent: true });
2987
+ if (tagPush.success) {
2988
+ console.log(colors.green(' ✓ Pushed with tags'));
2989
+ }
2990
+ else {
2991
+ console.log(colors.green(' ✓ Pushed (tags may need manual push)'));
2992
+ }
2993
+ // Re-read version after successful rebase+push
2994
+ const rebased = readPackageJson(cwd);
2995
+ console.log(colors.green(`Version bumped to ${rebased.version}`));
2996
+ autoFixed = true;
2997
+ }
2998
+ else {
2999
+ console.error(colors.red('Push still failed after rebase.'));
3000
+ console.error(' Try: git push --force-with-lease');
3001
+ if (!force) {
3002
+ return false;
3003
+ }
3004
+ }
3005
+ }
3006
+ else {
3007
+ console.error(colors.red('Auto-rebase failed (likely merge conflict).'));
3008
+ console.error(' Resolve conflicts, then: git rebase --continue && git push');
3009
+ if (!force) {
3010
+ return false;
3011
+ }
2946
3012
  }
2947
3013
  }
2948
3014
  else if (stderrLower.includes('tag') && stderrLower.includes('already exists')) {
@@ -3018,10 +3084,12 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3018
3084
  console.error(' • Disk space or permissions issues');
3019
3085
  console.error(colors.yellow('\nTry running with --verbose or check git status manually'));
3020
3086
  }
3021
- if (!force) {
3022
- return false;
3087
+ if (!autoFixed) {
3088
+ if (!force) {
3089
+ return false;
3090
+ }
3091
+ console.log(colors.yellow('Continuing with --force...'));
3023
3092
  }
3024
- console.log(colors.yellow('Continuing with --force...'));
3025
3093
  }
3026
3094
  }
3027
3095
  else {
@@ -3302,6 +3370,20 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3302
3370
  }
3303
3371
  }
3304
3372
  }
3373
+ // Freeze node_modules: replace symlinks/junctions with real copies
3374
+ if (freeze && !dryRun) {
3375
+ console.log('Freezing node_modules (replacing symlinks with real copies)...');
3376
+ try {
3377
+ freezeDependencies(cwd);
3378
+ console.log(colors.green('✓ node_modules frozen'));
3379
+ }
3380
+ catch (error) {
3381
+ console.error(colors.red(`✗ Freeze failed: ${error.message}`));
3382
+ }
3383
+ }
3384
+ else if (freeze && dryRun) {
3385
+ console.log(' [dry-run] Would freeze node_modules');
3386
+ }
3305
3387
  // Finalize - restore file: paths if --files mode (default)
3306
3388
  if (files && transformResult.transformed) {
3307
3389
  console.log('Restoring file: dependencies (--files mode)...');
@@ -3350,6 +3432,9 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
3350
3432
  if (wsl) {
3351
3433
  console.log(` Installed in WSL: ${colors.green('✓')}`);
3352
3434
  }
3435
+ if (freeze) {
3436
+ console.log(` Frozen node_modules: ${colors.green('✓')}`);
3437
+ }
3353
3438
  if (files && transformResult.transformed) {
3354
3439
  console.log(` Restored file: deps: ${colors.green('✓')}`);
3355
3440
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.108",
3
+ "version": "1.0.110",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -31,6 +31,7 @@
31
31
  "url": "https://github.com/BobFrankston/npmglobalize.git"
32
32
  },
33
33
  "dependencies": {
34
+ "@bobfrankston/freezepak": "^0.1.4",
34
35
  "@bobfrankston/userconfig": "^1.0.4",
35
36
  "@npmcli/package-json": "^7.0.4",
36
37
  "json5": "^2.2.3",
@@ -43,6 +44,7 @@
43
44
  "access": "public"
44
45
  },
45
46
  ".dependencies": {
47
+ "@bobfrankston/freezepak": "file:../freezepak",
46
48
  "@bobfrankston/userconfig": "file:../userconfig",
47
49
  "@npmcli/package-json": "^7.0.4",
48
50
  "json5": "^2.2.3",