anthropics / anthropics/claude-code

[BUG] /diff turn view: an image-only prompt does not start a turn, so its edits are folded into the previous turn or dropped

Open
#95,151 1 comment 0 reactions 0 assignees View on GitHub
area:tui bug has repro platform:macos
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

### Preflight Checklist

- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code

### What's Wrong?

In the turn tab of `/diff`, a prompt sent as an image alone (a pasted screenshot with no text) never starts a turn. Two visible results:

| Session | Turn tab shows |
|---|---|
| Prompt "first" → Claude edits `a.ts`; then a screenshot alone → Claude creates `b.ts` | One turn, `T1 "first"`, listing **both** `a.ts` and `b.ts` |
| Only prompt is a screenshot alone → Claude edits `a.ts` | **No turns at all** (the tab is empty although the git tab shows the edit) |

**Root cause** — `mods/diff/hooks/turns/turn-of/is-prompt-row/is-prompt-row.ts`:

```ts
export const isPromptRow = (message: SessionMessage) =>
message.role === 'user' &&
(message.toolResults === undefined || message.toolResults.length === 0) &&
message.text !== ''
```

`turnDiffsOf` starts a turn at every row `isPromptRow` accepts. The `text !== ''` clause was presumably meant to skip non-prompt user rows, but the `toolResults` check already does that, and it also rejects a real prompt with no text. `SessionMessage.text` is documented as "its text blocks joined; `''` when it has none", and that is what the engine records for an image-only prompt. I checked with a small function-hooks plugin that writes `$.session.messages()` at `turn.complete`, driving `claude` 2.1.274 in print mode (`--input-format stream-json`) with a user message whose only content block is an image:

```json
{ "role": "user", "text": "", "toolUses": [] }
```

No `toolResults`, empty `text` → not a turn start. The edits in that turn are then attributed to whichever earlier prompt did start a turn, or to nothing when there is none.

### What Should Happen?

A user row with no tool results is a prompt whatever its text. An image-only prompt should start its own turn (`Turn N`, with no quoted preview — `pane-state/turn-title-of` already draws an empty preview as no subtitle), and its edits should be listed under it.

### Error Messages/Logs

Two tests added beside the existing ones in `mods/diff/tests/turns/turn-diffs-of.test.ts`, on current `main` (68ac8bb):

```
(fail) turn-diffs-of > an image-only prompt (empty text, no tool results) starts its own turn
Expected: [[2, ""], [1, "first"]]
Received: [[1, "first"]]
(fail) turn-diffs-of > a session whose only prompt is image-only still lists its edits
Expected: length 1
Received: length 0
```

### Steps to Reproduce

1. In a git repo, fullscreen renderer, terminal wide enough for the `/diff` pane.
2. Type a prompt such as `add a comment to README.md` and let Claude edit the file.
3. Paste a screenshot into the prompt and send it with **no text** (for example, a screenshot of an error), so Claude makes another edit.
4. Open `/diff` and switch to the turn tab: there is one turn, `T1 "add a comment…"`, and it lists the second edit too.
5. Start a fresh session and send a screenshot alone as the first prompt; after Claude's edit, the turn tab lists nothing.

Or run the two tests above: `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude plugin test mods/diff`.

### Claude Model

Not model-specific

### Is this a regression?

No, present since `mods/diff` was published (`isPromptRow` is unchanged since d9c456d)

### Last Working Version

N/A

### Claude Code Version

2.1.274 (Claude Code), `mods/diff` at `main` 68ac8bb

### Platform

Anthropic API

### Operating System

macOS

### Terminal/Shell

Ghostty / zsh

### Additional Information

**Proposed fix**, on a branch against current `main`, since PRs from outside accounts are not accepted here:

https://github.com/anthropics/claude-code/compare/main...farmer-data:claude-code-1:fix/diff-turn-view-image-only-prompt

One commit: drop the `text !== ''` clause from `isPromptRow` (docstring updated) and add the two tests above. `tsc -p mods/tsconfig.json` passes; `claude plugin test mods/diff` is 144/144 on 2.1.274.

Two notes:

- The mod says it reads turns "as the built-in turn view" does, so the built-in may skip empty-text rows the same way; if so this is the same fix in both places.
- With the fix an image-only turn reads as `Turn N` with no quote. A `"(image)"` placeholder would be friendlier, but `SessionMessage` carries no attachment information, so that would need the engine to say so — a follow-up, not part of this change.

AI tools used: Claude Code (analysis, the probe plugin, tests and the patch); I reviewed and ran everything.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with mods/diff/hooks/turns/turn-of/is-prompt-row/is-prompt-row.ts and the turnDiffsOf tests in mods/diff/tests/turns/turn-diffs-of.test.ts. Run the two image-only prompt tests, then the full `claude plugin test mods/diff` suite. Done means an empty-text prompt with no tool results starts its own turn and its edits are listed there.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, testing
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.