1pub mod auth;
9pub mod automations;
10pub mod dashboard;
11pub mod dto;
12pub mod error;
13pub mod handlers;
14pub mod mcp;
15pub mod openapi;
16pub mod sse;
17
18use std::sync::Arc;
19
20use axum::Router;
21use axum::routing::{delete, get, post, put};
22use prospero_core::bus::EventBus;
23use prospero_core::store::Store;
24use prospero_core::{FleetAdmin, FleetProvider};
25
26#[derive(Clone)]
31pub struct AppState {
32 pub fleet: Arc<dyn FleetProvider>,
35 pub admin: Option<Arc<dyn FleetAdmin>>,
37 pub store: Arc<dyn Store>,
39 pub bus: Arc<dyn EventBus>,
41 pub auth: Arc<auth::AuthState>,
43 pub automations: Option<Arc<prospero_core::automation::AutomationEngine>>,
47}
48
49pub fn router_with_auth(
52 fleet: Arc<dyn FleetProvider>,
53 admin: Option<Arc<dyn FleetAdmin>>,
54 store: Arc<dyn Store>,
55 bus: Arc<dyn EventBus>,
56 automations: Option<Arc<prospero_core::automation::AutomationEngine>>,
57 auth: auth::AuthState,
58) -> Router {
59 let auth = Arc::new(auth);
60 let mcp_service = mcp::service(fleet.clone(), store.clone());
63 let state = AppState {
64 fleet,
65 admin,
66 store,
67 bus,
68 auth: auth.clone(),
69 automations,
70 };
71 Router::new()
72 .route("/", get(dashboard::index))
82 .route("/assets/{*path}", get(dashboard::asset))
83 .route("/healthz", get(handlers::healthz))
84 .route("/readyz", get(handlers::readyz))
85 .route(
86 "/api/session",
87 get(auth::handlers::get_session)
88 .post(auth::handlers::post_session)
89 .delete(auth::handlers::delete_session),
90 )
91 .route("/api/openapi.json", get(openapi::get_openapi))
95 .route("/api/metrics", get(handlers::get_metrics))
96 .route("/api/capabilities", get(handlers::get_capabilities))
97 .route("/api/fleet", get(handlers::get_fleet))
99 .route("/api/fleet/stream", get(sse::fleet_stream))
100 .nest_service("/mcp", mcp_service)
103 .route("/api/usage", get(handlers::get_usage))
104 .route(
105 "/api/workspaces",
106 get(handlers::get_workspaces).post(handlers::add_workspace),
107 )
108 .route("/api/workspaces/{name}", delete(handlers::delete_workspace))
109 .route(
110 "/api/workspaces/{name}/config",
111 put(handlers::set_workspace_config),
112 )
113 .route(
114 "/api/workspaces/{workspace}/agents",
115 get(handlers::get_workspace_agents).post(handlers::spawn_agent),
116 )
117 .route(
119 "/api/agents/{id}",
120 get(handlers::get_agent).delete(handlers::rm_agent),
121 )
122 .route("/api/agents/{id}/events", get(handlers::get_agent_events))
123 .route("/api/agents/{id}/stream", get(sse::agent_stream))
124 .route("/api/agents/{id}/kill", post(handlers::kill_agent))
125 .route("/api/agents/{id}/respawn", post(handlers::respawn_agent))
126 .route("/api/agents/{id}/input", post(handlers::agent_input))
127 .route(
128 "/api/agents/{id}/end-input",
129 post(handlers::agent_end_input),
130 )
131 .route(
133 "/api/automations",
134 get(automations::list_automations).post(automations::create_automation),
135 )
136 .route(
137 "/api/automations/{id}",
138 delete(automations::delete_automation),
139 )
140 .route(
141 "/api/automations/{id}/enabled",
142 put(automations::set_enabled),
143 )
144 .route("/api/automations/{id}/runs", get(automations::list_runs))
145 .route("/api/automations/{id}/run", post(automations::run_now))
146 .route("/api/automations/{id}/trigger", post(automations::trigger))
147 .route_layer(axum::middleware::from_fn_with_state(auth, auth::middleware))
148 .with_state(state)
149}
150
151pub fn router(
153 fleet: Arc<dyn FleetProvider>,
154 admin: Option<Arc<dyn FleetAdmin>>,
155 store: Arc<dyn Store>,
156 bus: Arc<dyn EventBus>,
157) -> Router {
158 router_with_auth(fleet, admin, store, bus, None, auth::AuthState::disabled())
159}
160
161pub fn router_with_automations(
163 fleet: Arc<dyn FleetProvider>,
164 admin: Option<Arc<dyn FleetAdmin>>,
165 store: Arc<dyn Store>,
166 bus: Arc<dyn EventBus>,
167 automations: Arc<prospero_core::automation::AutomationEngine>,
168) -> Router {
169 router_with_auth(
170 fleet,
171 admin,
172 store,
173 bus,
174 Some(automations),
175 auth::AuthState::disabled(),
176 )
177}