feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
428
crates/app-tauri/src/state.rs
Normal file
428
crates/app-tauri/src/state.rs
Normal file
@ -0,0 +1,428 @@
|
||||
//! Managed application state — the product of the **composition root**.
|
||||
//!
|
||||
//! The composition root ([`build_app_state`]) is the *single* place that
|
||||
//! constructs concrete adapters (`new ConcreteAdapter`) and injects them as
|
||||
//! `Arc<dyn Port>` into the use cases (ARCHITECTURE §1.1, §10). The use cases
|
||||
//! are then exposed through `tauri::State<AppState>` to the command handlers.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use application::{
|
||||
CloseProject, CloseTab, CloseTerminal, ConfigureProfiles, CreateAgentFromScratch,
|
||||
CreateAgentFromTemplate, CreateLayout, CreateProject, CreateTemplate, DeleteAgent,
|
||||
DeleteLayout, DeleteProfile, DeleteTemplate, DetectAgentDrift, DetectProfiles, FirstRunState,
|
||||
GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus, GitUnstage,
|
||||
HealthUseCase, LaunchAgent, ListAgents, ListLayouts, ListProfiles, ListProjects, ListTemplates,
|
||||
LoadLayout, MoveTabToNewWindow, MutateLayout, OpenProject, OpenTerminal, ReadAgentContext,
|
||||
ReferenceProfiles, RenameLayout, ResizeTerminal, SaveProfile, SetActiveLayout,
|
||||
SyncAgentWithTemplate, TerminalSessions, UpdateAgentContext, UpdateTemplate, WriteToTerminal,
|
||||
};
|
||||
use domain::ports::{
|
||||
AgentContextStore, AgentRuntime, Clock, EventBus, FileSystem, GitPort, IdGenerator,
|
||||
ProcessSpawner, ProfileStore, ProjectStore, PtyPort, TemplateStore,
|
||||
};
|
||||
|
||||
use infrastructure::{
|
||||
CliAgentRuntime, FsProfileStore, FsProjectStore, FsTemplateStore, Git2Repository,
|
||||
IdeaiContextStore, LocalFileSystem, LocalProcessSpawner, PortablePtyAdapter, SystemClock,
|
||||
TokioBroadcastEventBus, UuidGenerator,
|
||||
};
|
||||
|
||||
use crate::pty::PtyBridge;
|
||||
|
||||
/// Everything the IPC layer needs at runtime, managed by Tauri.
|
||||
///
|
||||
/// Use cases are stored behind `Arc` so handlers clone cheaply. The concrete
|
||||
/// adapters are owned here and never leak past the composition root as concrete
|
||||
/// types — downstream code only sees the `Arc<dyn Port>` held inside the use
|
||||
/// cases.
|
||||
pub struct AppState {
|
||||
/// Trivial health use case validating the end-to-end wiring.
|
||||
pub health: Arc<HealthUseCase>,
|
||||
/// Create a project (init `.ideai/`, register it).
|
||||
pub create_project: Arc<CreateProject>,
|
||||
/// Open a project (load meta + manifest).
|
||||
pub open_project: Arc<OpenProject>,
|
||||
/// Close a project (persist state).
|
||||
pub close_project: Arc<CloseProject>,
|
||||
/// Close a tab.
|
||||
pub close_tab: Arc<CloseTab>,
|
||||
/// List known projects.
|
||||
pub list_projects: Arc<ListProjects>,
|
||||
/// Open a terminal (spawn PTY, register session).
|
||||
pub open_terminal: Arc<OpenTerminal>,
|
||||
/// Write keystrokes to a terminal.
|
||||
pub write_terminal: Arc<WriteToTerminal>,
|
||||
/// Resize a terminal.
|
||||
pub resize_terminal: Arc<ResizeTerminal>,
|
||||
/// Close a terminal (kill PTY).
|
||||
pub close_terminal: Arc<CloseTerminal>,
|
||||
/// Load a project's persisted layout tree.
|
||||
pub load_layout: Arc<LoadLayout>,
|
||||
/// Mutate + persist a project's layout tree.
|
||||
pub mutate_layout: Arc<MutateLayout>,
|
||||
/// List all named layouts for a project (#4).
|
||||
pub list_layouts: Arc<ListLayouts>,
|
||||
/// Create a new named layout (#4).
|
||||
pub create_layout: Arc<CreateLayout>,
|
||||
/// Rename a named layout (#4).
|
||||
pub rename_layout: Arc<RenameLayout>,
|
||||
/// Delete a named layout (#4).
|
||||
pub delete_layout: Arc<DeleteLayout>,
|
||||
/// Set the active named layout (#4).
|
||||
pub set_active_layout: Arc<SetActiveLayout>,
|
||||
/// Detect which candidate profiles' CLIs are installed (first-run).
|
||||
pub detect_profiles: Arc<DetectProfiles>,
|
||||
/// List configured profiles.
|
||||
pub list_profiles: Arc<ListProfiles>,
|
||||
/// Save (upsert) a profile.
|
||||
pub save_profile: Arc<SaveProfile>,
|
||||
/// Delete a profile.
|
||||
pub delete_profile: Arc<DeleteProfile>,
|
||||
/// Persist the batch of chosen profiles (closes the first run).
|
||||
pub configure_profiles: Arc<ConfigureProfiles>,
|
||||
/// Expose the pre-filled reference catalogue.
|
||||
pub reference_profiles: Arc<ReferenceProfiles>,
|
||||
/// Whether the first-run wizard should show + the reference catalogue.
|
||||
pub first_run_state: Arc<FirstRunState>,
|
||||
/// The local PTY adapter, kept port-typed so the presentation layer can
|
||||
/// `subscribe_output` to pump bytes into the [`PtyBridge`] (it owns transport).
|
||||
pub pty_port: Arc<dyn PtyPort>,
|
||||
/// Active-terminal registry shared by the terminal use cases.
|
||||
pub terminal_sessions: Arc<TerminalSessions>,
|
||||
/// The domain event bus (also handed to the event relay).
|
||||
pub event_bus: Arc<TokioBroadcastEventBus>,
|
||||
/// Generic PTY↔Channel bridge registry (consumed by L3).
|
||||
pub pty_bridge: Arc<PtyBridge>,
|
||||
// --- Agents (L6) ---
|
||||
/// Create a project agent from scratch.
|
||||
pub create_agent: Arc<CreateAgentFromScratch>,
|
||||
/// List a project's agents.
|
||||
pub list_agents: Arc<ListAgents>,
|
||||
/// Read an agent's Markdown context.
|
||||
pub read_agent_context: Arc<ReadAgentContext>,
|
||||
/// Overwrite an agent's Markdown context.
|
||||
pub update_agent_context: Arc<UpdateAgentContext>,
|
||||
/// Delete an agent from the manifest.
|
||||
pub delete_agent: Arc<DeleteAgent>,
|
||||
/// Launch an agent (spawn PTY, apply injection strategy).
|
||||
pub launch_agent: Arc<LaunchAgent>,
|
||||
/// Project registry — used by agent commands to resolve a `Project` from an id.
|
||||
pub project_store: Arc<dyn ProjectStore>,
|
||||
// --- Windows (L10) ---
|
||||
/// Detach a tab into a new OS window (persists the workspace topology).
|
||||
pub move_tab: Arc<MoveTabToNewWindow>,
|
||||
// --- Templates & sync (L7) ---
|
||||
/// Create a template in the global store.
|
||||
pub create_template: Arc<CreateTemplate>,
|
||||
/// Update a template's content (bumps version).
|
||||
pub update_template: Arc<UpdateTemplate>,
|
||||
/// List all templates in the global store.
|
||||
pub list_templates: Arc<ListTemplates>,
|
||||
/// Delete a template from the global store.
|
||||
pub delete_template: Arc<DeleteTemplate>,
|
||||
/// Create an agent from a template.
|
||||
pub create_agent_from_template: Arc<CreateAgentFromTemplate>,
|
||||
/// Detect which synchronized agents are behind their template.
|
||||
pub detect_agent_drift: Arc<DetectAgentDrift>,
|
||||
/// Apply a template update to a synchronized agent.
|
||||
pub sync_agent_with_template: Arc<SyncAgentWithTemplate>,
|
||||
// --- Git (L8) ---
|
||||
/// Report the working-tree status of a repository.
|
||||
pub git_status: Arc<GitStatus>,
|
||||
/// Stage a path.
|
||||
pub git_stage: Arc<GitStage>,
|
||||
/// Unstage a path.
|
||||
pub git_unstage: Arc<GitUnstage>,
|
||||
/// Create a commit.
|
||||
pub git_commit: Arc<GitCommit>,
|
||||
/// List branches.
|
||||
pub git_branches: Arc<GitBranches>,
|
||||
/// Check out a branch.
|
||||
pub git_checkout: Arc<GitCheckout>,
|
||||
/// Return the recent commit log.
|
||||
pub git_log: Arc<GitLog>,
|
||||
/// Initialise a repository.
|
||||
pub git_init: Arc<GitInit>,
|
||||
/// Return the commit graph for all local branches.
|
||||
pub git_graph: Arc<GitGraph>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
/// **Composition root.** Builds all adapters and use cases.
|
||||
///
|
||||
/// `app_data_dir` is the machine-local IDE data directory (ARCHITECTURE
|
||||
/// §9.2), resolved by the caller via the Tauri path API and injected here so
|
||||
/// the stores never touch Tauri themselves (Dependency Inversion).
|
||||
///
|
||||
/// This is the only function that constructs concrete adapters; every other
|
||||
/// layer depends on ports. Adapters added in later lots (PTY, git, remote)
|
||||
/// are wired in here.
|
||||
#[must_use]
|
||||
pub fn build(app_data_dir: PathBuf) -> Self {
|
||||
// --- Concrete adapters (driven adapters) ---
|
||||
let event_bus = Arc::new(TokioBroadcastEventBus::new());
|
||||
let clock = Arc::new(SystemClock::new());
|
||||
let ids = Arc::new(UuidGenerator::new());
|
||||
let fs = Arc::new(LocalFileSystem::new());
|
||||
let store = Arc::new(FsProjectStore::new(
|
||||
Arc::clone(&fs) as Arc<dyn FileSystem>,
|
||||
app_data_dir.to_string_lossy().into_owned(),
|
||||
));
|
||||
|
||||
// Port-typed handles for injection.
|
||||
let fs_port = Arc::clone(&fs) as Arc<dyn FileSystem>;
|
||||
let store_port = Arc::clone(&store) as Arc<dyn ProjectStore>;
|
||||
let events_port = Arc::clone(&event_bus) as Arc<dyn EventBus>;
|
||||
|
||||
// --- Use cases (ports injected as Arc<dyn Port>) ---
|
||||
let health = Arc::new(HealthUseCase::new(
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
|
||||
let create_project = Arc::new(CreateProject::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&clock) as Arc<dyn Clock>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let open_project = Arc::new(OpenProject::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
));
|
||||
let close_project = Arc::new(CloseProject::new(Arc::clone(&store_port)));
|
||||
let close_tab = Arc::new(CloseTab::new(Arc::clone(&store_port)));
|
||||
let list_projects = Arc::new(ListProjects::new(Arc::clone(&store_port)));
|
||||
|
||||
// --- PTY adapter + terminal use cases (L3) ---
|
||||
let pty = Arc::new(PortablePtyAdapter::new());
|
||||
let pty_port = Arc::clone(&pty) as Arc<dyn PtyPort>;
|
||||
let terminal_sessions = Arc::new(TerminalSessions::new());
|
||||
|
||||
let open_terminal = Arc::new(OpenTerminal::new(
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&terminal_sessions),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let write_terminal = Arc::new(WriteToTerminal::new(
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&terminal_sessions),
|
||||
));
|
||||
let resize_terminal = Arc::new(ResizeTerminal::new(
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&terminal_sessions),
|
||||
));
|
||||
let close_terminal = Arc::new(CloseTerminal::new(
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&terminal_sessions),
|
||||
));
|
||||
|
||||
// --- Layout use cases (L4 + #4) ---
|
||||
let load_layout = Arc::new(LoadLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
));
|
||||
let mutate_layout = Arc::new(MutateLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let list_layouts = Arc::new(ListLayouts::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
));
|
||||
let create_layout = Arc::new(CreateLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let rename_layout = Arc::new(RenameLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let delete_layout = Arc::new(DeleteLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let set_active_layout = Arc::new(SetActiveLayout::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
|
||||
// --- Profiles & AI runtime (L5) ---
|
||||
// One generic, profile-driven runtime adapter (Open/Closed): it holds the
|
||||
// process spawner used for detection. The profile store persists
|
||||
// `profiles.json` in the same machine-local app-data dir as the project
|
||||
// registry.
|
||||
let spawner = Arc::new(LocalProcessSpawner::new());
|
||||
let spawner_port = Arc::clone(&spawner) as Arc<dyn ProcessSpawner>;
|
||||
let runtime = Arc::new(CliAgentRuntime::new(Arc::clone(&spawner_port)));
|
||||
let runtime_port = Arc::clone(&runtime) as Arc<dyn AgentRuntime>;
|
||||
|
||||
let profile_store = Arc::new(FsProfileStore::new(
|
||||
Arc::clone(&fs_port),
|
||||
app_data_dir.to_string_lossy().into_owned(),
|
||||
));
|
||||
let profile_store_port = Arc::clone(&profile_store) as Arc<dyn ProfileStore>;
|
||||
|
||||
let detect_profiles = Arc::new(DetectProfiles::new(Arc::clone(&runtime_port)));
|
||||
let list_profiles = Arc::new(ListProfiles::new(Arc::clone(&profile_store_port)));
|
||||
let save_profile = Arc::new(SaveProfile::new(Arc::clone(&profile_store_port)));
|
||||
let delete_profile = Arc::new(DeleteProfile::new(Arc::clone(&profile_store_port)));
|
||||
let configure_profiles = Arc::new(ConfigureProfiles::new(Arc::clone(&profile_store_port)));
|
||||
let reference_profiles = Arc::new(ReferenceProfiles::new());
|
||||
let first_run_state = Arc::new(FirstRunState::new(Arc::clone(&profile_store_port)));
|
||||
|
||||
let pty_bridge = Arc::new(PtyBridge::new());
|
||||
|
||||
// --- Agent context store + use cases (L6) ---
|
||||
let contexts = Arc::new(IdeaiContextStore::new(Arc::clone(&fs_port)));
|
||||
let contexts_port = Arc::clone(&contexts) as Arc<dyn AgentContextStore>;
|
||||
|
||||
let create_agent = Arc::new(CreateAgentFromScratch::new(
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let list_agents = Arc::new(ListAgents::new(Arc::clone(&contexts_port)));
|
||||
let read_agent_context = Arc::new(ReadAgentContext::new(Arc::clone(&contexts_port)));
|
||||
let update_agent_context = Arc::new(UpdateAgentContext::new(Arc::clone(&contexts_port)));
|
||||
let delete_agent = Arc::new(DeleteAgent::new(
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
// LaunchAgent shares the SAME pty_port and terminal_sessions as the terminal
|
||||
// use cases — indispensable for the PtyBridge to work correctly.
|
||||
let launch_agent = Arc::new(LaunchAgent::new(
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&profile_store_port),
|
||||
Arc::clone(&runtime_port),
|
||||
Arc::clone(&fs_port),
|
||||
Arc::clone(&pty_port),
|
||||
Arc::clone(&terminal_sessions),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
|
||||
let project_store = Arc::clone(&store_port);
|
||||
|
||||
// --- Template store + use cases (L7) ---
|
||||
let template_store = Arc::new(FsTemplateStore::new(
|
||||
Arc::clone(&fs_port),
|
||||
app_data_dir.to_string_lossy().into_owned(),
|
||||
));
|
||||
let template_store_port = Arc::clone(&template_store) as Arc<dyn TemplateStore>;
|
||||
|
||||
let create_template = Arc::new(CreateTemplate::new(
|
||||
Arc::clone(&template_store_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
));
|
||||
let update_template = Arc::new(UpdateTemplate::new(
|
||||
Arc::clone(&template_store_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let list_templates = Arc::new(ListTemplates::new(Arc::clone(&template_store_port)));
|
||||
let delete_template = Arc::new(DeleteTemplate::new(Arc::clone(&template_store_port)));
|
||||
let create_agent_from_template = Arc::new(CreateAgentFromTemplate::new(
|
||||
Arc::clone(&template_store_port),
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let detect_agent_drift = Arc::new(DetectAgentDrift::new(
|
||||
Arc::clone(&template_store_port),
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let sync_agent_with_template = Arc::new(SyncAgentWithTemplate::new(
|
||||
Arc::clone(&template_store_port),
|
||||
Arc::clone(&contexts_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
|
||||
// --- Git adapter + use cases (L8) ---
|
||||
let git = Arc::new(Git2Repository::new());
|
||||
let git_port = Arc::clone(&git) as Arc<dyn GitPort>;
|
||||
|
||||
let git_status = Arc::new(GitStatus::new(Arc::clone(&git_port)));
|
||||
let git_stage = Arc::new(GitStage::new(Arc::clone(&git_port)));
|
||||
let git_unstage = Arc::new(GitUnstage::new(Arc::clone(&git_port)));
|
||||
let git_commit = Arc::new(GitCommit::new(Arc::clone(&git_port), Arc::clone(&events_port)));
|
||||
let git_branches = Arc::new(GitBranches::new(Arc::clone(&git_port)));
|
||||
let git_checkout = Arc::new(GitCheckout::new(
|
||||
Arc::clone(&git_port),
|
||||
Arc::clone(&events_port),
|
||||
));
|
||||
let git_log = Arc::new(GitLog::new(Arc::clone(&git_port)));
|
||||
let git_init = Arc::new(GitInit::new(Arc::clone(&git_port), Arc::clone(&events_port)));
|
||||
let git_graph = Arc::new(GitGraph::new(Arc::clone(&git_port)));
|
||||
|
||||
// --- Windows (L10) ---
|
||||
let move_tab = Arc::new(MoveTabToNewWindow::new(
|
||||
Arc::clone(&store_port),
|
||||
Arc::clone(&ids) as Arc<dyn IdGenerator>,
|
||||
));
|
||||
|
||||
Self {
|
||||
health,
|
||||
create_project,
|
||||
open_project,
|
||||
close_project,
|
||||
close_tab,
|
||||
list_projects,
|
||||
open_terminal,
|
||||
write_terminal,
|
||||
resize_terminal,
|
||||
close_terminal,
|
||||
load_layout,
|
||||
mutate_layout,
|
||||
list_layouts,
|
||||
create_layout,
|
||||
rename_layout,
|
||||
delete_layout,
|
||||
set_active_layout,
|
||||
detect_profiles,
|
||||
list_profiles,
|
||||
save_profile,
|
||||
delete_profile,
|
||||
configure_profiles,
|
||||
reference_profiles,
|
||||
first_run_state,
|
||||
pty_port,
|
||||
terminal_sessions,
|
||||
event_bus,
|
||||
pty_bridge,
|
||||
create_agent,
|
||||
list_agents,
|
||||
read_agent_context,
|
||||
update_agent_context,
|
||||
delete_agent,
|
||||
launch_agent,
|
||||
project_store,
|
||||
create_template,
|
||||
update_template,
|
||||
list_templates,
|
||||
delete_template,
|
||||
create_agent_from_template,
|
||||
detect_agent_drift,
|
||||
sync_agent_with_template,
|
||||
git_status,
|
||||
git_stage,
|
||||
git_unstage,
|
||||
git_commit,
|
||||
git_branches,
|
||||
git_checkout,
|
||||
git_log,
|
||||
git_init,
|
||||
git_graph,
|
||||
move_tab,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user