UNPKG

gaunt-sloth-assistant

Version:

[![Tests and Lint](https://github.com/Galvanized-Pukeko/gaunt-sloth-assistant/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/Galvanized-Pukeko/gaunt-sloth-assistant/actions/workflows/unit-tests.yml) [![Integration Tests](https://github.co

173 lines 5.86 kB
import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'url'; import { ProgressIndicator } from '#src/utils.js'; import { createInterface } from 'node:readline/promises'; import { displayInfo, displayWarning } from './consoleUtils.js'; import { createWriteStream } from 'node:fs'; const innerState = { installDir: undefined, stringFromStdin: '', useColour: false, waitForEscapeCallback: undefined, logWriteStream: undefined, }; // eslint-disable-next-line @typescript-eslint/no-explicit-any const keypressHandler = (callback) => (_, key) => { if (key?.name === 'escape' || key?.name === 'q') { displayWarning('\nInterrupting...'); callback(); return; } }; export const waitForEscape = (callback, enabled) => { if (!enabled) { return; } process.stdin.setRawMode(true); innerState.waitForEscapeCallback = keypressHandler(callback); process.stdin.on('keypress', innerState.waitForEscapeCallback); displayInfo(` ┌--------------------------------------┐ │ Press Escape or Q to interrupt Agent │ └--------------------------------------┘ `); }; export const stopWaitingForEscape = () => { if (innerState.waitForEscapeCallback) { process.stdin.setRawMode(false); process.stdin.off('keypress', innerState.waitForEscapeCallback); innerState.waitForEscapeCallback = undefined; } }; export const setRawMode = (rawMode) => { if (process.stdin.isTTY) { process.stdin.setRawMode(rawMode); } }; export const initLogStream = (logFileName) => { try { // Close existing stream if present if (innerState.logWriteStream) { innerState.logWriteStream.end(); } // Create new write stream with append mode innerState.logWriteStream = createWriteStream(logFileName, { flags: 'a', autoClose: true, }); // Handle stream errors innerState.logWriteStream.on('error', (err) => { displayWarning(`Log stream error: ${err.message}`); innerState.logWriteStream = undefined; }); // Handle stream close innerState.logWriteStream.on('close', () => { innerState.logWriteStream = undefined; }); } catch (err) { displayWarning(`Failed to create log stream: ${err instanceof Error ? err.message : String(err)}`); innerState.logWriteStream = undefined; } }; export const writeToLogStream = (message) => { if (innerState.logWriteStream && !innerState.logWriteStream.destroyed) { innerState.logWriteStream.write(message); } }; export const closeLogStream = () => { if (innerState.logWriteStream && !innerState.logWriteStream.destroyed) { innerState.logWriteStream.end(); innerState.logWriteStream = undefined; } }; // Ensure log stream is closed on process exit process.on('exit', () => { closeLogStream(); }); process.on('SIGINT', () => { closeLogStream(); process.exit(0); }); process.on('SIGTERM', () => { closeLogStream(); process.exit(0); }); // Process-related functions and objects export const getProjectDir = () => process.cwd(); export const getInstallDir = () => { if (innerState.installDir) { return innerState.installDir; } throw new Error('Install directory not set'); }; /** * Cached string from stdin. Should only be called after readStdin completes execution. */ export const getStringFromStdin = () => { return innerState.stringFromStdin; }; /** * Get the current useColour setting. */ export const getUseColour = () => { return innerState.useColour; }; /** * Set the useColour setting. */ export const setUseColour = (useColour) => { innerState.useColour = useColour; }; export const isTTY = () => !!stdin.isTTY; export const exit = (code) => process.exit(code || 0); export const stdin = process.stdin; export const stdout = process.stdout; export const argv = process.argv; export const env = process.env; export { createInterface }; // noinspection JSUnusedGlobalSymbols /** * Provide the path to the entry point of the application. * This is used to set the install directory. * This is called from cli.js root entry point. */ export const setEntryPoint = (indexJs) => { const filePath = fileURLToPath(indexJs); const dirPath = dirname(filePath); innerState.installDir = resolve(dirPath); }; /** * Asynchronously reads the stdin and stores it as a string, * it can later be retrieved with getStringFromStdin. */ export function readStdin(program) { return new Promise((resolvePromise) => { if (stdin.isTTY || program.getOptionValue('nopipe')) { program.parseAsync().then(() => resolvePromise()); } else { // Support piping diff into gsloth const progressIndicator = new ProgressIndicator('reading STDIN', true); stdin.on('readable', function () { const chunk = this.read(); progressIndicator.indicate(); if (chunk !== null) { const chunkStr = chunk.toString('utf8'); innerState.stringFromStdin = innerState.stringFromStdin + chunkStr; } }); stdin.on('end', function () { program.parseAsync(argv).then(() => resolvePromise()); }); } }); } // Console-related functions export const log = (message) => console.log(message); export const error = (message) => console.error(message); export const warn = (message) => console.warn(message); export const info = (message) => console.info(message); export const debug = (message) => console.debug(message); export const stream = (chunk) => process.stdout.write(chunk); //# sourceMappingURL=systemUtils.js.map