diff --git a/src/apps/desktop/src/lib.rs b/src/apps/desktop/src/lib.rs index e1cf7fd6..729955d5 100644 --- a/src/apps/desktop/src/lib.rs +++ b/src/apps/desktop/src/lib.rs @@ -141,6 +141,7 @@ pub async fn run() { .level_for("tracing", log::LevelFilter::Off) .level_for("opentelemetry_sdk", log::LevelFilter::Off) .level_for("opentelemetry-otlp", log::LevelFilter::Off) + .level_for("notify", log::LevelFilter::Off) .level_for("hyper_util", log::LevelFilter::Info) .level_for("h2", log::LevelFilter::Info) .level_for("portable_pty", log::LevelFilter::Info) diff --git a/src/crates/core/src/agentic/coordination/coordinator.rs b/src/crates/core/src/agentic/coordination/coordinator.rs index 8b7f4c7e..51ee6587 100644 --- a/src/crates/core/src/agentic/coordination/coordinator.rs +++ b/src/crates/core/src/agentic/coordination/coordinator.rs @@ -18,7 +18,7 @@ use crate::agentic::session::SessionManager; use crate::agentic::tools::pipeline::{SubagentParentInfo, ToolPipeline}; use crate::agentic::WorkspaceBinding; use crate::service::bootstrap::{ - initialize_workspace_persona_files, is_workspace_bootstrap_pending, + ensure_workspace_persona_files_for_prompt, is_workspace_bootstrap_pending, }; use crate::util::errors::{BitFunError, BitFunResult}; use log::{debug, error, info, warn}; @@ -743,8 +743,8 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet ) -> BitFunResult { let workspace_root = PathBuf::from(&workspace_path); // Empty or partial assistant dirs may never have run create_assistant_workspace; fill only - // missing persona stubs (never overwrite). Ensures BOOTSTRAP.md exists when appropriate. - initialize_workspace_persona_files(&workspace_root).await?; + // missing persona stubs (never overwrite), while preserving completed bootstrap state. + ensure_workspace_persona_files_for_prompt(&workspace_root).await?; let bootstrap_pending = is_workspace_bootstrap_pending(&workspace_root); if !bootstrap_pending { return Ok(AssistantBootstrapEnsureOutcome::Skipped { diff --git a/src/crates/core/src/service/bootstrap/bootstrap.rs b/src/crates/core/src/service/bootstrap/bootstrap.rs index 576ed78e..c368e038 100644 --- a/src/crates/core/src/service/bootstrap/bootstrap.rs +++ b/src/crates/core/src/service/bootstrap/bootstrap.rs @@ -237,8 +237,9 @@ fn persona_file_description(file_name: &str) -> &'static str { #[cfg(test)] mod tests { use super::{ - initialize_workspace_persona_files, normalize_line_endings, BOOTSTRAP_FILE_NAME, - IDENTITY_FILE_NAME, SOUL_FILE_NAME, USER_FILE_NAME, + ensure_workspace_persona_files_for_prompt, initialize_workspace_persona_files, + normalize_line_endings, BOOTSTRAP_FILE_NAME, IDENTITY_FILE_NAME, SOUL_FILE_NAME, + USER_FILE_NAME, }; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::fs; @@ -288,4 +289,45 @@ mod tests { .await .expect("Failed to remove temp workspace"); } + + #[tokio::test] + async fn ensure_workspace_persona_files_for_prompt_preserves_completed_bootstrap() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("System time before unix epoch") + .as_nanos(); + let workspace_root = std::env::temp_dir().join(format!( + "bitfun-bootstrap-preserve-{}-{}", + std::process::id(), + unique + )); + + fs::create_dir_all(&workspace_root) + .await + .expect("Failed to create temp workspace"); + + fs::write(workspace_root.join(USER_FILE_NAME), "user") + .await + .expect("Failed to write USER.md"); + fs::write(workspace_root.join(IDENTITY_FILE_NAME), "identity") + .await + .expect("Failed to write IDENTITY.md"); + + ensure_workspace_persona_files_for_prompt(&workspace_root) + .await + .expect("Failed to ensure persona files for prompt"); + + assert!( + !workspace_root.join(BOOTSTRAP_FILE_NAME).exists(), + "BOOTSTRAP.md should not be recreated when USER.md and IDENTITY.md already exist" + ); + assert!( + workspace_root.join(SOUL_FILE_NAME).exists(), + "SOUL.md should still be backfilled" + ); + + fs::remove_dir_all(&workspace_root) + .await + .expect("Failed to remove temp workspace"); + } } diff --git a/src/crates/core/src/service/bootstrap/mod.rs b/src/crates/core/src/service/bootstrap/mod.rs index 5a10bfc7..04b56c3b 100644 --- a/src/crates/core/src/service/bootstrap/mod.rs +++ b/src/crates/core/src/service/bootstrap/mod.rs @@ -2,6 +2,7 @@ mod bootstrap; pub use bootstrap::reset_workspace_persona_files_to_default; pub(crate) use bootstrap::{ - build_workspace_persona_prompt, initialize_workspace_persona_files, + build_workspace_persona_prompt, ensure_workspace_persona_files_for_prompt, + initialize_workspace_persona_files, is_workspace_bootstrap_pending, };