diff --git a/apps/framework-cli/src/cli/commands.rs b/apps/framework-cli/src/cli/commands.rs index 02b5247fee..2ad50f5e4f 100644 --- a/apps/framework-cli/src/cli/commands.rs +++ b/apps/framework-cli/src/cli/commands.rs @@ -141,7 +141,7 @@ pub enum Commands { Ps {}, /// View Moose primitives & infrastructure Ls { - /// Filter by infrastructure type (tables, streams, ingestion, sql_resource, consumption) + /// Filter by infrastructure type (tables, streams, ingestion, sql_resource, consumption, workflows, web_apps) #[arg(long)] _type: Option, diff --git a/apps/framework-cli/src/cli/routines/ls.rs b/apps/framework-cli/src/cli/routines/ls.rs index 77cf0eab53..c58dd1f4c9 100644 --- a/apps/framework-cli/src/cli/routines/ls.rs +++ b/apps/framework-cli/src/cli/routines/ls.rs @@ -8,6 +8,7 @@ use crate::framework::core::infrastructure::api_endpoint::{APIType, ApiEndpoint} use crate::framework::core::infrastructure::function_process::FunctionProcess; use crate::framework::core::infrastructure::topic::Topic; use crate::framework::core::infrastructure::topic_sync_process::TopicToTableSyncProcess; +use crate::framework::core::infrastructure::web_app::WebApp; use crate::framework::core::infrastructure_map::InfrastructureMap; use crate::framework::scripts::Workflow; use crate::{ @@ -260,6 +261,37 @@ impl From for WorkflowInfo { } } +#[derive(Debug, Serialize)] +pub struct WebAppInfo { + pub name: String, + pub mount_path: String, +} + +impl From for WebAppInfo { + fn from(value: WebApp) -> Self { + Self { + name: value.name, + mount_path: value.mount_path, + } + } +} + +impl ResourceInfo for Vec { + fn show(&self) { + show_table( + "Web Apps".to_string(), + vec!["name".to_string(), "mount_path".to_string()], + self.iter() + .map(|app| vec![app.name.clone(), app.mount_path.clone()]) + .collect(), + ) + } + + fn to_json_string(&self) -> Result { + serde_json::to_string_pretty(&self) + } +} + #[derive(Debug, Serialize)] pub struct ResourceListing { pub tables: Vec, @@ -269,6 +301,7 @@ pub struct ResourceListing { pub consumption_apis: Vec, pub stream_transformations: Vec, pub workflows: Vec, + pub web_apps: Vec, } impl ResourceInfo for ResourceListing { @@ -280,6 +313,7 @@ impl ResourceInfo for ResourceListing { self.consumption_apis.show(); self.stream_transformations.show(); self.workflows.show(); + self.web_apps.show(); } fn to_json_string(&self) -> Result { @@ -351,6 +385,12 @@ pub async fn ls_dmv2( .filter(|api| name.is_none_or(|name| api.name().contains(name))) .map(|w| w.into()) .collect(), + web_apps: infra_map + .web_apps + .into_values() + .filter(|app| name.is_none_or(|n| app.name.contains(n))) + .map(Into::into) + .collect(), }; let listing: &dyn ResourceInfo = match _type { None => &resources, @@ -360,6 +400,7 @@ pub async fn ls_dmv2( Some("sql_resource") => &resources.sql_resources, Some("consumption") => &resources.consumption_apis, Some("workflows") => &resources.workflows, + Some("web_apps") => &resources.web_apps, _ => { return Err(RoutineFailure::error(Message::new( "Unknown".to_string(), diff --git a/apps/framework-cli/src/mcp/tools/infra_map.rs b/apps/framework-cli/src/mcp/tools/infra_map.rs index 9efe63b777..59043bde6c 100644 --- a/apps/framework-cli/src/mcp/tools/infra_map.rs +++ b/apps/framework-cli/src/mcp/tools/infra_map.rs @@ -47,7 +47,7 @@ pub fn tool_definition() -> Tool { Tool { name: "get_infra_map".into(), description: Some( - "🔍 START HERE: Get complete project topology showing all components (tables, topics, APIs, functions, workflows) with source file locations and data flow connections. Essential first step to understand project structure, locate files, and verify code changes are reflected. Use 'search' to focus on specific components (e.g., search='User' shows UserEvents topic, user tables, and all related connections).".into() + "🔍 START HERE: Get complete project topology showing all components (tables, topics, APIs, functions, workflows, web apps) with source file locations and data flow connections. Essential first step to understand project structure, locate files, and verify code changes are reflected. Use 'search' to focus on specific components (e.g., search='User' shows UserEvents topic, user tables, and all related connections).".into() ), input_schema: Arc::new(schema.as_object().unwrap().clone()), annotations: None,