From 1dbe04b9944c4fd074305b780a1f7bd4519053f0 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 14 Mar 2026 13:14:17 -0600 Subject: [PATCH] Part 8 --- codex-rs/app-server-client/src/lib.rs | 121 +++++++++--------- codex-rs/tui/src/app.rs | 38 +++--- codex-rs/tui/src/app/app_server_adapter.rs | 20 +-- codex-rs/tui/src/app_event.rs | 3 +- codex-rs/tui/src/chatwidget.rs | 72 +++++++---- codex-rs/tui/src/chatwidget/skills.rs | 31 +++-- .../tui/src/onboarding/onboarding_screen.rs | 6 +- codex-rs/tui/src/session_log.rs | 4 +- 8 files changed, 160 insertions(+), 135 deletions(-) diff --git a/codex-rs/app-server-client/src/lib.rs b/codex-rs/app-server-client/src/lib.rs index bd5f40cbc8..11fac78469 100644 --- a/codex-rs/app-server-client/src/lib.rs +++ b/codex-rs/app-server-client/src/lib.rs @@ -274,8 +274,6 @@ pub struct InProcessAppServerClient { command_tx: mpsc::Sender, event_rx: mpsc::Receiver, worker_handle: tokio::task::JoinHandle<()>, - auth_manager: Arc, - thread_manager: Arc, } impl InProcessAppServerClient { @@ -439,21 +437,9 @@ impl InProcessAppServerClient { command_tx, event_rx, worker_handle, - auth_manager: shared_core.auth_manager, - thread_manager: shared_core.thread_manager, }) } - /// Temporary bootstrap escape hatch for embedders migrating toward RPC-only usage. - pub fn auth_manager(&self) -> Arc { - self.auth_manager.clone() - } - - /// Temporary bootstrap escape hatch for embedders migrating toward RPC-only usage. - pub fn thread_manager(&self) -> Arc { - self.thread_manager.clone() - } - /// Sends a typed client request and returns raw JSON-RPC result. /// /// Callers that expect a concrete response type should usually prefer @@ -597,6 +583,25 @@ impl InProcessAppServerClient { self.event_rx.recv().await } + /// Receives the next non-legacy server event from the in-process runtime. + /// + /// Legacy bridge notifications are skipped so fully migrated callers can + /// consume only typed app-server notifications and requests. + pub async fn next_typed_event(&mut self) -> Option { + loop { + match self.next_event().await { + Some(InProcessServerEvent::LegacyNotification(notification)) => { + warn!( + notification.method = %notification.method, + "dropping legacy in-process app-server notification" + ); + } + Some(event) => return Some(event), + None => return None, + } + } + } + /// Shuts down worker and in-process runtime with bounded wait. /// /// If graceful shutdown exceeds timeout, the worker task is aborted to @@ -606,8 +611,6 @@ impl InProcessAppServerClient { command_tx, event_rx, worker_handle, - auth_manager: _, - thread_manager: _, } = self; let mut worker_handle = worker_handle; // Drop the caller-facing receiver before asking the worker to shut @@ -659,8 +662,6 @@ mod tests { use codex_app_server_protocol::SessionSource as ApiSessionSource; use codex_app_server_protocol::ThreadStartParams; use codex_app_server_protocol::ThreadStartResponse; - use codex_core::AuthManager; - use codex_core::ThreadManager; use codex_core::config::ConfigBuilder; use pretty_assertions::assert_eq; use tokio::time::Duration; @@ -757,7 +758,7 @@ mod tests { } #[tokio::test] - async fn shared_thread_manager_tracks_threads_started_via_app_server() { + async fn thread_read_loads_threads_started_via_app_server() { let client = start_test_client(SessionSource::Cli).await; let response: ThreadStartResponse = client @@ -770,17 +771,18 @@ mod tests { }) .await .expect("thread/start should succeed"); - let created_thread_id = codex_protocol::ThreadId::from_string(&response.thread.id) - .expect("thread id should parse"); - timeout( - Duration::from_secs(2), - client.thread_manager().get_thread(created_thread_id), - ) - .await - .expect("timed out waiting for retained thread manager to observe started thread") - .expect("started thread should be visible through the shared thread manager"); - let thread_ids = client.thread_manager().list_thread_ids().await; - assert!(thread_ids.contains(&created_thread_id)); + let thread_id = response.thread.id; + let read: codex_app_server_protocol::ThreadReadResponse = client + .request_typed(ClientRequest::ThreadRead { + request_id: RequestId::Integer(4), + params: codex_app_server_protocol::ThreadReadParams { + thread_id: thread_id.clone(), + include_turns: false, + }, + }) + .await + .expect("thread/read should succeed"); + assert_eq!(read.thread.id, thread_id); client.shutdown().await.expect("shutdown should complete"); } @@ -829,22 +831,6 @@ mod tests { let (command_tx, _command_rx) = mpsc::channel(1); let (event_tx, event_rx) = mpsc::channel(1); let worker_handle = tokio::spawn(async {}); - let config = build_test_config().await; - let auth_manager = AuthManager::shared( - config.codex_home.clone(), - false, - config.cli_auth_credentials_store_mode, - ); - let thread_manager = Arc::new(ThreadManager::new( - &config, - auth_manager.clone(), - SessionSource::Exec, - CollaborationModesConfig { - default_mode_request_user_input: config - .features - .enabled(codex_core::features::Feature::DefaultModeRequestUserInput), - }, - )); event_tx .send(InProcessServerEvent::Lagged { skipped: 3 }) .await @@ -855,8 +841,6 @@ mod tests { command_tx, event_rx, worker_handle, - auth_manager, - thread_manager, }; let event = timeout(Duration::from_secs(2), client.next_event()) @@ -901,17 +885,38 @@ mod tests { } #[tokio::test] - async fn accessors_expose_retained_shared_managers() { - let client = start_test_client(SessionSource::Cli).await; + async fn next_typed_event_skips_legacy_notifications() { + let (command_tx, _command_rx) = mpsc::channel(1); + let (event_tx, event_rx) = mpsc::channel(2); + let worker_handle = tokio::spawn(async {}); + event_tx + .send(InProcessServerEvent::LegacyNotification( + codex_app_server_protocol::JSONRPCNotification { + method: "codex/event/task_complete".to_string(), + params: None, + }, + )) + .await + .expect("legacy notification should enqueue"); + event_tx + .send(InProcessServerEvent::Lagged { skipped: 2 }) + .await + .expect("lagged marker should enqueue"); + drop(event_tx); - assert!( - Arc::ptr_eq(&client.auth_manager(), &client.auth_manager()), - "auth_manager accessor should clone the retained shared manager" - ); - assert!( - Arc::ptr_eq(&client.thread_manager(), &client.thread_manager()), - "thread_manager accessor should clone the retained shared manager" - ); + let mut client = InProcessAppServerClient { + command_tx, + event_rx, + worker_handle, + }; + + let event = timeout(Duration::from_secs(2), client.next_typed_event()) + .await + .expect("typed event should arrive before timeout"); + assert!(matches!( + event, + Some(InProcessServerEvent::Lagged { skipped: 2 }) + )); client.shutdown().await.expect("shutdown should complete"); } diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index e2de1d7ff0..835d479485 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -46,6 +46,8 @@ use codex_ansi_escape::ansi_escape_line; use codex_app_server_client::InProcessAppServerClient; use codex_app_server_protocol::ConfigLayerSource; use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::SkillErrorInfo; +use codex_app_server_protocol::SkillsListEntry; use codex_core::config::Config; use codex_core::config::ConfigBuilder; use codex_core::config::ConfigOverrides; @@ -71,15 +73,11 @@ use codex_protocol::openai_models::ModelPreset; use codex_protocol::openai_models::ModelUpgrade; use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig; use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::Event; -use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::FinalOutput; -use codex_protocol::protocol::ListSkillsResponseEvent; use codex_protocol::protocol::Op; use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionConfiguredEvent; use codex_protocol::protocol::SessionSource; -use codex_protocol::protocol::SkillErrorInfo; use codex_protocol::protocol::TokenUsage; use codex_utils_absolute_path::AbsolutePathBuf; use color_eyre::eyre::Result; @@ -88,6 +86,11 @@ use crossterm::event::KeyCode; use crossterm::event::KeyEvent; use crossterm::event::KeyEventKind; use ratatui::style::Stylize; + +#[cfg(test)] +use codex_protocol::protocol::Event; +#[cfg(test)] +use codex_protocol::protocol::EventMsg; use ratatui::text::Line; use ratatui::widgets::Paragraph; use ratatui::widgets::Wrap; @@ -201,9 +204,8 @@ fn session_summary( }) } -fn errors_for_cwd(cwd: &Path, response: &ListSkillsResponseEvent) -> Vec { - response - .skills +fn errors_for_cwd(cwd: &Path, skills_entries: &[SkillsListEntry]) -> Vec { + skills_entries .iter() .find(|entry| entry.cwd.as_path() == cwd) .map(|entry| entry.errors.clone()) @@ -2274,7 +2276,7 @@ impl App { Err(err) => break Err(err), } } - app_server_event = app_server.next_event(), if listen_for_app_server_events => { + app_server_event = app_server.next_typed_event(), if listen_for_app_server_events => { match app_server_event { Some(event) => app.handle_app_server_event(&app_server, event).await, None => { @@ -2626,8 +2628,8 @@ impl App { AppEvent::CommitTick => { self.chat_widget.on_commit_tick(); } - AppEvent::CodexEvent(event) => { - self.handle_codex_event_now(event); + AppEvent::PushApprovalRequest(request) => { + self.chat_widget.push_approval_request(request); } AppEvent::Exit(mode) => { return Ok(self.handle_exit_mode(app_server, mode).await); @@ -3810,6 +3812,15 @@ impl App { } } + fn handle_skills_list_response_now(&mut self, skills_entries: Vec) { + let cwd = self.chat_widget.config_ref().cwd.clone(); + let errors = errors_for_cwd(&cwd, &skills_entries); + emit_skill_load_warnings(&self.app_event_tx, &errors); + self.chat_widget + .handle_skills_list_response(&skills_entries); + } + + #[cfg(test)] fn handle_codex_event_now(&mut self, event: Event) { let needs_refresh = matches!( event.msg, @@ -3822,11 +3833,6 @@ impl App { self.suppress_shutdown_complete = false; return; } - if let EventMsg::ListSkillsResponse(response) = &event.msg { - let cwd = self.chat_widget.config_ref().cwd.clone(); - let errors = errors_for_cwd(&cwd, response); - emit_skill_load_warnings(&self.app_event_tx, &errors); - } self.handle_backtrack_event(&event.msg); self.chat_widget.handle_codex_event(event); @@ -3846,7 +3852,7 @@ impl App { return; } if let ThreadUpdate::ThreadRolledBack { num_turns } = update { - self.handle_backtrack_event(&EventMsg::ThreadRolledBack( + self.handle_backtrack_event(&codex_protocol::protocol::EventMsg::ThreadRolledBack( codex_protocol::protocol::ThreadRolledBackEvent { num_turns }, )); self.chat_widget diff --git a/codex-rs/tui/src/app/app_server_adapter.rs b/codex-rs/tui/src/app/app_server_adapter.rs index 8eda41b6f4..faba1e2c12 100644 --- a/codex-rs/tui/src/app/app_server_adapter.rs +++ b/codex-rs/tui/src/app/app_server_adapter.rs @@ -73,9 +73,6 @@ use codex_protocol::openai_models::ModelPreset; use codex_protocol::openai_models::ModelUpgrade; use codex_protocol::openai_models::ReasoningEffortPreset; use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::Event; -use codex_protocol::protocol::EventMsg; -use codex_protocol::protocol::ListSkillsResponseEvent; use codex_protocol::protocol::Op; use codex_protocol::protocol::ReviewTarget; use codex_protocol::protocol::SandboxPolicy; @@ -624,15 +621,7 @@ impl App { "skills/list", ) .await?; - let skills = serde_json::from_value( - serde_json::to_value(response.data) - .map_err(|err| format!("failed to encode skills/list response: {err}"))?, - ) - .map_err(|err| format!("failed to convert skills/list response: {err}"))?; - self.handle_codex_event_now(Event { - id: String::new(), - msg: EventMsg::ListSkillsResponse(ListSkillsResponseEvent { skills }), - }); + self.handle_skills_list_response_now(response.data); } Op::RefreshMcpServers { config } => { let _: McpServerRefreshResponse = send_request_with_response( @@ -1027,12 +1016,6 @@ impl App { self.handle_server_notification(app_server_client, notification) .await; } - InProcessServerEvent::LegacyNotification(notification) => { - tracing::warn!( - notification.method = %notification.method, - "unexpected legacy notification after TUI app-server typed-event migration" - ); - } InProcessServerEvent::ServerRequest(request) => { self.note_server_request(&request); match request.clone() { @@ -1095,6 +1078,7 @@ impl App { tracing::warn!("{err}"); } } + _ => unreachable!("legacy notifications are filtered by next_typed_event"), } } diff --git a/codex-rs/tui/src/app_event.rs b/codex-rs/tui/src/app_event.rs index b9c99bba2d..eed5eefcd7 100644 --- a/codex-rs/tui/src/app_event.rs +++ b/codex-rs/tui/src/app_event.rs @@ -14,7 +14,6 @@ use codex_chatgpt::connectors::AppInfo; use codex_file_search::FileMatch; use codex_protocol::ThreadId; use codex_protocol::openai_models::ModelPreset; -use codex_protocol::protocol::Event; use codex_utils_approval_presets::ApprovalPreset; use crate::bottom_pane::ApprovalRequest; @@ -68,7 +67,7 @@ pub(crate) struct ConnectorsSnapshot { #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub(crate) enum AppEvent { - CodexEvent(Event), + PushApprovalRequest(ApprovalRequest), /// Open the agent picker for switching active threads. OpenAgentPicker, /// Switch the active thread to the selected agent. diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 590a4ce59c..fc8af3357c 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -52,6 +52,8 @@ use crate::text_formatting::proper_join; use crate::thread_update::ThreadUpdate; use crate::version::CODEX_CLI_VERSION; use codex_app_server_protocol::ConfigLayerSource; +use codex_app_server_protocol::SkillMetadata as AppServerSkillMetadata; +use codex_app_server_protocol::SkillsListEntry; use codex_chatgpt::connectors; use codex_core::config::Config; use codex_core::config::Constrained; @@ -93,21 +95,28 @@ use codex_protocol::items::AgentMessageItem; use codex_protocol::models::MessagePhase; use codex_protocol::models::local_image_label_text; use codex_protocol::parse_command::ParsedCommand; +#[cfg(test)] use codex_protocol::protocol::AgentMessageDeltaEvent; +#[cfg(test)] use codex_protocol::protocol::AgentMessageEvent; +#[cfg(test)] use codex_protocol::protocol::AgentReasoningDeltaEvent; +#[cfg(test)] use codex_protocol::protocol::AgentReasoningEvent; +#[cfg(test)] use codex_protocol::protocol::AgentReasoningRawContentDeltaEvent; +#[cfg(test)] use codex_protocol::protocol::AgentReasoningRawContentEvent; use codex_protocol::protocol::ApplyPatchApprovalRequestEvent; +#[cfg(test)] use codex_protocol::protocol::BackgroundEventEvent; use codex_protocol::protocol::CodexErrorInfo; +#[cfg(test)] use codex_protocol::protocol::CollabAgentSpawnBeginEvent; use codex_protocol::protocol::CreditsSnapshot; use codex_protocol::protocol::DeprecationNoticeEvent; +#[cfg(test)] use codex_protocol::protocol::ErrorEvent; -use codex_protocol::protocol::Event; -use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::ExecApprovalRequestEvent; use codex_protocol::protocol::ExecCommandBeginEvent; use codex_protocol::protocol::ExecCommandEndEvent; @@ -119,7 +128,6 @@ use codex_protocol::protocol::GuardianAssessmentStatus; use codex_protocol::protocol::ImageGenerationBeginEvent; use codex_protocol::protocol::ImageGenerationEndEvent; use codex_protocol::protocol::ListCustomPromptsResponseEvent; -use codex_protocol::protocol::ListSkillsResponseEvent; use codex_protocol::protocol::McpListToolsResponseEvent; use codex_protocol::protocol::McpStartupCompleteEvent; use codex_protocol::protocol::McpStartupStatus; @@ -131,18 +139,21 @@ use codex_protocol::protocol::PatchApplyBeginEvent; use codex_protocol::protocol::RateLimitSnapshot; use codex_protocol::protocol::ReviewRequest; use codex_protocol::protocol::ReviewTarget; -use codex_protocol::protocol::SkillMetadata as ProtocolSkillMetadata; +#[cfg(test)] use codex_protocol::protocol::StreamErrorEvent; use codex_protocol::protocol::TerminalInteractionEvent; use codex_protocol::protocol::TokenUsage; use codex_protocol::protocol::TokenUsageInfo; use codex_protocol::protocol::TurnAbortReason; +#[cfg(test)] use codex_protocol::protocol::TurnCompleteEvent; +#[cfg(test)] use codex_protocol::protocol::TurnDiffEvent; use codex_protocol::protocol::UndoCompletedEvent; use codex_protocol::protocol::UndoStartedEvent; use codex_protocol::protocol::UserMessageEvent; use codex_protocol::protocol::ViewImageToolCallEvent; +#[cfg(test)] use codex_protocol::protocol::WarningEvent; use codex_protocol::protocol::WebSearchBeginEvent; use codex_protocol::protocol::WebSearchEndEvent; @@ -163,6 +174,13 @@ use ratatui::style::Modifier; use ratatui::style::Style; use ratatui::style::Stylize; use ratatui::text::Line; + +#[cfg(test)] +use codex_protocol::protocol::Event; +#[cfg(test)] +use codex_protocol::protocol::EventMsg; +#[cfg(test)] +use codex_protocol::protocol::ListSkillsResponseEvent; use ratatui::widgets::Paragraph; use ratatui::widgets::Wrap; use tokio::sync::mpsc::UnboundedSender; @@ -675,7 +693,7 @@ pub(crate) struct ChatWidget { running_commands: HashMap, pending_collab_spawn_requests: HashMap, suppressed_exec_calls: HashSet, - skills_all: Vec, + skills_all: Vec, skills_initial_state: Option>, last_unified_wait: Option, unified_exec_wait_streak: Option, @@ -1386,6 +1404,7 @@ impl ChatWidget { Constrained::allow_only(event.sandbox_policy.clone()); } self.config.approvals_reviewer = event.approvals_reviewer; + #[cfg(test)] let initial_messages = event.initial_messages.clone(); self.last_copyable_output = None; let forked_from_id = event.forked_from_id; @@ -1417,6 +1436,7 @@ impl ChatWidget { ); self.apply_session_info_cell(session_info_cell); + #[cfg(test)] if let Some(messages) = initial_messages { self.replay_initial_messages(messages); } @@ -4241,23 +4261,16 @@ impl ChatWidget { } } SlashCommand::TestApproval => { - use codex_protocol::protocol::EventMsg; use std::collections::HashMap; - use codex_protocol::protocol::ApplyPatchApprovalRequestEvent; use codex_protocol::protocol::FileChange; - self.app_event_tx.send(AppEvent::CodexEvent(Event { - id: "1".to_string(), - // msg: EventMsg::ExecApprovalRequest(ExecApprovalRequestEvent { - // call_id: "1".to_string(), - // command: vec!["git".into(), "apply".into()], - // cwd: self.config.cwd.clone(), - // reason: Some("test".to_string()), - // }), - msg: EventMsg::ApplyPatchApprovalRequest(ApplyPatchApprovalRequestEvent { - call_id: "1".to_string(), - turn_id: "turn-1".to_string(), + self.app_event_tx.send(AppEvent::PushApprovalRequest( + ApprovalRequest::ApplyPatch { + thread_id: self.thread_id.unwrap_or_default(), + thread_label: None, + id: "1".to_string(), + reason: None, changes: HashMap::from([ ( PathBuf::from("/tmp/test.txt"), @@ -4273,10 +4286,9 @@ impl ChatWidget { }, ), ]), - reason: None, - grant_root: Some(PathBuf::from("/tmp")), - }), - })); + cwd: PathBuf::from("/tmp"), + }, + )); } } } @@ -4815,6 +4827,7 @@ impl ChatWidget { self.request_redraw(); } + #[cfg(test)] /// Replay a subset of initial events into the UI to seed the transcript when /// resuming an existing session. This approximates the live event flow and /// is intentionally conservative: only safe-to-replay items are rendered to @@ -4833,6 +4846,7 @@ impl ChatWidget { } } + #[cfg(test)] pub(crate) fn handle_codex_event(&mut self, event: Event) { let Event { id, msg } = event; self.dispatch_event_msg(Some(id), msg, None); @@ -5277,6 +5291,7 @@ impl ChatWidget { } } + #[cfg(test)] /// Dispatch a protocol `EventMsg` to the appropriate handler. /// /// `id` is `Some` for live events and `None` for replayed events from @@ -8833,11 +8848,20 @@ impl ChatWidget { self.bottom_pane.set_custom_prompts(ev.custom_prompts); } - fn on_list_skills(&mut self, ev: ListSkillsResponseEvent) { - self.set_skills_from_response(&ev); + pub(crate) fn handle_skills_list_response(&mut self, entries: &[SkillsListEntry]) { + self.set_skills_from_entries(entries); self.refresh_plugin_mentions(); } + #[cfg(test)] + fn on_list_skills(&mut self, ev: ListSkillsResponseEvent) { + let entries: Vec = serde_json::from_value( + serde_json::to_value(ev.skills).expect("legacy skills list should serialize"), + ) + .expect("legacy skills list should map to app-server skills entries"); + self.handle_skills_list_response(&entries); + } + pub(crate) fn on_connectors_loaded( &mut self, result: Result, diff --git a/codex-rs/tui/src/chatwidget/skills.rs b/codex-rs/tui/src/chatwidget/skills.rs index a2a5e73e6c..45481e4e5d 100644 --- a/codex-rs/tui/src/chatwidget/skills.rs +++ b/codex-rs/tui/src/chatwidget/skills.rs @@ -12,6 +12,8 @@ use crate::bottom_pane::SkillsToggleView; use crate::bottom_pane::popup_consts::standard_popup_hint_line; use crate::skills_helpers::skill_description; use crate::skills_helpers::skill_display_name; +use codex_app_server_protocol::SkillMetadata as AppServerSkillMetadata; +use codex_app_server_protocol::SkillsListEntry; use codex_chatgpt::connectors::AppInfo; use codex_core::connectors::connector_mention_slug; use codex_core::mention_syntax::TOOL_MENTION_SIGIL; @@ -19,9 +21,7 @@ use codex_core::skills::model::SkillDependencies; use codex_core::skills::model::SkillInterface; use codex_core::skills::model::SkillMetadata; use codex_core::skills::model::SkillToolDependency; -use codex_protocol::protocol::ListSkillsResponseEvent; -use codex_protocol::protocol::SkillMetadata as ProtocolSkillMetadata; -use codex_protocol::protocol::SkillsListEntry; +use codex_protocol::protocol::SkillScope as ProtocolSkillScope; impl ChatWidget { pub(crate) fn open_skills_list(&mut self) { @@ -75,7 +75,7 @@ impl ChatWidget { .skills_all .iter() .map(|skill| { - let core_skill = protocol_skill_to_core(skill); + let core_skill = app_server_skill_to_core(skill); let display_name = skill_display_name(&core_skill).to_string(); let description = skill_description(&core_skill).to_string(); let name = core_skill.name.clone(); @@ -137,14 +137,14 @@ impl ChatWidget { ); } - pub(crate) fn set_skills_from_response(&mut self, response: &ListSkillsResponseEvent) { - let skills = skills_for_cwd(&self.config.cwd, &response.skills); + pub(crate) fn set_skills_from_entries(&mut self, entries: &[SkillsListEntry]) { + let skills = skills_for_cwd(&self.config.cwd, entries); self.skills_all = skills; self.set_skills(Some(enabled_skills_for_mentions(&self.skills_all))); } } -fn skills_for_cwd(cwd: &Path, skills_entries: &[SkillsListEntry]) -> Vec { +fn skills_for_cwd(cwd: &Path, skills_entries: &[SkillsListEntry]) -> Vec { skills_entries .iter() .find(|entry| entry.cwd.as_path() == cwd) @@ -152,15 +152,15 @@ fn skills_for_cwd(cwd: &Path, skills_entries: &[SkillsListEntry]) -> Vec Vec { +fn enabled_skills_for_mentions(skills: &[AppServerSkillMetadata]) -> Vec { skills .iter() .filter(|skill| skill.enabled) - .map(protocol_skill_to_core) + .map(app_server_skill_to_core) .collect() } -fn protocol_skill_to_core(skill: &ProtocolSkillMetadata) -> SkillMetadata { +fn app_server_skill_to_core(skill: &AppServerSkillMetadata) -> SkillMetadata { SkillMetadata { name: skill.name.clone(), description: skill.description.clone(), @@ -194,7 +194,16 @@ fn protocol_skill_to_core(skill: &ProtocolSkillMetadata) -> SkillMetadata { permission_profile: None, managed_network_override: None, path_to_skills_md: skill.path.clone(), - scope: skill.scope, + scope: protocol_skill_scope(skill.scope), + } +} + +fn protocol_skill_scope(scope: codex_app_server_protocol::SkillScope) -> ProtocolSkillScope { + match scope { + codex_app_server_protocol::SkillScope::User => ProtocolSkillScope::User, + codex_app_server_protocol::SkillScope::Repo => ProtocolSkillScope::Repo, + codex_app_server_protocol::SkillScope::System => ProtocolSkillScope::System, + codex_app_server_protocol::SkillScope::Admin => ProtocolSkillScope::Admin, } } diff --git a/codex-rs/tui/src/onboarding/onboarding_screen.rs b/codex-rs/tui/src/onboarding/onboarding_screen.rs index 1faee14670..f675347e42 100644 --- a/codex-rs/tui/src/onboarding/onboarding_screen.rs +++ b/codex-rs/tui/src/onboarding/onboarding_screen.rs @@ -448,7 +448,7 @@ pub(crate) async fn run_onboarding_app( &mut onboarding_screen, ).await; } - app_server_event = app_server.next_event() => { + app_server_event = app_server.next_typed_event() => { if let Some(event) = app_server_event { handle_app_server_event( event, @@ -595,9 +595,9 @@ async fn handle_app_server_event( auth_widget.apply_login_completed(payload); } } - InProcessServerEvent::LegacyNotification(_) - | InProcessServerEvent::ServerNotification(_) + InProcessServerEvent::ServerNotification(_) | InProcessServerEvent::ServerRequest(_) | InProcessServerEvent::Lagged { .. } => {} + _ => {} } } diff --git a/codex-rs/tui/src/session_log.rs b/codex-rs/tui/src/session_log.rs index e512c2f3cd..767ebde88c 100644 --- a/codex-rs/tui/src/session_log.rs +++ b/codex-rs/tui/src/session_log.rs @@ -125,9 +125,7 @@ pub(crate) fn log_inbound_app_event(event: &AppEvent) { } match event { - AppEvent::CodexEvent(ev) => { - write_record("to_tui", "codex_event", ev); - } + AppEvent::PushApprovalRequest(_) => {} AppEvent::NewSession => { let value = json!({ "ts": now_ts(),