Show Claude's live output/progress during the "asking Claude…" status #60

Closed
opened 2026-06-23 05:58:34 +00:00 by benstull · 0 comments
Owner

Show Claude's live output/progress during the "asking Claude…" status

Summary

While the plugin runs a Claude turn, surface Claude's live output / progress
in (or alongside) the "asking Claude…" status, so the writer can see what Claude
is doing instead of staring at an opaque spinner.

Problem / pain

When the writer asks Claude to edit, the plugin shows a single static
notification — "Cowriting: asking Claude…" — and then nothing until the whole
turn completes (extension.ts:232-233, trackChangesPreview.ts:232-233, which
await agent.run() as one opaque promise, liveTurn.ts:52). For anything beyond
a trivial edit this is a black box: the writer can't tell whether Claude is
thinking, reading, partway through writing, or stuck, and a long edit feels like
the tool hung. There's no signal of progress, no partial output to start reading,
and no way to gauge how much longer it will take — which makes the wait feel
longer and the tool feel less alive and less trustworthy.

This is especially frustrating because the streaming data already exists and
is simply discarded: the @cline/sdk emits live events (assistant-text-delta,
tool-started/updated/finished, usage-updated) that the extension never
subscribes to (liveTurn.ts:47-51 constructs the Agent with no event hook).

Who feels it

The human coauthor — anyone who asks Claude to edit and waits for the turn,
most acutely on longer or slower edits.

Desired outcome / value

The writer can watch Claude work — see streamed text and/or what step it's on —
while the turn runs, so the wait is legible: they know it's progressing, can
start reading the output as it forms, and gain confidence the tool is alive and
on task.

Acceptance — "done right"

  • During a Claude turn, the writer sees live progress rather than only a
    static title — at minimum a sign of forward motion, ideally streamed assistant
    text and/or the current activity (e.g. "writing…", tool/step in progress).
  • The live view updates incrementally as the SDK emits events, and resolves
    cleanly when the turn finishes (no leftover spinner/output).
  • It works for both entry points that show the status today (editSelection in
    extension.ts and the preview's askClaude in trackChangesPreview.ts).
  • Errors/cancellation are reflected (if the turn fails or is cancelled, the live
    view shows that, not a frozen "asking Claude…").
  • The sealed-webview / no-new-surface posture is respected (INV-21) — progress is
    relayed through existing host UI, not a new network surface.

Scope / non-goals

In scope: consuming the SDK's existing streaming events during a turn and
surfacing them as live progress/output tied to the "asking Claude…" status.

Non-goals:

  • A full chat/conversation UI or persistent transcript panel (this is
    in-flight progress, not a history surface) — could be a later increment.
  • Changing the propose/accept result handling or what the final edit produces.
  • Streaming into the document itself (the result still lands as proposals as it
    does today).
  • Cancellation as a feature in its own right (reflecting it is in scope; building
    rich cancel controls is not).

Assumptions · constraints · dependencies

  • Enabler already present: @cline/sdk (0.0.46) exposes streaming via
    agent.subscribe(listener) / an onEvent hook in the Agent config, emitting
    assistant-text-delta, assistant-reasoning-delta, tool-started|updated| finished, usage-updated, and lifecycle events
    (@cline/shared/.../agent.d.ts event union). The extension currently passes no
    hooks (liveTurn.ts:47-51) — wiring one in is the core of this work.
  • A design decision is needed on the surface and content: progress-notification
    text vs. a dedicated OutputChannel vs. status-bar vs. relaying into the
    preview webview; and how much to show (streamed text, tool/step activity, token
    usage, whether to surface reasoning). This is why it's a feature, not a story
    (R3 — design first).
  • Must not change the final result path (runEditAndPropose / proposals) — purely
    additive observability over the existing turn.

Source / signal

Self-originated — capture session vscode-cowriting-plugin-0054
(2026-06-15). Dev observation: "See the Claude output/progress in the 'asking
Claude…' status." Current opaque behavior + unused SDK streaming confirmed by
reading extension.ts, trackChangesPreview.ts, liveTurn.ts, and the
@cline/sdk event types.

Priority (WSJF)

Provisional: Value 6 · Time-criticality 3 · Opportunity-enablement 4 ÷ Size 4 =
~3.25. priority/P1 (operator call) — the opaque wait hurts every Claude
turn (the core gesture of the tool), and the enabling streaming data already
exists, so visible progress is treated as high priority despite not blocking core
functionality.

Decomposition

Feature → design-then-build (one increment):

  • Decide the progress surface + content (small design: notification text vs.
    OutputChannel vs. status bar vs. webview relay; which events to show).
  • Subscribe to the SDK agent's events (subscribe/onEvent) in
    liveTurn.ts, threading a progress callback out of runEditTurn.
  • Relay events to the chosen surface from both call sites (editSelection,
    preview askClaude), updating live and resolving on finish.
  • Reflect error/cancel states.
  • Manual smoke on a longer edit (E2E can't assert streamed UI well; unit-test
    the event→progress mapping).

Solution notes (optional — NOT a design)

Non-binding: the lowest-effort surface is reporting assistant-text-delta (and a
short "running tool X" line) into the existing withProgress notification via its
progress.report({ message }); a richer option is a dedicated OutputChannel that
streams the full assistant text (better for verbose output, and doubles as a debug
log). The design should pick based on how much output is typical and whether the
writer wants to read the stream vs. just see motion.

<!-- Set the type/* label: type/feature --> # Show Claude's live output/progress during the "asking Claude…" status ## Summary While the plugin runs a Claude turn, surface Claude's **live output / progress** in (or alongside) the "asking Claude…" status, so the writer can see what Claude is doing instead of staring at an opaque spinner. ## Problem / pain When the writer asks Claude to edit, the plugin shows a single static notification — *"Cowriting: asking Claude…"* — and then nothing until the whole turn completes (`extension.ts:232-233`, `trackChangesPreview.ts:232-233`, which await `agent.run()` as one opaque promise, `liveTurn.ts:52`). For anything beyond a trivial edit this is a black box: the writer can't tell whether Claude is thinking, reading, partway through writing, or stuck, and a long edit feels like the tool hung. There's no signal of progress, no partial output to start reading, and no way to gauge how much longer it will take — which makes the wait feel longer and the tool feel less alive and less trustworthy. This is especially frustrating because the streaming data **already exists** and is simply discarded: the `@cline/sdk` emits live events (`assistant-text-delta`, `tool-started/updated/finished`, `usage-updated`) that the extension never subscribes to (`liveTurn.ts:47-51` constructs the Agent with no event hook). ## Who feels it The **human coauthor** — anyone who asks Claude to edit and waits for the turn, most acutely on longer or slower edits. ## Desired outcome / value The writer can watch Claude work — see streamed text and/or what step it's on — while the turn runs, so the wait is legible: they know it's progressing, can start reading the output as it forms, and gain confidence the tool is alive and on task. ## Acceptance — "done right" - During a Claude turn, the writer sees **live progress** rather than only a static title — at minimum a sign of forward motion, ideally streamed assistant text and/or the current activity (e.g. "writing…", tool/step in progress). - The live view updates incrementally as the SDK emits events, and resolves cleanly when the turn finishes (no leftover spinner/output). - It works for both entry points that show the status today (`editSelection` in `extension.ts` and the preview's `askClaude` in `trackChangesPreview.ts`). - Errors/cancellation are reflected (if the turn fails or is cancelled, the live view shows that, not a frozen "asking Claude…"). - The sealed-webview / no-new-surface posture is respected (INV-21) — progress is relayed through existing host UI, not a new network surface. ## Scope / non-goals **In scope:** consuming the SDK's existing streaming events during a turn and surfacing them as live progress/output tied to the "asking Claude…" status. **Non-goals:** - A full chat/conversation UI or persistent transcript panel (this is *in-flight progress*, not a history surface) — could be a later increment. - Changing the propose/accept result handling or what the final edit produces. - Streaming into the document itself (the result still lands as proposals as it does today). - Cancellation as a feature in its own right (reflecting it is in scope; building rich cancel controls is not). ## Assumptions · constraints · dependencies - **Enabler already present:** `@cline/sdk` (0.0.46) exposes streaming via `agent.subscribe(listener)` / an `onEvent` hook in the Agent config, emitting `assistant-text-delta`, `assistant-reasoning-delta`, `tool-started|updated| finished`, `usage-updated`, and lifecycle events (`@cline/shared/.../agent.d.ts` event union). The extension currently passes no hooks (`liveTurn.ts:47-51`) — wiring one in is the core of this work. - A **design decision** is needed on the surface and content: progress-notification text vs. a dedicated **OutputChannel** vs. status-bar vs. relaying into the preview webview; and how much to show (streamed text, tool/step activity, token usage, whether to surface reasoning). This is why it's a feature, not a story (R3 — design first). - Must not change the final result path (`runEditAndPropose` / proposals) — purely additive observability over the existing turn. ## Source / signal Self-originated — capture session **vscode-cowriting-plugin-0054** (2026-06-15). Dev observation: "See the Claude output/progress in the 'asking Claude…' status." Current opaque behavior + unused SDK streaming confirmed by reading `extension.ts`, `trackChangesPreview.ts`, `liveTurn.ts`, and the `@cline/sdk` event types. ## Priority (WSJF) Provisional: Value 6 · Time-criticality 3 · Opportunity-enablement 4 ÷ Size 4 = ~3.25. **`priority/P1`** (operator call) — the opaque wait hurts *every* Claude turn (the core gesture of the tool), and the enabling streaming data already exists, so visible progress is treated as high priority despite not blocking core functionality. ## Decomposition Feature → design-then-build (one increment): - [ ] Decide the progress surface + content (small design: notification text vs. OutputChannel vs. status bar vs. webview relay; which events to show). - [ ] Subscribe to the SDK agent's events (`subscribe`/`onEvent`) in `liveTurn.ts`, threading a progress callback out of `runEditTurn`. - [ ] Relay events to the chosen surface from both call sites (`editSelection`, preview `askClaude`), updating live and resolving on finish. - [ ] Reflect error/cancel states. - [ ] Manual smoke on a longer edit (E2E can't assert streamed UI well; unit-test the event→progress mapping). ## Solution notes (optional — NOT a design) Non-binding: the lowest-effort surface is reporting `assistant-text-delta` (and a short "running tool X" line) into the existing `withProgress` notification via its `progress.report({ message })`; a richer option is a dedicated OutputChannel that streams the full assistant text (better for verbose output, and doubles as a debug log). The design should pick based on how much output is typical and whether the writer wants to *read* the stream vs. just see motion.
benstull added the type/featurepriority/P1 labels 2026-06-23 05:58:34 +00:00
Sign in to join this conversation.