diff --git a/package-lock.json b/package-lock.json index 6b2a818c27..c3e5f8b7ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32832,6 +32832,7 @@ "@shopify/cli-kit": "3.47.0", "@shopify/hydrogen-codegen": "^0.0.2", "@shopify/mini-oxygen": "^1.6.0", + "ansi-escapes": "^6.2.0", "diff": "^5.1.0", "fast-glob": "^3.2.12", "fs-extra": "^10.1.0", @@ -32912,6 +32913,20 @@ "node": ">=14.0.0" } }, + "packages/cli/node_modules/@oclif/core/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/@oclif/core/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -32926,6 +32941,17 @@ "node": ">=10" } }, + "packages/cli/node_modules/@oclif/core/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/@shopify/cli-kit": { "version": "3.47.0", "resolved": "https://registry.npmjs.org/@shopify/cli-kit/-/cli-kit-3.47.0.tgz", @@ -32999,20 +33025,6 @@ "node": ">=14.17.0" } }, - "packages/cli/node_modules/@shopify/cli-kit/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "dependencies": { - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/cli/node_modules/@shopify/cli-kit/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -33305,17 +33317,6 @@ "node": ">=14.18" } }, - "packages/cli/node_modules/@shopify/cli-kit/node_modules/type-fest": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", - "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/cli/node_modules/@types/archiver": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz", @@ -33330,6 +33331,31 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "packages/cli/node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/cli/node_modules/ansi-escapes/node_modules/type-fest": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", + "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/ansi-regex": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", @@ -33842,31 +33868,6 @@ } } }, - "packages/cli/node_modules/ink/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "dependencies": { - "type-fest": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/cli/node_modules/ink/node_modules/ansi-escapes/node_modules/type-fest": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", - "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/cli/node_modules/ink/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -34020,6 +34021,33 @@ "node": ">=8.0.0" } }, + "packages/cli/node_modules/inquirer/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/cli/node_modules/inquirer/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -34599,6 +34627,21 @@ "node": ">=10" } }, + "packages/cli/node_modules/oclif/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/oclif/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -34631,6 +34674,18 @@ "node": ">= 4.0.0" } }, + "packages/cli/node_modules/oclif/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/cli/node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -41255,6 +41310,7 @@ "@types/prettier": "^2.7.2", "@types/recursive-readdir": "^2.2.1", "@types/tar-fs": "^2.0.1", + "ansi-escapes": "^6.2.0", "diff": "^5.1.0", "fast-glob": "^3.2.12", "fs-extra": "^10.1.0", @@ -41313,6 +41369,14 @@ "wrap-ansi": "^7.0.0" }, "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } + }, "fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -41323,6 +41387,11 @@ "jsonfile": "^6.0.1", "universalify": "^2.0.0" } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" } } }, @@ -41391,14 +41460,6 @@ "zod": "3.21.4" }, "dependencies": { - "ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "requires": { - "type-fest": "^3.0.0" - } - }, "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -41570,11 +41631,6 @@ "has-flag": "^4.0.0", "supports-color": "^7.0.0" } - }, - "type-fest": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", - "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==" } } }, @@ -41592,6 +41648,21 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, + "ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "requires": { + "type-fest": "^3.0.0" + }, + "dependencies": { + "type-fest": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", + "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==" + } + } + }, "ansi-regex": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", @@ -41957,21 +42028,6 @@ "yoga-wasm-web": "~0.3.3" }, "dependencies": { - "ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", - "requires": { - "type-fest": "^3.0.0" - }, - "dependencies": { - "type-fest": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.12.0.tgz", - "integrity": "sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA==" - } - } - }, "ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -42062,6 +42118,23 @@ "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } } }, "is-buffer": { @@ -42513,6 +42586,15 @@ } } }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -42540,6 +42622,12 @@ "dev": true } } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true } } }, diff --git a/packages/cli/package.json b/packages/cli/package.json index 77cad13346..786bdb577f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -38,6 +38,7 @@ "@shopify/cli-kit": "3.47.0", "@shopify/hydrogen-codegen": "^0.0.2", "@shopify/mini-oxygen": "^1.6.0", + "ansi-escapes": "^6.2.0", "diff": "^5.1.0", "fast-glob": "^3.2.12", "fs-extra": "^10.1.0", diff --git a/packages/cli/src/lib/auth.ts b/packages/cli/src/lib/auth.ts index d4b8d25260..0b08d7a23b 100644 --- a/packages/cli/src/lib/auth.ts +++ b/packages/cli/src/lib/auth.ts @@ -1,4 +1,4 @@ -import {renderSelectPrompt} from '@shopify/cli-kit/node/ui'; +import {renderInfo, renderSelectPrompt} from '@shopify/cli-kit/node/ui'; import {AbortError} from '@shopify/cli-kit/node/error'; import { type AdminSession, @@ -7,9 +7,13 @@ import { ensureAuthenticatedBusinessPlatform, } from '@shopify/cli-kit/node/session'; import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn'; +import {outputContent, outputToken} from '@shopify/cli-kit/node/output'; +import {renderTasks} from '@shopify/cli-kit/node/ui'; +import colors from '@shopify/cli-kit/node/colors'; +import ansiEscapes from 'ansi-escapes'; import {getConfig, resetConfig, setUserAccount} from './shopify-config.js'; -import {muteAuthLogs} from './log.js'; import {getUserAccount} from './graphql/business-platform/user-account.js'; +import {muteAuthLogs} from './log.js'; export type {AdminSession}; @@ -40,7 +44,7 @@ export async function login(root?: string, shop?: string | true) { if (shop) shop = await normalizeStoreFqdn(shop); - muteAuthLogs(); + const hideLoginInfo = showLoginInfo(); if (!shop || shop !== existingConfig.shop || forcePrompt) { const token = await ensureAuthenticatedBusinessPlatform().catch(() => { @@ -51,6 +55,8 @@ export async function login(root?: string, shop?: string | true) { const userAccount = await getUserAccount(token); + await hideLoginInfo(); + const selected = await renderSelectPrompt({ message: 'Select a shop to log in to', choices: userAccount.activeShops.map(({name, fqdn}) => ({ @@ -70,9 +76,80 @@ export async function login(root?: string, shop?: string | true) { ]); }); + await hideLoginInfo(); + const config = root ? await setUserAccount(root, {shop, shopName, email}) : {shop, shopName, email}; return {session, config}; } + +function showLoginInfo() { + let deferredResolve: (value?: unknown) => void; + const promise = new Promise((resolve) => { + deferredResolve = resolve; + }); + + console.log(''); + + let hasLoggedTimeout = false; + let hasLoggedPressKey = false; + + const restoreLogs = muteAuthLogs({ + onKeyTimeout: (link) => { + if (link) { + hasLoggedTimeout = true; + process.stdout.write(ansiEscapes.eraseLines(9)); + + try { + const secureLink = link.replace('http://', 'https://'); + const url = new URL(secureLink); + const label = url.origin + '/...' + url.search.slice(-14); + + renderInfo({ + headline: 'Log in to Shopify', + body: outputContent`Timed out. Click to open your browser:\n${outputToken.link( + colors.white(label), + secureLink, + )}`.value, + }); + } catch { + // Parsed wrong link + } + } + }, + onPressKey: () => { + hasLoggedPressKey = true; + renderInfo({ + headline: 'Log in to Shopify', + body: 'Press any key to login with your default browser', + }); + + process.stdin.once('data', () => { + renderTasks([ + { + title: 'Waiting for Shopify authentication', + task: async () => { + await promise; + }, + }, + ]); + }); + }, + }); + + promise.then(() => { + restoreLogs(); + if (hasLoggedPressKey) { + process.stdout.write(ansiEscapes.eraseLines(hasLoggedTimeout ? 11 : 10)); + } + }); + + return async () => { + deferredResolve(); + // Without this timeout the process exits + // right after `renderTasks` is done. + await new Promise((resolve) => setTimeout(resolve, 0)); + }; +} diff --git a/packages/cli/src/lib/log.ts b/packages/cli/src/lib/log.ts index e3e310a001..b6a15104e9 100644 --- a/packages/cli/src/lib/log.ts +++ b/packages/cli/src/lib/log.ts @@ -6,8 +6,19 @@ const methodsReplaced = new Set(); type Matcher = (args: Array) => boolean; type Replacer = (args: Array) => void | string[]; +const addedReplacers = new Set(); const messageReplacers: Array<[Matcher, Replacer]> = []; +export function addMessageReplacers( + key: string, + ...items: Array<[Matcher, Replacer]> +) { + if (!addedReplacers.has(key)) { + addedReplacers.add(key); + messageReplacers.push(...items); + } +} + function injectLogReplacer(method: ConsoleMethod) { if (!methodsReplaced.has(method)) { methodsReplaced.add(method); @@ -21,16 +32,11 @@ function injectLogReplacer(method: ConsoleMethod) { } } -injectLogReplacer('log'); -injectLogReplacer('info'); - -let devMuted = false; export function muteDevLogs({workerReload}: {workerReload?: boolean} = {}) { - if (devMuted) return; - else devMuted = true; + injectLogReplacer('log'); let isFirstWorkerReload = true; - messageReplacers.push([ + addMessageReplacers('dev', [ ([first]) => typeof first === 'string' && first.includes('[mf:'), (args: string[]) => { const first = args[0] as string; @@ -53,16 +59,51 @@ export function muteDevLogs({workerReload}: {workerReload?: boolean} = {}) { ]); } -let authMuted = false; -export function muteAuthLogs() { - if (authMuted) return; - else authMuted = true; +const originalWrite = process.stdout.write; +export function muteAuthLogs({ + onPressKey, + onKeyTimeout, +}: { + onPressKey: () => void; + onKeyTimeout: (link?: string) => void; +}) { + if (process.stdout.write === originalWrite) { + const write = originalWrite.bind(process.stdout); + + process.stdout.write = ((item, cb: any) => { + if (typeof item !== 'string') return write(item, cb); - messageReplacers.push( + const replacer = messageReplacers.find(([matcher]) => + matcher([item]), + )?.[1]; + if (!replacer) return write(item, cb); + + const result = replacer([item]); + if (result) return write(result[0] as string, cb); + }) as typeof write; + } + + addMessageReplacers( + 'auth', [ ([first]) => typeof first === 'string' && first.includes('Auto-open'), ([first]) => { - return [first.replace(' to Shopify Partners', '')]; + const content = (first as string).replace(' to Shopify Partners', ''); + + const link = content.match(/(https?:\/\/.*)Log in/)?.[1]; + onKeyTimeout(link); + + if (link) return; + + return [content]; + }, + ], + [ + ([first]) => typeof first === 'string' && first.includes('👉'), + () => { + onPressKey(); + // Hide logs + return; }, ], [ @@ -75,6 +116,10 @@ export function muteAuthLogs() { }, ], ); + + return () => { + process.stdout.write = originalWrite; + }; } const warnings = new Set();