코워크와 코드의 작업 폴더 선택 멈춤을 완화한다
- 작업 폴더 변경 직후 UI 스레드에서 실행되던 스킬 소스 재탐색을 백그라운드 재로드로 분리한다. - 조건부 스킬 활성화 경로를 재로드와 분리해 첨부 파일 변경처럼 폴더가 바뀌지 않는 경우 불필요한 스킬 재탐색을 줄인다. - README와 DEVELOPMENT 문서에 2026-04-14 19:02(KST) 기준 작업 이력과 검증 결과를 반영한다. - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_folderpick\\ -p:IntermediateOutputPath=obj\\verify_folderpick\\ 경고 0 / 오류 0
This commit is contained in:
@@ -130,6 +130,8 @@ public partial class ChatWindow : Window
|
||||
private readonly DispatcherTimer _agentProgressHintTimer;
|
||||
private readonly DispatcherTimer _tokenUsagePopupCloseTimer;
|
||||
private readonly DispatcherTimer _responsiveLayoutTimer;
|
||||
private CancellationTokenSource? _workspaceSkillRefreshCts;
|
||||
private int _workspaceSkillRefreshVersion;
|
||||
private CancellationTokenSource? _gitStatusRefreshCts;
|
||||
private int _displayedLength; // 현재 화면에 표시된 글자 수
|
||||
private ResourceDictionary? _agentThemeDictionary;
|
||||
@@ -1833,7 +1835,7 @@ public partial class ChatWindow : Window
|
||||
UpdateChatTitle();
|
||||
RefreshConversationList();
|
||||
UpdateFolderBar();
|
||||
UpdateConditionalSkillActivation(reset: true);
|
||||
UpdateConditionalSkillActivation(reset: true, reloadSkillSources: true);
|
||||
Services.LogService.Info($"[SwitchTab] NO_SESSION done, emptyState={EmptyState.Visibility}");
|
||||
}
|
||||
|
||||
@@ -2228,7 +2230,7 @@ public partial class ChatWindow : Window
|
||||
UpdateFolderSelectButtonStyle();
|
||||
ScheduleGitBranchRefresh();
|
||||
|
||||
UpdateConditionalSkillActivation(reset: true);
|
||||
UpdateConditionalSkillActivation(reset: true, reloadSkillSources: true);
|
||||
}
|
||||
|
||||
private string GetCurrentWorkFolder()
|
||||
@@ -2250,18 +2252,81 @@ public partial class ChatWindow : Window
|
||||
SkillService.LoadSkills(_settings.Settings.Llm.SkillsFolderPath, GetCurrentWorkFolder(), _settings.Settings.Llm.AdditionalSkillFolders);
|
||||
}
|
||||
|
||||
private void ScheduleWorkspaceSkillRefresh(bool reset = false)
|
||||
{
|
||||
if (!_settings.Settings.Llm.EnableSkillSystem)
|
||||
return;
|
||||
|
||||
var version = Interlocked.Increment(ref _workspaceSkillRefreshVersion);
|
||||
_workspaceSkillRefreshCts?.Cancel();
|
||||
_workspaceSkillRefreshCts?.Dispose();
|
||||
_workspaceSkillRefreshCts = new CancellationTokenSource();
|
||||
var ct = _workspaceSkillRefreshCts.Token;
|
||||
|
||||
var skillFolder = _settings.Settings.Llm.SkillsFolderPath;
|
||||
var workFolder = GetCurrentWorkFolder();
|
||||
var additionalFolders = (_settings.Settings.Llm.AdditionalSkillFolders ?? [])
|
||||
.Where(path => !string.IsNullOrWhiteSpace(path))
|
||||
.ToArray();
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
SkillService.EnsureSkillFolder();
|
||||
SkillService.LoadSkills(skillFolder, workFolder, additionalFolders);
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
if (ct.IsCancellationRequested || version != _workspaceSkillRefreshVersion)
|
||||
return;
|
||||
|
||||
ApplyConditionalSkillActivation(reset, workFolder);
|
||||
}), DispatcherPriority.Background);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Services.LogService.Debug($"작업 폴더 스킬 재로드 실패: {ex.Message}");
|
||||
}
|
||||
}, ct);
|
||||
}
|
||||
|
||||
private void ApplyConditionalSkillActivation(bool reset = false, string? cwd = null)
|
||||
{
|
||||
if (!_settings.Settings.Llm.EnableSkillSystem)
|
||||
return;
|
||||
|
||||
cwd ??= GetCurrentWorkFolder();
|
||||
if (string.IsNullOrWhiteSpace(cwd) || !System.IO.Directory.Exists(cwd))
|
||||
return;
|
||||
|
||||
if (reset)
|
||||
SkillService.ResetConditionalSkillActivation();
|
||||
|
||||
SkillService.ActivateConditionalSkillsForPaths(_attachedFiles, cwd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 작업 컨텍스트(첨부 파일 + 작업 폴더) 기준으로
|
||||
/// 조건부 paths 스킬 활성화를 갱신합니다.
|
||||
/// </summary>
|
||||
private void UpdateConditionalSkillActivation(bool reset = false)
|
||||
private void UpdateConditionalSkillActivation(bool reset = false, bool reloadSkillSources = false)
|
||||
{
|
||||
if (!_settings.Settings.Llm.EnableSkillSystem) return;
|
||||
EnsureSkillSystemLoadedForCurrentWorkspace();
|
||||
var cwd = GetCurrentWorkFolder();
|
||||
if (string.IsNullOrWhiteSpace(cwd) || !System.IO.Directory.Exists(cwd)) return;
|
||||
if (reset) SkillService.ResetConditionalSkillActivation();
|
||||
SkillService.ActivateConditionalSkillsForPaths(_attachedFiles, cwd);
|
||||
if (!_settings.Settings.Llm.EnableSkillSystem)
|
||||
return;
|
||||
|
||||
if (reloadSkillSources)
|
||||
{
|
||||
ScheduleWorkspaceSkillRefresh(reset);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyConditionalSkillActivation(reset);
|
||||
}
|
||||
|
||||
private void BtnFolderClear_Click(object sender, RoutedEventArgs e)
|
||||
@@ -3102,7 +3167,7 @@ public partial class ChatWindow : Window
|
||||
UpdateChatTitle();
|
||||
UpdateFolderBar();
|
||||
UpdateSelectedPresetGuide();
|
||||
UpdateConditionalSkillActivation(reset: true);
|
||||
UpdateConditionalSkillActivation(reset: true, reloadSkillSources: true);
|
||||
RenderMessages();
|
||||
RefreshConversationList();
|
||||
BuildTopicButtons();
|
||||
|
||||
Reference in New Issue
Block a user