diff --git a/packages/create-lz-oapp/src/index.tsx b/packages/create-lz-oapp/src/index.tsx index 3dae794aa..e91e975cf 100644 --- a/packages/create-lz-oapp/src/index.tsx +++ b/packages/create-lz-oapp/src/index.tsx @@ -1,11 +1,12 @@ import React from "react"; import { render } from "ink"; import { Command } from "commander"; -import { promptForConfig, promptForContinue } from "@/utilities/prompts.js"; +import { promptForConfig } from "@/utilities/prompts.js"; import { Header } from "@/components/branding.js"; import { ConfigSummary } from "@/components/config.js"; import { Setup } from "@/components/setup.js"; import { Providers } from "@/components/providers.js"; +import { promptToContinue } from "@layerzerolabs/io-utils"; new Command("create-lz-oapp") .description("Create LayerZero OApp with one command") @@ -20,7 +21,7 @@ new Command("create-lz-oapp") render().unmount(); // Then we confirm we want to do this after showing the user what they have specified - const continuePlease = await promptForContinue(); + const continuePlease = await promptToContinue(); if (!continuePlease) { return; } diff --git a/packages/create-lz-oapp/src/utilities/prompts.ts b/packages/create-lz-oapp/src/utilities/prompts.ts index 8c1daaaf2..e52626140 100644 --- a/packages/create-lz-oapp/src/utilities/prompts.ts +++ b/packages/create-lz-oapp/src/utilities/prompts.ts @@ -1,27 +1,9 @@ import { EXAMPLES, PACKAGE_MANAGERS } from '@/config.js' import prompts from 'prompts' import { isPackageManagerAvailable } from './installation.js' -import { isDirectory } from '@layerzerolabs/io-utils' +import { handlePromptState, isDirectory } from '@layerzerolabs/io-utils' import { resolve } from 'path' -const handlePromptState = (state: { aborted: boolean }) => { - if (state.aborted) { - // If we don't re-enable the terminal cursor before exiting - // the program, the cursor will remain hidden - process.stdout.write('\x1B[?25h') - process.stdout.write('\n') - process.exit(1) - } -} - -export const promptForContinue = async () => - prompts({ - type: 'confirm', - name: 'pleasecontinue', - message: 'Would you like to continue?', - initial: true, - }).then(({ pleasecontinue }): boolean => pleasecontinue) - export const promptForConfig = () => prompts([ { diff --git a/packages/io-utils/src/stdio/prompts.ts b/packages/io-utils/src/stdio/prompts.ts index 3e323a896..bab716ced 100644 --- a/packages/io-utils/src/stdio/prompts.ts +++ b/packages/io-utils/src/stdio/prompts.ts @@ -1,6 +1,31 @@ import assert from 'assert' import prompts from 'prompts' +/** + * Helper utility to be used when raw access to prompts + * is required. + * + * This should be passed to `onState` property of the options + * to handle cases where the user sends a SIGTERM signal to the process + * (ctrl + c) usually. + * + * If not passed in, the SIGTERM will cancel the prompt but the promise + * will resolve with an invalid result and, what's more important, + * if cursor had been hidden it will be swallowed and people will need to + * restart their terminal to bring it back + * + * @param {{ aborted?: boolean}} state Prompts state object + */ +export const handlePromptState = (state: { aborted?: boolean }) => { + if (state.aborted) { + // If we don't re-enable the terminal cursor before exiting + // the program, the cursor will remain hidden + process.stdout.write('\x1B[?25h') + process.stdout.write('\n') + process.exit(1) + } +} + export const promptToContinue = async ( message: string = 'Do you want to continue?', defaultValue = true @@ -10,6 +35,7 @@ export const promptToContinue = async ( name: 'value', message, initial: defaultValue, + onState: handlePromptState, }) assert(typeof value === 'boolean', `Invariant error: Expected a boolean response, got ${value}`)