summaryrefslogtreecommitdiff
path: root/makima/src/bin/makima.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-19 13:47:32 +0000
committerGitHub <noreply@github.com>2026-01-19 13:47:32 +0000
commit0833fb1f30c0c3b920157deb882e0e902c3af02a (patch)
tree45110fb8cb9277dfbaccfeb53ed9c1f76975022b /makima/src/bin/makima.rs
parent786510379bed060db2b3742b7dfca671552d2c34 (diff)
downloadsoryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.tar.gz
soryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.zip
Add interactive TUI browser for tasks, contracts, and files (makima view) (#7)
* feat(tui): Implement fuzzy search with real-time filtering and highlighting Adds comprehensive fuzzy search functionality to the TUI browser: ## Fuzzy Matching (fuzzy.rs) - FuzzyMatcher wrapper using SkimMatcherV2 from fuzzy-matcher crate - fuzzy_match() returns score and matched character indices - fuzzy_match_all() supports multi-term search (space-separated) - Recency-aware scoring to boost recent items in results - Unit tests for all matching scenarios ## App State (app.rs) - FilteredItem struct with index, score, and matched_indices - apply_filter() uses fuzzy matching with score-based sorting - match_count() and has_no_matches() helper methods - Results sorted by match score (highest first) ## List View (list_view.rs) - Highlighted matched characters in search results - Yellow bold styling for matched chars - Status icons with color coding ## Search Input (search_input.rs) - Real-time match count display (X/Y matches) - Visual feedback for no matches (red border) - Placeholder text when search is empty - Active search mode indication (yellow border) ## Event Handling (event.rs) - Arrow key navigation while in search mode - Ctrl+K/J for vim-style navigation during search - Delete key support alongside backspace - Ctrl+U to clear search query - Tab toggles preview while searching - Escape clears search and exits search mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:20:34 UTC * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:31:19 UTC * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:39:07 UTC * fix(tui): Fix module exports and main binary integration - Update mod.rs to properly export app, event, fuzzy, and ui modules - Add run() function for TUI entry point - Fix run_view() to use ViewCommand enum instead of ViewArgs - Fix event handling to use poll_event and handle_key_event Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/bin/makima.rs')
-rw-r--r--makima/src/bin/makima.rs67
1 files changed, 66 insertions, 1 deletions
diff --git a/makima/src/bin/makima.rs b/makima/src/bin/makima.rs
index 6ed1761..8fc8b60 100644
--- a/makima/src/bin/makima.rs
+++ b/makima/src/bin/makima.rs
@@ -6,8 +6,9 @@ use std::sync::Arc;
use makima::daemon::api::ApiClient;
use makima::daemon::cli::{
- Cli, Commands, ContractCommand, SupervisorCommand,
+ Cli, Commands, ContractCommand, SupervisorCommand, ViewCommand, ViewArgs,
};
+use makima::daemon::tui::{self, App, ListItem, ViewType};
use makima::daemon::config::{DaemonConfig, RepoEntry};
use makima::daemon::db::LocalDb;
use makima::daemon::error::DaemonError;
@@ -26,6 +27,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Commands::Daemon(args) => run_daemon(args).await,
Commands::Supervisor(cmd) => run_supervisor(cmd).await,
Commands::Contract(cmd) => run_contract(cmd).await,
+ Commands::View(args) => run_view(args).await,
}
}
@@ -530,6 +532,69 @@ async fn run_contract(
Ok(())
}
+/// Run the TUI view command.
+async fn run_view(cmd: ViewCommand) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+ // Extract view type and args from command
+ let (view_type, args) = match cmd {
+ ViewCommand::Tasks(args) => (ViewType::Tasks, args),
+ ViewCommand::Contracts(args) => (ViewType::Contracts, args),
+ ViewCommand::Files(args) => (ViewType::Files, args),
+ };
+
+ // Create API client
+ let client = ApiClient::new(args.api_url.clone(), args.api_key.clone())?;
+
+ // Fetch initial data based on view type
+ let items = match view_type {
+ ViewType::Tasks => {
+ let contract_id = args.contract_id
+ .ok_or("Contract ID is required for tasks view (use --contract-id or MAKIMA_CONTRACT_ID)")?;
+ let result = client.supervisor_tasks(contract_id).await?;
+ // Parse tasks from JSON array
+ result.0.as_array()
+ .map(|arr| arr.iter().filter_map(ListItem::from_task).collect())
+ .unwrap_or_default()
+ }
+ ViewType::Contracts => {
+ // For contracts, we would need a list contracts endpoint
+ // For now, return empty or fetch from a different endpoint
+ eprintln!("Contracts view not yet implemented - requires list contracts endpoint");
+ Vec::new()
+ }
+ ViewType::Files => {
+ let contract_id = args.contract_id
+ .ok_or("Contract ID is required for files view (use --contract-id or MAKIMA_CONTRACT_ID)")?;
+ let result = client.contract_files(contract_id).await?;
+ // Parse files from JSON array
+ result.0.as_array()
+ .map(|arr| arr.iter().filter_map(ListItem::from_file).collect())
+ .unwrap_or_default()
+ }
+ };
+
+ // Create TUI app
+ let mut app = App::new(view_type);
+ app.contract_id = args.contract_id;
+ app.set_items(items);
+
+ // Run TUI
+ match tui::run(app) {
+ Ok(Some(path)) => {
+ // Output the path for shell integration (e.g., cd $(makima view tasks))
+ tui::print_path(&path);
+ }
+ Ok(None) => {
+ // Normal exit, no output needed
+ }
+ Err(e) => {
+ eprintln!("TUI error: {}", e);
+ std::process::exit(1);
+ }
+ }
+
+ Ok(())
+}
+
fn init_logging(level: &str, format: &str) {
let filter = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new(level))