mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat(tui): route /diff through workspace commands (#21001)
Stacked on #20892. ## Why #20892 adds the TUI workspace command abstraction so branch status metadata can run through app-server instead of assuming the CLI process has the active workspace locally. `/diff` still used direct local process execution, which means remote app-server sessions could compute the diff against the wrong machine or fail to see the active workspace at all. This PR moves `/diff` onto that same app-server-backed command path so Git runs wherever the active workspace lives. ## What Changed - Route `/diff` through the TUI `WorkspaceCommandExecutor` using the active chat cwd. - Replace direct `tokio::process::Command` usage in `get_git_diff` with argv-based workspace command requests. - Preserve the existing `/diff` behavior: tracked diff output, untracked file diffs, treating Git diff exit code `1` as success, and showing the existing non-git-repository message. - Extend `WorkspaceCommand` with caller-set timeouts and an explicit uncapped-output opt-out. Metadata probes remain capped by default; `/diff` opts out because its full output is the user-visible payload. ## How to Test Manual reviewer path: 1. Start the Codex TUI from a Git worktree with one tracked file change and one untracked file. 2. Run `/diff`. 3. Confirm the rendered diff includes both the tracked diff and the untracked file diff. 4. Start the TUI outside a Git worktree, or switch to a non-git cwd, then run `/diff`. 5. Confirm it shows the existing `/diff` not-inside-a-git-repository message. Targeted tests run: - `cargo test -p codex-tui get_git_diff -- --nocapture` - `cargo test -p codex-tui branch_summary -- --nocapture` - `cargo test -p codex-tui`
This commit is contained in:
committed by
GitHub
Unverified
parent
9e0c191c13
commit
52fbbe7cdd
@@ -1,14 +1,14 @@
|
||||
//! App-server-backed workspace command execution for TUI-owned background lookups.
|
||||
//!
|
||||
//! This module is the TUI boundary for short, non-interactive commands that need to run wherever
|
||||
//! This module is the TUI boundary for non-interactive commands that need to run wherever
|
||||
//! the active workspace lives. Callers describe a command in terms of argv, cwd, environment
|
||||
//! overrides, timeout, and output cap; the runner translates that request to app-server
|
||||
//! `command/exec`. Keeping this as a TUI-local abstraction lets status surfaces avoid knowing
|
||||
//! whether the current app-server is embedded or remote.
|
||||
//!
|
||||
//! Commands sent through this path are best-effort metadata probes. They should not prompt for
|
||||
//! stdin, should tolerate failure by omitting optional UI, and should keep output bounded so a
|
||||
//! status-line refresh cannot grow into an unbounded background process.
|
||||
//! Commands sent through this path should not prompt for stdin. Most callers should keep output
|
||||
//! bounded so metadata refreshes cannot grow into unbounded background processes; callers that own a
|
||||
//! full user-visible payload, such as `/diff`, can explicitly opt out of output capping.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
@@ -45,17 +45,20 @@ pub(crate) struct WorkspaceCommand {
|
||||
pub(crate) timeout: Duration,
|
||||
/// Maximum captured stdout/stderr bytes returned by app-server.
|
||||
pub(crate) output_bytes_cap: usize,
|
||||
/// Whether app-server should return uncapped stdout/stderr.
|
||||
pub(crate) disable_output_cap: bool,
|
||||
}
|
||||
|
||||
impl WorkspaceCommand {
|
||||
/// Creates a workspace command with conservative defaults for status-style metadata probes.
|
||||
/// Creates a workspace command with conservative defaults for metadata probes.
|
||||
pub(crate) fn new(argv: impl IntoIterator<Item = impl Into<String>>) -> Self {
|
||||
Self {
|
||||
argv: argv.into_iter().map(Into::into).collect(),
|
||||
cwd: None,
|
||||
env: HashMap::new(),
|
||||
timeout: Duration::from_secs(5),
|
||||
timeout: Duration::from_secs(/*secs*/ 5),
|
||||
output_bytes_cap: 64 * 1024,
|
||||
disable_output_cap: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +73,18 @@ impl WorkspaceCommand {
|
||||
self.env.insert(key.into(), Some(value.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the maximum wall-clock duration before app-server cancels the command.
|
||||
pub(crate) fn timeout(mut self, timeout: Duration) -> Self {
|
||||
self.timeout = timeout;
|
||||
self
|
||||
}
|
||||
|
||||
/// Requests uncapped stdout/stderr capture from app-server.
|
||||
pub(crate) fn disable_output_cap(mut self) -> Self {
|
||||
self.disable_output_cap = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Captured result from a completed workspace command.
|
||||
@@ -176,8 +191,9 @@ impl WorkspaceCommandExecutor for AppServerWorkspaceCommandRunner {
|
||||
tty: false,
|
||||
stream_stdin: false,
|
||||
stream_stdout_stderr: false,
|
||||
output_bytes_cap: Some(command.output_bytes_cap),
|
||||
disable_output_cap: false,
|
||||
output_bytes_cap: (!command.disable_output_cap)
|
||||
.then_some(command.output_bytes_cap),
|
||||
disable_output_cap: command.disable_output_cap,
|
||||
disable_timeout: false,
|
||||
timeout_ms: Some(timeout_ms),
|
||||
cwd: command.cwd,
|
||||
|
||||
Reference in New Issue
Block a user