diff --git a/Cargo.lock b/Cargo.lock index 20ab868..62409aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,7 +198,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -209,7 +209,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1680,7 +1680,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1801,7 +1801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3056,9 +3056,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.38.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76001fb4daed01e5f2b518aac0b4dc592e7c734da63dbffcf0c64fa612a8d0c" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ "cc", "pkg-config", @@ -3295,7 +3295,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4255,9 +4255,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.40.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3492ea85308705c3a5cc24fb9b9cf77273d30590349070db42991202b214c4" +checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" dependencies = [ "bitflags 2.11.1", "fallible-iterator", @@ -4316,7 +4316,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4395,7 +4395,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4819,7 +4819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4967,10 +4967,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand 2.4.1", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1da2fe9..3ea5edb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ cli-framework = { git = "https://github.com/aroff/cli-framework", rev = "76a83e0 validator = { version = "0.20", features = ["derive"] } # SQLite for vector index -rusqlite = { version = "0.40", features = ["bundled"] } +rusqlite = { version = "0.39", features = ["bundled"] } # SHA256 hashing for file integrity sha2 = "0.10" diff --git a/crates/fastskill-cli/src/commands/serve.rs b/crates/fastskill-cli/src/commands/serve.rs index aa418aa..ae9b916 100644 --- a/crates/fastskill-cli/src/commands/serve.rs +++ b/crates/fastskill-cli/src/commands/serve.rs @@ -90,7 +90,6 @@ pub async fn execute_serve( ); println!("FastSkill HTTP server starting..."); - println!(" Listening on: http://{}:{}", args.host, args.port); let server = fastskill_core::http::server::FastSkillServer::from_ref(&service, &args.host, args.port); diff --git a/crates/fastskill-core/src/http/server.rs b/crates/fastskill-core/src/http/server.rs index 06bc043..34e5d87 100644 --- a/crates/fastskill-core/src/http/server.rs +++ b/crates/fastskill-core/src/http/server.rs @@ -412,14 +412,24 @@ impl FastSkillServer { pub async fn serve(self) -> Result<(), Box> { // Load project configuration (same as previous create_router logic) let current_dir = env::current_dir()?; - let project_config = crate::core::load_project_config(¤t_dir) - .map_err(|e| format!("Failed to load project config: {}", e))?; + let project_config = crate::core::load_project_config(¤t_dir).ok(); + if project_config.is_none() { + tracing::warn!( + "No skill-project.toml found in {} or any parent. \ + Project-level features (manifest, skills install) will be unavailable. \ + Run `fastskill init` in your project root to create one.", + current_dir.display() + ); + } - let state = AppState::new(self.service.clone())?.with_project_config( - project_config.project_root, - project_config.project_file_path, - project_config.skills_directory, - ); + let mut state = AppState::new(self.service.clone())?; + if let Some(cfg) = project_config { + state = state.with_project_config( + cfg.project_root, + cfg.project_file_path, + cfg.skills_directory, + ); + } // Build versioned v1 router with compression (applied to fastskill routes only) let v1_router = Router::new() @@ -484,6 +494,7 @@ impl FastSkillServer { info!("Starting FastSkill HTTP server on {}", self.addr); let addr_str = self.addr.to_string(); + println!(" Listening on: http://{}", self.addr); server.serve(&addr_str).await?; Ok(()) diff --git a/tests/cli/serve_e2e_tests.rs b/tests/cli/serve_e2e_tests.rs index f3e2937..f592c92 100644 --- a/tests/cli/serve_e2e_tests.rs +++ b/tests/cli/serve_e2e_tests.rs @@ -272,6 +272,52 @@ fn test_serve_health_endpoints() { ); } +#[test] +fn test_serve_starts_without_skill_project_toml() { + if !can_bind_localhost_or_skip() { + return; + } + + // Create a temp dir with NO skill-project.toml + let temp_dir = TempDir::new().unwrap(); + + let mut child = Command::new(env!("CARGO_BIN_EXE_fastskill")) + .args(&["serve", "--port", "18086"]) + .current_dir(temp_dir.path()) + .spawn() + .expect("Failed to start server"); + + assert!( + wait_for_port(18086, 5), + "Server failed to start on port 18086 without skill-project.toml" + ); + + let rt = tokio::runtime::Runtime::new().unwrap(); + let client = reqwest::Client::new(); + + let health_status = rt.block_on(async { + client + .get("http://127.0.0.1:18086/healthz") + .send() + .await + .expect("GET /healthz") + .status() + }); + assert_eq!(health_status, reqwest::StatusCode::OK, "/healthz should return 200 without skill-project.toml"); + + let ready_status = rt.block_on(async { + client + .get("http://127.0.0.1:18086/readyz") + .send() + .await + .expect("GET /readyz") + .status() + }); + assert_eq!(ready_status, reqwest::StatusCode::OK, "/readyz should return 200 without skill-project.toml"); + + child.kill().expect("Failed to kill server"); +} + #[test] fn test_serve_port_already_in_use_error() { if !can_bind_localhost_or_skip() {