use std::sync::Arc;
use rho_providers::credentials::CredentialStore;
use crate::credential_store::AppCredentialStore;
use super::{
app_state::{HistoryUi, InputUi, PendingWorkUi, TurnUi},
clipboard::SystemClipboard,
feed_image::picker_from_environment,
palette::PaletteCaches,
process_panel::ProcessPanel,
statusline::StatusLine,
subagent_panel::SubagentPanel,
App, StatusSource, StreamUi, TuiBootstrap, UsageUi,
};
#[cfg(debug_assertions)]
use super::smoke_injection;
impl App {
pub(super) fn new(
info: TuiBootstrap,
herdr_graphics: crate::herdr::HerdrGraphicsCapability,
mcp_report: crate::tools::mcp::McpSessionReport,
mcp_catalog: crate::tools::mcp::McpCatalog,
plugins_report: crate::plugins::PluginLoadReport,
) -> Self {
#[cfg(debug_assertions)]
if smoke_injection::matrix_enabled() {
smoke_injection::seed_matrix_model_cache();
return Self::new_with_credentials(
info,
Arc::new(rho_providers::credentials::MemoryCredentialStore::default()),
herdr_graphics,
mcp_report,
mcp_catalog,
plugins_report,
);
}
Self::new_with_credentials(
info,
Arc::new(AppCredentialStore),
herdr_graphics,
mcp_report,
mcp_catalog,
plugins_report,
)
}
pub(super) fn new_with_credentials(
info: TuiBootstrap,
credential_store: Arc<dyn CredentialStore>,
herdr_graphics: crate::herdr::HerdrGraphicsCapability,
mcp_report: crate::tools::mcp::McpSessionReport,
mcp_catalog: crate::tools::mcp::McpCatalog,
plugins_report: crate::plugins::PluginLoadReport,
) -> Self {
let available_auths = Vec::new();
let using_unavailable_provider = info.services.auth_unavailable.is_some();
let mut info = info;
info.runtime.max_tool_output_lines = info.runtime.max_tool_output_lines.max(1);
let initial_status = info
.services
.auth_unavailable
.as_ref()
.map(|_| "no providers configured; run /login to sign in".to_string());
let pending_update_notice = info.services.pending_update_notice.take();
let pending_custom_models = info.services.pending_custom_models.take();
let pending_syntax_warmup = info.services.pending_syntax_warmup.take();
let prompt_history_limit = info
.services
.config_repository
.load()
.map(|config| config.prompt_history_limit)
.unwrap_or(0);
let prompt_history = super::prompt_history::PromptHistory::new(
prompt_history_limit,
info.services.pending_prompt_history.take(),
);
let statusline = StatusLine::new(&info.runtime);
let mut app = Self {
info,
terminal_session: None,
statusline,
subagent_panel: SubagentPanel::default(),
process_panel: ProcessPanel::default(),
subagent_inbox: crate::tui::subagent_inbox::SubagentInbox::default(),
pending_subagent_questionnaire: None,
input_ui: InputUi::default(),
palette_caches: PaletteCaches::default(),
status_overlay: None,
last_status: String::new(),
status_source: StatusSource::default(),
should_quit: false,
ctrl_c_streak: 0,
turn_finished_attention: false,
streams: StreamUi::default(),
turn: TurnUi::default(),
image_picker: picker_from_environment(herdr_graphics),
pending: PendingWorkUi::default(),
pending_inline_shells: Vec::new(),
deferred_inline_shell_context: Vec::new(),
goal: None,
history: HistoryUi::default(),
credential_store,
available_auths,
using_unavailable_provider,
pending_interactive_login: None,
exclusive: super::exclusive_screen::ExclusiveOccupant::Session,
pending_usage_limits: Vec::new(),
usage_limits_live: std::collections::BTreeMap::new(),
pending_changelog: None,
usage_limits_client: std::sync::OnceLock::new(),
usage: UsageUi::default(),
model_metadata: None,
pending_model_metadata: None,
pending_model_metadata_reasoning: None,
pending_update_notice,
pending_custom_models,
pending_syntax_warmup,
prompt_history,
pending_herdr_graphics: None,
held_turns: std::collections::VecDeque::new(),
compact_follow_up: super::compact_work::CompactFollowUp::None,
start_follow_ups: None,
pending_model_selection: None,
model_picker_scope_override: None,
internal_agent_model_target: None,
pending_auto_classifier_demote: false,
agent_editor_session: None,
sessions_hub_state: super::sessions_hub::SessionsHubState::default(),
pending_session_title: None,
session_title_locked: false,
clipboard: Box::new(SystemClipboard::default()),
media_attach_tasks: Vec::new(),
composer_attachment_layout_cache: None,
attach_run_filter: super::attach_picker::WorkspaceRunFilter::RunningOnly,
attach_disk_candidates: Vec::new(),
attach_seen_live: std::collections::HashSet::new(),
last_mouse_position: None,
screen_selection: None,
mcp_report,
mcp_catalog,
mcp_argument_completions:
super::mcp_argument_completion::McpArgumentCompletions::default(),
plugins_report,
};
if let Some(status) = initial_status {
app.set_status(status);
}
app
}
}