loadtoagent 1.1.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.ko.md +7 -0
  2. package/README.md +7 -0
  3. package/README.zh-CN.md +7 -0
  4. package/docs/PROVIDER-CONTRACTS.md +23 -1
  5. package/docs/UI-AUDIT-100.md +118 -0
  6. package/docs/UI-AUDIT-101-200.md +120 -0
  7. package/docs/UI-AUDIT-201-300.md +120 -0
  8. package/main.js +135 -38
  9. package/package.json +13 -4
  10. package/preload.js +6 -0
  11. package/renderer/app-agent-actions.js +125 -53
  12. package/renderer/app-bootstrap.js +54 -19
  13. package/renderer/app-dashboard.js +190 -55
  14. package/renderer/app-drawer-content.js +48 -44
  15. package/renderer/app-drawer-data.js +26 -13
  16. package/renderer/app-drawer.js +72 -54
  17. package/renderer/app-events-dialogs.js +146 -37
  18. package/renderer/app-events-filters.js +172 -13
  19. package/renderer/app-events-navigation.js +77 -30
  20. package/renderer/app-events-sessions.js +156 -9
  21. package/renderer/app-events.js +2 -1
  22. package/renderer/app-graph-model.js +20 -38
  23. package/renderer/app-graph-orchestration.js +15 -13
  24. package/renderer/app-graph-view.js +228 -113
  25. package/renderer/app-management.js +211 -0
  26. package/renderer/app-provider-visibility.js +124 -0
  27. package/renderer/app-quality.js +568 -0
  28. package/renderer/app-run-modal.js +103 -33
  29. package/renderer/app-runtime-overview.js +312 -0
  30. package/renderer/app-session-render.js +94 -37
  31. package/renderer/app-tmux-render.js +52 -44
  32. package/renderer/app.js +153 -75
  33. package/renderer/i18n-messages.js +833 -16
  34. package/renderer/i18n.js +104 -0
  35. package/renderer/index.html +145 -59
  36. package/renderer/shared.js +17 -0
  37. package/renderer/styles-agent-map.css +6 -0
  38. package/renderer/styles-cards.css +26 -0
  39. package/renderer/styles-components.css +86 -9
  40. package/renderer/styles-management.css +355 -0
  41. package/renderer/styles-overlays.css +8 -2
  42. package/renderer/styles-product.css +24 -16
  43. package/renderer/styles-quality.css +312 -0
  44. package/renderer/styles-readability.css +862 -0
  45. package/renderer/styles-responsive-product.css +84 -12
  46. package/renderer/styles-responsive-runtime.css +22 -14
  47. package/renderer/styles-responsive-shell.css +44 -48
  48. package/renderer/styles-responsive-workflows.css +37 -3
  49. package/renderer/styles-run-composer.css +5 -0
  50. package/renderer/styles-runtime-overview.css +285 -0
  51. package/renderer/styles-settings.css +160 -0
  52. package/renderer/styles-terminal.css +339 -2
  53. package/renderer/styles-workflow-map.css +362 -15
  54. package/renderer/styles-workflows.css +69 -2
  55. package/renderer/styles.css +27 -12
  56. package/renderer/terminal-agent.js +17 -13
  57. package/renderer/terminal-events.js +233 -40
  58. package/renderer/terminal-workbench.js +165 -77
  59. package/renderer/terminal.js +341 -34
  60. package/src/agentMonitor/claudeParser.js +96 -7
  61. package/src/agentMonitor/codexParser.js +59 -4
  62. package/src/agentMonitor/executionActivity.js +282 -0
  63. package/src/agentMonitor/genericParser.js +56 -13
  64. package/src/agentMonitor/hierarchy.js +17 -0
  65. package/src/agentMonitor/responseIntent.js +51 -0
  66. package/src/agentMonitor.js +21 -3
  67. package/src/agentRunner.js +66 -1
  68. package/src/attentionNotifier.js +14 -10
  69. package/src/automationMonitor.js +258 -0
  70. package/src/contracts.js +10 -1
  71. package/src/ipc/registerAgentIpc.js +9 -3
  72. package/src/ipc/registerAppIpc.js +4 -1
  73. package/src/ipc/registerTerminalIpc.js +12 -6
  74. package/src/macUpdateHelper.js +210 -0
  75. package/src/monitorWorker.js +65 -6
  76. package/src/platformPath.js +80 -0
  77. package/src/processMonitor.js +80 -22
  78. package/src/providerVisibilityStore.js +45 -0
  79. package/src/sessionIntelligence.js +247 -0
  80. package/src/terminalHost.js +381 -0
  81. package/src/terminalHostDaemon.js +60 -0
  82. package/src/terminalManager.js +158 -3
  83. package/src/updateInstaller.js +175 -0
@@ -17,17 +17,21 @@
17
17
  <link rel="stylesheet" href="styles-terminal.css" />
18
18
  <link rel="stylesheet" href="styles-run-composer.css" />
19
19
  <link rel="stylesheet" href="styles-product.css" />
20
+ <link rel="stylesheet" href="styles-management.css" />
21
+ <link rel="stylesheet" href="styles-runtime-overview.css" />
20
22
  <link rel="stylesheet" href="styles-onboarding.css" />
21
23
  <link rel="stylesheet" href="styles-settings.css" />
24
+ <link rel="stylesheet" href="styles-quality.css" />
22
25
  <link rel="stylesheet" href="styles-responsive-shell.css" />
23
26
  <link rel="stylesheet" href="styles-responsive-workflows.css" />
24
27
  <link rel="stylesheet" href="styles-responsive-runtime.css" />
25
28
  <link rel="stylesheet" href="styles-responsive-product.css" />
26
29
  <link rel="stylesheet" href="../node_modules/@xterm/xterm/css/xterm.css" />
30
+ <link rel="stylesheet" href="styles-readability.css" />
27
31
  </head>
28
32
  <body>
29
- <a class="skip-link" href="#mainContent" data-i18n="app.accessibility.skip_to_content">본문으로 바로가기</a>
30
- <div class="app-shell">
33
+ <div id="appShell" class="app-shell">
34
+ <a class="skip-link" href="#mainContent" data-i18n="app.accessibility.skip_to_content">본문으로 바로가기</a>
31
35
  <aside class="sidebar">
32
36
  <div class="brand">
33
37
  <div class="brand-orbit" aria-hidden="true"><span></span></div>
@@ -35,26 +39,30 @@
35
39
  </div>
36
40
 
37
41
  <nav class="view-nav" aria-label="화면 선택" data-i18n-aria-label="app.nav.label">
38
- <button class="nav-item active" type="button" data-view="all"><span class="nav-icon">⌂</span><span data-i18n="app.nav.home">홈</span><b id="navAllCount">0</b></button>
39
- <button class="nav-item" type="button" data-view="active"><span class="nav-icon live-dot"></span><span data-i18n="app.nav.active">진행 중</span><b id="navActiveCount">0</b></button>
40
- <button class="nav-item" type="button" data-view="waiting"><span class="nav-icon">!</span><span data-i18n="app.nav.needs_review">내 확인 필요</span><b id="navWaitingCount">0</b></button>
41
- <div class="nav-group-label" data-i18n="app.nav.continue_session">기존 세션에 이어서 입력</div>
42
- <button class="nav-item" type="button" data-view="terminal"><span class="nav-icon">›_</span><span data-i18n="app.nav.session_terminal">세션 터미널</span><b id="navTerminalCount">0</b></button>
43
- <div class="nav-group-label tmux-only" data-i18n="ui.tmux_only">tmux 전용</div>
44
- <button class="nav-item tmux-nav-item" type="button" data-view="tmux"><span class="nav-icon">▦</span><span data-i18n="app.nav.tmux">tmux 작업</span><b id="navTmuxCount">0</b></button>
42
+ <button class="nav-item active" type="button" data-view="all" aria-label="홈" data-i18n-aria-label="app.nav.home" aria-keyshortcuts="Meta+1 Control+1" aria-controls="operationsOverview liveSection globalStats sessionSection beginnerGuide providerOverview" title="홈" data-i18n-title="app.nav.home"><span class="nav-icon">⌂</span><span data-i18n="app.nav.home">홈</span><b><span id="navAllCount">0</span><small data-i18n="quality.unit.tasks">작업</small></b></button>
43
+ <button class="nav-item" type="button" data-view="active" aria-label="진행 중" data-i18n-aria-label="app.nav.active" aria-keyshortcuts="Meta+2 Control+2" aria-controls="operationsOverview liveSection activeEmptyState" title="진행 중" data-i18n-title="app.nav.active"><span class="nav-icon live-dot"></span><span data-i18n="app.nav.active">진행 중</span><b><span id="navActiveCount">0</span><small data-i18n="quality.unit.tasks">작업</small></b></button>
44
+ <button class="nav-item" type="button" data-view="waiting" aria-label="확인·주의" data-i18n-aria-label="app.nav.needs_review" aria-keyshortcuts="Meta+3 Control+3" aria-controls="attentionInbox" title="확인·주의" data-i18n-title="app.nav.needs_review"><span class="nav-icon">!</span><span data-i18n="app.nav.needs_review">확인·주의</span><b><span id="navWaitingCount">0</span><small data-i18n="quality.unit.tasks">작업</small></b></button>
45
+ <details id="advancedToolsNav" class="advanced-tools-nav">
46
+ <summary><span class="nav-icon">⌁</span><span data-i18n="management.advanced_tools">고급 도구</span><b><span id="advancedToolsCount">0</span><small data-i18n="quality.unit.items">항목</small></b><i aria-hidden="true">⌄</i></summary>
47
+ <div class="advanced-tools-list">
48
+ <button class="nav-item runtime-nav-item" type="button" data-view="runtime" aria-label="예약·반복" data-i18n-aria-label="app.nav.runtime" aria-keyshortcuts="Meta+4 Control+4" aria-controls="automationOverview" title="예약·반복" data-i18n-title="app.nav.runtime"><span class="nav-icon runtime-nav-icon">↻</span><span data-i18n="app.nav.runtime">예약·반복</span><b><span id="navRuntimeCount">0</span><small data-i18n="quality.unit.runs">실행</small></b></button>
49
+ <button class="nav-item" type="button" data-view="terminal" aria-label="대화·명령창" data-i18n-aria-label="app.nav.session_terminal" aria-keyshortcuts="Meta+5 Control+5" aria-controls="terminalSection" title="대화·명령창" data-i18n-title="app.nav.session_terminal"><span class="nav-icon">›_</span><span data-i18n="app.nav.session_terminal">대화·명령창</span><b><span id="navTerminalCount">0</span><small data-i18n="quality.unit.sessions">세션</small></b></button>
50
+ <button class="nav-item tmux-nav-item" type="button" data-view="tmux" aria-label="여러 명령창" data-i18n-aria-label="app.nav.tmux" aria-keyshortcuts="Meta+6 Control+6" aria-controls="tmuxSection" title="여러 명령창" data-i18n-title="app.nav.tmux"><span class="nav-icon">▦</span><span data-i18n="app.nav.tmux">여러 명령창</span><b><span id="navTmuxCount">0</span><small data-i18n="quality.unit.groups">묶음</small></b></button>
51
+ </div>
52
+ </details>
45
53
  <div class="nav-group-label" data-i18n="app.nav.application">프로그램</div>
46
- <button class="nav-item settings-nav-item" type="button" data-view="settings"><span class="nav-icon">⚙</span><span data-i18n="app.nav.settings">설정</span><b id="navUpdateBadge" class="hidden">NEW</b></button>
47
- <button id="mobileMoreBtn" class="nav-item mobile-more-nav" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="mobileToolsMenu"><span class="nav-icon">•••</span><span data-i18n="app.nav.more">더보기</span></button>
54
+ <button class="nav-item settings-nav-item" type="button" data-view="settings" aria-label="설정" data-i18n-aria-label="app.nav.settings" aria-keyshortcuts="Meta+7 Control+7" aria-controls="settingsSection" title="설정" data-i18n-title="app.nav.settings"><span class="nav-icon">⚙</span><span data-i18n="app.nav.settings">설정</span><b id="navUpdateBadge" class="hidden">NEW</b></button>
55
+ <button id="mobileMoreBtn" class="nav-item mobile-more-nav" type="button" aria-label="더보기" data-i18n-aria-label="app.nav.more" title="더보기" data-i18n-title="app.nav.more" aria-expanded="false" aria-controls="mobileToolsMenu"><span class="nav-icon">•••</span><span data-i18n="app.nav.more">더보기</span></button>
48
56
  </nav>
49
57
 
50
58
  <section class="sidebar-section">
51
- <div class="section-title"><span data-i18n="ui.available_ai">사용 가능한 AI</span><button id="probeBtn" class="icon-button" type="button" title="AI 연결 상태 다시 확인" data-i18n-title="ui.check_ai_connections_again" aria-label="AI 연결 상태 다시 확인" data-i18n-aria-label="ui.check_ai_connections_again">↻</button></div>
59
+ <div class="section-title"><span data-i18n="ui.available_ai">사용 가능한 AI</span><button id="probeBtn" class="icon-button" type="button" title="AI 연결 상태 다시 확인" data-i18n-title="ui.check_ai_connections_again" aria-label="AI 연결 상태 다시 확인" data-i18n-aria-label="ui.check_ai_connections_again" aria-controls="providerRail">↻</button></div>
52
60
  <div id="providerRail" class="provider-rail"></div>
53
61
  </section>
54
62
 
55
63
  <section class="sidebar-section workspace-section">
56
- <div class="section-title"><span data-i18n="ui.workspaces">작업 폴더</span><button id="addWorkspaceBtn" class="icon-button" type="button" title="작업 폴더 추가" data-i18n-title="ui.add_workspace" aria-label="작업 폴더 추가" data-i18n-aria-label="ui.add_workspace">+</button></div>
57
- <div id="workspaceList" class="workspace-list"></div>
64
+ <div class="section-title"><span data-i18n="ui.workspaces">프로젝트</span><button id="addWorkspaceBtn" class="icon-button" type="button" title="프로젝트 추가" data-i18n-title="ui.add_workspace" aria-label="프로젝트 추가" data-i18n-aria-label="ui.add_workspace" aria-controls="workspaceList">+</button></div>
65
+ <div id="workspaceList" class="workspace-list" role="group" aria-label="프로젝트별 세션 필터" data-i18n-aria-label="quality.workspace_filter"></div>
58
66
  </section>
59
67
 
60
68
  <div class="sidebar-footer">
@@ -72,12 +80,19 @@
72
80
  <p id="pageSubtitle" class="subtitle" data-i18n="ui.active_work_and_items_needing_your_review_appear_first_find">진행 중인 일과 내 확인이 필요한 일을 먼저 보여주고, 나머지 기록은 아래에서 찾을 수 있습니다.</p>
73
81
  </div>
74
82
  <div class="top-actions">
75
- <button id="guideBtn" class="guide-toggle" type="button" aria-controls="beginnerGuide" aria-expanded="true"><span aria-hidden="true">?</span><span><b data-i18n="ui.10_minute_quick_start">10분 시작 가이드</b><small id="guideButtonProgress" data-i18n="common.progress" data-i18n-params='{"current":0,"total":4}'>0 / 4 완료</small></span></button>
76
- <div class="sync-state"><span></span><div><b>LIVE</b><small id="lastSync" data-i18n="ui.connecting">연결 중</small></div></div>
83
+ <button id="shortcutHelpBtn" class="top-icon-action" type="button" aria-label="키보드 단축키 보기" data-i18n-aria-label="quality.shortcuts.open" aria-keyshortcuts="?" aria-controls="shortcutHelpModal"><span aria-hidden="true">⌨</span></button>
84
+ <button id="guideBtn" class="guide-toggle" type="button" aria-controls="beginnerGuide" aria-expanded="false"><span aria-hidden="true">?</span><span><b data-i18n="ui.10_minute_quick_start">10분 시작 가이드</b><small id="guideButtonProgress" data-i18n="common.progress" data-i18n-params='{"current":0,"total":4}'>0 / 4 완료</small></span></button>
85
+ <div id="appConnectionState" class="sync-state" role="status" aria-live="polite"><span aria-hidden="true"></span><div><b data-i18n="ui.app_connection">앱 연결</b><small id="lastSync" data-i18n="ui.connecting">연결 중</small></div></div>
77
86
  <button id="newRunBtn" class="primary-button new-run-cta" type="button" aria-label="AI에게 새 일 맡기기" data-i18n-aria-label="ui.assign_a_new_task_to_ai" aria-keyshortcuts="Meta+N Control+N"><span class="new-run-cta-icon" aria-hidden="true">+</span><span class="new-run-cta-copy"><b data-i18n="ui.new_ai_task">새 AI 작업</b><small><kbd>⌘N</kbd></small></span></button>
78
87
  </div>
79
88
  </header>
80
89
 
90
+ <section id="appErrorBanner" class="app-error-banner hidden" role="alert" aria-labelledby="appErrorTitle">
91
+ <span class="app-error-icon" aria-hidden="true">!</span>
92
+ <div><b id="appErrorTitle" data-i18n="bootstrap.error_title">작업 정보를 불러오지 못했습니다</b><p id="appErrorMessage" data-i18n="bootstrap.error_description">연결을 확인한 뒤 다시 시도하세요. 이 안내는 문제가 해결될 때까지 유지됩니다.</p></div>
93
+ <div class="app-error-actions"><button id="appRetryBtn" type="button" data-i18n="bootstrap.retry">다시 연결</button><button id="appErrorCopyBtn" type="button" data-i18n="bootstrap.copy_error">오류 내용 복사</button></div>
94
+ </section>
95
+
81
96
  <section id="beginnerGuide" class="beginner-guide" aria-labelledby="beginnerGuideTitle">
82
97
  <div class="beginner-guide-intro">
83
98
  <span class="guide-time" data-i18n="ui.first_10_minutes">첫 10분 코스</span>
@@ -88,7 +103,7 @@
88
103
  <ol>
89
104
  <li data-guide-step="create"><button type="button" data-guide-action="create"><i>1</i><span><b data-i18n="ui.assign_work_to_ai">AI에게 일 맡기기</b><small data-i18n="ui.choose_a_task_and_workspace_to_get_started">할 일과 작업 폴더를 고르면 바로 시작돼요.</small><em data-i18n="ui.try_it">직접 해보기 →</em></span></button></li>
90
105
  <li data-guide-step="active"><button type="button" data-guide-action="active"><i>2</i><span><b data-i18n="ui.check_progress">진행 상황 확인</b><small data-i18n="ui.ai_with_a_green_indicator_is_working_now">초록 표시가 있는 AI는 지금 일하고 있어요.</small><em data-i18n="ui.view_active_work">진행 중 보기 →</em></span></button></li>
91
- <li data-guide-step="waiting"><button type="button" data-guide-action="waiting"><i>3</i><span><b data-i18n="ui.find_items_to_review">확인할 찾기</b><small data-i18n="ui.items_marked_needs_review_need_a_response_or_choice">‘내 확인 필요’ 상태에는 답변이나 선택이 필요해요.</small><em data-i18n="ui.view_review_items">확인할 보기 →</em></span></button></li>
106
+ <li data-guide-step="waiting"><button type="button" data-guide-action="waiting"><i>3</i><span><b data-i18n="ui.find_items_to_review">확인·주의 항목 찾기</b><small data-i18n="ui.items_marked_needs_review_need_a_response_or_choice">답변·선택이 필요하거나 오류·주의 신호가 있는 일을 모아봐요.</small><em data-i18n="ui.view_review_items">확인·주의 항목 보기 →</em></span></button></li>
92
107
  <li data-guide-step="detail"><button type="button" data-guide-action="detail"><i>4</i><span><b data-i18n="drawer.title">작업 자세히 보기</b><small data-i18n="ui.see_conversation_progress_and_usage_in_one_place">대화, 진행 과정, 사용량을 한곳에서 확인해요.</small><em data-i18n="ui.open_a_task">작업 열어보기 →</em></span></button></li>
93
108
  </ol>
94
109
  <button id="dismissGuideBtn" class="guide-dismiss" type="button" data-i18n="ui.collapse_guide">가이드 접기</button>
@@ -99,9 +114,15 @@
99
114
  <section id="updateNotice" class="update-notice hidden" aria-live="polite">
100
115
  <span class="update-notice-signal" aria-hidden="true"><i></i></span>
101
116
  <div><b id="updateNoticeTitle" data-i18n="ui.a_new_version_is_available">새 버전을 사용할 수 있습니다.</b><small id="updateNoticeText" data-i18n="ui.download_the_update_from_settings">설정에서 업데이트 파일을 받을 수 있습니다.</small></div>
102
- <button id="updateNoticeBtn" type="button">업데이트 보기 <span>→</span></button>
117
+ <button id="updateNoticeBtn" type="button" aria-controls="updatePanel"><span data-i18n="settings.update.view">업데이트 보기</span> <span>→</span></button>
103
118
  </section>
104
119
 
120
+ <section id="automationOverview" class="automation-overview hidden" aria-label="예약 작업과 실행 루프" data-i18n-aria-label="runtime.section_label"></section>
121
+
122
+ <section id="operationsOverview" class="operations-overview hidden" aria-label="에이전트 운영 상태" data-i18n-aria-label="management.operations_label"></section>
123
+
124
+ <section id="attentionInbox" class="attention-inbox hidden" aria-label="확인 또는 주의가 필요한 AI 작업" data-i18n-aria-label="management.inbox_label"></section>
125
+
105
126
  <section id="settingsSection" class="settings-section hidden" aria-labelledby="settingsTitle">
106
127
  <header class="settings-head">
107
128
  <div class="settings-emblem" aria-hidden="true"><span>↟</span><i></i></div>
@@ -125,6 +146,15 @@
125
146
  </label>
126
147
  </section>
127
148
 
149
+ <section class="provider-visibility-card" aria-labelledby="providerVisibilityTitle">
150
+ <div class="provider-visibility-copy">
151
+ <span data-i18n="settings.providers.eyebrow">AI 표시 맞춤 설정</span>
152
+ <h3 id="providerVisibilityTitle" data-i18n="settings.providers.title">화면에 표시할 AI</h3>
153
+ <p data-i18n="settings.providers.description">끄면 해당 AI의 현황, 필터, 세션, 작업 실행 항목이 앱 전체에서 숨겨집니다. 언제든 다시 켤 수 있습니다.</p>
154
+ </div>
155
+ <div id="providerVisibilityList" class="provider-visibility-list"></div>
156
+ </section>
157
+
128
158
  <div id="updatePanel" class="update-panel" data-update-status="idle">
129
159
  <div class="version-route" aria-label="설치 버전과 최신 버전 비교" data-i18n-aria-label="ui.compare_installed_and_latest_versions">
130
160
  <article class="version-node local-version-node">
@@ -166,19 +196,19 @@
166
196
  </div>
167
197
  </section>
168
198
 
169
- <section id="terminalSection" class="terminal-section hidden" aria-label="명령창 직접 다루기">
199
+ <section id="terminalSection" class="terminal-section hidden" aria-label="명령창 직접 다루기" data-i18n-aria-label="terminal.direct_control">
170
200
  <div class="terminal-section-head">
171
- <div><span class="terminal-logo">›_</span><div><p class="eyebrow" data-i18n="ui.conversation_and_execution_together">대화와 실행 화면을 한곳에서</p><h2 data-i18n="app.nav.session_terminal">세션 터미널</h2><p id="terminalPlatformExplain" class="section-explain" data-i18n="ui.choose_a_session_on_the_left_to_continue_with_its">왼쪽에서 세션을 고르면 이전 AI 대화와 실시간 터미널을 나란히 보며 그대로 이어서 작업할 수 있습니다.</p></div></div>
201
+ <div><span class="terminal-logo">›_</span><div><p class="eyebrow" data-i18n="ui.conversation_and_execution_together">대화와 실행 화면을 한곳에서</p><h2 data-i18n="app.nav.session_terminal">대화·명령창</h2><p id="terminalPlatformExplain" class="section-explain" data-i18n="ui.choose_a_session_on_the_left_to_continue_with_its">왼쪽에서 세션을 고르면 이전 AI 대화와 실시간 터미널을 나란히 보며 그대로 이어서 작업할 수 있습니다.</p></div></div>
172
202
  <div class="terminal-create-actions">
173
203
  <button id="newPowerShellBtn" class="accent" type="button" data-i18n="ui.windows_session">+ Windows 세션</button>
174
204
  <button id="newWslBtn" type="button" data-i18n="ui.linux_session">+ Linux 세션</button>
175
205
  </div>
176
206
  </div>
177
207
  <div class="terminal-layout">
178
- <aside class="terminal-resource-panel">
208
+ <aside id="terminalResourcePanel" class="terminal-resource-panel">
179
209
  <div class="terminal-resource-head"><div><b data-i18n="ui.my_terminal_sessions">내 터미널 세션</b><span id="terminalSessionSummary" data-i18n="common.running" data-i18n-params='{"count":0}'>0개 실행 중</span></div><span class="terminal-resource-live"><i></i>LIVE</span></div>
180
210
  <p id="terminalReorderHelp" class="sr-only" data-i18n="terminal.reorder_help">세션 옆의 위아래 버튼을 누르거나, 세션에 초점을 둔 뒤 Alt와 위아래 화살표 키를 눌러 순서를 바꿀 수 있습니다.</p>
181
- <div id="terminalSessionList" class="terminal-session-list"></div>
211
+ <div id="terminalSessionList" class="terminal-session-list" role="listbox" aria-label="터미널 세션" data-i18n-aria-label="quality.terminal_sessions"></div>
182
212
  <div class="terminal-resource-tip"><span>⌘</span><p><b data-i18n="ui.sessions_stay_open_when_you_change_views">세션은 화면을 옮겨도 유지됩니다.</b><small data-i18n="ui.output_and_draft_commands_remain_when_you_return_from_another">다른 작업을 보고 돌아와도 출력과 작성 중인 명령이 그대로 남아 있어요.</small></p></div>
183
213
  </aside>
184
214
 
@@ -187,13 +217,16 @@
187
217
  <div class="terminal-target-cluster"><span id="terminalTargetIcon" class="terminal-target-icon">›_</span><div id="terminalTargetMeta" class="terminal-target-meta"><b data-i18n="ui.select_a_session">세션을 선택해 주세요</b><span data-i18n="ui.choose_a_session_on_the_left_or_create_a_new">왼쪽 목록에서 이어갈 세션을 고르거나 새 세션을 만드세요.</span></div></div>
188
218
  <div class="terminal-workspace-actions">
189
219
  <div id="terminalConnectionState" class="terminal-connection-state"><i></i><span data-i18n="ui.waiting_for_selection">선택 대기</span></div>
220
+ <details class="terminal-session-tools">
221
+ <summary><span data-i18n="terminal.session_controls">세션 관리</span><i aria-hidden="true">⌄</i></summary>
190
222
  <div class="terminal-key-actions">
191
- <button type="button" data-terminal-signal="interrupt" title="현재 실행 중인 명령 중단" data-i18n-title="ui.interrupt_the_running_command"><span data-i18n="ui.interrupt">실행 중단</span><kbd>Ctrl C</kbd></button>
192
- <button type="button" data-terminal-signal="clear" title="터미널 화면 정리" data-i18n-title="ui.clear_terminal_screen"><span data-i18n="ui.clear">화면 정리</span><kbd>Ctrl L</kbd></button>
223
+ <button type="button" data-terminal-signal="interrupt" title="현재 실행 중인 명령 중단" data-i18n-title="ui.interrupt_the_running_command" aria-keyshortcuts="Control+C"><span data-i18n="ui.interrupt">실행 중단</span><kbd>Ctrl C</kbd></button>
224
+ <button type="button" data-terminal-signal="clear" title="터미널 화면 정리" data-i18n-title="ui.clear_terminal_screen" aria-keyshortcuts="Control+L"><span data-i18n="ui.clear">화면 정리</span><kbd>Ctrl L</kbd></button>
193
225
  <button id="terminalRestartBtn" type="button" data-i18n="ui.restart">다시 시작</button>
194
226
  <button id="terminalAttachBtn" class="hidden" type="button" data-i18n="ui.control_directly">직접 조작하기</button>
195
227
  <button id="terminalCloseBtn" class="terminal-danger-button" type="button" data-i18n="ui.end_session">세션 종료</button>
196
228
  </div>
229
+ </details>
197
230
  </div>
198
231
  </div>
199
232
  <div id="terminalTmuxTools" class="terminal-tmux-tools hidden">
@@ -201,7 +234,7 @@
201
234
  <button type="button" data-tmux-manage="new-window" data-i18n="ui.add_window">창 추가</button>
202
235
  <button type="button" data-tmux-manage="split-horizontal" data-i18n="ui.split_left_right">좌우로 나누기</button>
203
236
  <button type="button" data-tmux-manage="split-vertical" data-i18n="ui.split_top_bottom">상하로 나누기</button>
204
- <label>창 배치 <select id="terminalTmuxLayout"><option value="tiled" data-i18n="ui.tiled">바둑판</option><option value="even-horizontal" data-i18n="ui.equal_width">같은 너비</option><option value="even-vertical" data-i18n="ui.equal_height">같은 높이</option><option value="main-horizontal" data-i18n="ui.main_window_on_top">중요 창 위쪽</option><option value="main-vertical" data-i18n="ui.main_window_on_left">중요 창 왼쪽</option></select></label>
237
+ <label><span data-i18n="terminal.window_layout">창 배치</span> <select id="terminalTmuxLayout"><option value="tiled" data-i18n="ui.tiled">바둑판</option><option value="even-horizontal" data-i18n="ui.equal_width">같은 너비</option><option value="even-vertical" data-i18n="ui.equal_height">같은 높이</option><option value="main-horizontal" data-i18n="ui.main_window_on_top">중요 창 위쪽</option><option value="main-vertical" data-i18n="ui.main_window_on_left">중요 창 왼쪽</option></select></label>
205
238
  <button type="button" class="danger" data-tmux-manage="kill-pane" data-i18n="ui.close_selected_pane">선택한 칸 닫기</button>
206
239
  <button type="button" class="danger" data-tmux-manage="kill-window" data-i18n="ui.close_entire_window">창 전체 닫기</button>
207
240
  <button type="button" class="danger" data-tmux-manage="kill-session" data-i18n="ui.end_workspace">작업 묶음 끝내기</button>
@@ -216,13 +249,24 @@
216
249
  <footer><span class="session-lock-dot"></span><b data-i18n="ui.this_conversation_is_connected_to_the_terminal_on_the_right">이 대화가 오른쪽 터미널과 연결되어 있습니다</b></footer>
217
250
  </aside>
218
251
  <section class="terminal-console-pane" aria-label="실시간 터미널과 명령 입력" data-i18n-aria-label="ui.live_terminal_and_command_input">
219
- <header class="terminal-console-head"><div><span class="terminal-console-pulse"></span><div><b data-i18n="ui.live_terminal">실시간 터미널</b><small id="terminalConsoleCaption" data-i18n="ui.select_a_session_to_show_its_output_here">세션을 선택하면 출력이 여기에 표시됩니다</small></div></div><span id="terminalConsoleState" class="terminal-console-state" data-i18n="ui.waiting_for_selection">선택 대기</span></header>
252
+ <header class="terminal-console-head">
253
+ <div class="terminal-console-title"><span class="terminal-console-pulse"></span><div><b data-i18n="ui.live_terminal">실시간 터미널</b><small id="terminalConsoleCaption" data-i18n="ui.select_a_session_to_show_its_output_here">세션을 선택하면 출력이 여기에 표시됩니다</small></div></div>
254
+ <div class="terminal-console-tools">
255
+ <span id="terminalConsoleState" class="terminal-console-state" data-i18n="ui.waiting_for_selection">선택 대기</span>
256
+ <div class="terminal-font-controls" role="group" aria-label="터미널 글자 크기" data-i18n-aria-label="terminal.view.font_size">
257
+ <button id="terminalFontDecreaseBtn" type="button" aria-label="터미널 글자 작게" data-i18n-aria-label="terminal.view.font_decrease" title="터미널 글자 작게" data-i18n-title="terminal.view.font_decrease">−</button>
258
+ <output id="terminalFontSizeLabel" aria-live="polite">15px</output>
259
+ <button id="terminalFontIncreaseBtn" type="button" aria-label="터미널 글자 크게" data-i18n-aria-label="terminal.view.font_increase" title="터미널 글자 크게" data-i18n-title="terminal.view.font_increase">+</button>
260
+ </div>
261
+ <button id="terminalFocusBtn" class="terminal-focus-button" type="button" aria-pressed="false" title="터미널만 크게 보기" data-i18n-title="terminal.view.focus"><span data-i18n="terminal.view.focus">집중 보기</span><b aria-hidden="true">⛶</b></button>
262
+ </div>
263
+ </header>
220
264
  <div id="terminalViewport" class="terminal-viewport"><div id="terminalEmpty" class="terminal-empty"><span>›_</span><h3 data-i18n="ui.choose_a_session_to_continue">이어갈 세션을 선택하세요</h3><p data-i18n="ui.choose_a_session_on_the_left_or_create_one_to">왼쪽 세션을 고르거나 새 세션을 만들면 실시간 출력과 명령 입력창이 열립니다.</p></div></div>
221
265
  <form id="terminalCommandForm" class="terminal-command-form">
222
266
  <div class="terminal-command-label"><label id="terminalCommandLabel" for="terminalCommandInput" data-i18n="ui.send_command_to_terminal">터미널에 명령 보내기</label><span data-i18n="ui.enter_to_send_shift_enter_for_newline">Enter 전송 · Shift+Enter 줄바꿈</span></div>
223
- <div class="terminal-command-composer"><textarea id="terminalCommandInput" rows="2" placeholder="먼저 왼쪽에서 세션을 선택하세요" data-i18n-placeholder="ui.select_a_session_on_the_left_first" spellcheck="false"></textarea><button type="submit"><span data-i18n="common.send">보내기</span><b>↵</b></button></div>
267
+ <div class="terminal-command-composer"><textarea id="terminalCommandInput" rows="2" maxlength="8000" aria-describedby="terminalCommandCount" placeholder="먼저 왼쪽에서 세션을 선택하세요" data-i18n-placeholder="ui.select_a_session_on_the_left_first" spellcheck="false"></textarea><button id="terminalCommandClearBtn" class="terminal-command-clear hidden" type="button" aria-label="작성 중인 명령 지우기" data-i18n-aria-label="quality.terminal_clear_draft">×</button><button type="submit"><span data-i18n="common.send">보내기</span><b>↵</b></button><small id="terminalCommandCount" class="terminal-command-count">0 / 8,000</small></div>
224
268
  </form>
225
- <div id="terminalNotice" class="terminal-notice" role="status" aria-live="polite" aria-atomic="true"><span class="terminal-notice-dot"></span><span data-i18n="ui.select_a_session_to_start_typing">세션을 선택하면 바로 입력할 수 있습니다.</span></div>
269
+ <div id="terminalNotice" class="terminal-notice" role="status" aria-live="polite" aria-atomic="true" tabindex="-1"><span class="terminal-notice-dot"></span><span data-i18n="ui.select_a_session_to_start_typing">세션을 선택하면 바로 입력할 수 있습니다.</span></div>
226
270
  </section>
227
271
  </div>
228
272
  </div></div>
@@ -232,7 +276,7 @@
232
276
  <section id="tmuxSection" class="tmux-section hidden" aria-label="여러 명령창 작업 보기" data-i18n-aria-label="ui.view_multi_terminal_work">
233
277
  <div class="tmux-section-head">
234
278
  <div><span class="tmux-logo">tmux</span><div><p class="eyebrow" data-i18n="ui.tmux_workspace">tmux 전용 공간</p><h2 data-i18n="ui.work_grouped_with_tmux">tmux로 묶은 작업</h2><p class="section-explain" data-i18n="ui.only_work_using_tmux_appears_here_regular_terminals_are_kept">tmux를 사용하는 작업만 모아 봅니다. 일반 명령창은 이 화면에 섞이지 않습니다.</p></div></div>
235
- <div class="tmux-section-actions"><button id="refreshTmuxTerminalBtn" type="button" data-i18n="ui.refresh">↻ 새로고침</button><button id="newTmuxSessionBtn" class="accent" type="button" data-i18n="ui.create_tmux_workspace">+ tmux 작업 만들기</button></div>
279
+ <div class="tmux-section-actions"><button id="refreshTmuxTerminalBtn" type="button" data-i18n="ui.refresh">↻ 새로고침</button><button id="newTmuxSessionBtn" class="accent" type="button" data-i18n="ui.create_tmux_workspace">+ 여러 명령창 만들기</button></div>
236
280
  </div>
237
281
  <div id="tmuxStats" class="tmux-stats"></div>
238
282
  <div class="tmux-map-toolbar">
@@ -245,7 +289,7 @@
245
289
  <div class="terminal-layout tmux-control-layout">
246
290
  <aside class="terminal-resource-panel tmux-resource-panel">
247
291
  <div class="terminal-resource-head tmux-resources"><div><b data-i18n="ui.tmux_terminals_only">tmux 안의 명령창만</b><span data-i18n="ui.regular_terminals_are_hidden">일반 명령창은 표시하지 않음</span></div></div>
248
- <div id="terminalTmuxList" class="terminal-tmux-list"></div>
292
+ <div id="terminalTmuxList" class="terminal-tmux-list" role="listbox" aria-label="tmux 칸" data-i18n-aria-label="quality.tmux_panes"></div>
249
293
  </aside>
250
294
  <div id="tmuxWorkbenchMount" class="terminal-workbench-mount"></div>
251
295
  </div>
@@ -254,14 +298,27 @@
254
298
 
255
299
  <section id="liveSection" class="live-section hidden" aria-label="현재 진행 중인 AI 작업" data-i18n-aria-label="ui.ai_work_currently_in_progress">
256
300
  <div class="live-section-head">
257
- <div><span class="live-beacon"></span><div><p class="eyebrow" data-i18n="ui.active_now">지금 진행 중</p><h2 data-i18n="ui.work_assigned_to_ai">AI들이 맡은 일</h2></div></div>
258
- <p data-i18n="ui.open_a_task_to_see_who_started_it_and_what">일을 누르면 누가 시작했고, 다른 AI에게 어떤 도움을 맡겼는지 쉽게 볼 수 있습니다.</p>
301
+ <div class="live-section-title"><span class="live-beacon"></span><div><p class="eyebrow" data-i18n="ui.active_now">지금 진행 중</p><h2 data-i18n="ui.work_assigned_to_ai">AI들이 맡은 일</h2></div></div>
302
+ <div class="live-section-tools">
303
+ <p class="live-section-description" data-i18n="ui.open_a_task_to_see_who_started_it_and_what">일을 누르면 누가 시작했고, 다른 AI에게 어떤 도움을 맡겼는지 쉽게 볼 수 있습니다.</p>
304
+ <button id="openTmuxFromAgentWork" class="live-tmux-shortcut" type="button" aria-label="여러 명령창 보기 · 묶음 0개" data-i18n-aria-label="graph.open_tmux_workspace_count" data-i18n-params='{"count":0}' title="여러 명령창 보기" data-i18n-title="graph.open_tmux_workspace">
305
+ <span class="live-tmux-shortcut-icon" aria-hidden="true">▦</span>
306
+ <span data-i18n="graph.open_tmux_workspace">여러 명령창 보기</span>
307
+ <b id="agentWorkTmuxCount">0</b>
308
+ </button>
309
+ </div>
259
310
  </div>
260
311
  <div class="agent-map-toolbar">
261
312
  <div id="graphBreadcrumbs" class="graph-breadcrumbs" aria-label="에이전트 탐색 경로" data-i18n-aria-label="ui.agent_navigation_path"></div>
262
313
  <button id="graphResetBtn" class="graph-reset hidden" type="button" data-i18n="ui.back_to_task_list">작업 목록으로</button>
263
314
  </div>
264
315
  <div id="liveSessionGrid" class="live-session-grid"></div>
316
+ <div id="activeEmptyState" class="empty-state hidden">
317
+ <div class="empty-orbit"><span></span></div>
318
+ <h3 data-i18n="ui.no_tasks_are_currently_active">현재 진행 중인 작업이 없습니다</h3>
319
+ <p data-i18n="ui.new_tasks_will_show_their_progress_here_immediately">새 작업을 시작하면 진행 상황이 여기에 바로 표시됩니다.</p>
320
+ <button class="primary-button" type="button" data-open-run data-i18n="ui.assign_a_new_task_to_ai">AI에게 새 일 맡기기</button>
321
+ </div>
265
322
  </section>
266
323
 
267
324
  <section id="globalStats" class="global-stats" aria-label="전체 통계" data-i18n-aria-label="ui.overall_statistics"></section>
@@ -270,48 +327,57 @@
270
327
  <div class="sessions-heading">
271
328
  <div><p class="eyebrow" data-i18n="ui.history">지난 기록</p><h2 id="viewTitle" data-i18n="ui.recent_conversations_and_tasks">최근 대화와 작업</h2></div>
272
329
  <div class="session-tools">
273
- <label class="search-box"><span aria-hidden="true">⌕</span><input id="searchInput" type="search" aria-label="작업 검색" data-i18n-aria-label="ui.search_tasks" placeholder="작업 이름, AI, 폴더 찾기" data-i18n-placeholder="ui.find_task_ai_or_folder" autocomplete="off" /></label>
274
- <div id="providerFilter" class="provider-filter" role="group" aria-label="AI 제공사 필터" data-i18n-aria-label="ui.ai_provider_filter"></div>
330
+ <label class="search-box"><span aria-hidden="true">⌕</span><input id="searchInput" type="search" maxlength="240" aria-label="작업 검색" data-i18n-aria-label="ui.search_tasks" aria-keyshortcuts="/" placeholder="작업 이름, AI, 폴더 찾기" data-i18n-placeholder="ui.find_task_ai_or_folder" autocomplete="off" /><button id="searchClearBtn" class="search-clear hidden" type="button" aria-label="검색어 지우기" data-i18n-aria-label="filter.clear_search" title="검색어 지우기" data-i18n-title="filter.clear_search">×</button></label>
331
+ <div id="providerFilter" class="provider-filter" role="toolbar" aria-label="AI 제공사 필터" data-i18n-aria-label="ui.ai_provider_filter"></div>
275
332
  <p id="providerFilterStatus" class="sr-only" role="status" aria-live="polite"></p>
276
333
  <select id="sortSelect" aria-label="정렬" data-i18n-aria-label="ui.sort"><option value="recent" data-i18n="ui.most_recently_active">최근에 움직인 순서</option><option value="tokens" data-i18n="ui.highest_usage">많이 사용한 순서</option><option value="context" data-i18n="ui.highest_context_usage">기억 공간을 많이 쓴 순서</option></select>
334
+ <button id="resetFiltersBtn" class="filter-reset hidden" type="button" data-i18n="filter.reset_all">필터 초기화</button>
277
335
  </div>
278
336
  </div>
337
+ <p id="sessionResultSummary" class="session-result-summary" aria-live="polite"></p>
279
338
  <div id="sessionGrid" class="session-grid"></div>
280
339
  <button id="loadMoreBtn" class="load-more hidden" type="button" data-i18n="ui.show_more_tasks">작업 더 보기</button>
281
340
  <div id="emptyState" class="empty-state hidden">
282
341
  <div class="empty-orbit"><span></span></div>
283
342
  <h3 data-i18n="ui.no_tasks_to_show_yet">아직 보여줄 작업이 없습니다</h3>
284
343
  <p data-i18n="ui.change_the_search_filters_or_assign_a_new_task_to">검색 조건을 바꾸거나 AI에게 새 일을 맡겨보세요.</p>
285
- <button class="primary-button" data-open-run data-i18n="ui.assign_a_new_task_to_ai">AI에게 새 일 맡기기</button>
344
+ <button id="emptyClearFiltersBtn" class="ghost-button hidden" type="button" data-i18n="quality.clear_conditions">조건 지우기</button>
345
+ <button class="primary-button" type="button" data-open-run data-i18n="ui.assign_a_new_task_to_ai">AI에게 새 일 맡기기</button>
286
346
  </div>
287
347
  </section>
288
348
  </main>
289
349
  </div>
290
350
 
291
- <nav id="mobileToolsMenu" class="mobile-tools-menu hidden" aria-label="고급 기능과 설정" data-i18n-aria-label="ui.advanced_tools_and_settings">
292
- <div><b data-i18n="app.nav.more">더보기</b><span data-i18n="ui.advanced_tools_to_open_only_when_needed">필요할 때만 여는 고급 기능이에요.</span></div>
293
- <button type="button" data-mobile-view="terminal"><i aria-hidden="true">›_</i><span><b data-i18n="app.nav.session_terminal">세션 터미널</b><small data-i18n="ui.continue_an_existing_ai_conversation_directly">기존 AI 대화를 직접 이어서 입력</small></span></button>
294
- <button type="button" data-mobile-view="tmux"><i aria-hidden="true">▦</i><span><b data-i18n="app.nav.tmux">tmux 작업</b><small data-i18n="ui.manage_multiple_terminals_together">여러 명령창을 묶어 관리</small></span></button>
351
+ <aside id="mobileToolsMenu" class="mobile-tools-menu hidden" role="dialog" aria-modal="true" aria-labelledby="mobileToolsTitle" aria-hidden="true" tabindex="-1" inert>
352
+ <div class="mobile-tools-head"><span><b id="mobileToolsTitle" data-i18n="app.nav.more">더보기</b><small data-i18n="ui.advanced_tools_to_open_only_when_needed">필요할 때만 여는 고급 기능이에요.</small></span><button id="mobileToolsCloseBtn" type="button" aria-label="닫기" data-i18n-aria-label="common.close">×</button></div>
353
+ <details class="mobile-project-picker">
354
+ <summary><i aria-hidden="true">□</i><span><b data-i18n="ui.workspaces">프로젝트</b><small id="mobileWorkspaceSummary" data-i18n="project.all">모든 프로젝트</small></span><em aria-hidden="true">⌄</em></summary>
355
+ <div class="mobile-project-picker-body"><div id="mobileWorkspaceList" class="workspace-list" role="group" aria-label="프로젝트별 세션 필터" data-i18n-aria-label="quality.workspace_filter"></div><button id="mobileAddWorkspaceBtn" type="button" data-i18n="ui.add_workspace">프로젝트 고정</button></div>
356
+ </details>
357
+ <button type="button" data-mobile-view="runtime"><i aria-hidden="true">↻</i><span><b data-i18n="runtime.title">예약·반복 작업</b><small data-i18n="runtime.description">다음 예약과 지금 반복 중인 에이전트 흐름을 함께 봅니다.</small></span></button>
358
+ <button type="button" data-mobile-view="terminal"><i aria-hidden="true">›_</i><span><b data-i18n="app.nav.session_terminal">대화·명령창</b><small data-i18n="ui.continue_an_existing_ai_conversation_directly">기존 AI 대화를 직접 이어서 입력</small></span></button>
359
+ <button type="button" data-mobile-view="tmux"><i aria-hidden="true">▦</i><span><b data-i18n="app.nav.tmux">여러 명령창</b><small data-i18n="ui.manage_multiple_terminals_together">여러 명령창을 묶어 관리</small></span></button>
295
360
  <button type="button" data-mobile-view="settings"><i aria-hidden="true">⚙</i><span><b data-i18n="settings.title">프로그램 설정</b><small data-i18n="ui.check_version_and_updates">버전과 업데이트 확인</small></span></button>
296
- </nav>
361
+ </aside>
297
362
 
298
363
  <div id="drawerBackdrop" class="drawer-backdrop hidden"></div>
299
364
  <aside id="detailDrawer" class="detail-drawer" role="dialog" aria-modal="true" aria-labelledby="drawerTitle" aria-hidden="true" tabindex="-1" inert>
300
365
  <div class="drawer-head">
301
366
  <div id="drawerProviderMark" class="provider-mark">AI</div>
302
367
  <div class="drawer-title"><span id="drawerProvider" data-i18n="ui.ai_task">AI 작업</span><h2 id="drawerTitle" data-i18n="drawer.title">작업 자세히 보기</h2></div>
303
- <button id="closeDrawerBtn" class="close-button" aria-label="닫기" data-i18n-aria-label="common.close">×</button>
368
+ <button id="closeDrawerBtn" class="close-button" type="button" aria-label="닫기" data-i18n-aria-label="common.close">×</button>
304
369
  </div>
305
370
  <div id="drawerMeta" class="drawer-meta"></div>
306
- <div class="drawer-tabs" role="tablist">
307
- <button id="drawerTabChat" class="drawer-tab active" role="tab" aria-selected="true" aria-controls="drawerContent" tabindex="0" data-tab="chat" data-i18n="ui.conversation">대화 내용</button>
308
- <button id="drawerTabLifecycle" class="drawer-tab" role="tab" aria-selected="false" aria-controls="drawerContent" tabindex="-1" data-tab="lifecycle" data-i18n="ui.progress">진행 과정</button>
309
- <button id="drawerTabTokens" class="drawer-tab" role="tab" aria-selected="false" aria-controls="drawerContent" tabindex="-1" data-tab="tokens" data-i18n="ui.usage">사용량</button>
371
+ <div class="drawer-tabs" role="tablist" aria-orientation="horizontal">
372
+ <button id="drawerTabSummary" class="drawer-tab" type="button" role="tab" aria-selected="false" aria-controls="drawerContent" tabindex="-1" data-tab="summary" data-i18n="management.summary">관리 요약</button>
373
+ <button id="drawerTabChat" class="drawer-tab active" type="button" role="tab" aria-selected="true" aria-controls="drawerContent" tabindex="0" data-tab="chat" data-i18n="ui.conversation">대화 내용</button>
374
+ <button id="drawerTabLifecycle" class="drawer-tab" type="button" role="tab" aria-selected="false" aria-controls="drawerContent" tabindex="-1" data-tab="lifecycle" data-i18n="ui.progress">진행 과정</button>
375
+ <button id="drawerTabTokens" class="drawer-tab" type="button" role="tab" aria-selected="false" aria-controls="drawerContent" tabindex="-1" data-tab="tokens" data-i18n="ui.usage">사용량</button>
310
376
  </div>
311
377
  <div id="drawerContent" class="drawer-content" role="tabpanel" aria-labelledby="drawerTabChat" tabindex="0"></div>
312
378
  </aside>
313
379
 
314
- <div id="runModal" class="modal-backdrop hidden" role="dialog" aria-modal="true" aria-labelledby="runModalTitle" aria-describedby="runModalDescription">
380
+ <div id="runModal" class="modal-backdrop hidden" role="dialog" aria-modal="true" aria-labelledby="runModalTitle" aria-describedby="runModalDescription" aria-hidden="true" inert>
315
381
  <form id="runForm" class="run-modal run-composer">
316
382
  <div class="modal-head">
317
383
  <div><p class="eyebrow" data-i18n="ui.start_ai_task">AI 작업 시작</p><h2 id="runModalTitle" data-i18n="ui.what_should_the_ai_work_on">무슨 일을 맡길까요?</h2><p id="runModalDescription" class="run-modal-intro" data-i18n="ui.describe_the_task_then_choose_which_ai_will_work_in">할 일을 먼저 적고, 어떤 AI가 어디서 작업할지 선택하세요.</p></div>
@@ -319,39 +385,55 @@
319
385
  </div>
320
386
  <section class="run-step run-request-step" aria-labelledby="runRequestLabel">
321
387
  <div class="run-step-head"><i>1</i><span><b id="runRequestLabel" data-i18n="ui.describe_the_task">할 일 적기</b><small data-i18n="ui.include_the_expected_result_and_constraints_for_better_accuracy">결과와 제약을 함께 적으면 더 정확해요.</small></span></div>
322
- <label class="run-prompt-field"><span class="sr-only" data-i18n="ui.task_for_ai">AI에게 맡길 일</span><textarea id="runPrompt" required rows="5" maxlength="8000" placeholder="예: 로그인 화면의 오류를 찾아 고치고, 관련 테스트까지 실행해줘" data-i18n-placeholder="ui.example_find_and_fix_the_login_screen_error_then_run"></textarea></label>
323
- <div class="run-prompt-tools"><div class="run-prompt-examples" aria-label="빠른 요청 예시" data-i18n-aria-label="ui.quick_prompt_examples"><button type="button" data-run-prompt-example="문제의 원인을 찾아 고치고 관련 테스트까지 실행해줘" data-i18n="ui.fix_a_bug">오류 수정</button><button type="button" data-run-prompt-example="현재 코드를 검토하고 중요도 순으로 개선해줘" data-i18n="ui.review_code">코드 검토</button><button type="button" data-run-prompt-example="현재 기능을 검증하는 테스트를 추가하고 실행해줘" data-i18n="ui.add_tests">테스트 추가</button></div><span id="runPromptCount" class="run-prompt-count">0 / 8,000</span></div>
388
+ <label class="run-prompt-field"><span class="sr-only" data-i18n="ui.task_for_ai">AI에게 맡길 일</span><textarea id="runPrompt" required rows="5" maxlength="8000" aria-describedby="runPromptCount" placeholder="예: 로그인 화면의 오류를 찾아 고치고, 관련 테스트까지 실행해줘" data-i18n-placeholder="ui.example_find_and_fix_the_login_screen_error_then_run"></textarea></label>
389
+ <div class="run-prompt-tools"><div class="run-prompt-examples" aria-label="빠른 요청 예시" data-i18n-aria-label="ui.quick_prompt_examples"><button type="button" data-run-prompt-key="run.example.fix" data-i18n="ui.fix_a_bug">오류 수정</button><button type="button" data-run-prompt-key="run.example.review" data-i18n="ui.review_code">코드 검토</button><button type="button" data-run-prompt-key="run.example.tests" data-i18n="ui.add_tests">테스트 추가</button></div><span id="runPromptCount" class="run-prompt-count">0 / 8,000</span></div>
324
390
  </section>
325
391
  <section class="run-step run-setup-step" aria-labelledby="runSetupLabel">
326
392
  <div class="run-step-head"><i>2</i><span><b id="runSetupLabel" data-i18n="ui.choose_how_to_run">실행 방법 선택</b><small data-i18n="ui.choose_an_ai_and_workspace_to_finish_setup">AI와 작업 폴더만 고르면 준비가 끝납니다.</small></span></div>
327
393
  <div id="runProviderLabel" class="field-label" data-i18n="ui.which_ai_should_handle_it">어떤 AI에게 맡길까요?</div>
328
- <div id="runProviderPicker" class="run-provider-picker" role="group" aria-labelledby="runProviderLabel"></div>
394
+ <div id="runProviderPicker" class="run-provider-picker" role="radiogroup" aria-labelledby="runProviderLabel"></div>
329
395
  <div id="runProviderHelp" class="run-provider-help hidden" role="status"></div>
330
396
  <div class="run-folder-field"><label class="field-label" for="runCwd" data-i18n="ui.workspaces">작업 폴더</label><div class="path-field"><input id="runCwd" required placeholder="프로젝트 폴더를 선택하세요" data-i18n-placeholder="ui.choose_a_project_folder" /><button type="button" id="pickRunCwdBtn" data-i18n="ui.browse">폴더 찾기</button></div></div>
331
397
  <div id="runWorkspaceSuggestions" class="run-workspace-suggestions" aria-label="최근 작업 폴더" data-i18n-aria-label="ui.recent_workspaces"></div>
332
398
  <label class="permission-toggle"><input id="allowWrites" type="checkbox" /><span class="toggle-track"></span><div><strong data-i18n="ui.allow_ai_to_edit_files">AI가 파일을 고칠 수 있게 허용</strong><small data-i18n="ui.when_enabled_the_ai_can_directly_edit_files_in_the">켜면 선택한 폴더의 파일을 직접 수정합니다.</small></div></label>
333
399
  <div id="runPermissionHint" class="run-permission-hint hidden" role="status" data-i18n="ui.this_request_appears_to_need_file_changes_without_edit_permission">이 요청은 파일 수정이 필요해 보여요. 위의 수정 허용을 켜지 않으면 AI가 코드 변경 없이 검토만 합니다.</div>
334
400
  </section>
335
- <details class="run-advanced">
401
+ <details class="run-advanced" data-disclosure-key="run:advanced">
336
402
  <summary><span><b data-i18n="ui.advanced_settings">고급 설정</b><small data-i18n="ui.use_only_when_selecting_a_specific_model">특정 모델을 직접 지정할 때만 사용</small></span><i aria-hidden="true">↓</i></summary>
337
- <label><span>사용 모델 <small data-i18n="ui.leave_blank_if_unsure">몰라도 비워두세요</small></span><input id="runModel" placeholder="비워두면 AI가 알아서 선택합니다" data-i18n-placeholder="ui.leave_blank_to_let_the_ai_choose" /></label>
403
+ <label><span><span data-i18n="ui.model">사용 모델</span> <small data-i18n="ui.leave_blank_if_unsure">몰라도 비워두세요</small></span><input id="runModel" autocomplete="off" spellcheck="false" placeholder="비워두면 AI가 알아서 선택합니다" data-i18n-placeholder="ui.leave_blank_to_let_the_ai_choose" /></label>
338
404
  </details>
339
- <div id="runError" class="form-error hidden" role="alert" aria-live="assertive"></div>
340
- <div class="modal-actions run-modal-actions"><span class="run-shortcut-hint"><kbd>⌘</kbd><kbd>Enter</kbd> 시작</span><button type="button" id="cancelRunBtn" class="ghost-button" data-i18n="common.cancel">취소</button><button type="submit" class="primary-button run-submit-button"><span class="run-submit-icon" aria-hidden="true">↗</span><span id="runSubmitLabel" data-i18n="ui.assign_to_ai">AI에게 맡기기</span></button></div>
405
+ <div id="runError" class="form-error hidden" role="alert" aria-live="assertive" tabindex="-1"></div>
406
+ <div class="modal-actions run-modal-actions"><span class="run-shortcut-hint"><kbd>⌘</kbd><kbd>Enter</kbd> <span data-i18n="ui.start">시작</span></span><button type="button" id="clearRunDraftBtn" class="ghost-button" data-i18n="quality.clear_draft">초안 지우기</button><button type="button" id="cancelRunBtn" class="ghost-button" data-i18n="common.cancel">취소</button><button type="submit" class="primary-button run-submit-button" aria-keyshortcuts="Meta+Enter Control+Enter"><span class="run-submit-icon" aria-hidden="true">↗</span><span id="runSubmitLabel" data-i18n="ui.assign_to_ai">AI에게 맡기기</span></button></div>
341
407
  </form>
342
408
  </div>
343
409
 
410
+ <div id="globalStatus" class="sr-only" role="status" aria-live="polite" aria-atomic="true"></div>
344
411
  <div id="toast" class="toast hidden" role="status" aria-live="polite" aria-atomic="true"></div>
345
- <div id="tmuxCreateModal" class="modal-backdrop hidden" role="dialog" aria-modal="true" aria-labelledby="tmuxCreateTitle">
412
+ <div id="quickPaletteModal" class="modal-backdrop quality-dialog hidden" role="dialog" aria-modal="true" aria-labelledby="quickPaletteTitle" aria-describedby="quickPaletteDescription" aria-hidden="true" inert>
413
+ <section class="quality-modal command-palette">
414
+ <header class="quality-modal-head"><div><p data-i18n="quality.quick_eyebrow">빠른 이동</p><h2 id="quickPaletteTitle" data-i18n="quality.quick_title">어디로 이동할까요?</h2></div><button id="closeQuickPaletteBtn" class="close-button" type="button" aria-label="빠른 이동 닫기" data-i18n-aria-label="quality.quick_close">×</button></header>
415
+ <p id="quickPaletteDescription" class="sr-only" data-i18n="quality.quick_description">화면이나 작업을 검색한 뒤 방향키와 Enter로 실행하세요.</p>
416
+ <label class="quality-search"><span aria-hidden="true">⌕</span><input id="quickPaletteInput" type="search" autocomplete="off" maxlength="80" role="combobox" aria-label="빠른 이동 검색" data-i18n-aria-label="quality.quick_search" aria-autocomplete="list" aria-controls="quickPaletteList" aria-expanded="true" placeholder="화면 또는 작업 검색" data-i18n-placeholder="quality.quick_placeholder" /></label>
417
+ <div id="quickPaletteList" class="quality-command-list" role="listbox" aria-label="빠른 이동 명령" data-i18n-aria-label="quality.quick_commands"></div>
418
+ <p id="quickPaletteStatus" class="quality-dialog-status" role="status" aria-live="polite"></p>
419
+ </section>
420
+ </div>
421
+ <div id="shortcutHelpModal" class="modal-backdrop quality-dialog hidden" role="dialog" aria-modal="true" aria-labelledby="shortcutHelpTitle" aria-hidden="true" inert>
422
+ <section class="quality-modal shortcut-help-modal">
423
+ <header class="quality-modal-head"><div><p data-i18n="quality.shortcuts.eyebrow">키보드 도움말</p><h2 id="shortcutHelpTitle" data-i18n="quality.shortcuts.title">앱 단축키</h2></div><button id="closeShortcutHelpBtn" class="close-button" type="button" aria-label="단축키 도움말 닫기" data-i18n-aria-label="quality.shortcuts.close">×</button></header>
424
+ <dl class="shortcut-help-list"><div><dt><kbd>⌘/Ctrl</kbd><kbd>K</kbd></dt><dd data-i18n="quality.shortcuts.quick">빠른 이동 열기</dd></div><div><dt><kbd>⌘/Ctrl</kbd><kbd>1–7</kbd></dt><dd data-i18n="quality.shortcuts.views">주요 화면 이동</dd></div><div><dt><kbd>/</kbd></dt><dd data-i18n="quality.shortcuts.search">작업 검색</dd></div><div><dt><kbd>⌘/Ctrl</kbd><kbd>N</kbd></dt><dd data-i18n="quality.shortcuts.new_task">새 AI 작업</dd></div><div><dt><kbd>?</kbd></dt><dd data-i18n="quality.shortcuts.help">이 도움말 열기</dd></div><div><dt><kbd>Esc</kbd></dt><dd data-i18n="quality.shortcuts.close_action">열린 창 닫기</dd></div></dl>
425
+ </section>
426
+ </div>
427
+ <div id="tmuxCreateModal" class="modal-backdrop hidden" role="dialog" aria-modal="true" aria-labelledby="tmuxCreateTitle" aria-hidden="true" inert>
346
428
  <form id="tmuxCreateForm" class="run-modal terminal-modal">
347
429
  <div class="modal-head"><div><p class="eyebrow" data-i18n="ui.advanced_work">고급 작업</p><h2 id="tmuxCreateTitle" data-i18n="ui.create_multi_window_workspace">여러 창 작업 만들기</h2></div><button type="button" id="closeTmuxCreateBtn" class="close-button" aria-label="여러 창 작업 만들기 닫기" data-i18n-aria-label="ui.close_multi_window_workspace_dialog">×</button></div>
348
430
  <div class="form-grid">
349
431
  <label><span id="tmuxEnvironmentLabel" data-i18n="ui.tmux_environment">tmux 환경</span><select id="tmuxCreateDistro" required></select></label>
350
- <label><span data-i18n="ui.workspace_name">작업 묶음 이름</span><input id="tmuxCreateName" required pattern="[A-Za-z0-9_.\-]+" placeholder="my-work" /></label>
432
+ <label><span data-i18n="ui.workspace_name">작업 묶음 이름</span><input id="tmuxCreateName" required pattern="[A-Za-z0-9_.\-]+" placeholder="my-work" aria-describedby="tmuxCreateNameHelp" /><small id="tmuxCreateNameHelp" data-i18n="tmux.name_requirements">영문, 숫자, 마침표, 밑줄, 하이픈만 사용할 수 있습니다.</small></label>
351
433
  </div>
352
- <label><span>시작 폴더 <small data-i18n="ui.optional">선택 사항</small></span><input id="tmuxCreateCwd" placeholder="프로젝트의 절대 경로" data-i18n-placeholder="ui.absolute_project_path" /></label>
353
- <label><span>처음 실행할 명령 <small data-i18n="ui.optional">선택 사항</small></span><textarea id="tmuxCreateCommand" rows="4" placeholder="예: claude 또는 codex" data-i18n-placeholder="ui.example_claude_or_codex"></textarea></label>
354
- <div id="tmuxCreateError" class="form-error hidden" role="alert" aria-live="assertive"></div>
434
+ <label><span><span data-i18n="terminal.start_folder">시작 폴더</span> <small data-i18n="ui.optional">선택 사항</small></span><span class="path-field"><input id="tmuxCreateCwd" placeholder="프로젝트의 절대 경로" data-i18n-placeholder="ui.absolute_project_path" /><button type="button" id="pickTmuxCwdBtn" data-i18n="ui.browse">폴더 찾기</button></span></label>
435
+ <label><span><span data-i18n="terminal.initial_command">처음 실행할 명령</span> <small data-i18n="ui.optional">선택 사항</small></span><textarea id="tmuxCreateCommand" rows="4" placeholder="예: 실행할 AI 명령" data-i18n-placeholder="ui.example_claude_or_codex"></textarea></label>
436
+ <div id="tmuxCreateError" class="form-error hidden" role="alert" aria-live="assertive" tabindex="-1"></div>
355
437
  <div class="modal-actions"><button type="button" id="cancelTmuxCreateBtn" class="ghost-button" data-i18n="common.cancel">취소</button><button type="submit" class="primary-button" data-i18n="ui.create_workspace">작업 묶음 만들기</button></div>
356
438
  </form>
357
439
  </div>
@@ -361,18 +443,22 @@
361
443
  <script src="i18n.js"></script>
362
444
  <script src="shared.js"></script>
363
445
  <script src="app.js"></script>
446
+ <script src="app-provider-visibility.js"></script>
364
447
  <script src="app-dashboard.js"></script>
448
+ <script src="app-runtime-overview.js"></script>
365
449
  <script src="app-graph-model.js"></script>
366
450
  <script src="app-graph-view.js"></script>
367
451
  <script src="app-graph-layout.js"></script>
368
452
  <script src="app-graph-orchestration.js"></script>
369
453
  <script src="app-tmux-render.js"></script>
370
- <script src="app-session-render.js"></script>
371
454
  <script src="app-agent-actions.js"></script>
455
+ <script src="app-management.js"></script>
456
+ <script src="app-session-render.js"></script>
372
457
  <script src="app-drawer-data.js"></script>
373
458
  <script src="app-drawer-content.js"></script>
374
459
  <script src="app-drawer.js"></script>
375
460
  <script src="app-run-modal.js"></script>
461
+ <script src="app-quality.js"></script>
376
462
  <script src="app-events-navigation.js"></script>
377
463
  <script src="app-events-sessions.js"></script>
378
464
  <script src="app-events-filters.js"></script>
@@ -19,6 +19,23 @@ window.LoadToAgentRendererUtils = Object.freeze({
19
19
  providerLabel(provider) {
20
20
  return ({ claude: 'Claude', codex: 'GPT · Codex', gemini: 'Gemini', grok: 'Grok' })[provider] || 'AI';
21
21
  },
22
+ preserveScrollPositions(targets) {
23
+ const positions = (Array.isArray(targets) ? targets : [targets]).map(target => {
24
+ const element = typeof target === 'string' ? document.querySelector(target) : target;
25
+ return element ? { element, left: element.scrollLeft, top: element.scrollTop } : null;
26
+ }).filter(Boolean);
27
+ return () => {
28
+ positions.forEach(({ element, left, top }) => {
29
+ if (!element.isConnected) return;
30
+ element.scrollLeft = left;
31
+ element.scrollTop = top;
32
+ });
33
+ };
34
+ },
35
+ isScrolledToEnd(element, tolerance = 2) {
36
+ if (!element) return true;
37
+ return element.scrollHeight - element.scrollTop - element.clientHeight <= tolerance;
38
+ },
22
39
  reportRecoverableError(operation, error) {
23
40
  const message = error && error.message ? error.message : String(error || 'unknown error');
24
41
  console.warn(`[LoadToAgent:${operation}] ${message}`);
@@ -311,6 +311,12 @@
311
311
  box-shadow: 0 0 0 6px rgba(138,232,255,.14)!important;
312
312
  }
313
313
 
314
+ @media (pointer:coarse) {
315
+ :where(button,[role="button"],summary) {
316
+ min-height: 44px;
317
+ }
318
+ }
319
+
314
320
  .provider-overview-card {
315
321
  --provider: #8fa2b7;
316
322
  position: relative;
@@ -109,6 +109,32 @@
109
109
  flex: 0 0 auto;
110
110
  }
111
111
 
112
+ .card-subtitle .origin-project {
113
+ display: inline-flex;
114
+ align-items: center;
115
+ min-width: 0;
116
+ gap: 5px;
117
+ }
118
+
119
+ .card-subtitle .origin-project small {
120
+ flex: 0 0 auto;
121
+ padding: 2px 5px;
122
+ border: 1px solid rgba(89,216,255,.18);
123
+ border-radius: 5px;
124
+ background: rgba(89,216,255,.06);
125
+ color: #76c8df;
126
+ font-size: 8px;
127
+ font-weight: 750;
128
+ letter-spacing: .02em;
129
+ }
130
+
131
+ .card-subtitle .origin-project b {
132
+ overflow: hidden;
133
+ color: #b8c6d4;
134
+ font-weight: 600;
135
+ text-overflow: ellipsis;
136
+ }
137
+
112
138
  .card-usage {
113
139
  display: grid;
114
140
  grid-template-columns: 1.1fr .9fr;