1pub mod actions;
10pub mod activity;
11pub mod app;
12pub mod cards;
13pub mod chat;
14pub mod command_exec;
15pub mod commands;
16pub mod driver;
17pub mod event_loop;
18pub mod hit;
19pub mod keymap;
20pub mod llm_activity;
21pub mod metrics;
22pub mod modal;
23pub mod modal_keys;
24pub mod projection;
25pub mod rail;
26pub mod render;
27pub mod theme;
28pub mod uimsg;
29pub mod wireshark;
30
31use std::sync::Arc;
32
33use anyhow::Result;
34use tokio::sync::{mpsc, Mutex};
35
36use crate::cli::theme::ColorPalette;
37use crate::events::EventHandler;
38use crate::llm::OllamaClient;
39use crate::settings::Settings;
40use crate::state::app_state::AppState;
41use crate::ui::App;
42
43use app::DashboardApp;
44use event_loop::LoopContext;
45use theme::Styles;
46
47#[cfg(not(target_arch = "wasm32"))]
49pub async fn run_dashboard(
50 state: AppState,
51 core: App,
52 event_handler: EventHandler,
53 llm_client: OllamaClient,
54 settings: Settings,
55 args: &crate::cli::Args,
56 palette: ColorPalette,
57) -> Result<()> {
58 let (app, ctx) = prepare_dashboard(
59 state,
60 core,
61 event_handler,
62 llm_client,
63 settings,
64 args,
65 palette,
66 )
67 .await?;
68 event_loop::run(app, ctx).await
69}
70
71pub type DashboardReady =
73 Box<dyn FnOnce(mpsc::UnboundedSender<String>, mpsc::UnboundedSender<uimsg::UiMsg>)>;
74
75#[allow(clippy::too_many_arguments)]
80pub async fn run_dashboard_on<B, S>(
81 terminal: &mut ratatui::Terminal<B>,
82 events: S,
83 state: AppState,
84 core: App,
85 event_handler: EventHandler,
86 llm_client: OllamaClient,
87 settings: Settings,
88 args: &crate::cli::Args,
89 palette: ColorPalette,
90 on_ready: Option<DashboardReady>,
91) -> Result<()>
92where
93 B: ratatui::backend::Backend,
94 S: futures::Stream<Item = std::io::Result<crossterm::event::Event>> + Unpin,
95{
96 let (app, ctx) = prepare_dashboard(
97 state,
98 core,
99 event_handler,
100 llm_client,
101 settings,
102 args,
103 palette,
104 )
105 .await?;
106 if let Some(ready) = on_ready {
110 ready(ctx.status_tx.clone(), app.ui_tx.clone());
111 }
112 event_loop::run_loop(terminal, events, app, ctx).await
113}
114
115async fn prepare_dashboard(
118 state: AppState,
119 mut core: App,
120 event_handler: EventHandler,
121 llm_client: OllamaClient,
122 settings: Settings,
123 args: &crate::cli::Args,
124 palette: ColorPalette,
125) -> Result<(DashboardApp, LoopContext)> {
126 let settings = Arc::new(Mutex::new(settings));
127
128 let resolved = {
130 let guard = settings.lock().await;
131 crate::cli::model_select::resolve_startup_model(args, &guard).await?
132 };
133 state
134 .set_ollama_model(if resolved.model.is_empty() {
135 None
136 } else {
137 Some(resolved.model.clone())
138 })
139 .await;
140 core.connection_info.model = resolved.model.clone();
141
142 let web_search_mode = settings.lock().await.get_web_search_mode();
144 state.set_web_search_mode(web_search_mode).await;
145 if let Ok(Some(handler_mode)) = args.parse_event_handler_mode() {
146 state.set_event_handler_mode(handler_mode).await;
147 }
148
149 let (status_tx, status_rx) = mpsc::unbounded_channel::<String>();
150 let (web_approval_tx, web_approval_rx) = mpsc::unbounded_channel();
151 let (ui_tx, ui_rx) = mpsc::unbounded_channel::<uimsg::UiMsg>();
152 state.set_web_approval_channel(web_approval_tx).await;
153
154 let styles = Styles::from_palette(&palette);
155 let mut app = DashboardApp::new(core, styles, status_tx.clone(), ui_tx, llm_client.clone());
156
157 app.push_system("NetGet — a starts a server or client, Tab reaches them, F1 lists every key");
158 for message in resolved.messages {
159 app.push_system(message);
160 }
161
162 #[cfg(not(target_arch = "wasm32"))]
164 if args.show_art {
165 let base_url = resolved.base_url.clone();
166 let model = resolved.model.clone();
167 let tx = status_tx.clone();
168 tokio::spawn(async move {
169 let _ =
170 crate::cli::banner::generate_and_stream_ascii_banner(&base_url, &model, tx).await;
171 });
172 }
173
174 let ctx = LoopContext {
175 state,
176 event_handler,
177 llm_client,
178 settings,
179 status_tx,
180 status_rx,
181 web_approval_rx,
182 ui_rx,
183 };
184
185 Ok((app, ctx))
186}