mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
fix(tui): clear full history region (incl. padding) each frame to eliminate rare margin artifacts and ensure background is fully painted
This commit is contained in:
+60
-4
@@ -5,6 +5,9 @@ set -euo pipefail
|
||||
# Change to the Rust project root directory
|
||||
cd codex-rs
|
||||
|
||||
# Compute repository root (one level up from codex-rs)
|
||||
REPO_ROOT="$(cd .. && pwd)"
|
||||
|
||||
# Use dev-fast profile by default for quick iteration
|
||||
# Can override with: PROFILE=release ./build-fast.sh
|
||||
PROFILE="${PROFILE:-dev-fast}"
|
||||
@@ -57,7 +60,7 @@ if command -v rustup >/dev/null 2>&1; then
|
||||
|
||||
if [ -n "$TOOLCHAIN" ]; then
|
||||
# Ensure toolchain is installed; if not, attempt install quietly
|
||||
if ! rustup toolchain list | awk '{print $1}' | grep -qx "$TOOLCHAIN"; then
|
||||
if ! rustup which rustc --toolchain "$TOOLCHAIN" >/dev/null 2>&1; then
|
||||
echo "rustup: installing toolchain $TOOLCHAIN ..."
|
||||
rustup toolchain install "$TOOLCHAIN" >/dev/null 2>&1 || true
|
||||
fi
|
||||
@@ -73,16 +76,44 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Optional trace mode for diagnosing environment differences
|
||||
if [ "${TRACE_BUILD:-}" = "1" ]; then
|
||||
echo "--- TRACE_BUILD environment ---"
|
||||
echo "whoami: $(whoami)"
|
||||
echo "pwd: $(pwd)"
|
||||
echo "SHELL: ${SHELL:-}"
|
||||
bash --version | head -n1 || true
|
||||
if [ -n "${TOOLCHAIN:-}" ]; then
|
||||
echo "TOOLCHAIN: ${TOOLCHAIN}"
|
||||
rustup run "$TOOLCHAIN" rustc -vV || true
|
||||
rustup run "$TOOLCHAIN" cargo -vV || true
|
||||
fi
|
||||
echo "Filtered env (CARGO|RUST*|PROFILE|CODE_HOME|CODEX_HOME):"
|
||||
env | egrep '^(CARGO|RUST|RUSTUP|PROFILE|CODE_HOME|CODEX_HOME)=' | sort || true
|
||||
echo "--------------------------------"
|
||||
fi
|
||||
|
||||
# Build for native target (no --target flag) for maximum speed
|
||||
# This reuses the host stdlib and normal cache
|
||||
|
||||
# Build with or without --locked based on lockfile validity
|
||||
${USE_CARGO} build ${USE_LOCKED} --profile "${PROFILE}" --bin code --bin code-tui --bin code-exec
|
||||
# Merge cargo's stderr into stdout so CI/harnesses that only capture stdout
|
||||
# still show all compilation lines and warnings just like an interactive shell.
|
||||
${USE_CARGO} build ${USE_LOCKED} --profile "${PROFILE}" --bin code --bin code-tui --bin code-exec 2>&1
|
||||
|
||||
# Check if build succeeded
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Build successful!"
|
||||
echo "Binary location: ${BIN_PATH}"
|
||||
# Compute absolute path and SHA256 for clarity
|
||||
ABS_BIN_PATH="$(cd "$(dirname "${BIN_PATH}")" && pwd)/$(basename "${BIN_PATH}")"
|
||||
if command -v shasum >/dev/null 2>&1; then
|
||||
BIN_SHA="$(shasum -a 256 "${ABS_BIN_PATH}" | awk '{print $1}')"
|
||||
elif command -v sha256sum >/dev/null 2>&1; then
|
||||
BIN_SHA="$(sha256sum "${ABS_BIN_PATH}" | awk '{print $1}')"
|
||||
else
|
||||
BIN_SHA=""
|
||||
fi
|
||||
|
||||
# Keep old symlink locations working for compatibility
|
||||
# Create symlink in target/release for npm wrapper expectations
|
||||
@@ -104,7 +135,12 @@ if [ $? -eq 0 ]; then
|
||||
|
||||
echo "✅ Symlinks updated"
|
||||
echo ""
|
||||
echo "You can now run: code"
|
||||
echo "You can run the CLI directly:"
|
||||
if [ -n "$BIN_SHA" ]; then
|
||||
echo " ${ABS_BIN_PATH} (sha256: ${BIN_SHA})"
|
||||
else
|
||||
echo " ${ABS_BIN_PATH}"
|
||||
fi
|
||||
echo "Binary size: $(du -h ${BIN_PATH} | cut -f1)"
|
||||
echo ""
|
||||
echo "Build profile: ${PROFILE}"
|
||||
@@ -113,6 +149,26 @@ if [ $? -eq 0 ]; then
|
||||
echo " → For production build, use: PROFILE=release-prod ./build-fast.sh"
|
||||
fi
|
||||
|
||||
# PATH guidance and collision warning
|
||||
REPO_BIN_DIR="${REPO_ROOT}/codex-cli/bin"
|
||||
CODE_PATH_ON_PATH="$(command -v code 2>/dev/null || true)"
|
||||
if [ -n "$CODE_PATH_ON_PATH" ] && [[ "$CODE_PATH_ON_PATH" != "${REPO_BIN_DIR}/code" && "$CODE_PATH_ON_PATH" != *"/codex-cli/bin/"* ]]; then
|
||||
echo ""
|
||||
echo "⚠️ PATH notice: 'code' currently resolves to: $CODE_PATH_ON_PATH"
|
||||
echo " That is likely Visual Studio Code, not this CLI."
|
||||
echo " To use this binary via 'code', prepend the repo bin directory to PATH:"
|
||||
echo " export PATH=\"${REPO_BIN_DIR}:\$PATH\""
|
||||
echo " Then verify with:"
|
||||
echo " which code"
|
||||
fi
|
||||
|
||||
if [ "${TRACE_BUILD:-}" = "1" ] && [ -n "$BIN_SHA" ]; then
|
||||
echo "--- TRACE_BUILD artifact ---"
|
||||
echo "ABS_BIN_PATH: ${ABS_BIN_PATH}"
|
||||
echo "SHA256: ${BIN_SHA}"
|
||||
echo "--------------------------------"
|
||||
fi
|
||||
|
||||
# If lockfile was out of date, remind user
|
||||
if [ -z "$USE_LOCKED" ]; then
|
||||
echo ""
|
||||
@@ -122,4 +178,4 @@ if [ $? -eq 0 ]; then
|
||||
else
|
||||
echo "❌ Build failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1059,7 +1059,7 @@ impl BrowserManager {
|
||||
|
||||
// Skip redundant overrides within a short window to prevent flash
|
||||
{
|
||||
let mut guard = self.last_metrics_applied.lock().await;
|
||||
let guard = self.last_metrics_applied.lock().await;
|
||||
if let Some((lw, lh, ldpr, lmob, ts)) = *guard {
|
||||
let same = lw == w && lh == h && (ldpr - dpr).abs() < 0.001 && lmob == mob;
|
||||
let recent = ts.elapsed() < std::time::Duration::from_secs(30);
|
||||
|
||||
@@ -131,6 +131,7 @@ impl Page {
|
||||
}
|
||||
|
||||
/// (NEW) Injects the script to prevent new tabs from opening and redirect them to the current tab.
|
||||
#[allow(dead_code)]
|
||||
async fn inject_tab_interception_script(cdp_page: &Arc<CdpPage>) -> Result<()> {
|
||||
// The comprehensive script ported from browser_session.ts
|
||||
let script = r#"
|
||||
@@ -485,7 +486,7 @@ impl Page {
|
||||
.await;
|
||||
match retry_attempt {
|
||||
Ok(Ok(resp)) => Ok(resp.result),
|
||||
Ok(Err(err2)) => {
|
||||
Ok(Err(_)) => {
|
||||
// Last resort for visible pages: try from_surface(true).
|
||||
// This can flash; we only do it after exhausting the safer path to prevent permanent failures.
|
||||
debug!(
|
||||
@@ -557,7 +558,7 @@ impl Page {
|
||||
.await;
|
||||
match retry_attempt {
|
||||
Ok(Ok(resp)) => Ok(resp.result),
|
||||
Ok(Err(e)) => {
|
||||
Ok(Err(_)) => {
|
||||
// Final fallback with from_surface(true) even though visible (see doc rationale)
|
||||
debug!(
|
||||
"Second attempt with from_surface(false) failed while visible; attempting final from_surface(true)"
|
||||
@@ -607,6 +608,7 @@ impl Page {
|
||||
}
|
||||
|
||||
/// Check and fix viewport scaling issues before taking screenshots
|
||||
#[allow(dead_code)]
|
||||
async fn check_and_fix_scaling(&self) -> Result<()> {
|
||||
// Never touch viewport metrics for external Chrome connections.
|
||||
// Changing device metrics on a user's Chrome causes a visible flash
|
||||
|
||||
@@ -394,17 +394,20 @@ impl ModelClient {
|
||||
}
|
||||
|
||||
/// Returns the currently configured model slug.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_model(&self) -> String {
|
||||
self.config.model.clone()
|
||||
}
|
||||
|
||||
/// Returns the currently configured model family.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_model_family(&self) -> ModelFamily {
|
||||
self.config.model_family.clone()
|
||||
}
|
||||
|
||||
// duplicate of earlier helpers removed during merge cleanup
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_auth_manager(&self) -> Option<Arc<AuthManager>> {
|
||||
self.auth_manager.clone()
|
||||
}
|
||||
|
||||
+11
-11
@@ -17,10 +17,10 @@ use base64::Engine;
|
||||
use codex_apply_patch::ApplyPatchAction;
|
||||
use codex_apply_patch::MaybeApplyPatchVerified;
|
||||
use codex_apply_patch::maybe_parse_apply_patch_verified;
|
||||
use codex_login::AuthManager;
|
||||
use codex_protocol::protocol::ConversationHistoryResponseEvent;
|
||||
// unused: AuthManager
|
||||
// unused: ConversationHistoryResponseEvent
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::TurnAbortedEvent;
|
||||
// unused: TurnAbortedEvent
|
||||
use futures::prelude::*;
|
||||
use mcp_types::CallToolResult;
|
||||
use serde::Serialize;
|
||||
@@ -549,7 +549,7 @@ pub(crate) struct Session {
|
||||
approval_policy: AskForApproval,
|
||||
sandbox_policy: SandboxPolicy,
|
||||
shell_environment_policy: ShellEnvironmentPolicy,
|
||||
writable_roots: Vec<PathBuf>,
|
||||
_writable_roots: Vec<PathBuf>,
|
||||
disable_response_storage: bool,
|
||||
tools_config: ToolsConfig,
|
||||
|
||||
@@ -580,8 +580,9 @@ pub(crate) struct Session {
|
||||
}
|
||||
|
||||
impl Session {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_writable_roots(&self) -> &[PathBuf] {
|
||||
&self.writable_roots
|
||||
&self._writable_roots
|
||||
}
|
||||
|
||||
pub(crate) fn get_approval_policy(&self) -> AskForApproval {
|
||||
@@ -903,7 +904,7 @@ impl Session {
|
||||
const MAX_STREAM_OUTPUT: usize = 5 * 1024; // 5KiB
|
||||
let stdout = stdout.text.chars().take(MAX_STREAM_OUTPUT).collect();
|
||||
let stderr = stderr.text.chars().take(MAX_STREAM_OUTPUT).collect();
|
||||
let formatted_output = format_exec_output_str(output);
|
||||
// Precompute formatted output if needed in future for logging/pretty UI.
|
||||
|
||||
let msg = if is_apply_patch {
|
||||
EventMsg::PatchApplyEnd(PatchApplyEndEvent {
|
||||
@@ -1279,7 +1280,7 @@ impl AgentAgent {
|
||||
}
|
||||
}
|
||||
|
||||
fn abort(self, reason: TurnAbortReason) {
|
||||
fn abort(self, _reason: TurnAbortReason) {
|
||||
// TOCTOU?
|
||||
if !self.handle.is_finished() {
|
||||
self.handle.abort();
|
||||
@@ -1483,7 +1484,7 @@ async fn submission_loop(
|
||||
sandbox_policy,
|
||||
shell_environment_policy: config.shell_environment_policy.clone(),
|
||||
cwd,
|
||||
writable_roots,
|
||||
_writable_roots: writable_roots,
|
||||
mcp_connection_manager,
|
||||
agents: config.agents.clone(),
|
||||
notify,
|
||||
@@ -2532,8 +2533,8 @@ async fn handle_browser_cleanup(
|
||||
sub_id: String,
|
||||
call_id: String,
|
||||
) -> ResponseInputItem {
|
||||
let sess_clone = sess;
|
||||
let call_id_clone = call_id.clone();
|
||||
let sess_clone = sess;
|
||||
execute_custom_tool(
|
||||
sess,
|
||||
&sub_id,
|
||||
@@ -3132,7 +3133,7 @@ async fn handle_wait_for_agent(
|
||||
let agents = manager.list_agents(None, Some(batch_id.clone()), false);
|
||||
|
||||
// Separate terminal vs non-terminal agents
|
||||
let mut completed_agents: Vec<_> = agents
|
||||
let completed_agents: Vec<_> = agents
|
||||
.iter()
|
||||
.filter(|t| {
|
||||
matches!(
|
||||
@@ -4085,7 +4086,6 @@ async fn handle_browser_open(
|
||||
// Parse arguments as JSON for the event
|
||||
let params = serde_json::from_str(&arguments).ok();
|
||||
|
||||
let sess_clone = sess;
|
||||
let arguments_clone = arguments.clone();
|
||||
let call_id_clone = call_id.clone();
|
||||
|
||||
|
||||
@@ -31,14 +31,14 @@ pub struct NewConversation {
|
||||
/// maintaining them in memory.
|
||||
pub struct ConversationManager {
|
||||
conversations: Arc<RwLock<HashMap<Uuid, Arc<CodexConversation>>>>,
|
||||
auth_manager: Arc<AuthManager>,
|
||||
_auth_manager: Arc<AuthManager>,
|
||||
}
|
||||
|
||||
impl ConversationManager {
|
||||
pub fn new(auth_manager: Arc<AuthManager>) -> Self {
|
||||
Self {
|
||||
conversations: Arc::new(RwLock::new(HashMap::new())),
|
||||
auth_manager,
|
||||
_auth_manager: auth_manager,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ impl ConversationManager {
|
||||
config: Config,
|
||||
) -> CodexResult<NewConversation> {
|
||||
// Compute the prefix up to the cut point.
|
||||
let truncated_history =
|
||||
let _truncated_history =
|
||||
truncate_after_dropping_last_messages(conversation_history, num_messages_to_drop);
|
||||
|
||||
// Spawn a new conversation with the computed initial history.
|
||||
|
||||
@@ -26,7 +26,6 @@ use std::time::Duration;
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use uuid::Uuid;
|
||||
use fs2::FileExt;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::config_types::HistoryPersistence;
|
||||
|
||||
@@ -15,9 +15,7 @@ use crate::model_family::ModelFamily;
|
||||
use crate::plan_tool::PLAN_TOOL;
|
||||
use crate::protocol::AskForApproval;
|
||||
use crate::protocol::SandboxPolicy;
|
||||
use crate::tool_apply_patch::ApplyPatchToolType;
|
||||
use crate::tool_apply_patch::create_apply_patch_freeform_tool;
|
||||
use crate::tool_apply_patch::create_apply_patch_json_tool;
|
||||
// apply_patch tools are not currently surfaced; keep imports out to avoid warnings.
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
pub struct ResponsesApiTool {
|
||||
@@ -46,6 +44,7 @@ pub struct FreeformToolFormat {
|
||||
|
||||
/// When serialized as JSON, this produces a valid "Tool" in the OpenAI
|
||||
/// Responses API.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
#[serde(tag = "type")]
|
||||
pub(crate) enum OpenAiTool {
|
||||
@@ -88,12 +87,6 @@ impl ToolsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
let apply_patch_tool_type = match model_family.apply_patch_tool_type {
|
||||
Some(ApplyPatchToolType::Freeform) => Some(ApplyPatchToolType::Freeform),
|
||||
Some(ApplyPatchToolType::Function) => Some(ApplyPatchToolType::Function),
|
||||
None => Some(ApplyPatchToolType::Freeform),
|
||||
};
|
||||
|
||||
Self {
|
||||
shell_type,
|
||||
plan_tool: include_plan_tool,
|
||||
|
||||
@@ -22,6 +22,7 @@ pub enum ApplyPatchToolType {
|
||||
|
||||
/// Returns a custom tool that can be used to edit files. Well-suited for GPT-5 models
|
||||
/// https://platform.openai.com/docs/guides/function-calling#custom-tools
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn create_apply_patch_freeform_tool() -> OpenAiTool {
|
||||
OpenAiTool::Freeform(FreeformTool {
|
||||
name: "apply_patch".to_string(),
|
||||
@@ -55,6 +56,7 @@ eof_line: "*** End of File" LF
|
||||
}
|
||||
|
||||
/// Returns a json tool that can be used to edit files. Should only be used with gpt-oss models
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn create_apply_patch_json_tool() -> OpenAiTool {
|
||||
let mut properties = BTreeMap::new();
|
||||
properties.insert(
|
||||
|
||||
@@ -21,7 +21,6 @@ use codex_core::protocol::PatchApplyBeginEvent;
|
||||
use codex_core::protocol::PatchApplyEndEvent;
|
||||
use codex_core::protocol::SessionConfiguredEvent;
|
||||
use codex_core::protocol::TaskCompleteEvent;
|
||||
use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_core::protocol::TurnDiffEvent;
|
||||
use owo_colors::OwoColorize;
|
||||
use owo_colors::Style;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use codex_core::CodexConversation;
|
||||
use codex_core::ConversationManager;
|
||||
@@ -31,16 +30,11 @@ 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_login::CLIENT_ID;
|
||||
use codex_login::ServerOptions as LoginServerOptions;
|
||||
use codex_login::ShutdownHandle;
|
||||
use codex_login::run_login_server;
|
||||
use codex_protocol::mcp_protocol::APPLY_PATCH_APPROVAL_METHOD;
|
||||
use codex_protocol::mcp_protocol::AddConversationListenerParams;
|
||||
use codex_protocol::mcp_protocol::AddConversationSubscriptionResponse;
|
||||
use codex_protocol::mcp_protocol::ApplyPatchApprovalParams;
|
||||
use codex_protocol::mcp_protocol::ApplyPatchApprovalResponse;
|
||||
use codex_protocol::mcp_protocol::AuthStatusChangeNotification;
|
||||
use codex_protocol::mcp_protocol::ClientRequest;
|
||||
use codex_protocol::mcp_protocol::ConversationId;
|
||||
use codex_protocol::mcp_protocol::EXEC_COMMAND_APPROVAL_METHOD;
|
||||
@@ -49,9 +43,7 @@ use codex_protocol::mcp_protocol::ExecCommandApprovalResponse;
|
||||
use codex_protocol::mcp_protocol::InputItem as WireInputItem;
|
||||
use codex_protocol::mcp_protocol::InterruptConversationParams;
|
||||
use codex_protocol::mcp_protocol::InterruptConversationResponse;
|
||||
use codex_protocol::mcp_protocol::LoginChatGptCompleteNotification;
|
||||
use codex_protocol::mcp_protocol::LoginChatGptResponse;
|
||||
use codex_protocol::mcp_protocol::GitDiffToRemoteParams;
|
||||
// Unused login-related and diff param imports removed
|
||||
use codex_protocol::mcp_protocol::GitDiffToRemoteResponse;
|
||||
use codex_protocol::mcp_protocol::NewConversationParams;
|
||||
use codex_protocol::mcp_protocol::NewConversationResponse;
|
||||
@@ -61,31 +53,17 @@ use codex_protocol::mcp_protocol::SendUserMessageParams;
|
||||
use codex_protocol::mcp_protocol::SendUserMessageResponse;
|
||||
use codex_protocol::mcp_protocol::SendUserTurnParams;
|
||||
use codex_protocol::mcp_protocol::SendUserTurnResponse;
|
||||
use codex_protocol::mcp_protocol::ServerNotification;
|
||||
|
||||
// Duration before a ChatGPT login attempt is abandoned.
|
||||
const LOGIN_CHATGPT_TIMEOUT: Duration = Duration::from_secs(10 * 60);
|
||||
|
||||
struct ActiveLogin {
|
||||
shutdown_handle: ShutdownHandle,
|
||||
login_id: Uuid,
|
||||
}
|
||||
|
||||
impl ActiveLogin {
|
||||
fn drop(&self) {
|
||||
self.shutdown_handle.shutdown();
|
||||
}
|
||||
}
|
||||
// Removed deprecated ChatGPT login support scaffolding
|
||||
|
||||
/// Handles JSON-RPC messages for Codex conversations.
|
||||
pub(crate) struct CodexMessageProcessor {
|
||||
auth_manager: Arc<AuthManager>,
|
||||
_auth_manager: Arc<AuthManager>,
|
||||
conversation_manager: Arc<ConversationManager>,
|
||||
outgoing: Arc<OutgoingMessageSender>,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
config: Arc<Config>,
|
||||
_config: Arc<Config>,
|
||||
conversation_listeners: HashMap<Uuid, oneshot::Sender<()>>,
|
||||
active_login: Arc<Mutex<Option<ActiveLogin>>>,
|
||||
// Queue of pending interrupt requests per conversation. We reply when TurnAborted arrives.
|
||||
pending_interrupts: Arc<Mutex<HashMap<Uuid, Vec<RequestId>>>>,
|
||||
}
|
||||
@@ -99,13 +77,12 @@ impl CodexMessageProcessor {
|
||||
config: Arc<Config>,
|
||||
) -> Self {
|
||||
Self {
|
||||
auth_manager,
|
||||
_auth_manager: auth_manager,
|
||||
conversation_manager,
|
||||
outgoing,
|
||||
codex_linux_sandbox_exe,
|
||||
config,
|
||||
_config: config,
|
||||
conversation_listeners: HashMap::new(),
|
||||
active_login: Arc::new(Mutex::new(None)),
|
||||
pending_interrupts: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
@@ -457,7 +434,7 @@ async fn apply_bespoke_event_handling(
|
||||
conversation_id: ConversationId,
|
||||
conversation: Arc<CodexConversation>,
|
||||
outgoing: Arc<OutgoingMessageSender>,
|
||||
pending_interrupts: Arc<Mutex<HashMap<Uuid, Vec<RequestId>>>>,
|
||||
_pending_interrupts: Arc<Mutex<HashMap<Uuid, Vec<RequestId>>>>,
|
||||
) {
|
||||
let Event { id: event_id, msg } = event;
|
||||
match msg {
|
||||
|
||||
@@ -122,6 +122,7 @@ impl OutgoingMessageSender {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn send_server_notification(&self, notification: ServerNotification) {
|
||||
let method = format!("codex/event/{}", notification);
|
||||
let params = match serde_json::to_value(¬ification) {
|
||||
|
||||
@@ -22,8 +22,6 @@ use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyEventKind;
|
||||
use crossterm::execute;
|
||||
use crossterm::terminal::EnterAlternateScreen;
|
||||
use crossterm::terminal::LeaveAlternateScreen;
|
||||
use crossterm::terminal::supports_keyboard_enhancement;
|
||||
use std::path::PathBuf;
|
||||
use ratatui::prelude::Rect;
|
||||
@@ -72,9 +70,9 @@ pub(crate) struct App<'a> {
|
||||
pending_redraw: Arc<AtomicBool>,
|
||||
|
||||
// Transcript overlay state
|
||||
transcript_overlay: Option<TranscriptApp>,
|
||||
deferred_history_lines: Vec<Line<'static>>,
|
||||
transcript_saved_viewport: Option<Rect>,
|
||||
_transcript_overlay: Option<TranscriptApp>,
|
||||
_deferred_history_lines: Vec<Line<'static>>,
|
||||
_transcript_saved_viewport: Option<Rect>,
|
||||
|
||||
enhanced_keys_supported: bool,
|
||||
|
||||
@@ -216,9 +214,9 @@ impl App<'_> {
|
||||
config,
|
||||
file_search,
|
||||
pending_redraw,
|
||||
transcript_overlay: None,
|
||||
deferred_history_lines: Vec::new(),
|
||||
transcript_saved_viewport: None,
|
||||
_transcript_overlay: None,
|
||||
_deferred_history_lines: Vec::new(),
|
||||
_transcript_saved_viewport: None,
|
||||
enhanced_keys_supported,
|
||||
_debug: debug,
|
||||
commit_anim_running: Arc::new(AtomicBool::new(false)),
|
||||
|
||||
@@ -81,6 +81,7 @@ pub(crate) enum AppEvent {
|
||||
},
|
||||
|
||||
/// Result of computing a `/diff` command.
|
||||
#[allow(dead_code)]
|
||||
DiffResult(String),
|
||||
|
||||
InsertHistory(Vec<Line<'static>>),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyModifiers;
|
||||
|
||||
@@ -5,7 +5,6 @@ use crossterm::event::KeyModifiers;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Color;
|
||||
use ratatui::style::Modifier;
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::Line;
|
||||
|
||||
@@ -5,7 +5,6 @@ use crossterm::event::KeyModifiers;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::style::Color;
|
||||
use ratatui::style::Modifier;
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::Line;
|
||||
|
||||
@@ -35,7 +35,6 @@ use codex_core::protocol::ExecApprovalRequestEvent;
|
||||
use codex_core::protocol::ExecCommandBeginEvent;
|
||||
use codex_core::protocol::ExecCommandEndEvent;
|
||||
use codex_core::protocol::InputItem;
|
||||
use codex_protocol::protocol::McpListToolsResponseEvent;
|
||||
use codex_core::protocol::McpToolCallBeginEvent;
|
||||
use codex_core::protocol::McpToolCallEndEvent;
|
||||
use codex_core::protocol::Op;
|
||||
@@ -59,8 +58,6 @@ use std::cell::RefCell;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use tokio::sync::mpsc::unbounded_channel;
|
||||
use tracing::info;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::get_git_diff::get_git_diff;
|
||||
// use image::GenericImageView;
|
||||
|
||||
use crate::app_event::AppEvent;
|
||||
@@ -69,8 +66,6 @@ use crate::bottom_pane::BottomPane;
|
||||
use crate::bottom_pane::BottomPaneParams;
|
||||
use crate::bottom_pane::CancellationEvent;
|
||||
use crate::bottom_pane::InputResult;
|
||||
use crate::bottom_pane::list_selection_view::SelectionAction;
|
||||
use crate::bottom_pane::list_selection_view::SelectionItem;
|
||||
use crate::history_cell;
|
||||
use crate::history_cell::CommandOutput;
|
||||
use crate::history_cell::ExecCell;
|
||||
@@ -678,7 +673,7 @@ impl ChatWidget<'_> {
|
||||
|
||||
// Try to replace the placeholder running cell in place to preserve order.
|
||||
let mut replaced = false;
|
||||
if let Some(mut idx) = history_index {
|
||||
if let Some(idx) = history_index {
|
||||
if idx < self.history_cells.len() {
|
||||
// Sanity check: ensure it's a running exec cell for the same command
|
||||
let is_match = self.history_cells[idx]
|
||||
@@ -2041,7 +2036,7 @@ impl ChatWidget<'_> {
|
||||
|
||||
if !original_text.is_empty() {
|
||||
// Check if this is the first user prompt to trigger fade-out animation
|
||||
let has_existing_user_prompts = self.history_cells.iter().any(|cell| {
|
||||
let _has_existing_user_prompts = self.history_cells.iter().any(|cell| {
|
||||
// Check if it's a user prompt by looking at display lines
|
||||
// This is a bit indirect but works with the trait-based system
|
||||
let lines = cell.display_lines();
|
||||
@@ -4384,6 +4379,7 @@ impl ChatWidget<'_> {
|
||||
self.add_to_history(history_cell::PlainHistoryCell { lines, kind: history_cell::HistoryCellType::BackgroundEvent });
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn switch_to_internal_browser(&mut self) {
|
||||
// Switch to internal browser mode
|
||||
let latest_screenshot = self.latest_browser_screenshot.clone();
|
||||
@@ -5567,14 +5563,15 @@ impl WidgetRef for &ChatWidget<'_> {
|
||||
// Record current viewport height for the next frame
|
||||
self.last_history_viewport_height.set(content_area.height);
|
||||
|
||||
// Clear the content area to prevent stale characters from previous frames
|
||||
// This fixes the "stuck characters" issue when scrolling through chat history
|
||||
// We fill with spaces while preserving the theme background color
|
||||
// Clear the entire history region (including left/right padding), not just
|
||||
// the inner content area. This avoids occasional artifacts at the margins
|
||||
// and ensures background is fully painted even when widths shrink.
|
||||
// Fill with spaces while preserving the theme background color.
|
||||
let clear_style = Style::default()
|
||||
.bg(crate::colors::background())
|
||||
.fg(crate::colors::text());
|
||||
for y in content_area.y..(content_area.y + content_area.height) {
|
||||
for x in content_area.x..(content_area.x + content_area.width) {
|
||||
for y in history_area.y..history_area.y.saturating_add(history_area.height) {
|
||||
for x in history_area.x..history_area.x.saturating_add(history_area.width) {
|
||||
buf[(x, y)].set_char(' ').set_style(clear_style);
|
||||
}
|
||||
}
|
||||
@@ -5816,7 +5813,7 @@ impl WidgetRef for &ChatWidget<'_> {
|
||||
}
|
||||
// Match the horizontal padding used by status bar and input
|
||||
let padding = 1u16;
|
||||
let mut area = Rect {
|
||||
let area = Rect {
|
||||
x: history_area.x + padding,
|
||||
y: history_area.y,
|
||||
width: history_area.width.saturating_sub(padding * 2),
|
||||
|
||||
@@ -52,6 +52,7 @@ pub(crate) fn border_dim() -> Color {
|
||||
Color::Rgb(r, g, bl)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn border_focused() -> Color {
|
||||
current_theme().border_focused
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ impl Default for HeightManagerConfig {
|
||||
#[derive(Default)]
|
||||
struct DevCounters {
|
||||
frames: u64,
|
||||
hysteresis_applied: u64,
|
||||
_hysteresis_applied: u64,
|
||||
hud_quantized: u64,
|
||||
}
|
||||
|
||||
@@ -136,8 +136,8 @@ impl HeightManager {
|
||||
let desired = bottom_desired_height.max(5).min(bottom_cap);
|
||||
|
||||
// Bottom pane policy: Grow immediately, confirm small decreases over a few frames
|
||||
let mut bottom_h = match (self.last_bottom, self.bypass_once) {
|
||||
(Some(prev), true) => desired,
|
||||
let bottom_h = match (self.last_bottom, self.bypass_once) {
|
||||
(Some(_), true) => desired,
|
||||
(Some(prev), false) => {
|
||||
if desired > prev {
|
||||
// grow immediately, reset counter
|
||||
@@ -172,7 +172,7 @@ impl HeightManager {
|
||||
if self.bypass_once { self.bypass_once = false; }
|
||||
|
||||
// Determine HUD height if present.
|
||||
let mut hud_h: u16 = 0;
|
||||
let mut hud_h: u16;
|
||||
if hud_present {
|
||||
// This mirrors the existing preview logic while centralizing its decision.
|
||||
// Compute HUD target height using 16:9 aspect on inner width.
|
||||
|
||||
@@ -11,7 +11,6 @@ use codex_core::parse_command::ParsedCommand;
|
||||
use codex_core::plan_tool::PlanItemArg;
|
||||
use codex_core::plan_tool::StepStatus;
|
||||
use codex_core::plan_tool::UpdatePlanArgs;
|
||||
use codex_core::project_doc::discover_project_doc_paths;
|
||||
use codex_core::protocol::FileChange;
|
||||
use crate::diff_render::create_diff_summary;
|
||||
use codex_core::protocol::McpInvocation;
|
||||
@@ -782,6 +781,7 @@ impl HistoryCell for ImageOutputCell {
|
||||
// ==================== ToolCallCell ====================
|
||||
|
||||
pub(crate) enum ToolState {
|
||||
#[allow(dead_code)]
|
||||
Running,
|
||||
Success,
|
||||
Failed,
|
||||
@@ -1091,7 +1091,7 @@ impl HistoryCell for StreamingContentCell {
|
||||
const PREVIEW_HEAD_LINES: usize = 2;
|
||||
const PREVIEW_TAIL_LINES: usize = 5;
|
||||
|
||||
fn build_preview_lines(text: &str, include_left_pipe: bool) -> Vec<Line<'static>> {
|
||||
fn build_preview_lines(text: &str, _include_left_pipe: bool) -> Vec<Line<'static>> {
|
||||
let processed = format_json_compact(text).unwrap_or_else(|| text.to_string());
|
||||
let non_empty: Vec<&str> = processed
|
||||
.lines()
|
||||
@@ -1783,6 +1783,7 @@ fn new_exec_command_generic(
|
||||
lines
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new_active_mcp_tool_call(invocation: McpInvocation) -> ToolCallCell {
|
||||
let title_line = Line::styled("Working", Style::default().fg(crate::colors::primary()));
|
||||
let lines: Vec<Line> = vec![
|
||||
@@ -1793,6 +1794,7 @@ pub(crate) fn new_active_mcp_tool_call(invocation: McpInvocation) -> ToolCallCel
|
||||
ToolCallCell { lines, state: ToolState::Running }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new_active_custom_tool_call(tool_name: String, args: Option<String>) -> ToolCallCell {
|
||||
let title_line = Line::styled("Working", Style::default().fg(crate::colors::primary()));
|
||||
let invocation_str = if let Some(args) = args {
|
||||
@@ -2207,7 +2209,7 @@ fn try_new_completed_mcp_tool_call_with_image_output(
|
||||
}
|
||||
|
||||
pub(crate) fn new_completed_mcp_tool_call(
|
||||
num_cols: usize,
|
||||
_num_cols: usize,
|
||||
invocation: McpInvocation,
|
||||
duration: Duration,
|
||||
success: bool,
|
||||
|
||||
@@ -279,6 +279,7 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[allow(dead_code)]
|
||||
pub struct SetUnderlineColor(pub CColor);
|
||||
|
||||
impl Command for SetUnderlineColor {
|
||||
|
||||
@@ -18,7 +18,6 @@ use codex_ollama::DEFAULT_OSS_MODEL;
|
||||
use codex_protocol::config_types::SandboxMode;
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::PathBuf;
|
||||
use tracing::error;
|
||||
use tracing_appender::non_blocking;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
@@ -2,6 +2,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
/// Truncate a tool result to fit within the given height and width. If the text is valid JSON, we format it in a compact way before truncating.
|
||||
/// This is a best-effort approach that may not work perfectly for text where 1 grapheme is rendered as multiple terminal cells.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn format_and_truncate_tool_result(
|
||||
text: &str,
|
||||
max_lines: usize,
|
||||
@@ -74,6 +75,7 @@ pub(crate) fn format_json_compact(text: &str) -> Option<String> {
|
||||
}
|
||||
|
||||
/// Truncate `text` to `max_graphemes` graphemes. Using graphemes to avoid accidentally truncating in the middle of a multi-codepoint character.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn truncate_text(text: &str, max_graphemes: usize) -> String {
|
||||
let mut graphemes = text.grapheme_indices(true);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use std::io::Result;
|
||||
|
||||
use crate::insert_history;
|
||||
@@ -50,7 +51,7 @@ impl TranscriptApp {
|
||||
self.transcript_lines.extend(lines);
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, tui: &mut tui::Tui, key_event: KeyEvent) {
|
||||
fn handle_key_event(&mut self, _tui: &mut tui::Tui, key_event: KeyEvent) {
|
||||
match key_event {
|
||||
KeyEvent {
|
||||
code: KeyCode::Char('q'),
|
||||
|
||||
Reference in New Issue
Block a user