loadtoagent 1.0.0 → 1.1.0

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.
@@ -209,7 +209,7 @@ window.LoadToAgentAppFactories.createGraphView = function createGraphView(contex
209
209
  for (const tmuxSession of distro.sessions || []) {
210
210
  for (const window of tmuxSession.windows || []) {
211
211
  for (const pane of window.panes || []) {
212
- if (!pane.agent) continue;
212
+ if (!pane.agent || pane.dead) continue;
213
213
  entries.push({ distro, tmuxSession, window, pane, agent: pane.agent });
214
214
  }
215
215
  }
@@ -267,13 +267,14 @@ window.LoadToAgentAppFactories.createGraphView = function createGraphView(contex
267
267
  const tmuxEntries = liveTmuxEntries(tmux);
268
268
  const tmuxLinkedIds = new Set(tmuxEntries.map((entry) => entry.agent.linkedSessionId).filter(Boolean));
269
269
  const tmuxRoots = roots.filter((root) => agentExecutionMode(root).kind === "tmux");
270
- const standardRoots = roots.filter((root) => agentExecutionMode(root).kind !== "tmux");
270
+ const standardRoots = roots.filter((root) => agentExecutionMode(root).kind !== "tmux" && !tmuxLinkedIds.has(root.id));
271
271
  const providerOrder = [...new Set([...state.providers.map((item) => item.id), ...roots.map((item) => item.provider)])];
272
272
  const lanesFor = (items) =>
273
273
  providerOrder.map((providerId) => ({ providerId, roots: items.filter((root) => root.provider === providerId) })).filter((item) => item.roots.length);
274
274
  const standardLanes = lanesFor(standardRoots);
275
- const fallbackTmuxLanes = lanesFor(tmuxRoots.filter((root) => !tmuxLinkedIds.has(root.id)));
276
- const summary = tmux.summary || {};
275
+ const fallbackTmuxRoots = tmuxRoots.filter((root) => !tmuxLinkedIds.has(root.id));
276
+ const fallbackTmuxLanes = lanesFor(fallbackTmuxRoots);
277
+ const tmuxDisplayCount = tmuxEntries.length + fallbackTmuxRoots.length;
277
278
  const standardHtml = standardLanes.length
278
279
  ? `<div class="agent-flow-overview">${standardLanes.map((item) => providerFlowLane(item.providerId, item.roots, model)).join("")}</div>`
279
280
  : '<div class="runtime-segment-empty"><b>일반 실행 AI가 없습니다</b><span>현재 감지된 작업은 모두 TMUX에서 실행 중입니다.</span></div>';
@@ -293,7 +294,7 @@ window.LoadToAgentAppFactories.createGraphView = function createGraphView(contex
293
294
  <header>
294
295
  <span class="runtime-segment-icon">▦</span>
295
296
  <span><small>TMUX 전용</small><b>TMUX 세션</b><em>Linux 작업 묶음·창·분할 칸을 유지해서 실행 중인 AI</em></span>
296
- <strong>${tmuxEntries.length || summary.aiPanes || 0}개</strong>
297
+ <strong>${tmuxDisplayCount}개</strong>
297
298
  <button type="button" class="live-tmux-overview-open">TMUX 전체 화면 →</button>
298
299
  </header>
299
300
  ${tmuxHtml}
@@ -3,7 +3,20 @@
3
3
  window.LoadToAgentAppFactories = window.LoadToAgentAppFactories || {};
4
4
 
5
5
  window.LoadToAgentAppFactories.createTmuxRenderer = function createTmuxRenderer(context = {}) {
6
- const { $, esc, state, compact, providerInfo, providerStyle } = context;
6
+ const {
7
+ $,
8
+ esc,
9
+ state,
10
+ compact,
11
+ providerInfo,
12
+ providerStyle,
13
+ agentRoleLabel,
14
+ subagentWorkState,
15
+ subagentWorkLabel,
16
+ latestWorkCopy,
17
+ readablePreview,
18
+ timeAgo,
19
+ } = context;
7
20
 
8
21
  function tmuxEntities(tmux) {
9
22
  const distros = new Map();
@@ -60,6 +73,65 @@ window.LoadToAgentAppFactories.createTmuxRenderer = function createTmuxRenderer(
60
73
  : [];
61
74
  }
62
75
 
76
+ function linkedTmuxSubagents(agent) {
77
+ if (!agent || !agent.linkedSessionId) return [];
78
+ const sessions = (state.snapshot && state.snapshot.sessions) || [];
79
+ const byId = new Map(sessions.map((session) => [session.id, session]));
80
+ const root = byId.get(agent.linkedSessionId);
81
+ const queue = (root && root.childIds || agent.childIds || []).map((id) => ({ id, depth: 1 }));
82
+ const seen = new Set(root ? [root.id] : []);
83
+ const children = [];
84
+ for (let cursor = 0; cursor < queue.length; cursor += 1) {
85
+ const item = queue[cursor];
86
+ if (!item.id || seen.has(item.id)) continue;
87
+ seen.add(item.id);
88
+ const child = byId.get(item.id);
89
+ if (!child) continue;
90
+ children.push({ session: child, depth: item.depth });
91
+ for (const childId of child.childIds || []) queue.push({ id: childId, depth: item.depth + 1 });
92
+ }
93
+ return children;
94
+ }
95
+
96
+ function tmuxSubagentPanel(pane, agent) {
97
+ const children = linkedTmuxSubagents(agent);
98
+ if (!children.length) return "";
99
+ const expanded = state.expandedTmuxSubagents.has(pane.id);
100
+ const listId = `tmux-subagents-list-${encodeURIComponent(pane.id)}`;
101
+ const working = children.filter(({ session }) => subagentWorkState(session) === "working").length;
102
+ const attention = children.filter(({ session }) => subagentWorkState(session) === "attention").length;
103
+ const statusSummary = [
104
+ working ? `${working}개 작업 중` : "",
105
+ attention ? `${attention}개 확인 필요` : "",
106
+ ].filter(Boolean).join(" · ") || "현재 모두 쉬는 중";
107
+ const rows = children
108
+ .map(({ session, depth }) => {
109
+ const provider = providerInfo(session.provider);
110
+ const role = session.agentName || agentRoleLabel(session.agentRole);
111
+ const assigned = session.delegation && session.delegation.assignment || session.taskName || session.title || "담당 작업 확인 중";
112
+ const work = readablePreview(latestWorkCopy(session) || session.statusDetail || "상태 확인 중", 96);
113
+ const workState = subagentWorkState(session);
114
+ return `<article class="tmux-subagent-row work-${workState}" data-tmux-subagent-id="${esc(session.id)}"
115
+ style="${providerStyle(session.provider)};--tmux-subagent-depth:${Math.min(2, Math.max(0, depth - 1))}">
116
+ <span class="provider-mark" aria-hidden="true">${esc(provider.mark)}</span>
117
+ <span class="tmux-subagent-copy">
118
+ <span><b>${esc(role)}</b><i>${esc(subagentWorkLabel(session))}</i><small>${esc(timeAgo(session.updatedAt))}</small></span>
119
+ <strong>${esc(assigned)}</strong>
120
+ <em title="${esc(work.full)}">${esc(work.text)}</em>
121
+ </span>
122
+ <button type="button" data-open-subagent-chat="${esc(session.id)}" aria-label="${esc(`${role} · ${assigned} 대화 보기`)}">대화 보기 ↗</button>
123
+ </article>`;
124
+ })
125
+ .join("");
126
+ return `<section class="tmux-subagents ${expanded ? "expanded" : ""}" data-tmux-subagents="${esc(pane.id)}">
127
+ <button type="button" class="tmux-subagents-toggle" data-tmux-subagents-toggle="${esc(pane.id)}" aria-expanded="${expanded}" aria-controls="${esc(listId)}">
128
+ <span><b>연결된 도움 AI ${children.length}개</b><small>${statusSummary} · tmux 메인 세션 기준</small></span>
129
+ <i aria-hidden="true">↓</i>
130
+ </button>
131
+ <div id="${esc(listId)}" class="tmux-subagent-list ${expanded ? "" : "hidden"}">${rows}</div>
132
+ </section>`;
133
+ }
134
+
63
135
  function tmuxPaneCard(pane) {
64
136
  const agent = pane.agent;
65
137
  const provider = agent && providerInfo(agent.provider);
@@ -103,6 +175,7 @@ window.LoadToAgentAppFactories.createTmuxRenderer = function createTmuxRenderer(
103
175
  : '<span class="tmux-shell-note">AI가 아닌 일반 명령창입니다.</span>'
104
176
  }
105
177
  </button>
178
+ ${tmuxSubagentPanel(pane, agent)}
106
179
  <footer>
107
180
  <span>${agent ? (agent.linkedSessionId ? "대화 기록과 연결됨" : "AI가 실행 중인 것을 확인함") : pane.title || "명령창"}</span>
108
181
  <span class="tmux-pane-actions">
@@ -243,5 +316,5 @@ window.LoadToAgentAppFactories.createTmuxRenderer = function createTmuxRenderer(
243
316
  .join("");
244
317
  }
245
318
 
246
- return { tmuxEntities, tmuxFocusPath, tmuxPaneCard, tmuxWindowTree, tmuxSessionTree, filteredTmuxDistros, renderTmuxMap };
319
+ return { tmuxEntities, tmuxFocusPath, linkedTmuxSubagents, tmuxPaneCard, tmuxWindowTree, tmuxSessionTree, filteredTmuxDistros, renderTmuxMap };
247
320
  };
package/renderer/app.js CHANGED
@@ -28,6 +28,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
28
28
  graphFocusId: null,
29
29
  graphExpandedProviders: new Set(),
30
30
  expandedCompletedSubagents: new Set(),
31
+ expandedTmuxSubagents: new Set(),
31
32
  tmuxFocus: null,
32
33
  agentCommandDrafts: new Map(),
33
34
  agentCommandTargets: new Map(),
@@ -277,7 +278,7 @@ window.LoadToAgentAppFactories.createCore = function createCore(context = {}) {
277
278
  function restoreDialogTrigger() {
278
279
  const trigger = motionState.activeDialogTrigger;
279
280
  motionState.activeDialogTrigger = null;
280
- if (trigger && trigger.isConnected) trigger.focus();
281
+ if (trigger && trigger.isConnected) trigger.focus({ preventScroll: true });
281
282
  }
282
283
  window.LoadToAgentA11y = { rememberDialogTrigger, restoreDialogTrigger };
283
284
  function readablePreview(value, maxCharacters = 120) {
@@ -28,6 +28,7 @@
28
28
  "common.send": {"ko":"보내기","en":"Send","zh-CN":"发送"},
29
29
  "drawer.title": {"ko":"작업 자세히 보기","en":"View task details","zh-CN":"查看任务详情"},
30
30
  "filter.result_summary": {"ko":"{providers} 선택 · {count}개 결과","en":"{providers} selected · {count} results","zh-CN":"已选择 {providers} · {count} 条结果"},
31
+ "filter.applied": {"ko":"필터 적용","en":"Filter applied","zh-CN":"已应用筛选"},
31
32
  "guide.steps_remaining": {"ko":"{count}단계 남았어요. 하나씩 눌러 직접 둘러보세요.","en":"{count} steps left. Try each one to explore the app.","zh-CN":"还剩 {count} 步。请逐项点击体验。"},
32
33
  "provider.assign": {"ko":"{provider}에게 맡기기","en":"Assign to {provider}","zh-CN":"交给 {provider}"},
33
34
  "provider.install_guide": {"ko":"{provider} 설치 안내","en":"{provider} setup guide","zh-CN":"{provider} 安装指南"},
@@ -78,6 +78,24 @@
78
78
  </div>
79
79
  </header>
80
80
 
81
+ <section id="beginnerGuide" class="beginner-guide" aria-labelledby="beginnerGuideTitle">
82
+ <div class="beginner-guide-intro">
83
+ <span class="guide-time" data-i18n="ui.first_10_minutes">첫 10분 코스</span>
84
+ <b id="beginnerGuideTitle" data-i18n="ui.these_four_steps_are_all_you_need">이 네 가지만 익히면 충분해요</b>
85
+ <span id="guideProgressText" data-i18n="ui.try_each_step_to_explore_the_app">하나씩 눌러 직접 둘러보세요.</span>
86
+ <div class="guide-progress" role="progressbar" aria-label="시작 가이드 진행률" data-i18n-aria-label="ui.quick_start_progress" aria-valuemin="0" aria-valuemax="4" aria-valuenow="0"><i id="guideProgressBar"></i></div>
87
+ </div>
88
+ <ol>
89
+ <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
+ <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>
92
+ <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
+ </ol>
94
+ <button id="dismissGuideBtn" class="guide-dismiss" type="button" data-i18n="ui.collapse_guide">가이드 접기</button>
95
+ </section>
96
+
97
+ <section id="providerOverview" class="provider-overview" aria-label="AI별 현황" data-i18n-aria-label="ui.status_by_ai"></section>
98
+
81
99
  <section id="updateNotice" class="update-notice hidden" aria-live="polite">
82
100
  <span class="update-notice-signal" aria-hidden="true"><i></i></span>
83
101
  <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>
@@ -148,22 +166,6 @@
148
166
  </div>
149
167
  </section>
150
168
 
151
- <section id="beginnerGuide" class="beginner-guide" aria-labelledby="beginnerGuideTitle">
152
- <div class="beginner-guide-intro">
153
- <span class="guide-time" data-i18n="ui.first_10_minutes">첫 10분 코스</span>
154
- <b id="beginnerGuideTitle" data-i18n="ui.these_four_steps_are_all_you_need">이 네 가지만 익히면 충분해요</b>
155
- <span id="guideProgressText" data-i18n="ui.try_each_step_to_explore_the_app">하나씩 눌러 직접 둘러보세요.</span>
156
- <div class="guide-progress" role="progressbar" aria-label="시작 가이드 진행률" data-i18n-aria-label="ui.quick_start_progress" aria-valuemin="0" aria-valuemax="4" aria-valuenow="0"><i id="guideProgressBar"></i></div>
157
- </div>
158
- <ol>
159
- <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>
160
- <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>
161
- <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>
162
- <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>
163
- </ol>
164
- <button id="dismissGuideBtn" class="guide-dismiss" type="button" data-i18n="ui.collapse_guide">가이드 접기</button>
165
- </section>
166
-
167
169
  <section id="terminalSection" class="terminal-section hidden" aria-label="명령창 직접 다루기">
168
170
  <div class="terminal-section-head">
169
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>
@@ -263,7 +265,6 @@
263
265
  </section>
264
266
 
265
267
  <section id="globalStats" class="global-stats" aria-label="전체 통계" data-i18n-aria-label="ui.overall_statistics"></section>
266
- <section id="providerOverview" class="provider-overview" aria-label="AI별 현황" data-i18n-aria-label="ui.status_by_ai"></section>
267
268
 
268
269
  <section id="sessionSection" class="sessions-section">
269
270
  <div class="sessions-heading">
@@ -330,7 +330,50 @@
330
330
 
331
331
  .provider-overview-card.selected {
332
332
  border-color: color-mix(in srgb,var(--provider) 66%,#344151);
333
- box-shadow: inset 0 0 0 1px color-mix(in srgb,var(--provider) 28%,transparent),0 10px 30px rgba(0,0,0,.2);
333
+ background: linear-gradient(145deg,color-mix(in srgb,var(--provider) 15%,#10151f),#0d111a 68%);
334
+ box-shadow: inset 0 0 0 2px color-mix(in srgb,var(--provider) 30%,transparent),0 10px 30px rgba(0,0,0,.28),0 0 24px color-mix(in srgb,var(--provider) 10%,transparent);
335
+ }
336
+
337
+ .provider-overview-card.selected:before {
338
+ width: 5px;
339
+ opacity: 1;
340
+ }
341
+
342
+ .poc-head-states {
343
+ display: grid;
344
+ justify-items: end;
345
+ gap: 4px;
346
+ margin-left: auto;
347
+ }
348
+
349
+ .poc-head-states .poc-state {
350
+ margin-left: 0;
351
+ }
352
+
353
+ .poc-filter-state {
354
+ display: none;
355
+ padding: 3px 7px;
356
+ border: 1px solid color-mix(in srgb,var(--provider) 58%,#28483f);
357
+ border-radius: 999px;
358
+ background: color-mix(in srgb,var(--provider) 16%,#0b1515);
359
+ color: color-mix(in srgb,var(--provider) 72%,#eafff8);
360
+ font-size: 9px;
361
+ font-weight: 800;
362
+ white-space: nowrap;
363
+ }
364
+
365
+ .poc-filter-state.visible {
366
+ display: inline-flex;
367
+ }
368
+
369
+ .provider-overview-card.filter-clicked {
370
+ animation: provider-card-confirm .38s cubic-bezier(.22,1,.36,1);
371
+ }
372
+
373
+ @keyframes provider-card-confirm {
374
+ 0% { transform: scale(.97); }
375
+ 60% { transform: translateY(-3px) scale(1.015); }
376
+ 100% { transform: translateY(0) scale(1); }
334
377
  }
335
378
 
336
379
  .poc-head strong {
@@ -336,103 +336,33 @@
336
336
  font-size: 10px;
337
337
  }
338
338
 
339
- .subagent-conversation-summary {
339
+ .subagent-work-source {
340
340
  display: grid;
341
- grid-template-columns: repeat(3,minmax(0,1fr));
342
- gap: 8px;
343
- margin-bottom: 12px;
344
- }
345
-
346
- .subagent-conversation-summary>span {
347
- padding: 11px;
348
- border: 1px solid #263b45;
349
- border-radius: 10px;
350
- background: #0c171e;
351
- }
352
-
353
- .subagent-conversation-summary small {
354
- display: block;
355
- color: #718591;
356
- font-size: 9px;
357
- }
358
-
359
- .subagent-conversation-summary b {
360
- display: block;
361
- margin-top: 5px;
362
- color: #dce8ec;
363
- font-size: 17px;
364
- }
365
-
366
- .subagent-conversation-summary>span:nth-child(1) b {
367
- color: #76dfb8;
368
- }
369
-
370
- .subagent-conversation-summary>span:nth-child(2) b {
371
- color: #8fc8df;
372
- }
373
-
374
- .subagent-dialog-row.user .chat-bubble {
375
- background: #10231e;
376
- }
377
-
378
- .subagent-dialog-row.assistant .chat-bubble {
379
- background: #111d28;
380
- }
381
-
382
- .subagent-dialog-row.system .chat-bubble {
383
- background: #0d151c;
384
- }
385
-
386
- .subagent-dialog-list .chat-row.assistant {
387
- padding-left: 28px;
388
- }
389
-
390
- .subagent-dialog-list .chat-row.user {
391
- padding-right: 28px;
392
- }
393
-
394
- .subagent-dialog-row .chat-bubble {
395
- border-color: #283c46;
396
- min-width: 0;
397
- max-width: 100%;
398
- overflow: hidden;
341
+ gap: 5px;
342
+ margin: 0 0 14px;
343
+ padding: 11px 13px;
344
+ border: 1px solid color-mix(in srgb,var(--drawer-provider) 28%,#263844);
345
+ border-radius: 11px;
346
+ background: color-mix(in srgb,var(--drawer-provider) 6%,#0c151d);
399
347
  }
400
348
 
401
- .subagent-dialog-row .chat-bubble-head {
402
- gap: 7px;
403
- min-width: 0;
349
+ .subagent-work-source b {
350
+ color: #dbe8e9;
351
+ font-size: 11px;
404
352
  }
405
353
 
406
- .subagent-dialog-row .chat-bubble-head b {
407
- min-width: 0;
408
- overflow: hidden;
409
- text-overflow: ellipsis;
410
- white-space: nowrap;
354
+ .subagent-work-source span {
355
+ color: #78909a;
356
+ font-size: 10px;
357
+ line-height: 1.55;
411
358
  }
412
359
 
413
- .subagent-dialog-row .subagent-route {
414
- margin-right: auto;
415
- padding: 3px 6px;
416
- border-radius: 6px;
417
- background: #13242a;
418
- color: #6fa89b;
419
- font-size: 8px;
420
- min-width: 0;
421
- overflow: hidden;
422
- text-overflow: ellipsis;
423
- white-space: nowrap;
360
+ .subagent-coordination {
361
+ margin-top: 16px;
424
362
  }
425
363
 
426
- .subagent-event-label {
427
- display: block;
428
- margin: 6px 0 -2px;
429
- color: #6b8f8a;
430
- font-size: 8px;
431
- font-weight: 750;
432
- min-width: 0;
433
- overflow: hidden;
434
- text-overflow: ellipsis;
435
- white-space: nowrap;
364
+ .subagent-coordination .subagent-message-preview p {
365
+ margin: 0;
436
366
  }
437
367
 
438
368
  .subagent-message-preview {
@@ -778,14 +778,31 @@ button {
778
778
  color: #7f8da1;
779
779
  white-space: nowrap;
780
780
  cursor: pointer;
781
- transition: color var(--motion-fast) ease, background-color var(--motion-fast) ease, border-color var(--motion-fast) ease;
781
+ transition: color var(--motion-fast) ease, background-color var(--motion-fast) ease, border-color var(--motion-fast) ease, box-shadow var(--motion-fast) ease, transform var(--motion-fast) ease;
782
782
  }
783
783
 
784
- .provider-filter-chip span {
784
+ .provider-filter-mark {
785
785
  font-family: "Cascadia Code", Consolas, monospace;
786
786
  font-size: 9px;
787
787
  }
788
788
 
789
+ .provider-filter-check {
790
+ display: inline-grid;
791
+ place-items: center;
792
+ width: 0;
793
+ height: 16px;
794
+ border-radius: 50%;
795
+ overflow: hidden;
796
+ background: #53d6aa;
797
+ color: #07130f;
798
+ font-size: 10px;
799
+ font-style: normal;
800
+ font-weight: 900;
801
+ opacity: 0;
802
+ transform: scale(.45);
803
+ transition: width var(--motion-fast) ease, opacity var(--motion-fast) ease, transform var(--motion-fast) ease;
804
+ }
805
+
789
806
  .provider-filter-chip b {
790
807
  font-size: 10px;
791
808
  }
@@ -796,9 +813,27 @@ button {
796
813
  }
797
814
 
798
815
  .provider-filter-chip.selected {
799
- color: #e7f8f2;
800
- border-color: #315f54;
801
- background: rgba(66,207,164,.13);
816
+ color: #f2fffb;
817
+ border-color: #53d6aa;
818
+ background: linear-gradient(135deg,rgba(66,207,164,.24),rgba(66,207,164,.11));
819
+ box-shadow: inset 0 0 0 1px rgba(119,238,198,.17),0 0 0 2px rgba(66,207,164,.08),0 6px 18px rgba(0,0,0,.22);
820
+ transform: translateY(-1px);
821
+ }
822
+
823
+ .provider-filter-chip.selected .provider-filter-check {
824
+ width: 16px;
825
+ opacity: 1;
826
+ transform: scale(1);
827
+ }
828
+
829
+ .provider-filter-chip.filter-clicked {
830
+ animation: provider-filter-confirm .36s cubic-bezier(.22,1,.36,1);
831
+ }
832
+
833
+ @keyframes provider-filter-confirm {
834
+ 0% { transform: scale(.93); }
835
+ 55% { transform: scale(1.06); }
836
+ 100% { transform: translateY(-1px) scale(1); }
802
837
  }
803
838
 
804
839
  .session-grid {
@@ -153,6 +153,7 @@
153
153
 
154
154
  .drawer-backdrop.closing {
155
155
  animation: motion-backdrop-out 260ms ease both;
156
+ pointer-events: none;
156
157
  }
157
158
 
158
159
  .detail-drawer {
@@ -176,6 +177,10 @@
176
177
  box-shadow: -32px 0 88px rgba(0,0,0,.52);
177
178
  }
178
179
 
180
+ .detail-drawer:not(.open) {
181
+ pointer-events: none;
182
+ }
183
+
179
184
  .modal-backdrop:not(.hidden) {
180
185
  animation: motion-backdrop-in var(--motion-medium) ease both;
181
186
  }
@@ -666,6 +666,15 @@
666
666
  flex-direction: column;
667
667
  }
668
668
 
669
+ .tmux-subagent-row {
670
+ grid-template-columns: 26px minmax(0,1fr);
671
+ }
672
+
673
+ .tmux-subagent-row>button {
674
+ grid-column: 2;
675
+ justify-self: start;
676
+ }
677
+
669
678
  .tmux-pane-actions {
670
679
  width: 100%;
671
680
  justify-content: flex-start;
@@ -375,20 +375,6 @@
375
375
  grid-column: 1/-1;
376
376
  }
377
377
 
378
- .subagent-conversation-summary {
379
- grid-template-columns: 1fr;
380
- }
381
-
382
- .subagent-dialog-list .chat-row.assistant {
383
- padding-left: 0;
384
- padding-right: 0;
385
- }
386
-
387
- .subagent-dialog-list .chat-row.user {
388
- padding-left: 0;
389
- padding-right: 0;
390
- }
391
-
392
378
  .completed-subagent-list {
393
379
  grid-template-columns: 1fr;
394
380
  }