fix(agent): restore raw mode

This commit is contained in:
fry69 committed 2026-06-09 03:43:37 +02:00
1 parent 59d9bc7830
commit ce5b70be9c
3 files changed
+64

No files matched your search

+39
View File
@@ -145,6 +145,7 @@ typedef struct {
bool more_valid;
agent_bash_job *bash_jobs;
int next_bash_job_id;
bool raw_mode_needs_restore;
} agent_worker;
static unsigned agent_next_prefill_label(void);
@@ -6586,6 +6587,7 @@ struct agent_bash_job {
bool running;
bool timed_out;
struct agent_bash_job *next;
agent_worker *worker; /* back-pointer for terminal state restoration */
};
static int agent_bash_display_lines(const agent_bash_job *job) {
@@ -6674,6 +6676,13 @@ static void agent_bash_finalize(agent_bash_job *job, int status) {
else if (WIFSIGNALED(status)) job->exit_status = 128 + WTERMSIG(status);
else job->exit_status = -1;
job->running = false;
/* A child process (especially sh) may have changed the terminal mode
* from raw to cooked. Notify the UI thread to restore raw mode. */
if (job->worker) {
pthread_mutex_lock(&job->worker->mu);
job->worker->raw_mode_needs_restore = true;
pthread_mutex_unlock(&job->worker->mu);
}
}
/* Drain available output, notice process exit, and enforce timeout. This is
@@ -6741,6 +6750,17 @@ static agent_bash_job *agent_bash_start(agent_worker *w, const char *cmd,
if (pid == 0) {
setpgid(0, 0);
close(tmpfd);
/* Redirect stdin to /dev/null so the shell does not attempt to
* change the terminal mode (cooked/raw) on the controlling
* terminal. If the shell sets cooked mode while linenoise has
* raw mode active, the terminal becomes unresponsive to user
* input until the process exits and linenoise re-enables raw
* mode. */
int null_fd = open("/dev/null", O_RDONLY);
if (null_fd >= 0) {
dup2(null_fd, STDIN_FILENO);
close(null_fd);
}
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[1], STDERR_FILENO);
@@ -6767,6 +6787,7 @@ static agent_bash_job *agent_bash_start(agent_worker *w, const char *cmd,
job->timeout_sec = timeout_sec;
job->exit_status = -1;
job->running = true;
job->worker = w;
job->next = w->bash_jobs;
w->bash_jobs = job;
return job;
@@ -8030,6 +8051,19 @@ static int set_nonblock(int fd, bool on, int *old_flags) {
return fcntl(fd, F_SETFL, next);
}
/* Check and clear the raw_mode_needs_restore flag under the worker mutex.
* Returns true if the UI thread should call linenoiseRestoreRawMode(). */
static bool worker_check_raw_mode_restore(agent_worker *w) {
bool needs = false;
pthread_mutex_lock(&w->mu);
if (w->raw_mode_needs_restore) {
w->raw_mode_needs_restore = false;
needs = true;
}
pthread_mutex_unlock(&w->mu);
return needs;
}
static void drain_wake_fd(int fd) {
char buf[128];
for (;;) {
@@ -9704,6 +9738,11 @@ static int run_agent(ds4_engine *engine, agent_config *cfg) {
bool force_status_redraw_after_restart = false;
char *restore_line = NULL;
while (running) {
/* If a bash child process changed the terminal mode (e.g., from raw
* to cooked), restore raw mode so linenoise continues to work. */
if (worker_check_raw_mode_restore(&worker)) {
linenoiseRestoreRawMode();
}
struct pollfd pfd[2] = {
{.fd = STDIN_FILENO, .events = POLLIN},
{.fd = worker.wake_fd[0], .events = POLLIN},
+23
View File
@@ -624,6 +624,29 @@ static void disableRawMode(int fd) {
}
}
/* Re-enable raw mode if a child process changed the terminal state. This is
* useful when the application spawns external processes that may reset the
* terminal to cooked mode. The caller should ensure that no concurrent
* linenoise operations are in progress (e.g., not inside a refresh cycle). */
void linenoiseRestoreRawMode(void) {
if (getenv("LINENOISE_ASSUME_TTY")) return;
if (!isatty(STDIN_FILENO)) return;
/* Re-fetch the original terminal attributes (they may have been changed
* by a child process) and re-apply raw mode. */
struct termios raw;
if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) return;
raw = orig_termios;
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
rawmode = 1;
/* Re-enable bracketed paste mode. */
if (write(rawmode_output, "\x1b[?2004h", 8) == -1) {}
}
/* Use the ESC [6n escape sequence to query the horizontal cursor position
* and return it. On error -1 is returned, on success the position of the
* cursor. */
+2
View File
@@ -139,6 +139,8 @@ void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
void linenoiseMaskModeEnable(void);
void linenoiseMaskModeDisable(void);
/* Re-enable raw mode if a child process changed the terminal state. */
void linenoiseRestoreRawMode(void);
#ifdef __cplusplus
}