앱 시작 시 무거운 초기화 지연으로 유휴 성능 개선
Some checks failed
Release Gate / gate (push) Has been cancelled

앱 시작 직후 AX Agent 창을 미리 생성하던 경로를 제거하고 실제로 AX Agent를 열 때만 ChatWindow를 만들도록 정리했습니다.

런처 검색 인덱스 전체 스캔과 파일 감시 시작도 부팅 시 즉시 실행하지 않고, 런처를 실제로 표시할 때 한 번만 지연 시작하도록 변경했습니다.

README와 DEVELOPMENT 문서를 2026-04-06 17:35(KST) 기준으로 갱신했고, Release 빌드 검증에서 경고 0 오류 0을 확인했습니다.
This commit is contained in:
2026-04-06 17:20:37 +09:00
parent ccb39f0fe0
commit 353c5ce471
3 changed files with 41 additions and 24 deletions

View File

@@ -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
/// <summary>AX Agent 창 열기 (트레이 메뉴 등에서 호출).</summary>
private Views.ChatWindow? _chatWindow;
/// <summary>
/// ChatWindow를 백그라운드에서 미리 생성합니다 (앱 시작 후 저우선순위로 호출).
/// 이후 OpenAiChat() 시 창 생성 비용 없이 즉시 Show/Activate만 수행합니다.
/// </summary>
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("!"));
};