Skip to content

feat(links): make .diff and .patch paths clickable - #644

Merged
Ark0N merged 1 commit into
Ark0N:masterfrom
irisitymichaelgrundberg:feat/link-diff-patch-paths
Oct 18, 2026
Merged

Ark0N merged 1 commit into
Ark0N:masterfrom
irisitymichaelgrundberg:feat/link-diff-patch-paths

Conversation

@irisitymichaelgrundberg

Copy link
Copy Markdown
Contributor

What

Paths ending in .diff or .patch are now clickable in the terminal and in the response viewer, the same as .txt or .json paths.

Why

Claude often writes a diff for review into its scratchpad and prints the path, for example /tmp/claude-1000/<project>/<session>/scratchpad/resolution.diff. That path rendered as plain text, because neither file-path link pattern had a diff or patch extension. Over a remote connection, a plain-text path leaves no easy way to read the file.

The server side already handles both extensions. TEXT_ATTACHMENT_EXTENSIONS is EDITABLE_EXTENSIONS, which lists diff and patch, so an out-of-workspace path registers as a text attachment and is served as inert text/plain with nosniff.

Change

  • src/web/public/constants.js adds diff|patch to the extension group of FILE_PATH_LINK_PATTERN and of RELATIVE_FILE_PATH_LINK_PATTERN. The two must stay equal, and an existing test pins that.
  • test/link-provider-regex.test.ts adds a scratchpad .diff path and a .patch path to the cases the rooted pattern must link.

Testing

  • npm run typecheck, lint, format:check, check:frontend-syntax and check:browser-excludes pass.
  • npm test passes on a clean npm ci of this branch.
  • On a dev server with its own instance, POST /api/sessions/:id/attachments accepted a /tmp/.../resolution.diff, and its /raw route returned 200 with text/plain; charset=utf-8 and nosniff.
  • In headless Chromium on the served page, findFilePathLinks() linked the full path out of the sentence ... scratchpad/resolution.diff., without the trailing full stop, and linked a relative ./fixes/one.patch.

🤖 Generated with Claude Code

An agent that writes a diff for review prints a path such as
/tmp/.../scratchpad/resolution.diff, and that path rendered as plain text
because the link patterns had no diff or patch extension. The attachment
allowlist already serves both as inert text/plain, so only the two link
patterns in constants.js change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Ark0N

Ark0N commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Thanks @irisitymichaelgrundberg, this is a nice small fix: paths ending in .diff or .patch are now clickable in both the terminal and the response viewer, so an agent's review diff in its scratchpad is one click away instead of a copy-paste.

I traced every click path and it holds up. The out-of-workspace case goes through the attachment routes, which already allowlist both extensions (TEXT_ATTACHMENT_EXTENSIONS is EDITABLE_EXTENSIONS) and serve them as text/plain with nosniff, and the in-workspace case uses the routes it always did. Typecheck, lint, format, the frontend checks and the link tests are all green here.

One bonus you did not mention: the hard-wrap joiner reads its extension list off the same pattern, so a long scratchpad .diff path that Claude Code wraps across two rows now links as one path.

One thing changed since you opened this: #621 landed and added tsv and zip to the same two extension groups in constants.js, so the branch now conflicts there. The resolution is to keep both, your diff|patch and master's tsv and zip. If you rebase, great; otherwise I'll resolve it when I merge. Apart from that, nothing to change. Two notes for later, neither is on you:

  • src/web/public/constants.js:2103: the relative pattern now also links method calls like df.diff(, np.diff( and mock.patch(. That is the same trade-off console.log( and res.json( already make on master, so it does not hold this PR; a lookahead that refuses a match followed by ( would fix the whole class in a separate change.
  • test/file-path-link-forms.test.ts:77: the trailing full stop and the relative ./fixes/one.patch forms you checked by hand would fit there as one-line cases if you ever touch this again.

This goes in with the next release.

@Ark0N
Ark0N merged commit 14a9e66 into Ark0N:master Oct 18, 2026
2 checks passed
Ark0N pushed a commit that referenced this pull request Oct 18, 2026
…ckable

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Ark0N

Ark0N commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Merged and shipped in 1.43.0. Thanks @irisitymichaelgrundberg! I resolved the constants.js conflict with #621 when merging, keeping your diff|patch and master's tsv and zip in both patterns, and the new parity test from #653 now guards that list.

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.

2 participants