diff --git a/packages/cli/src/ui/components/background-view/LiveAgentPanel.test.tsx b/packages/cli/src/ui/components/background-view/LiveAgentPanel.test.tsx
index 5402f50bf..8f89f874a 100644
--- a/packages/cli/src/ui/components/background-view/LiveAgentPanel.test.tsx
+++ b/packages/cli/src/ui/components/background-view/LiveAgentPanel.test.tsx
@@ -156,7 +156,10 @@ describe('', () => {
expect(frame).toContain('5s');
});
- it('marks foreground agents with the [in turn] prefix', () => {
+ it('does NOT surface a flavor marker on foreground agents', () => {
+ // Foreground vs background distinction stays with BackgroundTasksDialog
+ // (where cancel semantics differ); the panel reads as a glance roster
+ // and the marker added more confusion than signal.
const { lastFrame } = renderPanel({
entries: [
agentEntry({
@@ -167,7 +170,10 @@ describe('', () => {
}),
],
});
- expect(lastFrame() ?? '').toContain('[in turn]');
+ const frame = lastFrame() ?? '';
+ expect(frame).not.toContain('[in turn]');
+ expect(frame).toContain('editor');
+ expect(frame).toContain('tighten import order');
});
it('windows from the tail when entries exceed maxRows', () => {
@@ -190,8 +196,11 @@ describe('', () => {
];
const { lastFrame } = renderPanel({ entries, maxRows: 2 });
const frame = lastFrame() ?? '';
- // `more above` callout flagged with the dropped count.
+ // `more above` callout flagged with the dropped count and points
+ // at the dialog (the only surface where the user can scroll
+ // through the full roster + take action).
expect(frame).toContain('1 more above');
+ expect(frame).toContain('to view all');
// Tail window keeps the newest two rows.
expect(frame).toContain('mid-agent');
expect(frame).toContain('fresh-agent');
diff --git a/packages/cli/src/ui/components/background-view/LiveAgentPanel.tsx b/packages/cli/src/ui/components/background-view/LiveAgentPanel.tsx
index 691f4c40a..47601b884 100644
--- a/packages/cli/src/ui/components/background-view/LiveAgentPanel.tsx
+++ b/packages/cli/src/ui/components/background-view/LiveAgentPanel.tsx
@@ -237,9 +237,17 @@ export const LiveAgentPanel: React.FC = ({
{overflow > 0 && (
+ {/*
+ The panel is read-only (no keyboard focus — that would
+ steal input from the composer), so when the roster
+ overflows the row budget we point users at the dialog
+ that DOES support selection / scroll / cancel / resume.
+ Same keystroke the footer pill uses, kept in sync so
+ users only have to learn one thing.
+ */}
{` ^ ${overflow} more above`}
+ >{` ^ ${overflow} more above (↓ to view all)`}
)}
{visible.map((entry) => (
@@ -255,7 +263,13 @@ const AgentRow: React.FC<{ entry: AgentDialogEntry; now: number }> = ({
}) => {
const { glyph, color } = statusIcon(entry);
const label = descriptionWithoutPrefix(entry);
- const flavorPrefix = entry.flavor === 'foreground' ? '[in turn] ' : '';
+ // Note: foreground vs background is intentionally not surfaced here.
+ // Earlier iterations prefixed foreground rows with `[in turn]` (the
+ // BackgroundTasksDialog convention), but in the panel context the
+ // marker reads as cryptic — the foreground / background distinction
+ // matters in the dialog (where cancel semantics differ) but the
+ // glance roster just needs identity + intent + cost. Keep the
+ // dialog as the place that surfaces the flavor distinction.
const activity = activityLabel(entry);
const elapsed = elapsedLabel(entry, now);
const showType =
@@ -296,7 +310,7 @@ const AgentRow: React.FC<{ entry: AgentDialogEntry; now: number }> = ({
{': '}
>
)}
- {`${flavorPrefix}${label}`}
+ {label}
{activity && (
{` (${activity})`}
)}
diff --git a/packages/cli/src/ui/layouts/DefaultAppLayout.tsx b/packages/cli/src/ui/layouts/DefaultAppLayout.tsx
index 124ceef0a..aa59ee12b 100644
--- a/packages/cli/src/ui/layouts/DefaultAppLayout.tsx
+++ b/packages/cli/src/ui/layouts/DefaultAppLayout.tsx
@@ -115,9 +115,16 @@ export const DefaultAppLayout: React.FC = () => {
open (auth / permission / background tasks / etc.) so the modal
surface doesn't compete with the live roster, and the panel's
own internal self-hide handles the empty-roster case.
+
+ Panel uses `terminalWidth`, not `mainAreaWidth` — `mainAreaWidth`
+ is hard-capped at 100 cols (intended for markdown / code blocks
+ where soft-wrap matters), which on wider terminals leaves a
+ large empty gutter to the right of an already-truncating row.
+ Live progress lines have nothing to soft-wrap, so the panel
+ wants the full terminal width.
*/}
{!isAgentTab && !uiState.dialogsVisible && (
-
+
)}
);