99 lines
2.3 KiB
JavaScript
99 lines
2.3 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import { spawn } from 'node:child_process'
|
|
|
|
const SETUP_ENTRY_PATH = path.join('scripts', 'setup', 'setup.js')
|
|
const TSX_ENTRY_PATH = path.join(
|
|
process.cwd(),
|
|
'node_modules',
|
|
'tsx',
|
|
'dist',
|
|
'cli.mjs'
|
|
)
|
|
const TTY_PATH = '/dev/tty'
|
|
const WINDOWS_CONSOLE_IN_PATH = 'CONIN$'
|
|
const WINDOWS_CONSOLE_OUT_PATH = 'CONOUT$'
|
|
|
|
// pnpm 11 reads project config from pnpm-workspace.yaml. That also makes root
|
|
// lifecycle scripts run through pnpm's workspace runner, which does not expose
|
|
// a TTY to the child process. Leon setup needs a TTY to ask setup questions, so
|
|
// this wrapper reattaches the real setup process to the user's terminal.
|
|
function openWindowsConsoleStdio() {
|
|
try {
|
|
const stdin = fs.openSync(WINDOWS_CONSOLE_IN_PATH, 'r')
|
|
const stdout = fs.openSync(WINDOWS_CONSOLE_OUT_PATH, 'w')
|
|
|
|
return [stdin, stdout, stdout]
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
// Use the controlling terminal when available. In CI, Docker, or other
|
|
// non-interactive contexts there may be no terminal, so setup falls back to the
|
|
// inherited stdio and keeps its existing non-interactive behavior.
|
|
function getTTYStdio() {
|
|
if (process.platform === 'win32') {
|
|
return openWindowsConsoleStdio()
|
|
}
|
|
|
|
if (!fs.existsSync(TTY_PATH)) {
|
|
return null
|
|
}
|
|
|
|
try {
|
|
const tty = fs.openSync(TTY_PATH, 'r+')
|
|
|
|
return [tty, tty, tty]
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function closeTTYStdio(stdio) {
|
|
if (stdio === null) {
|
|
return
|
|
}
|
|
|
|
for (const descriptor of new Set(stdio)) {
|
|
fs.closeSync(descriptor)
|
|
}
|
|
}
|
|
|
|
async function runSetup() {
|
|
const ttyStdio = getTTYStdio()
|
|
|
|
try {
|
|
await new Promise((resolve, reject) => {
|
|
const child = spawn(process.execPath, [TSX_ENTRY_PATH, SETUP_ENTRY_PATH], {
|
|
cwd: process.cwd(),
|
|
env: process.env,
|
|
stdio: ttyStdio || 'inherit',
|
|
windowsHide: false
|
|
})
|
|
|
|
child.once('error', reject)
|
|
child.once('exit', (code, signal) => {
|
|
if (signal) {
|
|
process.kill(process.pid, signal)
|
|
return
|
|
}
|
|
|
|
if ((code ?? 0) !== 0) {
|
|
reject(new Error(`Setup exited with code ${code ?? 0}`))
|
|
return
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
} finally {
|
|
closeTTYStdio(ttyStdio)
|
|
}
|
|
}
|
|
|
|
runSetup().catch((error) => {
|
|
console.error(error)
|
|
process.exit(1)
|
|
})
|