diff --git a/README.md b/README.md index 09935dd..8842a1c 100644 --- a/README.md +++ b/README.md @@ -1301,3 +1301,7 @@ MIT License - 선택 텍스트 AI 명령의 기본값을 보수적으로 다시 조정했다. [AppSettings.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Models/AppSettings.cs), [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs) 에서 `선택 텍스트 명령 사용` 기본값을 `false`로 바꾸고, 활성 AI 명령 목록도 기본은 빈 리스트가 되도록 변경했다. - [SettingsWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml.cs) 의 `BuildTextActionCommandsPanel()`에서 `최소 1개 유지`를 강제하던 로직을 제거해 `다시 쓰기`를 포함한 모든 텍스트 AI 명령을 실제로 비활성화할 수 있게 수정했다. - [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml) 의 안내 문구도 현재 동작 기준으로 갱신해, 모든 명령을 꺼두면 선택 텍스트 팝업에는 `AX Commander 열기`만 남는다는 점을 명확히 안내하도록 정리했다. +- 업데이트: 2026-04-06 17:35 (KST) + - 앱이 아무 창도 열지 않은 유휴 상태에서 PC를 무겁게 만들던 추가 초기화 경로를 줄였다. [App.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/App.xaml.cs) 에서 앱 시작 직후 숨겨진 [ChatWindow](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 를 미리 생성하던 `PrewarmChatWindow()` 호출을 제거해, AX Agent를 실제로 열기 전에는 무거운 UI 트리를 만들지 않도록 바꿨다. + - 같은 파일에서 [IndexService](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/IndexService.cs) 의 전체 인덱스 빌드와 `FileSystemWatcher` 시작도 앱 시작 시 즉시 수행하지 않고, 사용자가 실제로 런처를 열 때 `EnsureIndexWarmupStarted()`로 한 번만 지연 시작하도록 바꿨다. + - 이 변경으로 런처/AX Agent를 열지 않은 상태에서 불필요한 전체 파일 스캔과 감시 훅, 숨겨진 대형 창 초기화가 줄어들어 PC 전체 체감 부하를 더 낮추도록 정리했다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 9d9dbac..26d7252 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4988,3 +4988,5 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - Document update: 2026-04-06 17:18 (KST) - `FileDialogWatcher` is no longer started at app boot when file-dialog integration is disabled. `App.xaml.cs` now toggles the global WinEvent hook through `UpdateFileDialogWatcherState()`, and `SchedulerService.cs` now self-stops when no enabled schedules remain. This directly targets the 3–5% idle CPU symptom reported while neither the launcher nor AX Agent was open. - Document update: 2026-04-06 17:24 (KST) - Changed the default launcher text-action profile to opt-in. `AppSettings.cs` and `SettingsViewModel.cs` now default `EnableTextAction` to `false`, and `TextActionCommands` now defaults to an empty list instead of all commands enabled. - Document update: 2026-04-06 17:24 (KST) - Removed the forced “at least one command must remain enabled” behavior from `SettingsWindow.xaml.cs`. The text-action command panel now allows every AI command, including `rewrite`, to be turned off, and the hint text in `SettingsWindow.xaml` now explains that the popup falls back to showing only `AX Commander 열기` when all AI commands are disabled. +- Document update: 2026-04-06 17:35 (KST) - Reduced another startup performance hotspot in `App.xaml.cs` by removing the idle-time `PrewarmChatWindow()` path. AX Agent is no longer instantiated in the background at app startup and is created only when the user actually opens it. +- Document update: 2026-04-06 17:35 (KST) - Changed launcher search warmup from eager startup work to on-demand initialization. `App.xaml.cs` now starts the first `IndexService.BuildAsync()` scan and `StartWatchers()` only when the launcher is actually shown through `ShowLauncherWindow()`, instead of running a full index scan and watcher hookup at boot even when the launcher is never opened. diff --git a/src/AxCopilot/App.xaml.cs b/src/AxCopilot/App.xaml.cs index c6af15d..05c616b 100644 --- a/src/AxCopilot/App.xaml.cs +++ b/src/AxCopilot/App.xaml.cs @@ -24,6 +24,7 @@ public partial class App : System.Windows.Application private DockBarWindow? _dockBar; private FileDialogWatcher? _fileDialogWatcher; private volatile IndexService? _indexService; + private int _indexWarmupStarted; public IndexService? IndexService => _indexService; public SettingsService? SettingsService => _settings; public ClipboardHistoryService? ClipboardHistoryService => _clipboardHistory; @@ -287,14 +288,8 @@ public partial class App : System.Windows.Application () => _clipboardHistory?.Initialize(), System.Windows.Threading.DispatcherPriority.ApplicationIdle); - // ─── ChatWindow 미리 생성 (앱 유휴 시점에 숨겨진 채로 초기화) ────────── - // 이후 OpenAiChat() 시 창 생성 비용 없이 즉시 열림 - Dispatcher.BeginInvoke( - () => PrewarmChatWindow(), - System.Windows.Threading.DispatcherPriority.SystemIdle); - - // ─── 인덱스 빌드 (백그라운드) + 완료 후 FileSystemWatcher 시작 ──────── - _ = indexService.BuildAsync().ContinueWith(_ => indexService.StartWatchers()); + // ─── 인덱스 빌드/감시는 실제 런처를 사용할 때 시작 ─────────────────── + // 앱 시작 직후 전체 스캔과 감시 훅을 붙이지 않아 유휴 체감 부하를 줄임 // ─── 글로벌 훅 + 스니펫 확장기 ─────────────────────────────────────── _inputListener = new InputListener(); @@ -327,7 +322,7 @@ public partial class App : System.Windows.Application if (_launcher == null || _launcher.IsVisible) return; if (_settings?.Settings.Launcher.EnableFileDialogIntegration != true) return; WindowTracker.Capture(); - _launcher.Show(); + ShowLauncherWindow(); Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, () => _launcher.SetInputText("cd ")); }); @@ -375,7 +370,7 @@ public partial class App : System.Windows.Application { if (_launcher == null) return; UsageStatisticsService.RecordLauncherOpen(); - _launcher.Show(); + ShowLauncherWindow(); }); return; } @@ -423,7 +418,7 @@ public partial class App : System.Windows.Application { case TextActionPopup.ActionResult.OpenLauncher: UsageStatisticsService.RecordLauncherOpen(); - _launcher.Show(); + ShowLauncherWindow(); break; case TextActionPopup.ActionResult.None: break; // Esc 또는 포커스 잃음 @@ -438,7 +433,7 @@ public partial class App : System.Windows.Application else { UsageStatisticsService.RecordLauncherOpen(); - _launcher.Show(); + ShowLauncherWindow(); } }); } @@ -514,7 +509,7 @@ public partial class App : System.Windows.Application }; // ! 프리픽스로 AX Agent에 전달 - _launcher?.Show(); + ShowLauncherWindow(); _launcher?.SetInputText($"! {prompt}"); } @@ -581,7 +576,7 @@ public partial class App : System.Windows.Application _trayMenu .AddHeader(versionText) .AddItem("\uE7C5", "AX Commander 호출하기", () => - Dispatcher.Invoke(() => _launcher?.Show())) + Dispatcher.Invoke(ShowLauncherWindow)) .AddItem("\uE8BD", "AX Agent 대화하기", () => Dispatcher.Invoke(OpenAiChat), out var aiTrayItem) .AddItem("\uE8A7", "독 바 표시", () => @@ -644,7 +639,7 @@ public partial class App : System.Windows.Application if (settings.Settings.AiEnabled) OpenAiChat(); else - _launcher?.Show(); + ShowLauncherWindow(); }); } else if (e.Button == System.Windows.Forms.MouseButtons.Right) @@ -679,14 +674,30 @@ public partial class App : System.Windows.Application /// AX Agent 창 열기 (트레이 메뉴 등에서 호출). private Views.ChatWindow? _chatWindow; - /// - /// ChatWindow를 백그라운드에서 미리 생성합니다 (앱 시작 후 저우선순위로 호출). - /// 이후 OpenAiChat() 시 창 생성 비용 없이 즉시 Show/Activate만 수행합니다. - /// - internal void PrewarmChatWindow() + private void EnsureIndexWarmupStarted() { - if (_chatWindow != null || _settings == null) return; - _chatWindow = new Views.ChatWindow(_settings); + if (_indexService == null) return; + if (Interlocked.Exchange(ref _indexWarmupStarted, 1) == 1) return; + + _ = Task.Run(async () => + { + try + { + await _indexService.BuildAsync().ConfigureAwait(false); + _indexService.StartWatchers(); + } + catch (Exception ex) + { + LogService.Warn($"런처 인덱스 초기화 실패: {ex.Message}"); + } + }); + } + + private void ShowLauncherWindow() + { + if (_launcher == null) return; + EnsureIndexWarmupStarted(); + _launcher.Show(); } private void OpenAiChat() @@ -714,7 +725,7 @@ public partial class App : System.Windows.Application _dockBar.OnQuickSearch = query => { if (_launcher == null) return; - _launcher.Show(); + ShowLauncherWindow(); _launcher.Activate(); // 독 바 뒤가 아닌 전면에 표시 if (!string.IsNullOrEmpty(query)) Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, @@ -729,7 +740,7 @@ public partial class App : System.Windows.Application _dockBar.OnOpenAgent = () => { if (_launcher == null) return; - _launcher.Show(); + ShowLauncherWindow(); Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, () => _launcher.SetInputText("!")); };