Skip to content

feat(app): show a background shell's output from the pill - #59496

Merged
kitlangton merged 3 commits into
devfrom
shell-panel
Oct 28, 2026
Merged

kitlangton merged 3 commits into
devfrom
shell-panel

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

Clicking a background shell in the pill now shows that shell's live output, with Stop, right in the menu.

Before: clicking a shell row in the pill closed the menu and scrolled the chat to the shell call, which shows no output. To see what a dev server or test watcher was printing, you had to ask the agent.

After: clicking a shell row turns the menu into a wider panel for that one shell: a back arrow, the command, how long it has run, Stop, and the last 14 lines of its output, live. Stop or an exit swaps Stop for how the shell ended ("Stopped", "Exited with code 1") instead of the panel vanishing. Escape closes it; the back arrow returns to the list and to the row you came from. This is option 3 of D-38 on the board.

dev server panel

watcher exited with code 1

Clip (open, back, open the watcher, Stop): https://problems.kitlangton.com/media/PaPQzmQK2hQaMzPJWCuYlw.mp4

  shell row onSelect
-   close menu, scroll the timeline to the shell call
+   keep menu open, panel.open(shell)
+     header: ← · command · elapsed · Stop | "Exited with code N" / "Stopped"
+     body:   followShellOutput(shell) → stripAnsi → last 14 lines, wrapped, no horizontal scroll
  shell leaves the running list while shown
+   ask shell.get how it ended; keep the panel, frozen elapsed, until back or close
Output the timeline's own followShellOutput and stripAnsi, so it reads the same as an expanded shell call
Motion none for list ↔ panel; the menu keeps its existing open fade
Stacked on #59480; merge that first

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" fill="none">
  <style>
    .list{animation:list 4s steps(1,end) infinite}
    .panel{animation:panel 4s steps(1,end) infinite;opacity:0}
    .line{animation:line 4s linear infinite}
    @keyframes list{0%{opacity:1}35%,100%{opacity:0}}
    @keyframes panel{0%{opacity:0}35%,100%{opacity:1}}
    @keyframes line{0%,40%{transform:translateY(0)}100%{transform:translateY(-12px)}}
    @media (prefers-reduced-motion:reduce){.list,.panel,.line{animation:none}.list{opacity:0}.panel{opacity:1}}
  </style>
  <rect x="20" y="58" width="44" height="12" rx="6" fill="currentColor" opacity=".3"/>
  <g class="list">
    <rect x="20" y="22" width="120" height="32" rx="6" stroke="currentColor" stroke-opacity=".3"/>
    <rect x="28" y="29" width="70" height="4" rx="2" fill="currentColor" opacity=".7"/>
    <rect x="28" y="42" width="84" height="4" rx="2" fill="currentColor" opacity=".7"/>
  </g>
  <g class="panel">
    <rect x="20" y="4" width="200" height="50" rx="6" stroke="currentColor" stroke-opacity=".3"/>
    <path d="M32 12h-6m0 0 3-3m-3 3 3 3" stroke="currentColor" stroke-opacity=".7" stroke-width="1.2"/>
    <rect x="40" y="10" width="80" height="4" rx="2" fill="currentColor" opacity=".7"/>
    <rect x="190" y="10" width="22" height="4" rx="2" fill="currentColor" opacity=".5"/>
    <clipPath id="c"><rect x="24" y="20" width="192" height="30" rx="3"/></clipPath>
    <rect x="24" y="20" width="192" height="30" rx="3" fill="currentColor" opacity=".08"/>
    <g clip-path="url(#c)"><g class="line" fill="currentColor" opacity=".55">
      <rect x="30" y="24" width="140" height="3" rx="1.5"/>
      <rect x="30" y="31" width="110" height="3" rx="1.5"/>
      <rect x="30" y="38" width="150" height="3" rx="1.5"/>
      <rect x="30" y="45" width="96" height="3" rx="1.5"/>
      <rect x="30" y="52" width="130" height="3" rx="1.5"/>
      <rect x="30" y="59" width="120" height="3" rx="1.5"/>
    </g></g>
  </g>
</svg>

Read: activity-chips.tsx (the panel and focus) and shell-panel.ts (its state). Checks: app typecheck, the 6 shell-panel unit tests and both activity-chips component tests pass. The existing elapsed-time component test needed the story's items to keep their start time (they were rebuilt with a fresh Date.now() on every read) and a paused clock. Argon review not run: no subagent tool in this session. Beta's e2e legs are known red until #59427.

Clicking a shell in the activity pill now opens its output in the menu
instead of revealing its call in the timeline, so four e2e tests expected
the old behaviour:

- "separates blocking and already-backgrounded work" now checks that the
  shell row opens the panel, goes Back, and opens the Used group itself
  before checking the shell call's shimmer.
- "holds a revealed shell ... under its stuck group header" (3 cases) now
  reveal a starting subagent call, the pill row that still reveals its call,
  with subagents grouped so the call sits in the collapsed group. They keep
  covering revealPart's group expansion and stuck-header hold. Revealing a
  call by shell ID stays covered by "jumps from a finished shell's notice
  to its call".
@kitlangton
kitlangton merged commit 97fd7ac into dev Oct 28, 2026
20 checks passed
@kitlangton
kitlangton deleted the shell-panel branch October 28, 2026 20:39
@amrkmn amrkmn mentioned this pull request Oct 29, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant