From 4a5fa4415c94aca02c4c660a389ed7a21c1021d9 Mon Sep 17 00:00:00 2001 From: Brandon Lucas Date: Sun, 22 Feb 2026 23:48:33 -0500 Subject: [PATCH] Fix interactive input by using Console.readLine instead of Process.exec Process.exec uses popen(cmd, "r") which creates a read-only pipe where the subprocess stdin is disconnected from the terminal. Console.readLine reads directly from the parent process stdin via fgets, fixing all interactive prompts (askConfirm, askInput, choice menus). Co-Authored-By: Claude Opus 4.6 --- cli/pal.lux | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/pal.lux b/cli/pal.lux index 0856715..edec12c 100644 --- a/cli/pal.lux +++ b/cli/pal.lux @@ -128,10 +128,10 @@ fn printStatusLine(name: String, state: String, detail: String): Unit with {Proc } // Ask for confirmation: returns true if user confirms -fn askConfirm(question: String, defaultYes: Bool): Bool with {Process} = { +fn askConfirm(question: String, defaultYes: Bool): Bool with {Console, Process} = { let prompt = if defaultYes then " [Y/n] " else " [y/N] " let ignore = Process.exec("printf '%s%s' \"" + question + "\" \"" + prompt + "\" >&2") - let response = String.trim(Process.exec("head -n1 0 then "printf '%s [%s]: ' \"" + prompt + "\" \"" + defaultVal + "\" >&2" else "printf '%s: ' \"" + prompt + "\" >&2" let ignore = Process.exec(display) - let input = String.trim(Process.exec("head -n1 &2") - let choice = String.trim(Process.exec("head -n1 { @@ -765,7 +765,7 @@ fn doServerUnmount(): Unit with {Process} = { // Export/Import // ============================================================================= -fn doExport(): Unit with {Process} = { +fn doExport(): Unit with {Console, Process} = { print("") let timestamp = execQuiet("date +%Y-%m-%d") let exportFile = "pal-export-" + timestamp + ".tar.zst" @@ -790,7 +790,7 @@ fn doExport(): Unit with {Process} = { print("") } -fn doImport(archivePath: String): Unit with {Process} = { +fn doImport(archivePath: String): Unit with {Console, Process} = { print("") if String.length(archivePath) == 0 then { @@ -974,7 +974,7 @@ fn showCompactStatus(): Unit with {Process} = { // Health check (default command) // ============================================================================= -fn showHealthCheck(): Unit with {Process} = { +fn showHealthCheck(): Unit with {Console, Process} = { // Check if this is an interactive terminal let isTty = execQuiet("test -t 0 && echo yes || echo no") @@ -1225,7 +1225,7 @@ fn showOnboardSummary(deviceName: String): Unit with {Process} = { print("") } -fn doOnboardSteps(): Unit with {Process} = { +fn doOnboardSteps(): Unit with {Console, Process} = { // ── Step 1: Device ────────────────────────────────────────────────── let ignore = Process.exec("printf '\\033[1m── Step 1: Device ──\\033[0m\\n\\n' >&2") @@ -1273,7 +1273,7 @@ fn doOnboardSteps(): Unit with {Process} = { print("") let ignore8 = Process.exec("printf 'Choice [3]: ' >&2") - let configChoice = String.trim(Process.exec("head -n1 c,