1mod handle;
2mod runner;
3mod state;
4pub mod types;
5
6use crate::history;
7use crate::history::HistoryEntry;
8use crate::runtime;
9use crate::ui::types::UiEvent;
10use anyhow::{Context, Result};
11use std::collections::HashMap;
12use std::env;
13use std::path::Path;
14use tokio::sync::mpsc;
15
16pub use handle::{UiBridge, UiHandle};
17pub use types::{UiCommand, UiJobInfo, UiJobResources, UiJobStatus};
18
19pub fn view_history(history: Vec<HistoryEntry>, current_run_id: String) -> Result<()> {
21 let (tx, rx) = mpsc::unbounded_channel();
22 let (cmd_tx, _cmd_rx) = mpsc::unbounded_channel();
23 let workdir = env::current_dir().unwrap_or_else(|_| Path::new(".").to_path_buf());
24 let runner = runner::UiRunner::new(
25 Vec::new(),
26 history,
27 current_run_id,
28 HashMap::new(),
29 String::new(),
30 workdir,
31 rx,
32 cmd_tx,
33 )?;
34 let _ = tx.send(UiEvent::PipelineFinished);
35 runner.run()
36}
37
38pub fn view_pipeline_logs(_root: &Path) -> Result<()> {
39 let history_path = runtime::history_path();
40 let history = history::load(&history_path)
41 .with_context(|| format!("failed to load history at {}", history_path.display()))?;
42 if history.is_empty() {
43 anyhow::bail!("no history entries found at {}", history_path.display());
44 }
45 let current_run_id = history
46 .last()
47 .map(|entry| entry.run_id.clone())
48 .unwrap_or_else(|| "history-view".to_string());
49 let (tx, rx) = mpsc::unbounded_channel();
50 let (cmd_tx, _cmd_rx) = mpsc::unbounded_channel();
51 let workdir = env::current_dir().unwrap_or_else(|_| Path::new(".").to_path_buf());
52 let runner = runner::UiRunner::new(
53 Vec::new(),
54 history,
55 current_run_id,
56 HashMap::new(),
57 String::new(),
58 workdir,
59 rx,
60 cmd_tx,
61 )?;
62 let _ = tx.send(UiEvent::PipelineFinished);
63 runner.run()
64}
65
66pub fn page_text_with_pager(content: &str) -> Result<()> {
67 state::page_text_with_pager(content)
68}