Skip to content

diff: a shell command the tool held read-only fetches nothing - #95423

Merged
poteat merged 3 commits into
mainfrom
poteat/diff-mod-telemetry-gaps
Sep 24, 2026
Merged

poteat merged 3 commits into
mainfrom
poteat/diff-mod-telemetry-gaps

Conversation

@poteat

@poteat poteat commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

With its pane open, the diff mod refetched the diff after every Bash or PowerShell tool call. The built-in panel refetches only after a shell command that may have written: one the tool holds read-only (ls, git status, cat, a grep) is skipped. The mod now reads isReadOnly off the shell tool's tool.call result and skips the refetch when it is set; where the engine does not set it, behaviour is unchanged. Adds a register test that fails before the change. Checked: tsc -p mods/tsconfig.json, claude plugin validate mods/diff, claude plugin test mods/diff (143 pass).

@poteat
poteat enabled auto-merge (squash) September 18, 2026 18:40
@konsta95

Copy link
Copy Markdown

Retested on Claude Code 2.1.278 against main 7974a70. The branch still conflicts: main's refactor moved the shell-tool gate from isStale into hasLanded (register.ts ~930), which now feeds both the open-pane refresh and the landed counter the catch-up re-read checks. Carrying Tools.mayHaveWritten(result) into hasLanded keeps the read-only skip in both places — ls during the initial fetch no longer forces a second read, make still does. Your test plus one for the pending-fetch case fail on unchanged main and pass with that; full suite 165/165, tsc clean. The adaptation is in konsta95:fix/diff-clear-resume-races (commit a7e4ee4, together with an unrelated clear/resume fix — the hasLanded hunk and may-have-written.ts are yours to lift). Controlled hook tests only, no physical terminal.

@poteat
poteat disabled auto-merge September 20, 2026 20:51
@poteat

poteat commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

@konsta95

Thanks for watching out! Indeed, there's a bit of ceremony involved re the timing of landing this due to those changes. I'd love feedback as well on the test kit on the thread if you've gotten a chance to play around with it.

@konsta95

Copy link
Copy Markdown

One data point on the producer side. On 2.1.278 (latest and next) and 2.1.274, a tool.call{tool=Bash} hook loaded with --plugin-dir sees { ref, result, text }, plus isError on a failing or denied command, and never isReadOnly, including for cat and echo that ran without a rule in the same permission mode where a touch was denied. In the 2.1.278 binary all 92 occurrences of isReadOnly are the tool descriptors' method definitions, tool.isReadOnly(input) calls, or the name as a string; none is a data value, and nothing copies it onto a result. So mayHaveWritten is today exactly the expression it replaced, and READ_ONLY_ANSWER is the only producer the kit will see, since a test's on('tool.call') sits beneath every plugin with no process behind it.

That also corrects my carry comment above: the skip is in both places in the code and fires on no current build.

Harmless to land. Worth pairing with whichever engine change sets the field, since if it lands on the descriptor or under another name, nothing here notices. The probe (three files, validates, about five seconds a run) is in #91870.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants