From 1c8c1350f1961ce3f170662c392d6d7c6e3248b6 Mon Sep 17 00:00:00 2001 From: wushijian Date: Mon, 20 Jul 2026 17:16:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=AE=B0=E5=BF=86=20CLI=20agent=20?= =?UTF-8?q?=E6=B5=AE=E7=AA=97=E5=B0=BA=E5=AF=B8=E5=B9=B6=E8=B7=A8=E9=87=8D?= =?UTF-8?q?=E5=90=AF=E4=BF=9D=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 每次新建对话时 CLI agent 浮窗都回到默认大小(360x320),因为 CLISubagentView::new 每次都创建全新的 ResizableStateHandle。 接入仓库统一的 ResizableData 机制(与 LeftPanel/RightPanel/WarpAI 相同): - ModalType 新增 CliSubagentWidth/CliSubagentHeight,ModalSizes 持有 共享 handle,同窗口内新对话自动复用记忆尺寸 - windows 表新增 cli_subagent_width/cli_subagent_height 两列 (迁移 2026-07-20-000000_add_cli_subagent_window_sizes), 经 WindowSnapshot 会话恢复链路跨重启保留 --- app/src/ai/blocklist/block/cli.rs | 27 +++++++++++++++++-- app/src/app_state.rs | 2 ++ app/src/launch_configs/launch_config_tests.rs | 4 +++ app/src/persistence/sqlite.rs | 4 +++ app/src/persistence/sqlite_tests.rs | 6 +++++ app/src/terminal/resizable_data.rs | 20 ++++++++++++++ app/src/workspace/view.rs | 16 +++++++++++ .../down.sql | 2 ++ .../up.sql | 2 ++ crates/persistence/src/model.rs | 4 +++ crates/persistence/src/schema.rs | 2 ++ 11 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/down.sql create mode 100644 crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/up.sql diff --git a/app/src/ai/blocklist/block/cli.rs b/app/src/ai/blocklist/block/cli.rs index 2c804c3a814..7b2d68a0fcc 100644 --- a/app/src/ai/blocklist/block/cli.rs +++ b/app/src/ai/blocklist/block/cli.rs @@ -61,6 +61,7 @@ use crate::server::telemetry::TelemetryEvent; use crate::settings::{AISettings, SelectionSettings}; use crate::terminal::input::SET_INPUT_MODE_TERMINAL_ACTION_NAME; use crate::terminal::model::block::{AgentInteractionMetadata, BlockId}; +use crate::terminal::resizable_data::{ModalType, ResizableData}; use crate::terminal::{ShellLaunchData, TerminalModel}; use crate::view_components::DismissibleToast; use crate::workspace::WorkspaceAction; @@ -837,6 +838,28 @@ impl CLISubagentView { _ => {} }); + let resizable_data_handle = ResizableData::handle(ctx); + let resizable_width = match resizable_data_handle + .as_ref(ctx) + .get_handle(ctx.window_id(), ModalType::CliSubagentWidth) + { + Some(handle) => handle, + None => { + log::error!("Couldn't retrieve CLI subagent width resizable state handle."); + resizable_state_handle(MIN_RESIZABLE_WIDTH) + } + }; + let resizable_height = match resizable_data_handle + .as_ref(ctx) + .get_handle(ctx.window_id(), ModalType::CliSubagentHeight) + { + Some(handle) => handle, + None => { + log::error!("Couldn't retrieve CLI subagent height resizable state handle."); + resizable_state_handle(MAX_HEIGHT) + } + }; + let mut view = Self { block_id, model, @@ -867,8 +890,8 @@ impl CLISubagentView { hidden_response_scroll_offset: None, is_input_dismissed: false, input_dismiss_timer_handle: None, - resizable_width: resizable_state_handle(MIN_RESIZABLE_WIDTH), - resizable_height: resizable_state_handle(MAX_HEIGHT), + resizable_width, + resizable_height, current_working_directory, shell_launch_data, selected_text: Arc::new(RwLock::new(None)), diff --git a/app/src/app_state.rs b/app/src/app_state.rs index e1fa16a467e..8c12b73930b 100644 --- a/app/src/app_state.rs +++ b/app/src/app_state.rs @@ -56,6 +56,8 @@ pub struct WindowSnapshot { pub vertical_tabs_panel_open: bool, pub left_panel_width: Option, pub right_panel_width: Option, + pub cli_subagent_width: Option, + pub cli_subagent_height: Option, pub agent_management_filters: Option, /// The per-window theme override for this window, if the user set one via the /// theme chooser's "This window" scope. Re-applied on restore. diff --git a/app/src/launch_configs/launch_config_tests.rs b/app/src/launch_configs/launch_config_tests.rs index 98bd01f51d3..26ce863b124 100644 --- a/app/src/launch_configs/launch_config_tests.rs +++ b/app/src/launch_configs/launch_config_tests.rs @@ -34,6 +34,8 @@ fn single_tab_snapshot(root: PaneNodeSnapshot) -> AppState { fullscreen_state: Default::default(), left_panel_width: None, right_panel_width: None, + cli_subagent_width: None, + cli_subagent_height: None, agent_management_filters: None, theme_override: None, }], @@ -59,6 +61,8 @@ fn multi_tab_snapshot(active_tab_index: usize, tabs: Vec) -> AppSta fullscreen_state: Default::default(), left_panel_width: None, right_panel_width: None, + cli_subagent_width: None, + cli_subagent_height: None, agent_management_filters: None, theme_override: None, }], diff --git a/app/src/persistence/sqlite.rs b/app/src/persistence/sqlite.rs index eb2bef3c454..d91b66dd8b6 100644 --- a/app/src/persistence/sqlite.rs +++ b/app/src/persistence/sqlite.rs @@ -1086,6 +1086,8 @@ fn save_app_state(conn: &mut SqliteConnection, app_state: &AppState) -> Result<( .theme_override .as_ref() .and_then(|k| serde_json::to_string(k).ok()), + cli_subagent_width: window.cli_subagent_width, + cli_subagent_height: window.cli_subagent_height, }; diesel::insert_into(schema::windows::dsl::windows) .values(new_window) @@ -2851,6 +2853,8 @@ fn read_sqlite_data( fullscreen_state: fullscreen_state_val, left_panel_width, right_panel_width, + cli_subagent_width: window.cli_subagent_width, + cli_subagent_height: window.cli_subagent_height, agent_management_filters: window .agent_management_filters .and_then(|s| serde_json::from_str(&s).ok()), diff --git a/app/src/persistence/sqlite_tests.rs b/app/src/persistence/sqlite_tests.rs index 1c4e597c597..207ee30c073 100644 --- a/app/src/persistence/sqlite_tests.rs +++ b/app/src/persistence/sqlite_tests.rs @@ -154,6 +154,8 @@ fn test_terminal_window_snapshot(vertical_tabs_panel_open: bool) -> WindowSnapsh vertical_tabs_panel_open, left_panel_width: None, right_panel_width: None, + cli_subagent_width: None, + cli_subagent_height: None, agent_management_filters: None, theme_override: None, } @@ -238,6 +240,8 @@ fn test_sqlite_round_trips_custom_vertical_tabs_title() { vertical_tabs_panel_open: false, left_panel_width: None, right_panel_width: None, + cli_subagent_width: None, + cli_subagent_height: None, agent_management_filters: None, theme_override: None, }], @@ -311,6 +315,8 @@ fn test_sqlite_round_trips_code_pane_with_multiple_tabs() { vertical_tabs_panel_open: false, left_panel_width: None, right_panel_width: None, + cli_subagent_width: None, + cli_subagent_height: None, agent_management_filters: None, theme_override: None, }], diff --git a/app/src/terminal/resizable_data.rs b/app/src/terminal/resizable_data.rs index 10ffe6fc17b..6b47d14f040 100644 --- a/app/src/terminal/resizable_data.rs +++ b/app/src/terminal/resizable_data.rs @@ -15,6 +15,8 @@ pub const DEFAULT_WARP_DRIVE_INDEX_WIDTH: f32 = 300.; pub const DEFAULT_SETTINGS_PANEL_WIDTH: f32 = 194.; pub const DEFAULT_LEFT_PANEL_WIDTH: f32 = 240.; pub const DEFAULT_RIGHT_PANEL_WIDTH: f32 = 480.; +pub const DEFAULT_CLI_SUBAGENT_WIDTH: f32 = 360.; +pub const DEFAULT_CLI_SUBAGENT_HEIGHT: f32 = 320.; /// A naming system for the ResizableStateHandles pub enum ModalType { UniversalSearchWidth, @@ -24,6 +26,8 @@ pub enum ModalType { SettingsPanelWidth, LeftPanelWidth, RightPanelWidth, + CliSubagentWidth, + CliSubagentHeight, } /// A grouping of state handles for the resizables that should be stored and loaded as a part @@ -36,6 +40,8 @@ pub struct ModalSizes { pub settings_panel_width: ResizableStateHandle, pub left_panel_width: ResizableStateHandle, pub right_panel_width: ResizableStateHandle, + pub cli_subagent_width: ResizableStateHandle, + pub cli_subagent_height: ResizableStateHandle, } impl ModalSizes { @@ -62,6 +68,12 @@ impl ModalSizes { let right_panel_width = window_snapshot .right_panel_width .unwrap_or(right_panel_size); + let cli_subagent_width = window_snapshot + .cli_subagent_width + .unwrap_or(DEFAULT_CLI_SUBAGENT_WIDTH); + let cli_subagent_height = window_snapshot + .cli_subagent_height + .unwrap_or(DEFAULT_CLI_SUBAGENT_HEIGHT); Self { universal_search_width: resizable_state_handle(universal_search_width), @@ -71,6 +83,8 @@ impl ModalSizes { settings_panel_width: resizable_state_handle(settings_panel_width), left_panel_width: resizable_state_handle(left_panel_width), right_panel_width: resizable_state_handle(right_panel_width), + cli_subagent_width: resizable_state_handle(cli_subagent_width), + cli_subagent_height: resizable_state_handle(cli_subagent_height), } } @@ -83,6 +97,8 @@ impl ModalSizes { settings_panel_width: resizable_state_handle(DEFAULT_SETTINGS_PANEL_WIDTH), left_panel_width: resizable_state_handle(left_default), right_panel_width: resizable_state_handle(right_default), + cli_subagent_width: resizable_state_handle(DEFAULT_CLI_SUBAGENT_WIDTH), + cli_subagent_height: resizable_state_handle(DEFAULT_CLI_SUBAGENT_HEIGHT), } } @@ -96,6 +112,8 @@ impl ModalSizes { ModalType::SettingsPanelWidth => self.settings_panel_width.clone(), ModalType::LeftPanelWidth => self.left_panel_width.clone(), ModalType::RightPanelWidth => self.right_panel_width.clone(), + ModalType::CliSubagentWidth => self.cli_subagent_width.clone(), + ModalType::CliSubagentHeight => self.cli_subagent_height.clone(), } } } @@ -111,6 +129,8 @@ impl Default for ModalSizes { settings_panel_width: resizable_state_handle(DEFAULT_SETTINGS_PANEL_WIDTH), left_panel_width: resizable_state_handle(DEFAULT_LEFT_PANEL_WIDTH), right_panel_width: resizable_state_handle(DEFAULT_RIGHT_PANEL_WIDTH), + cli_subagent_width: resizable_state_handle(DEFAULT_CLI_SUBAGENT_WIDTH), + cli_subagent_height: resizable_state_handle(DEFAULT_CLI_SUBAGENT_HEIGHT), } } } diff --git a/app/src/workspace/view.rs b/app/src/workspace/view.rs index 9a0fb455aaf..73dfc918842 100644 --- a/app/src/workspace/view.rs +++ b/app/src/workspace/view.rs @@ -9662,6 +9662,20 @@ impl Workspace { .unwrap_or(DEFAULT_RIGHT_PANEL_WIDTH) }); + let cli_subagent_width = modal_sizes.map(|ms| { + ms.cli_subagent_width + .lock() + .expect("should be able to lock cli subagent resizable state handle") + .size() + }); + + let cli_subagent_height = modal_sizes.map(|ms| { + ms.cli_subagent_height + .lock() + .expect("should be able to lock cli subagent resizable state handle") + .size() + }); + WindowSnapshot { tabs, active_tab_index, @@ -9676,6 +9690,8 @@ impl Workspace { vertical_tabs_panel_open: self.vertical_tabs_panel_open, left_panel_width, right_panel_width, + cli_subagent_width, + cli_subagent_height, agent_management_filters: None, theme_override: self.theme_override.clone(), } diff --git a/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/down.sql b/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/down.sql new file mode 100644 index 00000000000..b9e0582bd1c --- /dev/null +++ b/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/down.sql @@ -0,0 +1,2 @@ +ALTER TABLE windows DROP COLUMN cli_subagent_width; +ALTER TABLE windows DROP COLUMN cli_subagent_height; diff --git a/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/up.sql b/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/up.sql new file mode 100644 index 00000000000..edc8dd5fe0d --- /dev/null +++ b/crates/persistence/migrations/2026-07-20-000000_add_cli_subagent_window_sizes/up.sql @@ -0,0 +1,2 @@ +ALTER TABLE windows ADD cli_subagent_width FLOAT CHECK (cli_subagent_width >= 0); +ALTER TABLE windows ADD cli_subagent_height FLOAT CHECK (cli_subagent_height >= 0); diff --git a/crates/persistence/src/model.rs b/crates/persistence/src/model.rs index fcaecdd3146..94acded1767 100644 --- a/crates/persistence/src/model.rs +++ b/crates/persistence/src/model.rs @@ -43,6 +43,8 @@ pub struct Window { pub left_panel_open: Option, pub vertical_tabs_panel_open: Option, pub theme_override: Option, + pub cli_subagent_width: Option, + pub cli_subagent_height: Option, } #[derive(Identifiable, Insertable, Queryable)] @@ -305,6 +307,8 @@ pub struct NewWindow { pub left_panel_open: Option, pub vertical_tabs_panel_open: Option, pub theme_override: Option, + pub cli_subagent_width: Option, + pub cli_subagent_height: Option, } #[derive(Identifiable, Queryable, Associations)] diff --git a/crates/persistence/src/schema.rs b/crates/persistence/src/schema.rs index 881d51b7ddf..dc56f9994c2 100644 --- a/crates/persistence/src/schema.rs +++ b/crates/persistence/src/schema.rs @@ -488,6 +488,8 @@ diesel::table! { left_panel_open -> Nullable, vertical_tabs_panel_open -> Nullable, theme_override -> Nullable, + cli_subagent_width -> Nullable, + cli_subagent_height -> Nullable, } }