diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 75309c9bb5..bcda301b7c 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -766,9 +766,11 @@ pub struct GhostSnapshotToml { #[serde(alias = "ignore_untracked_files_over_bytes")] pub ignore_large_untracked_files: Option, /// Ignore untracked directories that contain this many files or more. - /// (Still emits a warning.) + /// (Still emits a warning unless warnings are disabled.) #[serde(alias = "large_untracked_dir_warning_threshold")] pub ignore_large_untracked_dirs: Option, + /// Disable all ghost snapshot warning events. + pub disable_warnings: Option, } #[derive(Debug, PartialEq, Eq)] @@ -1087,6 +1089,11 @@ impl Config { config.ignore_large_untracked_dirs = if threshold > 0 { Some(threshold) } else { None }; } + if let Some(ghost_snapshot) = cfg.ghost_snapshot.as_ref() + && let Some(disable_warnings) = ghost_snapshot.disable_warnings + { + config.disable_warnings = disable_warnings; + } config }; diff --git a/codex-rs/core/src/tasks/ghost_snapshot.rs b/codex-rs/core/src/tasks/ghost_snapshot.rs index ec6f829c79..48a6137c6d 100644 --- a/codex-rs/core/src/tasks/ghost_snapshot.rs +++ b/codex-rs/core/src/tasks/ghost_snapshot.rs @@ -41,31 +41,36 @@ impl SessionTask for GhostSnapshotTask { ) -> Option { tokio::task::spawn(async move { let token = self.token; + let warnings_enabled = !ctx.ghost_snapshot.disable_warnings; // Channel used to signal when the snapshot work has finished so the // timeout warning task can exit early without sending a warning. let (snapshot_done_tx, snapshot_done_rx) = oneshot::channel::<()>(); - let ctx_for_warning = ctx.clone(); - let cancellation_token_for_warning = cancellation_token.clone(); - let session_for_warning = session.clone(); - // Fire a generic warning if the snapshot is still running after - // three minutes; this helps users discover large untracked files - // that might need to be added to .gitignore. - tokio::task::spawn(async move { - tokio::select! { - _ = tokio::time::sleep(SNAPSHOT_WARNING_THRESHOLD) => { - session_for_warning.session - .send_event( - &ctx_for_warning, - EventMsg::Warning(WarningEvent { - message: "Repository snapshot is taking longer than expected. Large untracked or ignored files can slow snapshots; consider adding large files or directories to .gitignore or disabling `undo` in your config.".to_string() - }), - ) - .await; + if warnings_enabled { + let ctx_for_warning = ctx.clone(); + let cancellation_token_for_warning = cancellation_token.clone(); + let session_for_warning = session.clone(); + // Fire a generic warning if the snapshot is still running after + // three minutes; this helps users discover large untracked files + // that might need to be added to .gitignore. + tokio::task::spawn(async move { + tokio::select! { + _ = tokio::time::sleep(SNAPSHOT_WARNING_THRESHOLD) => { + session_for_warning.session + .send_event( + &ctx_for_warning, + EventMsg::Warning(WarningEvent { + message: "Repository snapshot is taking longer than expected. Large untracked or ignored files can slow snapshots; consider adding large files or directories to .gitignore or disabling `undo` in your config.".to_string() + }), + ) + .await; + } + _ = snapshot_done_rx => {} + _ = cancellation_token_for_warning.cancelled() => {} } - _ = snapshot_done_rx => {} - _ = cancellation_token_for_warning.cancelled() => {} - } - }); + }); + } else { + drop(snapshot_done_rx); + } let ctx_for_task = ctx.clone(); let cancelled = tokio::select! { @@ -84,18 +89,20 @@ impl SessionTask for GhostSnapshotTask { { Ok(Ok((ghost_commit, report))) => { info!("ghost snapshot blocking task finished"); - for message in format_snapshot_warnings( - ghost_snapshot.ignore_large_untracked_files, - ghost_snapshot.ignore_large_untracked_dirs, - &report, - ) { - session - .session - .send_event( - &ctx_for_task, - EventMsg::Warning(WarningEvent { message }), - ) - .await; + if warnings_enabled { + for message in format_snapshot_warnings( + ghost_snapshot.ignore_large_untracked_files, + ghost_snapshot.ignore_large_untracked_dirs, + &report, + ) { + session + .session + .send_event( + &ctx_for_task, + EventMsg::Warning(WarningEvent { message }), + ) + .await; + } } session .session diff --git a/codex-rs/utils/git/src/ghost_commits.rs b/codex-rs/utils/git/src/ghost_commits.rs index 1e3c606f09..4555781185 100644 --- a/codex-rs/utils/git/src/ghost_commits.rs +++ b/codex-rs/utils/git/src/ghost_commits.rs @@ -65,6 +65,7 @@ pub struct RestoreGhostCommitOptions<'a> { pub struct GhostSnapshotConfig { pub ignore_large_untracked_files: Option, pub ignore_large_untracked_dirs: Option, + pub disable_warnings: bool, } impl Default for GhostSnapshotConfig { @@ -72,6 +73,7 @@ impl Default for GhostSnapshotConfig { Self { ignore_large_untracked_files: Some(DEFAULT_IGNORE_LARGE_UNTRACKED_FILES), ignore_large_untracked_dirs: Some(DEFAULT_IGNORE_LARGE_UNTRACKED_DIRS), + disable_warnings: false, } } } @@ -1164,6 +1166,7 @@ mod tests { let snapshot_config = GhostSnapshotConfig { ignore_large_untracked_files: Some(DEFAULT_IGNORE_LARGE_UNTRACKED_FILES), ignore_large_untracked_dirs: Some(threshold), + disable_warnings: false, }; let (ghost, _report) = create_ghost_commit_with_report( &CreateGhostCommitOptions::new(repo).ghost_snapshot(snapshot_config), diff --git a/docs/config.md b/docs/config.md index 511e15f03c..8d4cfe349e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -944,6 +944,7 @@ Valid values: | `tui.animations` | boolean | Enable terminal animations (welcome screen, shimmer, spinner). Defaults to true; set to `false` to disable visual motion. | | `instructions` | string | Currently ignored; use `experimental_instructions_file` or `AGENTS.md`. | | `features.` | boolean | See [feature flags](#feature-flags) for details | +| `ghost_snapshot.disable_warnings` | boolean | Disable every warnings around ghost snapshot (large files, directory, ...) | | `ghost_snapshot.ignore_large_untracked_files` | number | Exclude untracked files larger than this many bytes from ghost snapshots (default: 10 MiB). Set to `0` to disable. | | `ghost_snapshot.ignore_large_untracked_dirs` | number | Ignore untracked directories with at least this many files (default: 200). Set to `0` to disable. | | `mcp_servers..command` | string | MCP server launcher command (stdio servers only). |