diff --git a/docs/NEXT_ROADMAP.md b/docs/NEXT_ROADMAP.md
index e322392..bea076a 100644
--- a/docs/NEXT_ROADMAP.md
+++ b/docs/NEXT_ROADMAP.md
@@ -4892,5 +4892,67 @@ ThemeResourceHelper에 5개 정적 필드 추가:
---
-최종 업데이트: 2026-04-03 (Phase 22~52 + Phase 17-UI-A~B 구현 완료)
+## Phase 17-UI-C — AgentSessionHeaderBar UserControl 통합 (v1.8.0) ✅ 완료
+
+> **목표**: 기존 Row 1 서브 바의 모델·Plan·권한 칩을 `AgentSessionHeaderBar` UserControl로 교체.
+> 투명 배경으로 기존 레이아웃에 임베드. 이벤트 기반 위임으로 ChatWindow 기존 로직 재사용.
+
+### 변경 파일
+
+| 파일 | 변경 내용 |
+|------|----------|
+| `AgentSessionHeaderBar.xaml` | 외부 Border를 `Background="Transparent" BorderThickness="0"`으로 수정. 높이 42→38px. `x:Name="PlanIcon"`, `x:Name="PermIcon"` 추가. |
+| `AgentSessionHeaderBar.xaml.cs` | `SetPlanMode()`: `PlanIcon` x:Name 직접 참조. `ChipPermission_Click`: 이벤트 발행만 (팝업은 ChatWindow 처리). `SetPermissionMode()`: PermIcon 색상 업데이트. |
+| `ChatWindow.xaml` | Row 1 우측에서 `ModelHeaderChip`, `BtnPlanMode`, `PermissionHeaderChip` 제거 → `` 추가. |
+| `ChatWindow.SessionHeaderBar.cs` | 신규: `InitSessionHeaderBar()` — ModelChipClicked·PlanModeChanged·PermissionModeChanged·SettingsRequested 이벤트 구독. |
+| `ChatWindow.ModelSelector.cs` | `UpdateModelLabel()`: `SessionHeaderBar?.SetModel()` 동기화. |
+| `ChatWindow.PermissionMenu.cs` | `UpdatePermissionUI()`: `SessionHeaderBar?.SetPermissionMode()` 동기화. |
+| `ChatWindow.TabSwitching.cs` | `UpdateTabUI()`: `SessionHeaderBar?.SetTabLabel()` 동기화. `UpdatePlanModeUI()`: SessionHeaderBar 전용으로 단순화. |
+| `ChatWindow.xaml.cs` | Loaded: `InitSessionHeaderBar()` 호출 추가. |
+
+- **빌드**: 경고 0, 오류 0
+
+---
+
+## Phase 17-UI-D — AgentSidebarView UserControl 통합 (v1.8.0) ✅ 완료
+
+> **목표**: 기존 `SidebarPanel` Border(인라인 XAML 110줄)를 `AgentSidebarView` UserControl로 교체.
+> 34개 기존 ChatWindow 파셜 파일이 사이드바 내부 요소를 무수정으로 참조할 수 있도록 프록시 패턴 적용.
+
+### 변경 파일
+
+| 파일 | 변경 내용 |
+|------|----------|
+| `AgentSidebarView.xaml` | 7행 구조로 재작성: 헤더(로고+새대화) / 탭세그먼트 / 검색 / 카테고리드롭다운 / 대화목록 / 삭제 / 사용자계정. |
+| `AgentSidebarView.xaml.cs` | 완전 재작성: `internal` 프록시 프로퍼티 8개 + `SidebarTabChanged`/`NewChatRequested`/`DeleteAllRequested`/`CategoryDropClicked`/`SearchTextChanged` 이벤트. |
+| `ChatWindow.xaml` | `` 인라인 110줄 → `` 1줄 대체. |
+| `ChatWindow.SidebarCompat.cs` | 신규: 8개 계산 프로퍼티(`ConversationPanel`, `SearchBox`, `CategoryIcon`, `CategoryLabel`, `BtnCategoryDrop`, `UserInitialSidebar`, `UserNameText`, `UserPcText`) + `InitSidebarEvents()`. |
+| `ChatWindow.PermissionMenu.cs` | `BtnToggleSidebar_Click()`: `SidebarPanel.Visibility` → `Sidebar.Visibility`. `PermissionHeaderChip_Click()`: `PermissionHeaderChip` → `SessionHeaderBar`. |
+| `ChatWindow.TabSwitching.cs` | 탭 핸들러 3개: `Sidebar?.SetActiveTab()` 동기화 추가. `UpdatePlanModeUI()`: 죽은 코드 제거. |
+| `ChatWindow.xaml.cs` | Loaded: `InitSidebarEvents()` 호출 추가. |
+
+- **빌드**: 경고 0, 오류 0
+
+---
+
+## Phase 17-UI-E — AgentInputArea 툴바 통합 (v1.8.0) ✅ 완료
+
+> **목표**: `AgentInputArea` UserControl에 `IsToolbarOnly` 모드 추가.
+> 기존 InputBox 위에 @ / 스킬 / 첨부 툴바 행을 추가하여 Claude.ai 스타일 입력 경험 제공.
+
+### 변경 파일
+
+| 파일 | 변경 내용 |
+|------|----------|
+| `AgentInputArea.xaml` | `x:Name="OuterBorder"`, `x:Name="InputTextBoxRow"`, `x:Name="ChipsSendRow"` 추가. |
+| `AgentInputArea.xaml.cs` | `IsToolbarOnly` 의존성 프로퍼티 추가. `ApplyToolbarOnlyMode()`: TextBox/칩 행 Collapsed, 외부 Border 투명화. |
+| `ChatWindow.xaml` | InputBorder Grid에 Row 0 추가(`ctrl:AgentInputArea x:Name="InputToolbar" IsToolbarOnly="True"`). 기존 Row 0→1, 1→2, 2→3 시프트. |
+| `ChatWindow.InputToolbar.cs` | 신규: `InitInputToolbar()` — MentionRequested(@삽입), SkillRequested(/삽입), AttachRequested(BtnAttach_Click 위임). |
+| `ChatWindow.xaml.cs` | Loaded: `InitInputToolbar()` 호출 추가. |
+
+- **빌드**: 경고 0, 오류 0
+
+---
+
+최종 업데이트: 2026-04-03 (Phase 22~52 + Phase 17-UI-A~E 구현 완료)
diff --git a/src/AxCopilot/Views/ChatWindow.InputToolbar.cs b/src/AxCopilot/Views/ChatWindow.InputToolbar.cs
new file mode 100644
index 0000000..043e875
--- /dev/null
+++ b/src/AxCopilot/Views/ChatWindow.InputToolbar.cs
@@ -0,0 +1,37 @@
+using System.Windows;
+
+namespace AxCopilot.Views;
+
+///
+/// Phase 17-UI-E: AgentInputArea InputToolbar 이벤트 연결.
+/// @ 멘션, / 스킬, 📎 첨부 버튼을 기존 ChatWindow 동작에 위임합니다.
+///
+public partial class ChatWindow
+{
+ private void InitInputToolbar()
+ {
+ if (InputToolbar == null) return;
+
+ // @ 멘션 클릭 → InputBox에 "@" 삽입 후 포커스
+ InputToolbar.MentionRequested += (_, _) =>
+ {
+ InputBox.Text += "@";
+ InputBox.CaretIndex = InputBox.Text.Length;
+ InputBox.Focus();
+ };
+
+ // / 스킬 클릭 → InputBox에 "/" 삽입 후 포커스 (슬래시 팝업 트리거)
+ InputToolbar.SkillRequested += (_, _) =>
+ {
+ InputBox.Text += "/";
+ InputBox.CaretIndex = InputBox.Text.Length;
+ InputBox.Focus();
+ };
+
+ // 첨부 클릭 → 기존 파일 첨부 다이얼로그 (BtnAttach_Click 대응)
+ InputToolbar.AttachRequested += (_, _) =>
+ {
+ BtnAttach_Click(InputToolbar, new RoutedEventArgs());
+ };
+ }
+}
diff --git a/src/AxCopilot/Views/ChatWindow.ModelSelector.cs b/src/AxCopilot/Views/ChatWindow.ModelSelector.cs
index 7f39065..3554722 100644
--- a/src/AxCopilot/Views/ChatWindow.ModelSelector.cs
+++ b/src/AxCopilot/Views/ChatWindow.ModelSelector.cs
@@ -141,9 +141,8 @@ public partial class ChatWindow
};
var modelName = GetCurrentModelDisplayName();
ModelLabel.Text = $"{serviceLabel} · {modelName}";
- // Phase 17-UI-B: 헤더 바 모델 칩도 갱신
- if (ModelHeaderLabel != null)
- ModelHeaderLabel.Text = $"{serviceLabel} · {modelName}";
+ // Phase 17-UI-C: SessionHeaderBar 모델 칩 동기화
+ SessionHeaderBar?.SetModel($"{serviceLabel} · {modelName}");
}
private void BtnModelSelector_Click(object sender, RoutedEventArgs e)
diff --git a/src/AxCopilot/Views/ChatWindow.PermissionMenu.cs b/src/AxCopilot/Views/ChatWindow.PermissionMenu.cs
index 1592716..e74aa4c 100644
--- a/src/AxCopilot/Views/ChatWindow.PermissionMenu.cs
+++ b/src/AxCopilot/Views/ChatWindow.PermissionMenu.cs
@@ -101,12 +101,12 @@ public partial class ChatWindow
AutoPermissionWarning.Visibility = Visibility.Collapsed;
}
- /// Phase 17-UI-B: 헤더 바 권한 칩 클릭 — 권한 팝업을 칩 위치에 표시.
+ /// Phase 17-UI-C: SessionHeaderBar 권한 칩 클릭 — 권한 팝업을 SessionHeaderBar 위치에 표시.
private void PermissionHeaderChip_Click(object sender, RoutedEventArgs e)
{
if (PermissionPopup == null) return;
- // 팝업 기준점을 헤더 칩으로 변경
- PermissionPopup.PlacementTarget = PermissionHeaderChip;
+ // 팝업 기준점을 SessionHeaderBar로 변경 (PermissionHeaderChip → SessionHeaderBar로 대체)
+ PermissionPopup.PlacementTarget = SessionHeaderBar;
PermissionPopup.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
BtnPermission_Click(sender, e);
}
@@ -116,8 +116,8 @@ public partial class ChatWindow
if (PermissionLabel == null || PermissionIcon == null) return;
var perm = Llm.FilePermission;
PermissionLabel.Text = perm;
- // Phase 17-UI-B: 헤더 칩 텍스트도 갱신
- if (PermissionHeaderLabel != null) PermissionHeaderLabel.Text = perm;
+ // Phase 17-UI-C: SessionHeaderBar 권한 칩 동기화
+ SessionHeaderBar?.SetPermissionMode(perm);
PermissionIcon.Text = perm switch
{
"Auto" => "\uE73E",
@@ -466,7 +466,7 @@ public partial class ChatWindow
// 사이드바 열기, 아이콘 바 숨기기
IconBarColumn.Width = new GridLength(0);
IconBarPanel.Visibility = Visibility.Collapsed;
- SidebarPanel.Visibility = Visibility.Visible;
+ Sidebar.Visibility = Visibility.Visible;
ToggleSidebarIcon.Text = "\uE76B";
AnimateSidebar(0, 270, () => SidebarColumn.MinWidth = 200);
}
@@ -477,7 +477,7 @@ public partial class ChatWindow
ToggleSidebarIcon.Text = "\uE76C";
AnimateSidebar(270, 0, () =>
{
- SidebarPanel.Visibility = Visibility.Collapsed;
+ Sidebar.Visibility = Visibility.Collapsed;
IconBarColumn.Width = new GridLength(52);
IconBarPanel.Visibility = Visibility.Visible;
});
diff --git a/src/AxCopilot/Views/ChatWindow.SessionHeaderBar.cs b/src/AxCopilot/Views/ChatWindow.SessionHeaderBar.cs
new file mode 100644
index 0000000..4dfa090
--- /dev/null
+++ b/src/AxCopilot/Views/ChatWindow.SessionHeaderBar.cs
@@ -0,0 +1,38 @@
+using System.Windows;
+
+namespace AxCopilot.Views;
+
+///
+/// Phase 17-UI-C: AgentSessionHeaderBar 이벤트 연결 및 상태 동기화.
+/// SessionHeaderBar(UserControl) ↔ ChatWindow 기존 로직 브리지.
+///
+public partial class ChatWindow
+{
+ /// Loaded 핸들러에서 호출 — SessionHeaderBar 이벤트 연결.
+ private void InitSessionHeaderBar()
+ {
+ // 모델 칩 클릭 → 기존 BtnModelSelector_Click 재사용
+ SessionHeaderBar.ModelChipClicked += (_, _) =>
+ BtnModelSelector_Click(SessionHeaderBar, new RoutedEventArgs());
+
+ // Plan 모드 순환 → 설정 저장 + 기존 UI 동기화
+ SessionHeaderBar.PlanModeChanged += (_, mode) =>
+ {
+ Llm.PlanMode = mode;
+ _settings.Save();
+ UpdatePlanModeUI(); // SessionHeaderBar.SetPlanMode()가 내부서 호출됨
+ };
+
+ // 권한 칩 클릭 → 권한 팝업을 SessionHeaderBar 위치에 표시
+ SessionHeaderBar.PermissionModeChanged += (_, _) =>
+ {
+ if (PermissionPopup == null) return;
+ PermissionPopup.PlacementTarget = SessionHeaderBar;
+ PermissionPopup.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
+ BtnPermission_Click(SessionHeaderBar, new RoutedEventArgs());
+ };
+
+ // 설정 버튼 → 기존 ToggleSettingsPanel() 재사용
+ SessionHeaderBar.SettingsRequested += (_, _) => ToggleSettingsPanel();
+ }
+}
diff --git a/src/AxCopilot/Views/ChatWindow.SidebarCompat.cs b/src/AxCopilot/Views/ChatWindow.SidebarCompat.cs
new file mode 100644
index 0000000..f468a6b
--- /dev/null
+++ b/src/AxCopilot/Views/ChatWindow.SidebarCompat.cs
@@ -0,0 +1,80 @@
+using System.Windows;
+using System.Windows.Controls;
+using AxCopilot.Views.Controls;
+
+namespace AxCopilot.Views;
+
+///
+/// Phase 17-UI-D: AgentSidebarView 프록시 어댑터.
+/// 34개 기존 ChatWindow 파셜 파일이 사이드바 내부 요소를 그대로 참조할 수 있도록
+/// 계산 프로퍼티(computed property)로 위임합니다.
+///
+public partial class ChatWindow
+{
+ // ── 사이드바 내부 요소 프록시 (기존 코드 무수정 호환) ─────────────────
+
+ /// 대화 목록 StackPanel — RefreshConversationList 등에서 직접 사용.
+ private StackPanel ConversationPanel => Sidebar.SidebarConversationPanel;
+
+ /// 검색 TextBox — SearchBox_TextChanged 및 검색 필터링에서 사용.
+ private TextBox SearchBox => Sidebar.SidebarSearchBox;
+
+ /// 카테고리 아이콘 TextBlock — UpdateCategoryLabel()에서 사용.
+ private TextBlock CategoryIcon => Sidebar.SidebarCategoryIcon;
+
+ /// 카테고리 레이블 TextBlock — UpdateCategoryLabel()에서 사용.
+ private TextBlock CategoryLabel => Sidebar.SidebarCategoryLabel;
+
+ /// 카테고리 드롭다운 Border — 팝업 PlacementTarget으로 사용.
+ private Border BtnCategoryDrop => Sidebar.SidebarCategoryDropTarget;
+
+ /// 사용자 이니셜 TextBlock — SetupUserInfo()에서 사용.
+ private TextBlock UserInitialSidebar => Sidebar.SidebarUserInitial;
+
+ /// 사용자 이름 TextBlock — SetupUserInfo()에서 사용.
+ private TextBlock UserNameText => Sidebar.SidebarUserName;
+
+ /// 사용자 PC 텍스트 TextBlock — SetupUserInfo()에서 사용.
+ private TextBlock UserPcText => Sidebar.SidebarUserPc;
+
+ // ── 사이드바 이벤트 구독 초기화 ──────────────────────────────────────
+
+ private void InitSidebarEvents()
+ {
+ // 탭 전환: 사이드바 탭 클릭 → 메인 탭 RadioButton 동기화
+ Sidebar.SidebarTabChanged += (_, tab) =>
+ {
+ _activeTab = tab;
+ switch (tab)
+ {
+ case "Cowork": TabCowork.IsChecked = true; break;
+ case "Code": TabCode.IsChecked = true; break;
+ default: TabChat.IsChecked = true; break;
+ }
+ };
+
+ // 새 대화 요청
+ Sidebar.NewChatRequested += (_, _) =>
+ {
+ BtnNewChat_Click(Sidebar, new RoutedEventArgs());
+ };
+
+ // 전체 삭제 요청
+ Sidebar.DeleteAllRequested += (_, _) =>
+ {
+ BtnDeleteAll_Click(Sidebar, new RoutedEventArgs());
+ };
+
+ // 카테고리 드롭다운 클릭
+ Sidebar.CategoryDropClicked += (_, _) =>
+ {
+ BtnCategoryDrop_Click(Sidebar, new RoutedEventArgs());
+ };
+
+ // 검색어 변경 — SearchBox_TextChanged는 기존 코드가 TextBox sender로 받음
+ Sidebar.SearchTextChanged += (sender, e) =>
+ {
+ SearchBox_TextChanged(sender, e);
+ };
+ }
+}
diff --git a/src/AxCopilot/Views/ChatWindow.TabSwitching.cs b/src/AxCopilot/Views/ChatWindow.TabSwitching.cs
index a063d67..8a9ee1b 100644
--- a/src/AxCopilot/Views/ChatWindow.TabSwitching.cs
+++ b/src/AxCopilot/Views/ChatWindow.TabSwitching.cs
@@ -1,6 +1,5 @@
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Media;
using AxCopilot.Services;
namespace AxCopilot.Views;
@@ -64,6 +63,7 @@ public partial class ChatWindow
SaveCurrentTabConversationId();
_activeTab = "Chat";
_selectedCategory = ""; UpdateCategoryLabel();
+ Sidebar?.SetActiveTab("Chat"); // Phase 17-UI-D: 사이드바 탭 하이라이트 동기화
UpdateTabUI();
UpdatePlanModeUI();
}
@@ -75,6 +75,7 @@ public partial class ChatWindow
SaveCurrentTabConversationId();
_activeTab = "Cowork";
_selectedCategory = ""; UpdateCategoryLabel();
+ Sidebar?.SetActiveTab("Cowork"); // Phase 17-UI-D: 사이드바 탭 하이라이트 동기화
UpdateTabUI();
UpdatePlanModeUI();
}
@@ -86,6 +87,7 @@ public partial class ChatWindow
SaveCurrentTabConversationId();
_activeTab = "Code";
_selectedCategory = ""; UpdateCategoryLabel();
+ Sidebar?.SetActiveTab("Code"); // Phase 17-UI-D: 사이드바 탭 하이라이트 동기화
UpdateTabUI();
UpdatePlanModeUI();
}
@@ -143,6 +145,9 @@ public partial class ChatWindow
// 현재 대화를 해당 탭 대화로 전환
SwitchToTabConversation();
+ // Phase 17-UI-C: SessionHeaderBar 탭 레이블 동기화
+ SessionHeaderBar?.SetTabLabel(_activeTab);
+
// Phase 17-UI: 설정 패널이 열려 있으면 탭 전환 시 패널 업데이트
if (SettingsPanel?.IsOpen == true)
SettingsPanel.UpdateActiveTab(_activeTab);
@@ -167,23 +172,8 @@ public partial class ChatWindow
private void UpdatePlanModeUI()
{
var planMode = Llm.PlanMode ?? "off";
- if (PlanModeValue == null) return;
-
- PlanModeValue.Text = planMode switch
- {
- "auto" => "Auto",
- "always" => "Always",
- _ => "Off"
- };
- var isActive = planMode != "off";
- var activeBrush = ThemeResourceHelper.Accent(this);
- var secondaryBrush = ThemeResourceHelper.Secondary(this);
- if (PlanModeIcon != null) PlanModeIcon.Foreground = isActive ? activeBrush : secondaryBrush;
- if (PlanModeLabel != null) PlanModeLabel.Foreground = isActive ? activeBrush : secondaryBrush;
- if (BtnPlanMode != null)
- BtnPlanMode.Background = isActive
- ? new SolidColorBrush(Color.FromArgb(0x1A, 0x4B, 0x5E, 0xFC))
- : Brushes.Transparent;
+ // Phase 17-UI-C: SessionHeaderBar가 Plan 칩을 완전히 대체함
+ SessionHeaderBar?.SetPlanMode(planMode);
}
private void SwitchToTabConversation()
diff --git a/src/AxCopilot/Views/ChatWindow.xaml b/src/AxCopilot/Views/ChatWindow.xaml
index 19f9e8e..57edadf 100644
--- a/src/AxCopilot/Views/ChatWindow.xaml
+++ b/src/AxCopilot/Views/ChatWindow.xaml
@@ -185,121 +185,9 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -340,52 +228,10 @@
KeyDown="ChatTitleEdit_KeyDown"/>
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+