@bobfrankston/npmglobalize 1.0.104 → 1.0.106
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/README.md +9 -2
- package/cli.js +3 -2
- package/lib.d.ts +4 -0
- package/lib.js +133 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,6 +169,12 @@ For single-developer projects, this safely pulls remote changes before publishin
|
|
|
169
169
|
|
|
170
170
|
### 📂 Git Repository Setup
|
|
171
171
|
|
|
172
|
+
**Change visibility of an existing repo:**
|
|
173
|
+
```bash
|
|
174
|
+
npmglobalize -git public # Makes the GitHub repo public (with confirmation)
|
|
175
|
+
npmglobalize -git private # Makes the GitHub repo private
|
|
176
|
+
```
|
|
177
|
+
|
|
172
178
|
When initializing a new repository with `--init`, npmglobalize automatically sets up:
|
|
173
179
|
|
|
174
180
|
**File structure** (per programming.md standards):
|
|
@@ -266,8 +272,9 @@ Publishing requires being on a branch so commits and tags can be properly tracke
|
|
|
266
272
|
|
|
267
273
|
### Git/npm Visibility
|
|
268
274
|
```
|
|
269
|
-
-git private
|
|
270
|
-
-git public
|
|
275
|
+
-git private Set GitHub repo to private (default for new repos)
|
|
276
|
+
-git public Set GitHub repo to public (requires confirmation)
|
|
277
|
+
Works on both new and existing repos
|
|
271
278
|
-npm private Mark npm package private (skip publish) (default)
|
|
272
279
|
-npm public Publish to npm
|
|
273
280
|
```
|
package/cli.js
CHANGED
|
@@ -47,8 +47,9 @@ Mode Options:
|
|
|
47
47
|
-nofiles Keep npm versions permanently
|
|
48
48
|
|
|
49
49
|
Git/npm Visibility:
|
|
50
|
-
-git private
|
|
51
|
-
-git public
|
|
50
|
+
-git private Set GitHub repo to private (default for new repos)
|
|
51
|
+
-git public Set GitHub repo to public (requires confirmation)
|
|
52
|
+
Works on both new and existing repos
|
|
52
53
|
-npm private Mark npm package private (skip publish) (default)
|
|
53
54
|
-npm public Publish to npm
|
|
54
55
|
|
package/lib.d.ts
CHANGED
|
@@ -78,6 +78,8 @@ export interface GlobalizeOptions {
|
|
|
78
78
|
_fromWorkspace?: boolean;
|
|
79
79
|
/** Internal: signals this call is from CLI (version already printed) */
|
|
80
80
|
_fromCli?: boolean;
|
|
81
|
+
/** Internal: tracks which options were explicitly set on the CLI */
|
|
82
|
+
explicitKeys?: Set<string>;
|
|
81
83
|
}
|
|
82
84
|
/** Result from a single package in workspace mode */
|
|
83
85
|
interface WorkspacePackageResult {
|
|
@@ -186,6 +188,8 @@ export declare function fixVersionTagMismatch(cwd: string, pkg: any, verbose?: b
|
|
|
186
188
|
/** Run a command and return success status */
|
|
187
189
|
export declare function runCommand(cmd: string, args: string[], options?: {
|
|
188
190
|
silent?: boolean;
|
|
191
|
+
verbose?: boolean;
|
|
192
|
+
showCommand?: boolean;
|
|
189
193
|
cwd?: string;
|
|
190
194
|
}): {
|
|
191
195
|
success: boolean;
|
package/lib.js
CHANGED
|
@@ -36,6 +36,7 @@ const colors = {
|
|
|
36
36
|
green: (text) => styleText('green', text),
|
|
37
37
|
italic: (text) => styleText('italic', text),
|
|
38
38
|
blue: (text) => styleText('blue', text),
|
|
39
|
+
cyan: (text) => styleText('cyan', text),
|
|
39
40
|
dim: (text) => styleText('dim', text),
|
|
40
41
|
};
|
|
41
42
|
/**
|
|
@@ -962,23 +963,23 @@ function waitForNpmVersion(pkgName, version, maxWaitMs = 90000) {
|
|
|
962
963
|
}
|
|
963
964
|
/** Run npm install -g with retries for registry propagation delay */
|
|
964
965
|
function installGlobalWithRetry(pkgSpec, cwd, maxRetries = 3) {
|
|
965
|
-
let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false });
|
|
966
|
+
let result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
966
967
|
for (let attempt = 1; attempt < maxRetries && !result.success; attempt++) {
|
|
967
968
|
console.log(colors.yellow(` Retrying install (attempt ${attempt + 1}/${maxRetries}) in 10 seconds...`));
|
|
968
969
|
spawnSafe(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['/t', '10', '/nobreak'] : ['10'], { stdio: 'pipe', shell: process.platform === 'win32' });
|
|
969
|
-
result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false });
|
|
970
|
+
result = runCommand('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
970
971
|
}
|
|
971
972
|
return result;
|
|
972
973
|
}
|
|
973
974
|
/** Run a command and return success status */
|
|
974
975
|
export function runCommand(cmd, args, options = {}) {
|
|
975
|
-
const { silent = false, cwd } = options;
|
|
976
|
+
const { silent = false, verbose = false, showCommand = false, cwd } = options;
|
|
976
977
|
try {
|
|
977
978
|
// Use shell:true for npm/gh commands which need it on Windows
|
|
978
979
|
const needsShell = cmd === 'npm' || cmd === 'npm.cmd' || cmd === 'gh';
|
|
979
|
-
//
|
|
980
|
-
if (!silent) {
|
|
981
|
-
console.log(colors.
|
|
980
|
+
// Show command for important actions (install, etc.) or in verbose mode
|
|
981
|
+
if (!silent && (showCommand || verbose)) {
|
|
982
|
+
console.log(colors.cyan(`> ${cmd} ${args.join(' ')}`));
|
|
982
983
|
}
|
|
983
984
|
const result = spawnSafe(cmd, args, {
|
|
984
985
|
encoding: 'utf-8',
|
|
@@ -1865,7 +1866,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
1865
1866
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
1866
1867
|
return true;
|
|
1867
1868
|
}
|
|
1868
|
-
const result = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
|
|
1869
|
+
const result = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
1869
1870
|
if (result.success) {
|
|
1870
1871
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
1871
1872
|
}
|
|
@@ -1876,7 +1877,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
1876
1877
|
}
|
|
1877
1878
|
if (wsl) {
|
|
1878
1879
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
1879
|
-
const wslResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false });
|
|
1880
|
+
const wslResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
1880
1881
|
if (wslResult.success) {
|
|
1881
1882
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
1882
1883
|
}
|
|
@@ -1971,7 +1972,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
1971
1972
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
1972
1973
|
return true;
|
|
1973
1974
|
}
|
|
1974
|
-
const result = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
|
|
1975
|
+
const result = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
1975
1976
|
if (result.success) {
|
|
1976
1977
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
1977
1978
|
}
|
|
@@ -1982,7 +1983,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
1982
1983
|
}
|
|
1983
1984
|
if (wsl) {
|
|
1984
1985
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
1985
|
-
const wslResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false });
|
|
1986
|
+
const wslResult = runCommand('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
1986
1987
|
if (wslResult.success) {
|
|
1987
1988
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
1988
1989
|
}
|
|
@@ -2115,6 +2116,33 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2115
2116
|
return false;
|
|
2116
2117
|
justInitialized = true;
|
|
2117
2118
|
}
|
|
2119
|
+
// Change GitHub repo visibility if explicitly requested on an existing repo
|
|
2120
|
+
const explicitKeys = options.explicitKeys;
|
|
2121
|
+
if (!justInitialized && gitStatus.isRepo && gitStatus.hasRemote && explicitKeys?.has('gitVisibility')) {
|
|
2122
|
+
const targetVis = gitVisibility;
|
|
2123
|
+
if (targetVis === 'public') {
|
|
2124
|
+
const ok = await confirm(`Change GitHub repo visibility to PUBLIC? Anyone will be able to see your code.`, false);
|
|
2125
|
+
if (!ok) {
|
|
2126
|
+
console.log('Aborted visibility change.');
|
|
2127
|
+
return false;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
if (dryRun) {
|
|
2131
|
+
console.log(` [dry-run] Would change GitHub repo visibility to ${targetVis}`);
|
|
2132
|
+
}
|
|
2133
|
+
else {
|
|
2134
|
+
console.log(`Changing GitHub repo visibility to ${targetVis}...`);
|
|
2135
|
+
const visResult = runCommand('gh', ['repo', 'edit', '--visibility', targetVis], { cwd, silent: true });
|
|
2136
|
+
if (visResult.success) {
|
|
2137
|
+
console.log(colors.green(`✓ GitHub repo is now ${targetVis.toUpperCase()}`));
|
|
2138
|
+
}
|
|
2139
|
+
else {
|
|
2140
|
+
console.error(colors.red(`✗ Failed to change repo visibility: ${visResult.stderr}`));
|
|
2141
|
+
if (!force)
|
|
2142
|
+
return false;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2118
2146
|
// Re-check git status after potential init
|
|
2119
2147
|
let currentGitStatus = getGitStatus(cwd);
|
|
2120
2148
|
// Validate git state
|
|
@@ -2349,12 +2377,22 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2349
2377
|
}
|
|
2350
2378
|
}
|
|
2351
2379
|
if (currentAccess === 'public') {
|
|
2352
|
-
console.
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2380
|
+
console.log(colors.yellow(`Package '${pkg.name}' is currently PUBLIC on npm. Converting to private...`));
|
|
2381
|
+
if (!dryRun) {
|
|
2382
|
+
const accessResult = runCommand('npm', ['access', 'set', 'status=restricted', pkg.name], { cwd, silent: false });
|
|
2383
|
+
if (accessResult.success) {
|
|
2384
|
+
console.log(colors.green(`✓ Changed ${pkg.name} to PRIVATE on npm`));
|
|
2385
|
+
currentAccess = 'restricted';
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
console.error(colors.red(`Failed to change access. Try manually: npm access set status=restricted ${pkg.name}`));
|
|
2389
|
+
if (!force)
|
|
2390
|
+
return false;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
else {
|
|
2394
|
+
console.log(colors.dim(` [dry-run] Would run: npm access set status=restricted ${pkg.name}`));
|
|
2395
|
+
}
|
|
2358
2396
|
}
|
|
2359
2397
|
// Don't set "private": true in package.json - that blocks all publishing
|
|
2360
2398
|
console.log(`Package '${pkg.name}' will publish as PRIVATE (restricted access).`);
|
|
@@ -2365,12 +2403,22 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2365
2403
|
else if (effectiveNpmVisibility === 'public') {
|
|
2366
2404
|
// User explicitly wants public (or confirmed via prompt)
|
|
2367
2405
|
if (currentAccess === 'restricted') {
|
|
2368
|
-
console.
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2406
|
+
console.log(colors.yellow(`Package '${pkg.name}' is currently PRIVATE on npm. Converting to public...`));
|
|
2407
|
+
if (!dryRun) {
|
|
2408
|
+
const accessResult = runCommand('npm', ['access', 'set', 'status=public', pkg.name], { cwd, silent: false });
|
|
2409
|
+
if (accessResult.success) {
|
|
2410
|
+
console.log(colors.green(`✓ Changed ${pkg.name} to PUBLIC on npm`));
|
|
2411
|
+
currentAccess = 'public';
|
|
2412
|
+
}
|
|
2413
|
+
else {
|
|
2414
|
+
console.error(colors.red(`Failed to change access. Try manually: npm access set status=public ${pkg.name}`));
|
|
2415
|
+
if (!force)
|
|
2416
|
+
return false;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
else {
|
|
2420
|
+
console.log(colors.dim(` [dry-run] Would run: npm access set status=public ${pkg.name}`));
|
|
2421
|
+
}
|
|
2374
2422
|
}
|
|
2375
2423
|
if (!publicConfirmed) {
|
|
2376
2424
|
console.log(`Will publish '${pkg.name}' to PUBLIC npm registry.`);
|
|
@@ -2677,7 +2725,16 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2677
2725
|
const isFirstPublish = !currentAccess;
|
|
2678
2726
|
if (!currentGitStatus.hasUncommitted && !message && !justInitialized && !isFirstPublish) {
|
|
2679
2727
|
console.log('');
|
|
2680
|
-
|
|
2728
|
+
if (currentAccess === 'public') {
|
|
2729
|
+
console.log(`${pkg.name}@${pkg.version} is already PUBLIC on npm. No changes to publish.`);
|
|
2730
|
+
}
|
|
2731
|
+
else if (currentAccess === 'restricted') {
|
|
2732
|
+
console.log(`${pkg.name}@${pkg.version} is PRIVATE on npm. No changes to publish.`);
|
|
2733
|
+
}
|
|
2734
|
+
else {
|
|
2735
|
+
console.log('No changes to commit and no custom message specified.');
|
|
2736
|
+
}
|
|
2737
|
+
console.log(colors.dim(' Use -m "message" to force a version bump and republish.'));
|
|
2681
2738
|
// If install/link flag is set, install globally
|
|
2682
2739
|
if (install || link || wsl) {
|
|
2683
2740
|
if (verbose) {
|
|
@@ -2696,7 +2753,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2696
2753
|
if (pkg.bin && (install || link || wsl)) {
|
|
2697
2754
|
if (link) {
|
|
2698
2755
|
console.log(`Installing ${pkgName} globally from local directory (link)...`);
|
|
2699
|
-
const localInstallResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
|
|
2756
|
+
const localInstallResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
2700
2757
|
if (localInstallResult.success) {
|
|
2701
2758
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
2702
2759
|
}
|
|
@@ -2722,7 +2779,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2722
2779
|
if (!link && !install)
|
|
2723
2780
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
2724
2781
|
console.log(`Installing ${pkgName} in WSL${link ? ' (link)' : ' from registry'}...`);
|
|
2725
|
-
const wslInstallResult = runCommand('wsl', wslArgs, { cwd, silent: false });
|
|
2782
|
+
const wslInstallResult = runCommand('wsl', wslArgs, { cwd, silent: false, showCommand: true });
|
|
2726
2783
|
if (wslInstallResult.success) {
|
|
2727
2784
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
2728
2785
|
}
|
|
@@ -3194,7 +3251,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3194
3251
|
if (link) {
|
|
3195
3252
|
console.log(`Linking globally: ${pkgName}@${pkgVersion}...`);
|
|
3196
3253
|
if (!dryRun) {
|
|
3197
|
-
const installResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false });
|
|
3254
|
+
const installResult = runCommand('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3198
3255
|
if (installResult.success) {
|
|
3199
3256
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
3200
3257
|
}
|
|
@@ -3230,7 +3287,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3230
3287
|
waitForNpmVersion(pkgName, pkgVersion);
|
|
3231
3288
|
console.log(`Installing in WSL${link ? ' (link)' : ' from registry'}: ${pkgName}@${pkgVersion}...`);
|
|
3232
3289
|
if (!dryRun) {
|
|
3233
|
-
const wslResult = runCommand('wsl', wslArgs, { cwd, silent: false });
|
|
3290
|
+
const wslResult = runCommand('wsl', wslArgs, { cwd, silent: false, showCommand: true });
|
|
3234
3291
|
if (wslResult.success) {
|
|
3235
3292
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
3236
3293
|
}
|
|
@@ -3279,6 +3336,9 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3279
3336
|
console.log(` Version: ${colors.green('v' + finalPkg.version)}`);
|
|
3280
3337
|
console.log(` Published: ${colors.green('✓')} (${accessLabel})`);
|
|
3281
3338
|
console.log(` Git pushed: ${colors.green('✓')}`);
|
|
3339
|
+
if (explicitKeys?.has('gitVisibility')) {
|
|
3340
|
+
console.log(` Git visibility: ${colors.green(gitVisibility.toUpperCase())}`);
|
|
3341
|
+
}
|
|
3282
3342
|
if (link) {
|
|
3283
3343
|
console.log(` Linked globally: ${colors.green('✓')}`);
|
|
3284
3344
|
}
|
|
@@ -3357,6 +3417,52 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
3357
3417
|
console.log(`Filtered to: ${filteredOrder.join(', ')}`);
|
|
3358
3418
|
console.log('');
|
|
3359
3419
|
}
|
|
3420
|
+
// Check for visibility mismatches: public packages depending on would-be-private siblings
|
|
3421
|
+
const visibilityMap = new Map();
|
|
3422
|
+
for (const pkgInfo of packages) {
|
|
3423
|
+
const pkgConfig = readConfig(pkgInfo.dir);
|
|
3424
|
+
const vis = pkgConfig.npmVisibility
|
|
3425
|
+
|| pkgInfo.pkg.publishConfig?.access
|
|
3426
|
+
|| options.npmVisibility; // CLI-level default
|
|
3427
|
+
if (vis === 'public') {
|
|
3428
|
+
visibilityMap.set(pkgInfo.name, 'public');
|
|
3429
|
+
}
|
|
3430
|
+
else if (pkgInfo.pkg.private) {
|
|
3431
|
+
visibilityMap.set(pkgInfo.name, 'private');
|
|
3432
|
+
}
|
|
3433
|
+
else {
|
|
3434
|
+
visibilityMap.set(pkgInfo.name, 'unknown');
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
const wsNameSet = new Set(packages.map(p => p.name));
|
|
3438
|
+
for (const pkgInfo of packages) {
|
|
3439
|
+
if (visibilityMap.get(pkgInfo.name) !== 'public')
|
|
3440
|
+
continue;
|
|
3441
|
+
const deps = { ...pkgInfo.pkg.dependencies, ...pkgInfo.pkg.devDependencies };
|
|
3442
|
+
for (const depName of Object.keys(deps || {})) {
|
|
3443
|
+
if (!wsNameSet.has(depName))
|
|
3444
|
+
continue;
|
|
3445
|
+
if (visibilityMap.get(depName) === 'public')
|
|
3446
|
+
continue;
|
|
3447
|
+
const depInfo = packages.find(p => p.name === depName);
|
|
3448
|
+
if (!depInfo)
|
|
3449
|
+
continue;
|
|
3450
|
+
console.log(colors.yellow(`⚠ Public package ${pkgInfo.name} depends on ${depName} which has no public visibility set.`));
|
|
3451
|
+
if (!options.dryRun) {
|
|
3452
|
+
const makePublic = await confirm(`Make ${depName} public too?`, true);
|
|
3453
|
+
if (makePublic) {
|
|
3454
|
+
const depConfig = readConfig(depInfo.dir);
|
|
3455
|
+
depConfig.npmVisibility = 'public';
|
|
3456
|
+
writeConfig(depInfo.dir, depConfig, new Set(['npmVisibility']));
|
|
3457
|
+
visibilityMap.set(depName, 'public');
|
|
3458
|
+
console.log(colors.green(`✓ Set ${depName} to public in .globalize.json5`));
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
else {
|
|
3462
|
+
console.log(colors.dim(` [dry-run] Would ask to make ${depName} public`));
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3360
3466
|
// Process each package in dependency order
|
|
3361
3467
|
const results = [];
|
|
3362
3468
|
for (const pkgName of filteredOrder) {
|