@bobfrankston/npmglobalize 1.0.174 → 1.0.176
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 +1 -1
- package/lib.d.ts +22 -6
- package/lib.js +164 -67
- package/package.json +3 -3
package/cli.js
CHANGED
|
@@ -446,7 +446,7 @@ export async function main() {
|
|
|
446
446
|
// Ensures consumers' tsc sees up-to-date `.d.ts` from sibling checkouts
|
|
447
447
|
// whose source has changed since their last build.
|
|
448
448
|
if (!cliOptions.cleanup) {
|
|
449
|
-
ensureFileDepModules(cwd, !!cliOptions.verbose);
|
|
449
|
+
await ensureFileDepModules(cwd, !!cliOptions.verbose);
|
|
450
450
|
const depsOk = await buildFileDepsTopologically(cwd, { verbose: !!cliOptions.verbose, force: !!cliOptions.force });
|
|
451
451
|
if (!depsOk && !cliOptions.force) {
|
|
452
452
|
printBuildSummary();
|
package/lib.d.ts
CHANGED
|
@@ -293,7 +293,7 @@ export declare function missingDeps(pkgDir: string, pkg: any): string[];
|
|
|
293
293
|
* "fresh clone, no `node_modules/`" and "dep added but `npm install` not
|
|
294
294
|
* re-run" (partial-sync) cases. Also covers `cwd` itself on the first call.
|
|
295
295
|
* Cycle-safe via the shared `visited` set. */
|
|
296
|
-
export declare function ensureFileDepModules(cwd: string, verbose?: boolean, visited?: Set<string>): void
|
|
296
|
+
export declare function ensureFileDepModules(cwd: string, verbose?: boolean, visited?: Set<string>): Promise<void>;
|
|
297
297
|
/** Build a single project: detect tsconfig, prompt to add `build: tsc` if a
|
|
298
298
|
* TypeScript project lacks a build script, run `npm run build`, record
|
|
299
299
|
* failures. Returns true if build succeeded (or was skipped because no
|
|
@@ -319,7 +319,7 @@ export declare function buildFileDepsTopologically(cwd: string, opts?: {
|
|
|
319
319
|
export declare function ensureWorkspaceDepModules(rootDir: string, members: Array<{
|
|
320
320
|
dir: string;
|
|
321
321
|
pkg: any;
|
|
322
|
-
}>, verbose?: boolean): void
|
|
322
|
+
}>, verbose?: boolean): Promise<void>;
|
|
323
323
|
/** Run a command and return success status */
|
|
324
324
|
export declare function runCommand(cmd: string, args: string[], options?: {
|
|
325
325
|
silent?: boolean;
|
|
@@ -331,15 +331,31 @@ export declare function runCommand(cmd: string, args: string[], options?: {
|
|
|
331
331
|
output: string;
|
|
332
332
|
stderr: string;
|
|
333
333
|
};
|
|
334
|
+
/** Async variant of `runCommand`: spawns the child via `child_process.spawn`
|
|
335
|
+
* (not spawnSync) so the JS event loop keeps turning. Used for long-running
|
|
336
|
+
* commands (npm install/pack/publish/build, git push/pull, gh, wsl) so that
|
|
337
|
+
* a SIGINT pressed mid-command can fire its handler immediately, kill the
|
|
338
|
+
* child, restore deps, and exit — instead of being queued behind spawnSync. */
|
|
339
|
+
export declare function runCommandAsync(cmd: string, args: string[], options?: {
|
|
340
|
+
silent?: boolean;
|
|
341
|
+
verbose?: boolean;
|
|
342
|
+
showCommand?: boolean;
|
|
343
|
+
cwd?: string;
|
|
344
|
+
}): Promise<{
|
|
345
|
+
success: boolean;
|
|
346
|
+
output: string;
|
|
347
|
+
stderr: string;
|
|
348
|
+
signal: NodeJS.Signals | null;
|
|
349
|
+
}>;
|
|
334
350
|
/** Install a package globally in WSL, auto-fixing the root-owned /usr/local/lib/node_modules
|
|
335
351
|
* EACCES case by switching npm to a user prefix (~/.npm-global) and retrying once.
|
|
336
352
|
* Output is captured (so we can scan for the error) and then mirrored to the terminal. */
|
|
337
353
|
export declare function installInWsl(wslArgs: string[], opts?: {
|
|
338
354
|
cwd?: string;
|
|
339
|
-
}): {
|
|
355
|
+
}): Promise<{
|
|
340
356
|
success: boolean;
|
|
341
357
|
fixed: boolean;
|
|
342
|
-
}
|
|
358
|
+
}>;
|
|
343
359
|
/** Run a command and throw on failure */
|
|
344
360
|
export declare function runCommandOrThrow(cmd: string, args: string[], options?: {
|
|
345
361
|
silent?: boolean;
|
|
@@ -370,11 +386,11 @@ export declare function promptChoice(message: string, choices: string[]): Promis
|
|
|
370
386
|
export declare function initGit(cwd: string, visibility: 'private' | 'public', dryRun: boolean, allowTs?: boolean): Promise<boolean>;
|
|
371
387
|
/** Main globalize function */
|
|
372
388
|
/** Run npm audit and optionally fix vulnerabilities */
|
|
373
|
-
export declare function runNpmAudit(cwd: string, fix?: boolean, verbose?: boolean): {
|
|
389
|
+
export declare function runNpmAudit(cwd: string, fix?: boolean, verbose?: boolean): Promise<{
|
|
374
390
|
success: boolean;
|
|
375
391
|
report: string;
|
|
376
392
|
hasVulnerabilities: boolean;
|
|
377
|
-
}
|
|
393
|
+
}>;
|
|
378
394
|
/** Get the version of npmglobalize itself */
|
|
379
395
|
export declare function getToolVersion(): string;
|
|
380
396
|
export declare function globalize(cwd: string, options?: GlobalizeOptions, configOptions?: Partial<GlobalizeOptions>): Promise<boolean>;
|
package/lib.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import fs from 'fs';
|
|
13
13
|
import os from 'os';
|
|
14
14
|
import path from 'path';
|
|
15
|
-
import { execSync, spawnSync } from 'child_process';
|
|
15
|
+
import { execSync, spawn, spawnSync } from 'child_process';
|
|
16
16
|
import { readConfig as readUserConfig, writeConfig as writeUserConfig, configDir } from '@bobfrankston/userconfig';
|
|
17
17
|
import { freezeDependencies } from '@bobfrankston/freezepak';
|
|
18
18
|
import { importgen as runImportgen } from '@bobfrankston/importgen';
|
|
@@ -403,6 +403,29 @@ function emergencyRestoreDeps() {
|
|
|
403
403
|
}
|
|
404
404
|
dirtyPackageJsons.clear();
|
|
405
405
|
}
|
|
406
|
+
/** Children spawned by `runCommandAsync`. The SIGINT handler iterates and kills
|
|
407
|
+
* these on abort so `npm` / `git` don't keep running and so cmd.exe doesn't
|
|
408
|
+
* prompt "Terminate batch job (Y/N)?" after we exit. */
|
|
409
|
+
const activeChildren = new Set();
|
|
410
|
+
/** Force-terminate a child process (and on Windows, its whole tree, since
|
|
411
|
+
* npm.cmd / gh.cmd are batch files that spawn node and won't be killed by a
|
|
412
|
+
* bare child.kill). */
|
|
413
|
+
function killChildTree(child) {
|
|
414
|
+
if (!child.pid || child.exitCode !== null || child.signalCode !== null)
|
|
415
|
+
return;
|
|
416
|
+
if (process.platform === 'win32') {
|
|
417
|
+
try {
|
|
418
|
+
spawnSync('taskkill', ['/T', '/F', '/PID', String(child.pid)], { stdio: 'ignore' });
|
|
419
|
+
}
|
|
420
|
+
catch { /* best-effort */ }
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
try {
|
|
424
|
+
child.kill('SIGTERM');
|
|
425
|
+
}
|
|
426
|
+
catch { /* best-effort */ }
|
|
427
|
+
}
|
|
428
|
+
}
|
|
406
429
|
let cleanupHandlersInstalled = false;
|
|
407
430
|
/** Install signal/exit handlers that restore `.dependencies` backups on abnormal exit. */
|
|
408
431
|
export function installCleanupHandlers() {
|
|
@@ -421,6 +444,11 @@ export function installCleanupHandlers() {
|
|
|
421
444
|
}
|
|
422
445
|
aborting = true;
|
|
423
446
|
console.error(colors.yellow(`\n${signal} received — aborting, restoring file: dependencies...`));
|
|
447
|
+
// Kill any in-flight child process (npm/git/etc.) so it stops promptly
|
|
448
|
+
// and Windows cmd.exe doesn't ask "Terminate batch job (Y/N)?".
|
|
449
|
+
for (const child of activeChildren)
|
|
450
|
+
killChildTree(child);
|
|
451
|
+
activeChildren.clear();
|
|
424
452
|
emergencyRestoreDeps();
|
|
425
453
|
process.exit(128 + (signal === 'SIGINT' ? 2 : signal === 'SIGTERM' ? 15 : 1));
|
|
426
454
|
};
|
|
@@ -661,7 +689,7 @@ export async function cascadePublicVisibility(cwd, opts = {}) {
|
|
|
661
689
|
const access = checkNpmAccess(targetName);
|
|
662
690
|
if (access === 'restricted') {
|
|
663
691
|
if (!dryRun) {
|
|
664
|
-
const r =
|
|
692
|
+
const r = await runCommandAsync('npm', ['access', 'set', 'status=public', targetName], { cwd: targetPath, silent: true });
|
|
665
693
|
if (r.success) {
|
|
666
694
|
promoted.push(targetName);
|
|
667
695
|
console.log(colors.green(` ✓ Flipped ${targetName} to PUBLIC on npm`));
|
|
@@ -1624,7 +1652,7 @@ function formatMissingReason(missing) {
|
|
|
1624
1652
|
* "fresh clone, no `node_modules/`" and "dep added but `npm install` not
|
|
1625
1653
|
* re-run" (partial-sync) cases. Also covers `cwd` itself on the first call.
|
|
1626
1654
|
* Cycle-safe via the shared `visited` set. */
|
|
1627
|
-
export function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
|
|
1655
|
+
export async function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
|
|
1628
1656
|
const abs = path.resolve(cwd);
|
|
1629
1657
|
if (visited.has(abs))
|
|
1630
1658
|
return;
|
|
@@ -1651,7 +1679,7 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1651
1679
|
catch { /* best-effort */ }
|
|
1652
1680
|
}
|
|
1653
1681
|
console.log(colors.yellow(`↻ installing node_modules in ${pkg?.name || abs} (${formatMissingReason(cwdMissing)})`));
|
|
1654
|
-
const r =
|
|
1682
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: abs, silent: !verbose });
|
|
1655
1683
|
if (!r.success) {
|
|
1656
1684
|
console.error(colors.red(` ✗ npm install failed in ${abs}`));
|
|
1657
1685
|
if (r.stderr)
|
|
@@ -1688,14 +1716,14 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1688
1716
|
catch { /* best-effort */ }
|
|
1689
1717
|
}
|
|
1690
1718
|
console.log(colors.yellow(`↻ restoring node_modules in ${name} (${target}) (${formatMissingReason(targetMissing)})`));
|
|
1691
|
-
const r =
|
|
1719
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: target, silent: !verbose });
|
|
1692
1720
|
if (!r.success) {
|
|
1693
1721
|
console.error(colors.red(` ✗ npm install failed in ${target}`));
|
|
1694
1722
|
if (r.stderr)
|
|
1695
1723
|
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
1696
1724
|
}
|
|
1697
1725
|
}
|
|
1698
|
-
ensureFileDepModules(target, verbose, visited);
|
|
1726
|
+
await ensureFileDepModules(target, verbose, visited);
|
|
1699
1727
|
}
|
|
1700
1728
|
}
|
|
1701
1729
|
}
|
|
@@ -1732,7 +1760,7 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
1732
1760
|
}
|
|
1733
1761
|
}
|
|
1734
1762
|
console.log(`Building ${pkg.name || cwd}...`);
|
|
1735
|
-
const buildResult =
|
|
1763
|
+
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
1736
1764
|
if (buildResult.success) {
|
|
1737
1765
|
console.log(colors.green(`✓ Build succeeded (${pkg.name || path.basename(cwd)})`));
|
|
1738
1766
|
return true;
|
|
@@ -1796,7 +1824,7 @@ export async function buildFileDepsTopologically(cwd, opts = {}, visited = new S
|
|
|
1796
1824
|
* member `package.json` without a follow-up `npm install` at the root leaves
|
|
1797
1825
|
* the root `node_modules/` stale — the case where `member/` dirs exist but
|
|
1798
1826
|
* the actual package (e.g. `marked`) is not hoisted. */
|
|
1799
|
-
export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
1827
|
+
export async function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
1800
1828
|
const root = path.resolve(rootDir);
|
|
1801
1829
|
let rootPkg;
|
|
1802
1830
|
try {
|
|
@@ -1816,7 +1844,7 @@ export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
|
1816
1844
|
return;
|
|
1817
1845
|
const list = [...allMissing];
|
|
1818
1846
|
console.log(colors.yellow(`↻ installing workspace node_modules in ${rootPkg?.name || path.basename(root)} (${formatMissingReason(list)})`));
|
|
1819
|
-
const r =
|
|
1847
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: root, silent: !verbose });
|
|
1820
1848
|
if (!r.success) {
|
|
1821
1849
|
console.error(colors.red(` ✗ npm install failed in ${root}`));
|
|
1822
1850
|
if (r.stderr)
|
|
@@ -1827,14 +1855,14 @@ export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
|
1827
1855
|
* Brand-new packages (first-time publish) take much longer to become
|
|
1828
1856
|
* installable than version bumps, so we use longer waits and more
|
|
1829
1857
|
* attempts when `isNewPackage` is true. */
|
|
1830
|
-
function installGlobalWithRetry(pkgSpec, cwd, isNewPackage = false, maxRetries) {
|
|
1858
|
+
async function installGlobalWithRetry(pkgSpec, cwd, isNewPackage = false, maxRetries) {
|
|
1831
1859
|
const retries = maxRetries ?? (isNewPackage ? 6 : 3);
|
|
1832
1860
|
const delaySec = isNewPackage ? 30 : 10;
|
|
1833
|
-
let result =
|
|
1861
|
+
let result = await runCommandAsync('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
1834
1862
|
for (let attempt = 1; attempt < retries && !result.success; attempt++) {
|
|
1835
1863
|
console.log(colors.yellow(` Retrying install (attempt ${attempt + 1}/${retries}) in ${delaySec} seconds...`));
|
|
1836
1864
|
sleepSync(delaySec * 1000);
|
|
1837
|
-
result =
|
|
1865
|
+
result = await runCommandAsync('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
1838
1866
|
}
|
|
1839
1867
|
return result;
|
|
1840
1868
|
}
|
|
@@ -1876,6 +1904,58 @@ export function runCommand(cmd, args, options = {}) {
|
|
|
1876
1904
|
return { success: false, output: '', stderr: error.message };
|
|
1877
1905
|
}
|
|
1878
1906
|
}
|
|
1907
|
+
/** Async variant of `runCommand`: spawns the child via `child_process.spawn`
|
|
1908
|
+
* (not spawnSync) so the JS event loop keeps turning. Used for long-running
|
|
1909
|
+
* commands (npm install/pack/publish/build, git push/pull, gh, wsl) so that
|
|
1910
|
+
* a SIGINT pressed mid-command can fire its handler immediately, kill the
|
|
1911
|
+
* child, restore deps, and exit — instead of being queued behind spawnSync. */
|
|
1912
|
+
export function runCommandAsync(cmd, args, options = {}) {
|
|
1913
|
+
const { silent = false, verbose = false, showCommand = false, cwd } = options;
|
|
1914
|
+
const needsShell = cmd === 'npm' || cmd === 'npm.cmd' || cmd === 'gh';
|
|
1915
|
+
if (!silent && (showCommand || verbose)) {
|
|
1916
|
+
console.log(colors.cyan(`> ${cmd} ${args.join(' ')}`));
|
|
1917
|
+
}
|
|
1918
|
+
return new Promise((resolve) => {
|
|
1919
|
+
let child;
|
|
1920
|
+
try {
|
|
1921
|
+
const spawnOpts = {
|
|
1922
|
+
stdio: silent ? 'pipe' : 'inherit',
|
|
1923
|
+
cwd,
|
|
1924
|
+
env: process.env,
|
|
1925
|
+
shell: needsShell,
|
|
1926
|
+
};
|
|
1927
|
+
// Match spawnSafe's quoting when shell:true to avoid DEP0190
|
|
1928
|
+
if (needsShell && args.length > 0) {
|
|
1929
|
+
const cmdStr = [cmd, ...args].map(a => /[\s"&|<>^]/.test(a) ? `"${a.replace(/"/g, '\\"')}"` : a).join(' ');
|
|
1930
|
+
child = spawn(cmdStr, spawnOpts);
|
|
1931
|
+
}
|
|
1932
|
+
else {
|
|
1933
|
+
child = spawn(cmd, args, spawnOpts);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
catch (err) {
|
|
1937
|
+
resolve({ success: false, output: '', stderr: err.message, signal: null });
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
activeChildren.add(child);
|
|
1941
|
+
let stdout = '';
|
|
1942
|
+
let stderr = '';
|
|
1943
|
+
if (silent) {
|
|
1944
|
+
child.stdout?.setEncoding('utf-8');
|
|
1945
|
+
child.stderr?.setEncoding('utf-8');
|
|
1946
|
+
child.stdout?.on('data', (d) => { stdout += d; });
|
|
1947
|
+
child.stderr?.on('data', (d) => { stderr += d; });
|
|
1948
|
+
}
|
|
1949
|
+
child.on('error', (err) => {
|
|
1950
|
+
activeChildren.delete(child);
|
|
1951
|
+
resolve({ success: false, output: stdout, stderr: stderr || err.message, signal: null });
|
|
1952
|
+
});
|
|
1953
|
+
child.on('close', (code, signal) => {
|
|
1954
|
+
activeChildren.delete(child);
|
|
1955
|
+
resolve({ success: code === 0, output: stdout, stderr, signal });
|
|
1956
|
+
});
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1879
1959
|
/** Dump forensic info to a temp file when `npm pack` is killed by a spurious
|
|
1880
1960
|
* Ctrl+C. Goal: correlate the failure with whatever else was attached to the
|
|
1881
1961
|
* console (Claude Code wrapper, VS Code task, AV, etc.). Returns the log path. */
|
|
@@ -1918,9 +1998,9 @@ function dumpPackCtrlcDiagnostics(pkg, cwd, packOutput, packStderr) {
|
|
|
1918
1998
|
/** Install a package globally in WSL, auto-fixing the root-owned /usr/local/lib/node_modules
|
|
1919
1999
|
* EACCES case by switching npm to a user prefix (~/.npm-global) and retrying once.
|
|
1920
2000
|
* Output is captured (so we can scan for the error) and then mirrored to the terminal. */
|
|
1921
|
-
export function installInWsl(wslArgs, opts = {}) {
|
|
2001
|
+
export async function installInWsl(wslArgs, opts = {}) {
|
|
1922
2002
|
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1923
|
-
let result =
|
|
2003
|
+
let result = await runCommandAsync('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1924
2004
|
if (result.output)
|
|
1925
2005
|
process.stdout.write(result.output);
|
|
1926
2006
|
if (result.stderr)
|
|
@@ -1933,7 +2013,7 @@ export function installInWsl(wslArgs, opts = {}) {
|
|
|
1933
2013
|
return { success: false, fixed: false };
|
|
1934
2014
|
console.log(colors.yellow('Detected root-owned npm prefix in WSL — switching to ~/.npm-global and retrying...'));
|
|
1935
2015
|
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`;
|
|
1936
|
-
const fixResult =
|
|
2016
|
+
const fixResult = await runCommandAsync('wsl', ['bash', '-lc', fix], { silent: true });
|
|
1937
2017
|
if (!fixResult.success) {
|
|
1938
2018
|
console.error(colors.red('Failed to apply WSL npm prefix fix:'));
|
|
1939
2019
|
if (fixResult.stderr)
|
|
@@ -1942,7 +2022,7 @@ export function installInWsl(wslArgs, opts = {}) {
|
|
|
1942
2022
|
}
|
|
1943
2023
|
console.log(colors.green('✓ WSL npm prefix set to ~/.npm-global; PATH appended to ~/.bashrc'));
|
|
1944
2024
|
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1945
|
-
result =
|
|
2025
|
+
result = await runCommandAsync('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1946
2026
|
if (result.output)
|
|
1947
2027
|
process.stdout.write(result.output);
|
|
1948
2028
|
if (result.stderr)
|
|
@@ -2547,11 +2627,11 @@ function parsePushProtection(errorOutput, cwd) {
|
|
|
2547
2627
|
}
|
|
2548
2628
|
/** Try to auto-bypass push protection for installed OAuth secrets via gh API.
|
|
2549
2629
|
* Returns true if all bypasses succeeded and push should be retried. */
|
|
2550
|
-
function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
2630
|
+
async function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
2551
2631
|
if (!ppInfo.allInstalledOAuth || ppInfo.secrets.length === 0)
|
|
2552
2632
|
return false;
|
|
2553
2633
|
// Check if gh CLI is available
|
|
2554
|
-
const ghCheck =
|
|
2634
|
+
const ghCheck = await runCommandAsync('gh', ['auth', 'status'], { cwd, silent: true });
|
|
2555
2635
|
if (!ghCheck.success)
|
|
2556
2636
|
return false;
|
|
2557
2637
|
// Extract repo owner/name from unblock URLs or git remote
|
|
@@ -2581,7 +2661,7 @@ function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
|
2581
2661
|
}
|
|
2582
2662
|
const placeholderId = idMatch[1];
|
|
2583
2663
|
console.log(colors.cyan(` Bypassing push protection for: ${s.type} (false_positive — installed app ID)...`));
|
|
2584
|
-
const bypassResult =
|
|
2664
|
+
const bypassResult = await runCommandAsync('gh', [
|
|
2585
2665
|
'api', `repos/${repo}/secret-scanning/push-protection-bypasses`,
|
|
2586
2666
|
'-X', 'POST',
|
|
2587
2667
|
'-f', 'reason=false_positive',
|
|
@@ -2619,8 +2699,8 @@ function showPushProtectionGuidance(ppInfo) {
|
|
|
2619
2699
|
}
|
|
2620
2700
|
/** Push to git with push-protection detection and auto-bypass for installed OAuth.
|
|
2621
2701
|
* Returns true if push succeeded (possibly after auto-bypass). */
|
|
2622
|
-
function pushWithProtection(cwd, verbose) {
|
|
2623
|
-
let pushResult =
|
|
2702
|
+
async function pushWithProtection(cwd, verbose) {
|
|
2703
|
+
let pushResult = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2624
2704
|
if (pushResult.success) {
|
|
2625
2705
|
if (verbose)
|
|
2626
2706
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
@@ -2641,7 +2721,7 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2641
2721
|
// Detect current branch name
|
|
2642
2722
|
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
2643
2723
|
const branch = branchResult.output.trim() || 'master';
|
|
2644
|
-
pushResult =
|
|
2724
|
+
pushResult = await runCommandAsync('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
2645
2725
|
if (pushResult.success) {
|
|
2646
2726
|
if (verbose)
|
|
2647
2727
|
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
@@ -2651,7 +2731,7 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2651
2731
|
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
2652
2732
|
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
2653
2733
|
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
|
2654
|
-
pushResult =
|
|
2734
|
+
pushResult = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2655
2735
|
if (pushResult.success) {
|
|
2656
2736
|
if (verbose)
|
|
2657
2737
|
console.log(colors.green(' ✓ Pushed to remote (retry)'));
|
|
@@ -2672,9 +2752,9 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2672
2752
|
return false;
|
|
2673
2753
|
}
|
|
2674
2754
|
// Try auto-bypass for installed OAuth credentials
|
|
2675
|
-
if (ppInfo.allInstalledOAuth && tryAutoBypassPushProtection(ppInfo, cwd)) {
|
|
2755
|
+
if (ppInfo.allInstalledOAuth && await tryAutoBypassPushProtection(ppInfo, cwd)) {
|
|
2676
2756
|
console.log(colors.green(' ✓ Auto-bypassed push protection (installed OAuth — not a real secret)'));
|
|
2677
|
-
const retryPush =
|
|
2757
|
+
const retryPush = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2678
2758
|
if (retryPush.success) {
|
|
2679
2759
|
if (verbose)
|
|
2680
2760
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
@@ -3065,7 +3145,7 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3065
3145
|
}
|
|
3066
3146
|
// Create GitHub repo (or link to existing one)
|
|
3067
3147
|
const visFlag = visibility === 'private' ? '--private' : '--public';
|
|
3068
|
-
const createResult =
|
|
3148
|
+
const createResult = await runCommandAsync('gh', ['repo', 'create', repoName, visFlag, '--source=.', '--push'], { cwd, silent: true });
|
|
3069
3149
|
if (!createResult.success) {
|
|
3070
3150
|
const errText = createResult.stderr + createResult.output;
|
|
3071
3151
|
// Check if repo was created but push failed (GitHub propagation delay)
|
|
@@ -3098,7 +3178,7 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3098
3178
|
console.log(colors.yellow(' Retrying push...'));
|
|
3099
3179
|
spawnSafe(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['\t', '3', '\nobreak'] : ['3'], { stdio: 'pipe' }); // brief delay for GitHub propagation
|
|
3100
3180
|
}
|
|
3101
|
-
const pushRes =
|
|
3181
|
+
const pushRes = await runCommandAsync('git', ['push', '-u', 'origin', 'master'], { cwd, silent: true });
|
|
3102
3182
|
pushed = pushRes.success;
|
|
3103
3183
|
}
|
|
3104
3184
|
if (pushed) {
|
|
@@ -3130,9 +3210,9 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3130
3210
|
}
|
|
3131
3211
|
/** Main globalize function */
|
|
3132
3212
|
/** Run npm audit and optionally fix vulnerabilities */
|
|
3133
|
-
export function runNpmAudit(cwd, fix = false, verbose = false) {
|
|
3213
|
+
export async function runNpmAudit(cwd, fix = false, verbose = false) {
|
|
3134
3214
|
if (fix) {
|
|
3135
|
-
|
|
3215
|
+
await runCommandAsync('npm', ['audit', 'fix'], { cwd, silent: true });
|
|
3136
3216
|
}
|
|
3137
3217
|
// Check remaining vulnerabilities
|
|
3138
3218
|
const auditResult = spawnSafe('npm', ['audit', '--json'], {
|
|
@@ -3207,7 +3287,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
3207
3287
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
3208
3288
|
return true;
|
|
3209
3289
|
}
|
|
3210
|
-
const result =
|
|
3290
|
+
const result = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3211
3291
|
if (result.success) {
|
|
3212
3292
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
3213
3293
|
}
|
|
@@ -3218,7 +3298,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
3218
3298
|
}
|
|
3219
3299
|
if (wsl) {
|
|
3220
3300
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
3221
|
-
const wslResult =
|
|
3301
|
+
const wslResult = await runCommandAsync('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3222
3302
|
if (wslResult.success) {
|
|
3223
3303
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
3224
3304
|
}
|
|
@@ -3323,7 +3403,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3323
3403
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
3324
3404
|
return true;
|
|
3325
3405
|
}
|
|
3326
|
-
const result =
|
|
3406
|
+
const result = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3327
3407
|
if (result.success) {
|
|
3328
3408
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
3329
3409
|
}
|
|
@@ -3541,7 +3621,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3541
3621
|
}
|
|
3542
3622
|
else {
|
|
3543
3623
|
console.log(`Changing GitHub repo visibility to ${targetVis}...`);
|
|
3544
|
-
const visResult =
|
|
3624
|
+
const visResult = await runCommandAsync('gh', ['repo', 'edit', '--visibility', targetVis, '--accept-visibility-change-consequences'], { cwd, silent: true });
|
|
3545
3625
|
if (visResult.success) {
|
|
3546
3626
|
console.log(colors.green(`✓ GitHub repo is now ${targetVis.toUpperCase()}`));
|
|
3547
3627
|
}
|
|
@@ -3625,7 +3705,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3625
3705
|
console.log(colors.yellow('Local branch is behind remote.'));
|
|
3626
3706
|
if (rebase) {
|
|
3627
3707
|
console.log('Rebasing local changes (--rebase)...');
|
|
3628
|
-
const rebaseResult =
|
|
3708
|
+
const rebaseResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd, silent: false });
|
|
3629
3709
|
if (!rebaseResult.success) {
|
|
3630
3710
|
console.error(colors.red('ERROR: Rebase failed.'));
|
|
3631
3711
|
console.error('You may need to resolve conflicts manually.');
|
|
@@ -3659,7 +3739,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3659
3739
|
// with new declared deps still needs its own `npm install` even if it has
|
|
3660
3740
|
// no build step. CLI entrypoint already ran this, so skip when _fromCli.
|
|
3661
3741
|
if (!options._fromCli && !dryRun)
|
|
3662
|
-
ensureFileDepModules(cwd, verbose);
|
|
3742
|
+
await ensureFileDepModules(cwd, verbose);
|
|
3663
3743
|
// Run build step if package.json has a build script (skip if CLI already built)
|
|
3664
3744
|
if (pkg.scripts?.build && !options._fromCli) {
|
|
3665
3745
|
console.log(`${timestamp()} Running build...`);
|
|
@@ -3670,7 +3750,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3670
3750
|
const restoreWorkspaces = reorderWorkspacesForBuild(cwd, pkg, verbose);
|
|
3671
3751
|
try {
|
|
3672
3752
|
// Always capture output so we can extract tsc errors for the summary
|
|
3673
|
-
const buildResult =
|
|
3753
|
+
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
3674
3754
|
if (!buildResult.success) {
|
|
3675
3755
|
const buildOutput = buildResult.stderr || buildResult.output;
|
|
3676
3756
|
if (buildOutput)
|
|
@@ -3837,7 +3917,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3837
3917
|
if (currentAccess === 'public') {
|
|
3838
3918
|
console.log(colors.yellow(`Package '${pkg.name}' is currently PUBLIC on npm. Converting to private...`));
|
|
3839
3919
|
if (!dryRun) {
|
|
3840
|
-
const accessResult =
|
|
3920
|
+
const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=restricted', pkg.name], { cwd, silent: false });
|
|
3841
3921
|
if (accessResult.success) {
|
|
3842
3922
|
console.log(colors.green(`✓ Changed ${pkg.name} to PRIVATE on npm`));
|
|
3843
3923
|
currentAccess = 'restricted';
|
|
@@ -3860,7 +3940,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3860
3940
|
if (currentAccess === 'restricted') {
|
|
3861
3941
|
console.log(colors.yellow(`Package '${pkg.name}' is currently PRIVATE on npm. Converting to public...`));
|
|
3862
3942
|
if (!dryRun) {
|
|
3863
|
-
const accessResult =
|
|
3943
|
+
const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=public', pkg.name], { cwd, silent: false });
|
|
3864
3944
|
if (accessResult.success) {
|
|
3865
3945
|
console.log(colors.green(`✓ Changed ${pkg.name} to PUBLIC on npm`));
|
|
3866
3946
|
currentAccess = 'public';
|
|
@@ -4278,7 +4358,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4278
4358
|
// Run npm audit if requested or if dependencies were transformed
|
|
4279
4359
|
if ((fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps)) {
|
|
4280
4360
|
if (!dryRun) {
|
|
4281
|
-
runNpmAudit(cwd, fix, verbose);
|
|
4361
|
+
await runNpmAudit(cwd, fix, verbose);
|
|
4282
4362
|
}
|
|
4283
4363
|
else {
|
|
4284
4364
|
console.log(' [dry-run] Would run npm audit');
|
|
@@ -4286,7 +4366,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4286
4366
|
}
|
|
4287
4367
|
else if (fix && !dryRun) {
|
|
4288
4368
|
// Run fix even if no deps changed
|
|
4289
|
-
runNpmAudit(cwd, fix, verbose);
|
|
4369
|
+
await runNpmAudit(cwd, fix, verbose);
|
|
4290
4370
|
}
|
|
4291
4371
|
if (noPublish) {
|
|
4292
4372
|
console.log('Transform complete (--nopublish mode).');
|
|
@@ -4309,7 +4389,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4309
4389
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
4310
4390
|
gitCommit('Restore file: dependencies', cwd);
|
|
4311
4391
|
if (currentGitStatus.hasRemote) {
|
|
4312
|
-
pushWithProtection(cwd, verbose);
|
|
4392
|
+
await pushWithProtection(cwd, verbose);
|
|
4313
4393
|
}
|
|
4314
4394
|
}
|
|
4315
4395
|
}
|
|
@@ -4367,7 +4447,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4367
4447
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
4368
4448
|
gitCommit('Restore file: dependencies', cwd);
|
|
4369
4449
|
if (currentGitStatus.hasRemote) {
|
|
4370
|
-
pushWithProtection(cwd, verbose);
|
|
4450
|
+
await pushWithProtection(cwd, verbose);
|
|
4371
4451
|
}
|
|
4372
4452
|
}
|
|
4373
4453
|
}
|
|
@@ -4429,7 +4509,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4429
4509
|
// Push any unpushed commits (e.g., from a previous failed push)
|
|
4430
4510
|
if (currentGitStatus.hasRemote && currentGitStatus.hasUnpushed && !dryRun) {
|
|
4431
4511
|
console.log(colors.yellow('Pushing unpushed commits...'));
|
|
4432
|
-
pushWithProtection(cwd, verbose);
|
|
4512
|
+
await pushWithProtection(cwd, verbose);
|
|
4433
4513
|
}
|
|
4434
4514
|
// If install/link flag is set, install globally
|
|
4435
4515
|
if (install || link || wsl) {
|
|
@@ -4445,7 +4525,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4445
4525
|
if (pkg.bin && (install || link || wsl)) {
|
|
4446
4526
|
if (link) {
|
|
4447
4527
|
console.log(`Installing ${pkgName} globally from local directory (link)...`);
|
|
4448
|
-
const localInstallResult =
|
|
4528
|
+
const localInstallResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4449
4529
|
if (localInstallResult.success) {
|
|
4450
4530
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
4451
4531
|
}
|
|
@@ -4460,7 +4540,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4460
4540
|
// sibling imports. Local install handles workspace linking correctly.
|
|
4461
4541
|
if (pkg.workspaces) {
|
|
4462
4542
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local (workspace)...`);
|
|
4463
|
-
const localResult =
|
|
4543
|
+
const localResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4464
4544
|
if (localResult.success) {
|
|
4465
4545
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
4466
4546
|
}
|
|
@@ -4479,7 +4559,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4479
4559
|
const vOnNpm = vCheck.status === 0 && vCheck.stdout?.trim() === pkgVersion;
|
|
4480
4560
|
if (vOnNpm) {
|
|
4481
4561
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from registry...`);
|
|
4482
|
-
const registryInstallResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
4562
|
+
const registryInstallResult = await installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
4483
4563
|
if (registryInstallResult.success) {
|
|
4484
4564
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
4485
4565
|
}
|
|
@@ -4499,7 +4579,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4499
4579
|
else {
|
|
4500
4580
|
console.log(colors.yellow(`${pkgName}@${pkgVersion} not found on npm — installing from local directory.`));
|
|
4501
4581
|
console.log(colors.dim(' Use -m "message" to publish this version to npm.'));
|
|
4502
|
-
const localResult =
|
|
4582
|
+
const localResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4503
4583
|
if (localResult.success) {
|
|
4504
4584
|
console.log(colors.green(`✓ Installed globally from local: ${pkgName}@${pkgVersion}`));
|
|
4505
4585
|
}
|
|
@@ -4552,7 +4632,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4552
4632
|
if (nulCount > 0 && verbose) {
|
|
4553
4633
|
console.log(` Removed ${nulCount} 'nul' file(s) (Windows reserved name)`);
|
|
4554
4634
|
}
|
|
4635
|
+
const addStart = Date.now();
|
|
4636
|
+
process.stdout.write(` git add -A ... `);
|
|
4555
4637
|
let addResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
4638
|
+
process.stdout.write(`done (${((Date.now() - addStart) / 1000).toFixed(1)}s)\n`);
|
|
4556
4639
|
if (!addResult.success) {
|
|
4557
4640
|
const errText = addResult.stderr + addResult.output;
|
|
4558
4641
|
const deniedFiles = parseDeniedFiles(errText);
|
|
@@ -4572,7 +4655,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4572
4655
|
}
|
|
4573
4656
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
4574
4657
|
console.log(colors.green('✓ Updated .gitignore'));
|
|
4658
|
+
const retryStart = Date.now();
|
|
4659
|
+
console.log(` ${timestamp()} git add -A (retry) ...`);
|
|
4575
4660
|
addResult = runCommand('git', ['add', '-A'], { cwd, silent: true });
|
|
4661
|
+
console.log(` ${timestamp()} git add -A done (${((Date.now() - retryStart) / 1000).toFixed(1)}s)`);
|
|
4576
4662
|
if (addResult.success) {
|
|
4577
4663
|
console.log(colors.green('✓ git add succeeded after updating .gitignore'));
|
|
4578
4664
|
}
|
|
@@ -4589,7 +4675,10 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4589
4675
|
console.log(colors.yellow('Continuing with --force...'));
|
|
4590
4676
|
}
|
|
4591
4677
|
}
|
|
4678
|
+
const commitStart = Date.now();
|
|
4679
|
+
console.log(` ${timestamp()} git commit ... (pre-commit hooks may run)`);
|
|
4592
4680
|
let commitResult = gitCommit(commitMsg, cwd);
|
|
4681
|
+
console.log(` ${timestamp()} git commit done (${((Date.now() - commitStart) / 1000).toFixed(1)}s)`);
|
|
4593
4682
|
if (!commitResult.success) {
|
|
4594
4683
|
// Check for corrupted git index ("invalid object" / "Error building trees")
|
|
4595
4684
|
const errText = commitResult.stderr + commitResult.output;
|
|
@@ -4614,7 +4703,15 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4614
4703
|
}
|
|
4615
4704
|
// Pull latest from remote before version bump to avoid push rejection
|
|
4616
4705
|
if (currentGitStatus.hasRemote && !dryRun) {
|
|
4617
|
-
const
|
|
4706
|
+
const pullStart = Date.now();
|
|
4707
|
+
console.log(` ${timestamp()} git pull --rebase origin ${currentGitStatus.currentBranch} ...`);
|
|
4708
|
+
const heartbeat = setInterval(() => {
|
|
4709
|
+
const elapsed = ((Date.now() - pullStart) / 1000).toFixed(0);
|
|
4710
|
+
console.log(` ${timestamp()} ... still pulling (${elapsed}s elapsed)`);
|
|
4711
|
+
}, 10000);
|
|
4712
|
+
const pullResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd, silent: true });
|
|
4713
|
+
clearInterval(heartbeat);
|
|
4714
|
+
console.log(` ${timestamp()} git pull done (${((Date.now() - pullStart) / 1000).toFixed(1)}s)`);
|
|
4618
4715
|
if (!pullResult.success) {
|
|
4619
4716
|
console.error(colors.yellow('Warning: git pull --rebase failed before version bump'));
|
|
4620
4717
|
if (verbose) {
|
|
@@ -4715,12 +4812,12 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4715
4812
|
// Version bump + tag succeeded locally; only the push failed.
|
|
4716
4813
|
// Auto-pull --rebase and retry the push.
|
|
4717
4814
|
console.log(colors.yellow('\nLocal branch is behind remote — pulling with rebase...'));
|
|
4718
|
-
const pullResult =
|
|
4815
|
+
const pullResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd });
|
|
4719
4816
|
if (pullResult.success) {
|
|
4720
4817
|
console.log(colors.green(' ✓ Rebased onto remote'));
|
|
4721
|
-
const pushResult =
|
|
4818
|
+
const pushResult = await runCommandAsync('git', ['push'], { cwd });
|
|
4722
4819
|
if (pushResult.success) {
|
|
4723
|
-
const tagPush =
|
|
4820
|
+
const tagPush = await runCommandAsync('git', ['push', '--tags'], { cwd, silent: true });
|
|
4724
4821
|
if (tagPush.success) {
|
|
4725
4822
|
console.log(colors.green(' ✓ Pushed with tags'));
|
|
4726
4823
|
}
|
|
@@ -4995,11 +5092,11 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4995
5092
|
// broadcast to the console group (e.g. from another tool sharing the
|
|
4996
5093
|
// console) makes cmd.exe print "Terminate batch job (Y/N)?" and kill
|
|
4997
5094
|
// npm.cmd. Our process survives, so a retry usually succeeds.
|
|
4998
|
-
let packResult =
|
|
5095
|
+
let packResult = await runCommandAsync('npm', ['pack'], { cwd, silent: true });
|
|
4999
5096
|
if (!packResult.success && /Terminate batch job|\^C/.test(packResult.output + packResult.stderr)) {
|
|
5000
5097
|
const logPath = dumpPackCtrlcDiagnostics(pkg, cwd, packResult.output, packResult.stderr);
|
|
5001
5098
|
console.error(colors.yellow(` npm pack interrupted by spurious Ctrl+C — retrying once... (diag: ${logPath})`));
|
|
5002
|
-
packResult =
|
|
5099
|
+
packResult = await runCommandAsync('npm', ['pack'], { cwd, silent: true });
|
|
5003
5100
|
}
|
|
5004
5101
|
// Restore stashed node_modules now that pack is done — must happen
|
|
5005
5102
|
// before any subsequent install -g symlinks to these dep targets.
|
|
@@ -5035,7 +5132,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5035
5132
|
if (sizeMB > 50) {
|
|
5036
5133
|
console.error(colors.red(`\n⚠ Tarball is ${sizeMB.toFixed(0)}MB — something large is being included!`));
|
|
5037
5134
|
// Show biggest files in the tarball
|
|
5038
|
-
const listResult =
|
|
5135
|
+
const listResult = await runCommandAsync('npm', ['pack', '--dry-run'], { cwd, silent: true });
|
|
5039
5136
|
if (listResult.success) {
|
|
5040
5137
|
const lines = listResult.output.trim().split('\n')
|
|
5041
5138
|
.filter(l => l.includes('B '))
|
|
@@ -5084,7 +5181,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5084
5181
|
console.log(colors.yellow(`⏱ Waiting ${retryDelay} seconds before retry (attempt ${attempt + 1}/${maxRetries})...`));
|
|
5085
5182
|
await new Promise(resolve => setTimeout(resolve, retryDelay * 1000));
|
|
5086
5183
|
}
|
|
5087
|
-
publishResult =
|
|
5184
|
+
publishResult = await runCommandAsync('npm', npmArgs, { cwd, silent: true });
|
|
5088
5185
|
if (publishResult.success) {
|
|
5089
5186
|
break; // Success!
|
|
5090
5187
|
}
|
|
@@ -5202,7 +5299,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5202
5299
|
if (logResult.success) {
|
|
5203
5300
|
console.log(colors.green(` ✓ Appended to npmchanges.md and removed .commitmsg`));
|
|
5204
5301
|
if (currentGitStatus.hasRemote)
|
|
5205
|
-
pushWithProtection(cwd, verbose);
|
|
5302
|
+
await pushWithProtection(cwd, verbose);
|
|
5206
5303
|
}
|
|
5207
5304
|
}
|
|
5208
5305
|
catch (err) {
|
|
@@ -5219,8 +5316,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5219
5316
|
console.log(`${timestamp()} Pushing to git...`);
|
|
5220
5317
|
}
|
|
5221
5318
|
if (!dryRun) {
|
|
5222
|
-
if (pushWithProtection(cwd, verbose)) {
|
|
5223
|
-
const tagResult =
|
|
5319
|
+
if (await pushWithProtection(cwd, verbose)) {
|
|
5320
|
+
const tagResult = await runCommandAsync('git', ['push', '--tags'], { cwd, silent: true });
|
|
5224
5321
|
if (verbose && tagResult.success)
|
|
5225
5322
|
console.log(colors.green(' ✓ Pushed tags'));
|
|
5226
5323
|
}
|
|
@@ -5242,7 +5339,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5242
5339
|
if (link) {
|
|
5243
5340
|
console.log(`Linking globally: ${pkgName}@${pkgVersion}...`);
|
|
5244
5341
|
if (!dryRun) {
|
|
5245
|
-
const installResult =
|
|
5342
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
5246
5343
|
if (installResult.success) {
|
|
5247
5344
|
globalInstallOk = true;
|
|
5248
5345
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5262,7 +5359,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5262
5359
|
// Workspace packages: install from local for proper workspace linking
|
|
5263
5360
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local (workspace)...`);
|
|
5264
5361
|
if (!dryRun) {
|
|
5265
|
-
const installResult =
|
|
5362
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
5266
5363
|
if (installResult.success) {
|
|
5267
5364
|
globalInstallOk = true;
|
|
5268
5365
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5281,7 +5378,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5281
5378
|
console.log(`${timestamp()} Installing globally from registry: ${pkgName}@${pkgVersion}...`);
|
|
5282
5379
|
if (!dryRun) {
|
|
5283
5380
|
waitForNpmVersion(pkgName, pkgVersion, wasNewPackage);
|
|
5284
|
-
const installResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd, wasNewPackage);
|
|
5381
|
+
const installResult = await installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd, wasNewPackage);
|
|
5285
5382
|
if (installResult.success) {
|
|
5286
5383
|
globalInstallOk = true;
|
|
5287
5384
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5313,7 +5410,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5313
5410
|
waitForNpmVersion(pkgName, pkgVersion, wasNewPackage);
|
|
5314
5411
|
console.log(`Installing in WSL${useLocalWsl ? ' (local)' : ' from registry'}: ${pkgName}@${pkgVersion}...`);
|
|
5315
5412
|
if (!dryRun) {
|
|
5316
|
-
const wslResult = installInWsl(wslArgs, { cwd });
|
|
5413
|
+
const wslResult = await installInWsl(wslArgs, { cwd });
|
|
5317
5414
|
if (wslResult.success) {
|
|
5318
5415
|
wslInstallOk = true;
|
|
5319
5416
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
@@ -5353,7 +5450,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5353
5450
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
5354
5451
|
gitCommit('Restore file: dependencies', cwd);
|
|
5355
5452
|
if (currentGitStatus.hasRemote) {
|
|
5356
|
-
pushWithProtection(cwd, verbose);
|
|
5453
|
+
await pushWithProtection(cwd, verbose);
|
|
5357
5454
|
}
|
|
5358
5455
|
}
|
|
5359
5456
|
}
|
|
@@ -5364,7 +5461,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5364
5461
|
// Run final audit report if not already run
|
|
5365
5462
|
const auditAlreadyRun = (fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps);
|
|
5366
5463
|
if (!auditAlreadyRun && (fix || updateDeps || transformResult.transformed) && !dryRun) {
|
|
5367
|
-
runNpmAudit(cwd, false, verbose); // Just report, don't fix again
|
|
5464
|
+
await runNpmAudit(cwd, false, verbose); // Just report, don't fix again
|
|
5368
5465
|
}
|
|
5369
5466
|
// Print summary
|
|
5370
5467
|
console.log('');
|
|
@@ -5627,7 +5724,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5627
5724
|
// the case where a dep was added to a member package.json but `npm install`
|
|
5628
5725
|
// wasn't re-run — the builds would otherwise fail resolving the new dep.
|
|
5629
5726
|
if (!options.dryRun) {
|
|
5630
|
-
ensureWorkspaceDepModules(rootDir, packages.map(p => ({ dir: p.dir, pkg: p.pkg })), !!options.verbose);
|
|
5727
|
+
await ensureWorkspaceDepModules(rootDir, packages.map(p => ({ dir: p.dir, pkg: p.pkg })), !!options.verbose);
|
|
5631
5728
|
}
|
|
5632
5729
|
// Prescan: decide which packages actually need processing so we don't waste
|
|
5633
5730
|
// time rebuilding+republishing ones with no relevant changes.
|
|
@@ -5821,7 +5918,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5821
5918
|
// Workspace root is private — always install from local directory
|
|
5822
5919
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local directory...`);
|
|
5823
5920
|
if (!dryRun) {
|
|
5824
|
-
const installResult =
|
|
5921
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd: rootDir, silent: false, showCommand: true });
|
|
5825
5922
|
if (installResult.success) {
|
|
5826
5923
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
5827
5924
|
}
|
|
@@ -5838,7 +5935,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5838
5935
|
if (wsl) {
|
|
5839
5936
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
5840
5937
|
if (!dryRun) {
|
|
5841
|
-
const wslResult = installInWsl(['npm', 'install', '-g', '.'], { cwd: rootDir });
|
|
5938
|
+
const wslResult = await installInWsl(['npm', 'install', '-g', '.'], { cwd: rootDir });
|
|
5842
5939
|
if (wslResult.success) {
|
|
5843
5940
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
5844
5941
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.176",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@bobfrankston/mailx": "^1.0.466",
|
|
37
37
|
"@bobfrankston/npmglobalize": "^1.0.153",
|
|
38
38
|
"@bobfrankston/themecolors": "^0.1.6",
|
|
39
|
-
"@bobfrankston/userconfig": "^1.0.
|
|
39
|
+
"@bobfrankston/userconfig": "^1.0.9",
|
|
40
40
|
"@npmcli/package-json": "^7.0.4",
|
|
41
41
|
"json5": "^2.2.3",
|
|
42
42
|
"libnpmversion": "^8.0.3",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@bobfrankston/mailx": "^1.0.466",
|
|
69
69
|
"@bobfrankston/npmglobalize": "^1.0.153",
|
|
70
70
|
"@bobfrankston/themecolors": "^0.1.6",
|
|
71
|
-
"@bobfrankston/userconfig": "^1.0.
|
|
71
|
+
"@bobfrankston/userconfig": "^1.0.9",
|
|
72
72
|
"@npmcli/package-json": "^7.0.4",
|
|
73
73
|
"json5": "^2.2.3",
|
|
74
74
|
"libnpmversion": "^8.0.3",
|