merge(upstream): integrate upstream/main via merge branch; keep TUI fork; fix build\n\n- Create merge branch, merge origin/main and upstream/main with -X ours\n- Resolve conflicts: keep our TUI; drop upstream vt100 tests and snapshots\n- Decouple core from codex-login to break cycle; re-export auth in core\n- apply-patch: robust heredoc parsing via tree-sitter; minor fixes\n- protocol: align FileChange::Delete variants across core/wire code paths\n- TUI: adjust Git repo detection; simplify parsed command labels\n- mcp-server/exec: update imports and Delete handling\n- message_history: use fs2 locks; add dead_code allows\n\nValidated with ./build-fast.sh

This commit is contained in:
James Peter
2025-09-03 20:14:55 +10:00
parent 2f34578e6d
commit ed50f15337
13 changed files with 21 additions and 26 deletions
+1
View File
@@ -787,6 +787,7 @@ dependencies = [
"codex-common",
"codex-core",
"codex-login",
"codex-protocol",
"reqwest",
"serde",
"serde_json",
+1
View File
@@ -11,6 +11,7 @@ anyhow = "1"
clap = { version = "4", features = ["derive"] }
codex-common = { path = "../common", features = ["cli"] }
codex-core = { path = "../core" }
codex-protocol = { path = "../protocol" }
codex-login = { path = "../login" }
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }
serde = { version = "1", features = ["derive"] }
+1 -1
View File
@@ -145,7 +145,7 @@ pub(crate) async fn stream_chat_completions(
// Track last assistant text we emitted to avoid duplicate assistant messages
// in the outbound Chat Completions payload (can happen if a final
// aggregated assistant message was recorded alongside an earlier partial).
let mut last_assistant_text: Option<String> = None;
let _last_assistant_text: Option<String> = None;
for (idx, item) in input.iter().enumerate() {
match item {
+2 -2
View File
@@ -1,6 +1,6 @@
use std::io::BufRead;
use std::path::Path;
use std::sync::OnceLock;
// use std::sync::OnceLock;
use std::time::Duration;
use crate::AuthManager;
@@ -9,7 +9,7 @@ use codex_protocol::mcp_protocol::AuthMode;
use codex_protocol::models::ResponseItem;
use eventsource_stream::Eventsource;
use futures::prelude::*;
use regex_lite::Regex;
// use regex_lite::Regex;
use reqwest::StatusCode;
use serde::Deserialize;
use serde::Serialize;
-1
View File
@@ -11,7 +11,6 @@ use std::sync::Mutex;
use std::sync::atomic::AtomicU64;
use std::time::Duration;
use crate::AuthManager;
use async_channel::Receiver;
use async_channel::Sender;
use base64::Engine;
+1 -1
View File
@@ -129,7 +129,7 @@ impl ConversationManager {
&self,
config: Config,
rollout_path: PathBuf,
auth_manager: Arc<AuthManager>,
_auth_manager: Arc<AuthManager>,
) -> CodexResult<NewConversation> {
let _initial_history = RolloutRecorder::get_rollout_history(&rollout_path).await?;
let CodexSpawnOk {
+2
View File
@@ -141,6 +141,7 @@ pub(crate) async fn append_entry(text: &str, session_id: &Uuid, config: &Config)
/// times if the lock is currently held by another process. This prevents a
/// potential indefinite wait while still giving other writers some time to
/// finish their operation.
#[allow(dead_code)]
async fn acquire_exclusive_lock_with_retry(file: &File) -> Result<()> {
use tokio::time::sleep;
@@ -292,6 +293,7 @@ pub(crate) fn lookup(log_id: u64, offset: usize, config: &Config) -> Option<Hist
}
#[cfg(unix)]
#[allow(dead_code)]
fn acquire_shared_lock_with_retry(file: &File) -> Result<()> {
for _ in 0..MAX_RETRIES {
match fs2::FileExt::try_lock_shared(file) {
@@ -403,16 +403,13 @@ impl EventProcessor for EventProcessorWithHumanOutput {
println!("{}", line.style(self.green));
}
}
FileChange::Delete { content } => {
FileChange::Delete => {
let header = format!(
"{} {}",
format_file_change(change),
path.to_string_lossy()
);
println!("{}", header.style(self.magenta));
for line in content.lines() {
println!("{}", line.style(self.red));
}
}
FileChange::Update {
unified_diff,
@@ -32,7 +32,6 @@ use codex_protocol::protocol::TurnAbortReason;
use codex_core::protocol::InputItem as CoreInputItem;
use codex_core::protocol::Op;
use codex_core::protocol as core_protocol;
use codex_login::AuthManager;
use codex_protocol::mcp_protocol::APPLY_PATCH_APPROVAL_METHOD;
use codex_protocol::mcp_protocol::AddConversationListenerParams;
use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse;
@@ -516,7 +515,7 @@ async fn apply_bespoke_event_handling(
codex_protocol::protocol::FileChange::Add { content }
}
codex_core::protocol::FileChange::Delete => {
codex_protocol::protocol::FileChange::Delete
codex_protocol::protocol::FileChange::Delete { content: String::new() }
}
codex_core::protocol::FileChange::Update { unified_diff, move_path } => {
codex_protocol::protocol::FileChange::Update { unified_diff, move_path }
+1 -2
View File
@@ -14,8 +14,7 @@ use codex_core::AuthManager;
use codex_core::ConversationManager;
use codex_core::config::Config;
use codex_core::protocol::Submission;
use codex_login::AuthManager;
use codex_login::AuthMode;
use codex_protocol::mcp_protocol::AuthMode;
use mcp_types::CallToolRequestParams;
use mcp_types::CallToolResult;
use mcp_types::ClientRequest as McpClientRequest;
+1 -1
View File
@@ -3046,7 +3046,7 @@ impl ChatWidget<'_> {
let arch = std::env::consts::ARCH;
lines.push(Line::from(format!(" • Platform: {os}-{arch}")));
lines.push(Line::from(format!(" • CWD: {}", self.config.cwd.display())));
let in_git = codex_core::util::is_inside_git_repo(&self.config.cwd);
let in_git = codex_core::git_info::get_git_repo_root(&self.config.cwd).is_some();
lines.push(Line::from(format!(
" • Git repo: {}",
if in_git { "yes" } else { "no" }
+7 -10
View File
@@ -2168,9 +2168,7 @@ fn exec_render_parts_parsed(
(None, None) => ("Search".to_string(), cmd.clone()),
}
}
ParsedCommand::Format { .. } => ("Format".to_string(), String::new()),
ParsedCommand::Test { cmd } => ("Test".to_string(), cmd.clone()),
ParsedCommand::Lint { cmd, .. } => ("Lint".to_string(), cmd.clone()),
// Upstream variants not present in our core parser are ignored or treated as generic runs
ParsedCommand::Unknown { cmd } => {
// Suppress separator helpers like `echo ---` which are used
// internally to delimit chunks when reading files.
@@ -2182,14 +2180,15 @@ fn exec_render_parts_parsed(
("Run".to_string(), cmd.clone())
}
}
ParsedCommand::Noop { .. } => continue,
// Noop variant not present in our core parser
// ParsedCommand::Noop { .. } => continue,
};
// Enforce per-action grouping: only keep entries matching this cell's action.
if let Some(exp) = expected_label {
if label != exp {
continue;
}
} else if !(label == "Run" || label == "Test" || label == "Lint" || label == "Format") {
} else if !(label == "Run" || label == "Search") {
// For generic "run" header, keep common run-like labels only.
continue;
}
@@ -4602,9 +4601,7 @@ fn new_parsed_command(
(None, None) => ("Search".to_string(), cmd.clone()),
}
}
ParsedCommand::Format { .. } => ("Format".to_string(), String::new()),
ParsedCommand::Test { cmd } => ("Test".to_string(), cmd.clone()),
ParsedCommand::Lint { cmd, .. } => ("Lint".to_string(), cmd.clone()),
// Upstream-only variants handled as generic runs in this fork
ParsedCommand::Unknown { cmd } => {
let t = cmd.trim();
let lower = t.to_lowercase();
@@ -4614,7 +4611,7 @@ fn new_parsed_command(
("Run".to_string(), cmd.clone())
}
}
ParsedCommand::Noop { .. } => continue,
// ParsedCommand::Noop { .. } => continue,
};
// Keep only entries that match the primary action grouping.
@@ -4622,7 +4619,7 @@ fn new_parsed_command(
if label != exp {
continue;
}
} else if !(label == "Run" || label == "Test" || label == "Lint" || label == "Format") {
} else if !(label == "Run" || label == "Search") {
continue;
}
@@ -1,4 +1,4 @@
use codex_core::util::is_inside_git_repo;
use codex_core::git_info::get_git_repo_root;
use crossterm::event::KeyEvent;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
@@ -84,7 +84,7 @@ impl OnboardingScreen {
preferred_auth_method: codex_login::AuthMode::ApiKey,
}))
}
let is_git_repo = is_inside_git_repo(&cwd);
let is_git_repo = get_git_repo_root(&cwd).is_some();
let highlighted = if is_git_repo {
TrustDirectorySelection::Trust
} else {