@bobfrankston/npmglobalize 1.0.173 → 1.0.175
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 +163 -67
- package/package.json +4 -1
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() {
|
|
@@ -410,7 +433,22 @@ export function installCleanupHandlers() {
|
|
|
410
433
|
return;
|
|
411
434
|
cleanupHandlersInstalled = true;
|
|
412
435
|
process.on('exit', emergencyRestoreDeps);
|
|
436
|
+
// Idempotent abort: first ^C prints an immediate ack so the user doesn't
|
|
437
|
+
// press again and accidentally kill the process mid-restore. Subsequent
|
|
438
|
+
// signals while already aborting are absorbed (with a brief reminder).
|
|
439
|
+
let aborting = false;
|
|
413
440
|
const signalHandler = (signal) => {
|
|
441
|
+
if (aborting) {
|
|
442
|
+
console.error(colors.yellow(' ...still aborting, please wait'));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
aborting = true;
|
|
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();
|
|
414
452
|
emergencyRestoreDeps();
|
|
415
453
|
process.exit(128 + (signal === 'SIGINT' ? 2 : signal === 'SIGTERM' ? 15 : 1));
|
|
416
454
|
};
|
|
@@ -418,11 +456,17 @@ export function installCleanupHandlers() {
|
|
|
418
456
|
process.on('SIGTERM', signalHandler);
|
|
419
457
|
process.on('SIGHUP', signalHandler);
|
|
420
458
|
process.on('uncaughtException', (err) => {
|
|
459
|
+
if (aborting)
|
|
460
|
+
return;
|
|
461
|
+
aborting = true;
|
|
421
462
|
console.error(colors.red('\nUncaught exception:'), err);
|
|
422
463
|
emergencyRestoreDeps();
|
|
423
464
|
process.exit(1);
|
|
424
465
|
});
|
|
425
466
|
process.on('unhandledRejection', (reason) => {
|
|
467
|
+
if (aborting)
|
|
468
|
+
return;
|
|
469
|
+
aborting = true;
|
|
426
470
|
console.error(colors.red('\nUnhandled rejection:'), reason);
|
|
427
471
|
emergencyRestoreDeps();
|
|
428
472
|
process.exit(1);
|
|
@@ -645,7 +689,7 @@ export async function cascadePublicVisibility(cwd, opts = {}) {
|
|
|
645
689
|
const access = checkNpmAccess(targetName);
|
|
646
690
|
if (access === 'restricted') {
|
|
647
691
|
if (!dryRun) {
|
|
648
|
-
const r =
|
|
692
|
+
const r = await runCommandAsync('npm', ['access', 'set', 'status=public', targetName], { cwd: targetPath, silent: true });
|
|
649
693
|
if (r.success) {
|
|
650
694
|
promoted.push(targetName);
|
|
651
695
|
console.log(colors.green(` ✓ Flipped ${targetName} to PUBLIC on npm`));
|
|
@@ -1608,7 +1652,7 @@ function formatMissingReason(missing) {
|
|
|
1608
1652
|
* "fresh clone, no `node_modules/`" and "dep added but `npm install` not
|
|
1609
1653
|
* re-run" (partial-sync) cases. Also covers `cwd` itself on the first call.
|
|
1610
1654
|
* Cycle-safe via the shared `visited` set. */
|
|
1611
|
-
export function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
|
|
1655
|
+
export async function ensureFileDepModules(cwd, verbose = false, visited = new Set()) {
|
|
1612
1656
|
const abs = path.resolve(cwd);
|
|
1613
1657
|
if (visited.has(abs))
|
|
1614
1658
|
return;
|
|
@@ -1635,7 +1679,7 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1635
1679
|
catch { /* best-effort */ }
|
|
1636
1680
|
}
|
|
1637
1681
|
console.log(colors.yellow(`↻ installing node_modules in ${pkg?.name || abs} (${formatMissingReason(cwdMissing)})`));
|
|
1638
|
-
const r =
|
|
1682
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: abs, silent: !verbose });
|
|
1639
1683
|
if (!r.success) {
|
|
1640
1684
|
console.error(colors.red(` ✗ npm install failed in ${abs}`));
|
|
1641
1685
|
if (r.stderr)
|
|
@@ -1672,14 +1716,14 @@ export function ensureFileDepModules(cwd, verbose = false, visited = new Set())
|
|
|
1672
1716
|
catch { /* best-effort */ }
|
|
1673
1717
|
}
|
|
1674
1718
|
console.log(colors.yellow(`↻ restoring node_modules in ${name} (${target}) (${formatMissingReason(targetMissing)})`));
|
|
1675
|
-
const r =
|
|
1719
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: target, silent: !verbose });
|
|
1676
1720
|
if (!r.success) {
|
|
1677
1721
|
console.error(colors.red(` ✗ npm install failed in ${target}`));
|
|
1678
1722
|
if (r.stderr)
|
|
1679
1723
|
console.error(colors.dim(r.stderr.split('\n').slice(0, 5).join('\n')));
|
|
1680
1724
|
}
|
|
1681
1725
|
}
|
|
1682
|
-
ensureFileDepModules(target, verbose, visited);
|
|
1726
|
+
await ensureFileDepModules(target, verbose, visited);
|
|
1683
1727
|
}
|
|
1684
1728
|
}
|
|
1685
1729
|
}
|
|
@@ -1716,7 +1760,7 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
1716
1760
|
}
|
|
1717
1761
|
}
|
|
1718
1762
|
console.log(`Building ${pkg.name || cwd}...`);
|
|
1719
|
-
const buildResult =
|
|
1763
|
+
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
1720
1764
|
if (buildResult.success) {
|
|
1721
1765
|
console.log(colors.green(`✓ Build succeeded (${pkg.name || path.basename(cwd)})`));
|
|
1722
1766
|
return true;
|
|
@@ -1780,7 +1824,7 @@ export async function buildFileDepsTopologically(cwd, opts = {}, visited = new S
|
|
|
1780
1824
|
* member `package.json` without a follow-up `npm install` at the root leaves
|
|
1781
1825
|
* the root `node_modules/` stale — the case where `member/` dirs exist but
|
|
1782
1826
|
* the actual package (e.g. `marked`) is not hoisted. */
|
|
1783
|
-
export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
1827
|
+
export async function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
1784
1828
|
const root = path.resolve(rootDir);
|
|
1785
1829
|
let rootPkg;
|
|
1786
1830
|
try {
|
|
@@ -1800,7 +1844,7 @@ export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
|
1800
1844
|
return;
|
|
1801
1845
|
const list = [...allMissing];
|
|
1802
1846
|
console.log(colors.yellow(`↻ installing workspace node_modules in ${rootPkg?.name || path.basename(root)} (${formatMissingReason(list)})`));
|
|
1803
|
-
const r =
|
|
1847
|
+
const r = await runCommandAsync('npm', ['install'], { cwd: root, silent: !verbose });
|
|
1804
1848
|
if (!r.success) {
|
|
1805
1849
|
console.error(colors.red(` ✗ npm install failed in ${root}`));
|
|
1806
1850
|
if (r.stderr)
|
|
@@ -1811,14 +1855,14 @@ export function ensureWorkspaceDepModules(rootDir, members, verbose = false) {
|
|
|
1811
1855
|
* Brand-new packages (first-time publish) take much longer to become
|
|
1812
1856
|
* installable than version bumps, so we use longer waits and more
|
|
1813
1857
|
* attempts when `isNewPackage` is true. */
|
|
1814
|
-
function installGlobalWithRetry(pkgSpec, cwd, isNewPackage = false, maxRetries) {
|
|
1858
|
+
async function installGlobalWithRetry(pkgSpec, cwd, isNewPackage = false, maxRetries) {
|
|
1815
1859
|
const retries = maxRetries ?? (isNewPackage ? 6 : 3);
|
|
1816
1860
|
const delaySec = isNewPackage ? 30 : 10;
|
|
1817
|
-
let result =
|
|
1861
|
+
let result = await runCommandAsync('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
1818
1862
|
for (let attempt = 1; attempt < retries && !result.success; attempt++) {
|
|
1819
1863
|
console.log(colors.yellow(` Retrying install (attempt ${attempt + 1}/${retries}) in ${delaySec} seconds...`));
|
|
1820
1864
|
sleepSync(delaySec * 1000);
|
|
1821
|
-
result =
|
|
1865
|
+
result = await runCommandAsync('npm', ['install', '-g', pkgSpec], { cwd, silent: false, showCommand: true });
|
|
1822
1866
|
}
|
|
1823
1867
|
return result;
|
|
1824
1868
|
}
|
|
@@ -1860,6 +1904,58 @@ export function runCommand(cmd, args, options = {}) {
|
|
|
1860
1904
|
return { success: false, output: '', stderr: error.message };
|
|
1861
1905
|
}
|
|
1862
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
|
+
}
|
|
1863
1959
|
/** Dump forensic info to a temp file when `npm pack` is killed by a spurious
|
|
1864
1960
|
* Ctrl+C. Goal: correlate the failure with whatever else was attached to the
|
|
1865
1961
|
* console (Claude Code wrapper, VS Code task, AV, etc.). Returns the log path. */
|
|
@@ -1902,9 +1998,9 @@ function dumpPackCtrlcDiagnostics(pkg, cwd, packOutput, packStderr) {
|
|
|
1902
1998
|
/** Install a package globally in WSL, auto-fixing the root-owned /usr/local/lib/node_modules
|
|
1903
1999
|
* EACCES case by switching npm to a user prefix (~/.npm-global) and retrying once.
|
|
1904
2000
|
* Output is captured (so we can scan for the error) and then mirrored to the terminal. */
|
|
1905
|
-
export function installInWsl(wslArgs, opts = {}) {
|
|
2001
|
+
export async function installInWsl(wslArgs, opts = {}) {
|
|
1906
2002
|
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1907
|
-
let result =
|
|
2003
|
+
let result = await runCommandAsync('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1908
2004
|
if (result.output)
|
|
1909
2005
|
process.stdout.write(result.output);
|
|
1910
2006
|
if (result.stderr)
|
|
@@ -1917,7 +2013,7 @@ export function installInWsl(wslArgs, opts = {}) {
|
|
|
1917
2013
|
return { success: false, fixed: false };
|
|
1918
2014
|
console.log(colors.yellow('Detected root-owned npm prefix in WSL — switching to ~/.npm-global and retrying...'));
|
|
1919
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`;
|
|
1920
|
-
const fixResult =
|
|
2016
|
+
const fixResult = await runCommandAsync('wsl', ['bash', '-lc', fix], { silent: true });
|
|
1921
2017
|
if (!fixResult.success) {
|
|
1922
2018
|
console.error(colors.red('Failed to apply WSL npm prefix fix:'));
|
|
1923
2019
|
if (fixResult.stderr)
|
|
@@ -1926,7 +2022,7 @@ export function installInWsl(wslArgs, opts = {}) {
|
|
|
1926
2022
|
}
|
|
1927
2023
|
console.log(colors.green('✓ WSL npm prefix set to ~/.npm-global; PATH appended to ~/.bashrc'));
|
|
1928
2024
|
console.log(colors.cyan(`> wsl ${wslArgs.join(' ')}`));
|
|
1929
|
-
result =
|
|
2025
|
+
result = await runCommandAsync('wsl', wslArgs, { cwd: opts.cwd, silent: true });
|
|
1930
2026
|
if (result.output)
|
|
1931
2027
|
process.stdout.write(result.output);
|
|
1932
2028
|
if (result.stderr)
|
|
@@ -2531,11 +2627,11 @@ function parsePushProtection(errorOutput, cwd) {
|
|
|
2531
2627
|
}
|
|
2532
2628
|
/** Try to auto-bypass push protection for installed OAuth secrets via gh API.
|
|
2533
2629
|
* Returns true if all bypasses succeeded and push should be retried. */
|
|
2534
|
-
function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
2630
|
+
async function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
2535
2631
|
if (!ppInfo.allInstalledOAuth || ppInfo.secrets.length === 0)
|
|
2536
2632
|
return false;
|
|
2537
2633
|
// Check if gh CLI is available
|
|
2538
|
-
const ghCheck =
|
|
2634
|
+
const ghCheck = await runCommandAsync('gh', ['auth', 'status'], { cwd, silent: true });
|
|
2539
2635
|
if (!ghCheck.success)
|
|
2540
2636
|
return false;
|
|
2541
2637
|
// Extract repo owner/name from unblock URLs or git remote
|
|
@@ -2565,7 +2661,7 @@ function tryAutoBypassPushProtection(ppInfo, cwd) {
|
|
|
2565
2661
|
}
|
|
2566
2662
|
const placeholderId = idMatch[1];
|
|
2567
2663
|
console.log(colors.cyan(` Bypassing push protection for: ${s.type} (false_positive — installed app ID)...`));
|
|
2568
|
-
const bypassResult =
|
|
2664
|
+
const bypassResult = await runCommandAsync('gh', [
|
|
2569
2665
|
'api', `repos/${repo}/secret-scanning/push-protection-bypasses`,
|
|
2570
2666
|
'-X', 'POST',
|
|
2571
2667
|
'-f', 'reason=false_positive',
|
|
@@ -2603,8 +2699,8 @@ function showPushProtectionGuidance(ppInfo) {
|
|
|
2603
2699
|
}
|
|
2604
2700
|
/** Push to git with push-protection detection and auto-bypass for installed OAuth.
|
|
2605
2701
|
* Returns true if push succeeded (possibly after auto-bypass). */
|
|
2606
|
-
function pushWithProtection(cwd, verbose) {
|
|
2607
|
-
let pushResult =
|
|
2702
|
+
async function pushWithProtection(cwd, verbose) {
|
|
2703
|
+
let pushResult = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2608
2704
|
if (pushResult.success) {
|
|
2609
2705
|
if (verbose)
|
|
2610
2706
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
@@ -2625,7 +2721,7 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2625
2721
|
// Detect current branch name
|
|
2626
2722
|
const branchResult = runCommand('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, silent: true });
|
|
2627
2723
|
const branch = branchResult.output.trim() || 'master';
|
|
2628
|
-
pushResult =
|
|
2724
|
+
pushResult = await runCommandAsync('git', ['push', '--set-upstream', 'origin', branch], { cwd, silent: true });
|
|
2629
2725
|
if (pushResult.success) {
|
|
2630
2726
|
if (verbose)
|
|
2631
2727
|
console.log(colors.green(' ✓ Pushed to remote (set upstream)'));
|
|
@@ -2635,7 +2731,7 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2635
2731
|
// Transient network errors (HTTP 408, RPC failed, unexpected disconnect) — retry once
|
|
2636
2732
|
if (/rpc failed|curl \d+|unexpected disconnect|hung up unexpectedly/i.test(pushResult.stderr)) {
|
|
2637
2733
|
console.log(colors.yellow('Git push failed with transient error — retrying...'));
|
|
2638
|
-
pushResult =
|
|
2734
|
+
pushResult = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2639
2735
|
if (pushResult.success) {
|
|
2640
2736
|
if (verbose)
|
|
2641
2737
|
console.log(colors.green(' ✓ Pushed to remote (retry)'));
|
|
@@ -2656,9 +2752,9 @@ function pushWithProtection(cwd, verbose) {
|
|
|
2656
2752
|
return false;
|
|
2657
2753
|
}
|
|
2658
2754
|
// Try auto-bypass for installed OAuth credentials
|
|
2659
|
-
if (ppInfo.allInstalledOAuth && tryAutoBypassPushProtection(ppInfo, cwd)) {
|
|
2755
|
+
if (ppInfo.allInstalledOAuth && await tryAutoBypassPushProtection(ppInfo, cwd)) {
|
|
2660
2756
|
console.log(colors.green(' ✓ Auto-bypassed push protection (installed OAuth — not a real secret)'));
|
|
2661
|
-
const retryPush =
|
|
2757
|
+
const retryPush = await runCommandAsync('git', ['push'], { cwd, silent: true });
|
|
2662
2758
|
if (retryPush.success) {
|
|
2663
2759
|
if (verbose)
|
|
2664
2760
|
console.log(colors.green(' ✓ Pushed to remote'));
|
|
@@ -3049,7 +3145,7 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3049
3145
|
}
|
|
3050
3146
|
// Create GitHub repo (or link to existing one)
|
|
3051
3147
|
const visFlag = visibility === 'private' ? '--private' : '--public';
|
|
3052
|
-
const createResult =
|
|
3148
|
+
const createResult = await runCommandAsync('gh', ['repo', 'create', repoName, visFlag, '--source=.', '--push'], { cwd, silent: true });
|
|
3053
3149
|
if (!createResult.success) {
|
|
3054
3150
|
const errText = createResult.stderr + createResult.output;
|
|
3055
3151
|
// Check if repo was created but push failed (GitHub propagation delay)
|
|
@@ -3082,7 +3178,7 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3082
3178
|
console.log(colors.yellow(' Retrying push...'));
|
|
3083
3179
|
spawnSafe(process.platform === 'win32' ? 'timeout' : 'sleep', process.platform === 'win32' ? ['\t', '3', '\nobreak'] : ['3'], { stdio: 'pipe' }); // brief delay for GitHub propagation
|
|
3084
3180
|
}
|
|
3085
|
-
const pushRes =
|
|
3181
|
+
const pushRes = await runCommandAsync('git', ['push', '-u', 'origin', 'master'], { cwd, silent: true });
|
|
3086
3182
|
pushed = pushRes.success;
|
|
3087
3183
|
}
|
|
3088
3184
|
if (pushed) {
|
|
@@ -3114,9 +3210,9 @@ export async function initGit(cwd, visibility, dryRun, allowTs) {
|
|
|
3114
3210
|
}
|
|
3115
3211
|
/** Main globalize function */
|
|
3116
3212
|
/** Run npm audit and optionally fix vulnerabilities */
|
|
3117
|
-
export function runNpmAudit(cwd, fix = false, verbose = false) {
|
|
3213
|
+
export async function runNpmAudit(cwd, fix = false, verbose = false) {
|
|
3118
3214
|
if (fix) {
|
|
3119
|
-
|
|
3215
|
+
await runCommandAsync('npm', ['audit', 'fix'], { cwd, silent: true });
|
|
3120
3216
|
}
|
|
3121
3217
|
// Check remaining vulnerabilities
|
|
3122
3218
|
const auditResult = spawnSafe('npm', ['audit', '--json'], {
|
|
@@ -3191,7 +3287,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
3191
3287
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
3192
3288
|
return true;
|
|
3193
3289
|
}
|
|
3194
|
-
const result =
|
|
3290
|
+
const result = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3195
3291
|
if (result.success) {
|
|
3196
3292
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
3197
3293
|
}
|
|
@@ -3202,7 +3298,7 @@ async function doLocalInstall(cwd, options) {
|
|
|
3202
3298
|
}
|
|
3203
3299
|
if (wsl) {
|
|
3204
3300
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
3205
|
-
const wslResult =
|
|
3301
|
+
const wslResult = await runCommandAsync('wsl', ['npm', 'install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3206
3302
|
if (wslResult.success) {
|
|
3207
3303
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}`));
|
|
3208
3304
|
}
|
|
@@ -3307,7 +3403,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3307
3403
|
console.log(' [dry-run] Would run: wsl npm install -g .');
|
|
3308
3404
|
return true;
|
|
3309
3405
|
}
|
|
3310
|
-
const result =
|
|
3406
|
+
const result = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
3311
3407
|
if (result.success) {
|
|
3312
3408
|
console.log(colors.green(`✓ Installed locally: ${pkgName}@${pkgVersion}`));
|
|
3313
3409
|
}
|
|
@@ -3525,7 +3621,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3525
3621
|
}
|
|
3526
3622
|
else {
|
|
3527
3623
|
console.log(`Changing GitHub repo visibility to ${targetVis}...`);
|
|
3528
|
-
const visResult =
|
|
3624
|
+
const visResult = await runCommandAsync('gh', ['repo', 'edit', '--visibility', targetVis, '--accept-visibility-change-consequences'], { cwd, silent: true });
|
|
3529
3625
|
if (visResult.success) {
|
|
3530
3626
|
console.log(colors.green(`✓ GitHub repo is now ${targetVis.toUpperCase()}`));
|
|
3531
3627
|
}
|
|
@@ -3609,7 +3705,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3609
3705
|
console.log(colors.yellow('Local branch is behind remote.'));
|
|
3610
3706
|
if (rebase) {
|
|
3611
3707
|
console.log('Rebasing local changes (--rebase)...');
|
|
3612
|
-
const rebaseResult =
|
|
3708
|
+
const rebaseResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd, silent: false });
|
|
3613
3709
|
if (!rebaseResult.success) {
|
|
3614
3710
|
console.error(colors.red('ERROR: Rebase failed.'));
|
|
3615
3711
|
console.error('You may need to resolve conflicts manually.');
|
|
@@ -3643,7 +3739,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3643
3739
|
// with new declared deps still needs its own `npm install` even if it has
|
|
3644
3740
|
// no build step. CLI entrypoint already ran this, so skip when _fromCli.
|
|
3645
3741
|
if (!options._fromCli && !dryRun)
|
|
3646
|
-
ensureFileDepModules(cwd, verbose);
|
|
3742
|
+
await ensureFileDepModules(cwd, verbose);
|
|
3647
3743
|
// Run build step if package.json has a build script (skip if CLI already built)
|
|
3648
3744
|
if (pkg.scripts?.build && !options._fromCli) {
|
|
3649
3745
|
console.log(`${timestamp()} Running build...`);
|
|
@@ -3654,7 +3750,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3654
3750
|
const restoreWorkspaces = reorderWorkspacesForBuild(cwd, pkg, verbose);
|
|
3655
3751
|
try {
|
|
3656
3752
|
// Always capture output so we can extract tsc errors for the summary
|
|
3657
|
-
const buildResult =
|
|
3753
|
+
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
3658
3754
|
if (!buildResult.success) {
|
|
3659
3755
|
const buildOutput = buildResult.stderr || buildResult.output;
|
|
3660
3756
|
if (buildOutput)
|
|
@@ -3821,7 +3917,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3821
3917
|
if (currentAccess === 'public') {
|
|
3822
3918
|
console.log(colors.yellow(`Package '${pkg.name}' is currently PUBLIC on npm. Converting to private...`));
|
|
3823
3919
|
if (!dryRun) {
|
|
3824
|
-
const accessResult =
|
|
3920
|
+
const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=restricted', pkg.name], { cwd, silent: false });
|
|
3825
3921
|
if (accessResult.success) {
|
|
3826
3922
|
console.log(colors.green(`✓ Changed ${pkg.name} to PRIVATE on npm`));
|
|
3827
3923
|
currentAccess = 'restricted';
|
|
@@ -3844,7 +3940,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
3844
3940
|
if (currentAccess === 'restricted') {
|
|
3845
3941
|
console.log(colors.yellow(`Package '${pkg.name}' is currently PRIVATE on npm. Converting to public...`));
|
|
3846
3942
|
if (!dryRun) {
|
|
3847
|
-
const accessResult =
|
|
3943
|
+
const accessResult = await runCommandAsync('npm', ['access', 'set', 'status=public', pkg.name], { cwd, silent: false });
|
|
3848
3944
|
if (accessResult.success) {
|
|
3849
3945
|
console.log(colors.green(`✓ Changed ${pkg.name} to PUBLIC on npm`));
|
|
3850
3946
|
currentAccess = 'public';
|
|
@@ -4262,7 +4358,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4262
4358
|
// Run npm audit if requested or if dependencies were transformed
|
|
4263
4359
|
if ((fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps)) {
|
|
4264
4360
|
if (!dryRun) {
|
|
4265
|
-
runNpmAudit(cwd, fix, verbose);
|
|
4361
|
+
await runNpmAudit(cwd, fix, verbose);
|
|
4266
4362
|
}
|
|
4267
4363
|
else {
|
|
4268
4364
|
console.log(' [dry-run] Would run npm audit');
|
|
@@ -4270,7 +4366,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4270
4366
|
}
|
|
4271
4367
|
else if (fix && !dryRun) {
|
|
4272
4368
|
// Run fix even if no deps changed
|
|
4273
|
-
runNpmAudit(cwd, fix, verbose);
|
|
4369
|
+
await runNpmAudit(cwd, fix, verbose);
|
|
4274
4370
|
}
|
|
4275
4371
|
if (noPublish) {
|
|
4276
4372
|
console.log('Transform complete (--nopublish mode).');
|
|
@@ -4293,7 +4389,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4293
4389
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
4294
4390
|
gitCommit('Restore file: dependencies', cwd);
|
|
4295
4391
|
if (currentGitStatus.hasRemote) {
|
|
4296
|
-
pushWithProtection(cwd, verbose);
|
|
4392
|
+
await pushWithProtection(cwd, verbose);
|
|
4297
4393
|
}
|
|
4298
4394
|
}
|
|
4299
4395
|
}
|
|
@@ -4351,7 +4447,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4351
4447
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
4352
4448
|
gitCommit('Restore file: dependencies', cwd);
|
|
4353
4449
|
if (currentGitStatus.hasRemote) {
|
|
4354
|
-
pushWithProtection(cwd, verbose);
|
|
4450
|
+
await pushWithProtection(cwd, verbose);
|
|
4355
4451
|
}
|
|
4356
4452
|
}
|
|
4357
4453
|
}
|
|
@@ -4413,7 +4509,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4413
4509
|
// Push any unpushed commits (e.g., from a previous failed push)
|
|
4414
4510
|
if (currentGitStatus.hasRemote && currentGitStatus.hasUnpushed && !dryRun) {
|
|
4415
4511
|
console.log(colors.yellow('Pushing unpushed commits...'));
|
|
4416
|
-
pushWithProtection(cwd, verbose);
|
|
4512
|
+
await pushWithProtection(cwd, verbose);
|
|
4417
4513
|
}
|
|
4418
4514
|
// If install/link flag is set, install globally
|
|
4419
4515
|
if (install || link || wsl) {
|
|
@@ -4429,7 +4525,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4429
4525
|
if (pkg.bin && (install || link || wsl)) {
|
|
4430
4526
|
if (link) {
|
|
4431
4527
|
console.log(`Installing ${pkgName} globally from local directory (link)...`);
|
|
4432
|
-
const localInstallResult =
|
|
4528
|
+
const localInstallResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4433
4529
|
if (localInstallResult.success) {
|
|
4434
4530
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
4435
4531
|
}
|
|
@@ -4444,7 +4540,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4444
4540
|
// sibling imports. Local install handles workspace linking correctly.
|
|
4445
4541
|
if (pkg.workspaces) {
|
|
4446
4542
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local (workspace)...`);
|
|
4447
|
-
const localResult =
|
|
4543
|
+
const localResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4448
4544
|
if (localResult.success) {
|
|
4449
4545
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
4450
4546
|
}
|
|
@@ -4463,7 +4559,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4463
4559
|
const vOnNpm = vCheck.status === 0 && vCheck.stdout?.trim() === pkgVersion;
|
|
4464
4560
|
if (vOnNpm) {
|
|
4465
4561
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from registry...`);
|
|
4466
|
-
const registryInstallResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
4562
|
+
const registryInstallResult = await installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd);
|
|
4467
4563
|
if (registryInstallResult.success) {
|
|
4468
4564
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
4469
4565
|
}
|
|
@@ -4483,7 +4579,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4483
4579
|
else {
|
|
4484
4580
|
console.log(colors.yellow(`${pkgName}@${pkgVersion} not found on npm — installing from local directory.`));
|
|
4485
4581
|
console.log(colors.dim(' Use -m "message" to publish this version to npm.'));
|
|
4486
|
-
const localResult =
|
|
4582
|
+
const localResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
4487
4583
|
if (localResult.success) {
|
|
4488
4584
|
console.log(colors.green(`✓ Installed globally from local: ${pkgName}@${pkgVersion}`));
|
|
4489
4585
|
}
|
|
@@ -4598,7 +4694,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4598
4694
|
}
|
|
4599
4695
|
// Pull latest from remote before version bump to avoid push rejection
|
|
4600
4696
|
if (currentGitStatus.hasRemote && !dryRun) {
|
|
4601
|
-
const pullResult =
|
|
4697
|
+
const pullResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd, silent: true });
|
|
4602
4698
|
if (!pullResult.success) {
|
|
4603
4699
|
console.error(colors.yellow('Warning: git pull --rebase failed before version bump'));
|
|
4604
4700
|
if (verbose) {
|
|
@@ -4699,12 +4795,12 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4699
4795
|
// Version bump + tag succeeded locally; only the push failed.
|
|
4700
4796
|
// Auto-pull --rebase and retry the push.
|
|
4701
4797
|
console.log(colors.yellow('\nLocal branch is behind remote — pulling with rebase...'));
|
|
4702
|
-
const pullResult =
|
|
4798
|
+
const pullResult = await runCommandAsync('git', ['pull', '--rebase', 'origin', currentGitStatus.currentBranch], { cwd });
|
|
4703
4799
|
if (pullResult.success) {
|
|
4704
4800
|
console.log(colors.green(' ✓ Rebased onto remote'));
|
|
4705
|
-
const pushResult =
|
|
4801
|
+
const pushResult = await runCommandAsync('git', ['push'], { cwd });
|
|
4706
4802
|
if (pushResult.success) {
|
|
4707
|
-
const tagPush =
|
|
4803
|
+
const tagPush = await runCommandAsync('git', ['push', '--tags'], { cwd, silent: true });
|
|
4708
4804
|
if (tagPush.success) {
|
|
4709
4805
|
console.log(colors.green(' ✓ Pushed with tags'));
|
|
4710
4806
|
}
|
|
@@ -4979,11 +5075,11 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4979
5075
|
// broadcast to the console group (e.g. from another tool sharing the
|
|
4980
5076
|
// console) makes cmd.exe print "Terminate batch job (Y/N)?" and kill
|
|
4981
5077
|
// npm.cmd. Our process survives, so a retry usually succeeds.
|
|
4982
|
-
let packResult =
|
|
5078
|
+
let packResult = await runCommandAsync('npm', ['pack'], { cwd, silent: true });
|
|
4983
5079
|
if (!packResult.success && /Terminate batch job|\^C/.test(packResult.output + packResult.stderr)) {
|
|
4984
5080
|
const logPath = dumpPackCtrlcDiagnostics(pkg, cwd, packResult.output, packResult.stderr);
|
|
4985
5081
|
console.error(colors.yellow(` npm pack interrupted by spurious Ctrl+C — retrying once... (diag: ${logPath})`));
|
|
4986
|
-
packResult =
|
|
5082
|
+
packResult = await runCommandAsync('npm', ['pack'], { cwd, silent: true });
|
|
4987
5083
|
}
|
|
4988
5084
|
// Restore stashed node_modules now that pack is done — must happen
|
|
4989
5085
|
// before any subsequent install -g symlinks to these dep targets.
|
|
@@ -5019,7 +5115,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5019
5115
|
if (sizeMB > 50) {
|
|
5020
5116
|
console.error(colors.red(`\n⚠ Tarball is ${sizeMB.toFixed(0)}MB — something large is being included!`));
|
|
5021
5117
|
// Show biggest files in the tarball
|
|
5022
|
-
const listResult =
|
|
5118
|
+
const listResult = await runCommandAsync('npm', ['pack', '--dry-run'], { cwd, silent: true });
|
|
5023
5119
|
if (listResult.success) {
|
|
5024
5120
|
const lines = listResult.output.trim().split('\n')
|
|
5025
5121
|
.filter(l => l.includes('B '))
|
|
@@ -5068,7 +5164,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5068
5164
|
console.log(colors.yellow(`⏱ Waiting ${retryDelay} seconds before retry (attempt ${attempt + 1}/${maxRetries})...`));
|
|
5069
5165
|
await new Promise(resolve => setTimeout(resolve, retryDelay * 1000));
|
|
5070
5166
|
}
|
|
5071
|
-
publishResult =
|
|
5167
|
+
publishResult = await runCommandAsync('npm', npmArgs, { cwd, silent: true });
|
|
5072
5168
|
if (publishResult.success) {
|
|
5073
5169
|
break; // Success!
|
|
5074
5170
|
}
|
|
@@ -5186,7 +5282,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5186
5282
|
if (logResult.success) {
|
|
5187
5283
|
console.log(colors.green(` ✓ Appended to npmchanges.md and removed .commitmsg`));
|
|
5188
5284
|
if (currentGitStatus.hasRemote)
|
|
5189
|
-
pushWithProtection(cwd, verbose);
|
|
5285
|
+
await pushWithProtection(cwd, verbose);
|
|
5190
5286
|
}
|
|
5191
5287
|
}
|
|
5192
5288
|
catch (err) {
|
|
@@ -5203,8 +5299,8 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5203
5299
|
console.log(`${timestamp()} Pushing to git...`);
|
|
5204
5300
|
}
|
|
5205
5301
|
if (!dryRun) {
|
|
5206
|
-
if (pushWithProtection(cwd, verbose)) {
|
|
5207
|
-
const tagResult =
|
|
5302
|
+
if (await pushWithProtection(cwd, verbose)) {
|
|
5303
|
+
const tagResult = await runCommandAsync('git', ['push', '--tags'], { cwd, silent: true });
|
|
5208
5304
|
if (verbose && tagResult.success)
|
|
5209
5305
|
console.log(colors.green(' ✓ Pushed tags'));
|
|
5210
5306
|
}
|
|
@@ -5226,7 +5322,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5226
5322
|
if (link) {
|
|
5227
5323
|
console.log(`Linking globally: ${pkgName}@${pkgVersion}...`);
|
|
5228
5324
|
if (!dryRun) {
|
|
5229
|
-
const installResult =
|
|
5325
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
5230
5326
|
if (installResult.success) {
|
|
5231
5327
|
globalInstallOk = true;
|
|
5232
5328
|
console.log(colors.green(`✓ Linked globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5246,7 +5342,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5246
5342
|
// Workspace packages: install from local for proper workspace linking
|
|
5247
5343
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local (workspace)...`);
|
|
5248
5344
|
if (!dryRun) {
|
|
5249
|
-
const installResult =
|
|
5345
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd, silent: false, showCommand: true });
|
|
5250
5346
|
if (installResult.success) {
|
|
5251
5347
|
globalInstallOk = true;
|
|
5252
5348
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5265,7 +5361,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5265
5361
|
console.log(`${timestamp()} Installing globally from registry: ${pkgName}@${pkgVersion}...`);
|
|
5266
5362
|
if (!dryRun) {
|
|
5267
5363
|
waitForNpmVersion(pkgName, pkgVersion, wasNewPackage);
|
|
5268
|
-
const installResult = installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd, wasNewPackage);
|
|
5364
|
+
const installResult = await installGlobalWithRetry(`${pkgName}@${pkgVersion}`, cwd, wasNewPackage);
|
|
5269
5365
|
if (installResult.success) {
|
|
5270
5366
|
globalInstallOk = true;
|
|
5271
5367
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
@@ -5297,7 +5393,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5297
5393
|
waitForNpmVersion(pkgName, pkgVersion, wasNewPackage);
|
|
5298
5394
|
console.log(`Installing in WSL${useLocalWsl ? ' (local)' : ' from registry'}: ${pkgName}@${pkgVersion}...`);
|
|
5299
5395
|
if (!dryRun) {
|
|
5300
|
-
const wslResult = installInWsl(wslArgs, { cwd });
|
|
5396
|
+
const wslResult = await installInWsl(wslArgs, { cwd });
|
|
5301
5397
|
if (wslResult.success) {
|
|
5302
5398
|
wslInstallOk = true;
|
|
5303
5399
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
@@ -5337,7 +5433,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5337
5433
|
runCommand('git', ['add', 'package.json'], { cwd });
|
|
5338
5434
|
gitCommit('Restore file: dependencies', cwd);
|
|
5339
5435
|
if (currentGitStatus.hasRemote) {
|
|
5340
|
-
pushWithProtection(cwd, verbose);
|
|
5436
|
+
await pushWithProtection(cwd, verbose);
|
|
5341
5437
|
}
|
|
5342
5438
|
}
|
|
5343
5439
|
}
|
|
@@ -5348,7 +5444,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
5348
5444
|
// Run final audit report if not already run
|
|
5349
5445
|
const auditAlreadyRun = (fix || updateDeps) && (transformResult.transformed || alreadyTransformed || updateDeps);
|
|
5350
5446
|
if (!auditAlreadyRun && (fix || updateDeps || transformResult.transformed) && !dryRun) {
|
|
5351
|
-
runNpmAudit(cwd, false, verbose); // Just report, don't fix again
|
|
5447
|
+
await runNpmAudit(cwd, false, verbose); // Just report, don't fix again
|
|
5352
5448
|
}
|
|
5353
5449
|
// Print summary
|
|
5354
5450
|
console.log('');
|
|
@@ -5611,7 +5707,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5611
5707
|
// the case where a dep was added to a member package.json but `npm install`
|
|
5612
5708
|
// wasn't re-run — the builds would otherwise fail resolving the new dep.
|
|
5613
5709
|
if (!options.dryRun) {
|
|
5614
|
-
ensureWorkspaceDepModules(rootDir, packages.map(p => ({ dir: p.dir, pkg: p.pkg })), !!options.verbose);
|
|
5710
|
+
await ensureWorkspaceDepModules(rootDir, packages.map(p => ({ dir: p.dir, pkg: p.pkg })), !!options.verbose);
|
|
5615
5711
|
}
|
|
5616
5712
|
// Prescan: decide which packages actually need processing so we don't waste
|
|
5617
5713
|
// time rebuilding+republishing ones with no relevant changes.
|
|
@@ -5805,7 +5901,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5805
5901
|
// Workspace root is private — always install from local directory
|
|
5806
5902
|
console.log(`Installing ${pkgName}@${pkgVersion} globally from local directory...`);
|
|
5807
5903
|
if (!dryRun) {
|
|
5808
|
-
const installResult =
|
|
5904
|
+
const installResult = await runCommandAsync('npm', ['install', '-g', '.'], { cwd: rootDir, silent: false, showCommand: true });
|
|
5809
5905
|
if (installResult.success) {
|
|
5810
5906
|
console.log(colors.green(`✓ Installed globally: ${pkgName}@${pkgVersion}`));
|
|
5811
5907
|
}
|
|
@@ -5822,7 +5918,7 @@ export async function globalizeWorkspace(rootDir, options = {}, configOptions =
|
|
|
5822
5918
|
if (wsl) {
|
|
5823
5919
|
console.log(`Installing ${pkgName} in WSL (local)...`);
|
|
5824
5920
|
if (!dryRun) {
|
|
5825
|
-
const wslResult = installInWsl(['npm', 'install', '-g', '.'], { cwd: rootDir });
|
|
5921
|
+
const wslResult = await installInWsl(['npm', 'install', '-g', '.'], { cwd: rootDir });
|
|
5826
5922
|
if (wslResult.success) {
|
|
5827
5923
|
console.log(colors.green(`✓ Installed in WSL: ${pkgName}@${pkgVersion}${wslResult.fixed ? ' (after prefix fix)' : ''}`));
|
|
5828
5924
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.175",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@bobfrankston/freezepak": "^0.1.8",
|
|
35
35
|
"@bobfrankston/importgen": "^0.1.35",
|
|
36
|
+
"@bobfrankston/mailx": "^1.0.466",
|
|
36
37
|
"@bobfrankston/npmglobalize": "^1.0.153",
|
|
37
38
|
"@bobfrankston/themecolors": "^0.1.6",
|
|
38
39
|
"@bobfrankston/userconfig": "^1.0.8",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
".dependencies": {
|
|
50
51
|
"@bobfrankston/freezepak": "file:../freezepak",
|
|
51
52
|
"@bobfrankston/importgen": "file:../importgen",
|
|
53
|
+
"@bobfrankston/mailx": "^1.0.466",
|
|
52
54
|
"@bobfrankston/npmglobalize": "^1.0.153",
|
|
53
55
|
"@bobfrankston/themecolors": "file:../themecolors",
|
|
54
56
|
"@bobfrankston/userconfig": "file:../userconfig",
|
|
@@ -63,6 +65,7 @@
|
|
|
63
65
|
"dependencies": {
|
|
64
66
|
"@bobfrankston/freezepak": "^0.1.8",
|
|
65
67
|
"@bobfrankston/importgen": "^0.1.35",
|
|
68
|
+
"@bobfrankston/mailx": "^1.0.466",
|
|
66
69
|
"@bobfrankston/npmglobalize": "^1.0.153",
|
|
67
70
|
"@bobfrankston/themecolors": "^0.1.6",
|
|
68
71
|
"@bobfrankston/userconfig": "^1.0.8",
|