Skip to content

fix(response-viewer): open markdown links to file paths in the preview, not as a same-origin URL - #665

Merged
Ark0N merged 1 commit into
Ark0N:masterfrom
JDProfresh:fix/response-viewer-path-links
Oct 22, 2026
Merged

Ark0N merged 1 commit into
Ark0N:masterfrom
JDProfresh:fix/response-viewer-path-links

Conversation

@JDProfresh

Copy link
Copy Markdown
Contributor

Problem

Codex cites files as Markdown links whose target is a bare path, for example [Our incident record](/home/me/llm-bench/runs/crash-20261017/incident-summary.json). In the Response Viewer, clicking one opened a new tab at https://<codeman-host>/home/me/llm-bench/runs/crash-20261017/incident-summary.json, which answers:

{"message":"Route GET:/home/me/llm-bench/runs/crash-20261017/incident-summary.json not found","error":"Not Found","statusCode":404}

The same path written as prose or in backticks already opens the file preview, so only the form Codex uses most was broken. Seen with codex-cli 0.160.0 on Codeman 1.42.0; the code is unchanged on master.

Cause

_renderMarkdown gives every link target="_blank", and _linkifyFilePaths skips text inside an <a>, so a link whose href is a path stays a plain browser link that resolves against Codeman's own origin. The File Viewer already handles this for rendered documents (_rebaseFilePreviewMarkdownRefs turns workspace refs into a.rv-path); the Response Viewer had no equivalent.

Fix

_linkifyFilePaths now gives a link with a scheme-less, non-// href the same a.rv-path shape a linkified path gets, so the existing click delegate opens it in the file preview:

  • #L42, ?query and a :42 or :42:7 suffix are dropped, so the link opens the file itself. The suffix is cut before the href is percent-decoded (as the File Viewer's rebase decodes), so an encoded %3A stays part of the name.
  • A relative target resolves against the session's working directory (data-linkified, as for prose paths), and a folder target opens the folder grid.
  • https:, mailto:, //host and #fragment links are untouched, so new-tab, loopback web-tab and in-document behavior stay as they are. Tabs and newlines are removed before the scheme check, as the URL parser does, so http&#9;://localhost:5173 still counts as a URL.
  • In the File Viewer the rebase runs first and already converts or unwraps every workspace ref, so rendered documents behave exactly as before.

Out-of-workspace targets go through the attachment routes like any other clicked path, so the blocked trees and extension allowlist still apply. Working-With-Files and Mobile-Guide in the wiki now mention the link form (the Mobile Guide said every Response Viewer link opens a tab).

Independent of #545; if that lands, these links get its panel like any other a.rv-path.

Testing

  • test/response-viewer-file-links.test.ts: a path link becomes a.rv-path with the right data-path and no target/rel (absolute, relative with %20 and :42:7, folders with and without a trailing slash, an encoded %3A); https:, mailto:, //host, #fragment and a tab-split scheme keep their href; and a behavioral click through _bindResponseViewerInteractions calls openFilePreview with the path and prevents the navigation. Removing any one of the seven guards turns at least one of these red, and the behavior tests fail against master's app.js.
  • npm test: 11806 passed. typecheck, lint, format:check, check:frontend-syntax and check:browser-excludes pass.
  • Verified in Chromium against a real Codex message: the link opens the file preview with the JSON, the page does not navigate and no tab opens, and an https: link in the same message still opens in a new tab. Running on my own install since today, clicking the links in a live Codex session.

…w, not as a same-origin URL

Codex cites files as [label](/abs/path). The chat view gave those links target=_blank, so a click opened <origin>/abs/path and landed on a Fastify 404. Path-shaped hrefs now take the linkified-path shape the file preview already opens; scheme, protocol-relative and fragment links are unchanged.
@Ark0N

Ark0N commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Thanks @JDProfresh, this is a careful fix: Markdown links whose target is a bare path (Codex's [label](/abs/path.json)) now open in the file preview instead of a same-origin 404 tab, while links with a scheme, //host or a bare #fragment keep their behaviour. The write-up, the guards and the click-through test made it quick to review, and I confirmed both new behaviour tests fail against master's app.js and that the real marked + DOMPurify pipeline produces the hrefs your tests assume.

Four small things, which I'll apply on top at merge time unless you'd rather push them yourself:

  1. Link labels now render in the path style (src/web/public/app.js:2987, src/web/public/styles.css:14922). A converted link becomes a.rv-path inside .rv-text, so its label ("Our incident record") gets monospace, 0.92em and word-break: break-all, which splits prose mid-word at a line end on a phone. The File Viewer already resets this for labelled document links (styles.css:12347, font: inherit; word-break: normal). The fix is a second class on the converted anchor (a.className = 'rv-path rv-path-link';) and a .rv-text a.rv-path.rv-path-link { font: inherit; word-break: normal; } rule after the existing one.
  2. The ?query strip has no test (src/web/public/app.js:2979). Dropping .split('?')[0] keeps all 13 tests green, so [x](/tmp/a.json?raw=true) could regress unnoticed. One more href in the first new test (test/response-viewer-file-links.test.ts:113) covers it. The path.endsWith('/') shortcut at app.js:2990 is in the same position: docs/ is already a folder through findFilePathLinks, so the branch only matters for /tmp/ or </tmp/my dir/>, and a case for one of those pins why it is there.
  3. The invariant docs still describe a text-node walk only (docs/architecture-invariants.md:389 and the _linkifyFilePaths JSDoc at app.js:2957). One sentence saying the function also rewrites anchors whose href is a scheme-less, non-// path, on purpose without FILE_PATH_LINK_PATTERN's root and extension filter, keeps them accurate.
  4. Mobile Guide bullet 1 (docs/wiki/Mobile-Guide.md:134) still says every link in the response viewer opens a tab; "a web link" there matches your new bullet below it.

None of these block the change. CI is green, so this merges with those touches on top.

@Ark0N
Ark0N merged commit 6f785e1 into Ark0N:master Oct 22, 2026
2 checks passed
Ark0N pushed a commit that referenced this pull request Oct 22, 2026
… its edges

Merge-time fix for #665.

- A markdown link converted to a preview link became `a.rv-path`, so its
  label ("Our incident record") took the path style: monospace, 0.92em
  and `word-break: break-all`, which split prose mid-word on a phone. The
  anchor now also carries `rv-path-link`, and
  `.rv-text a.rv-path.rv-path-link` resets font and word-break, as the
  File Viewer does for its labelled document links.
- The first new test adds `/tmp/a.json?raw=true` (pins the `?query`
  strip) and `/tmp/` (pins the trailing-slash folder check, since
  findFilePathLinks finds no folder in a bare `/tmp/`), and checks the
  new class.
- The `_linkifyFilePaths` JSDoc and docs/architecture-invariants.md say
  the function also rewrites anchors whose href is a scheme-less,
  non-`//` path, on purpose without FILE_PATH_LINK_PATTERN's root and
  extension filter.
- Mobile Guide: "a web link" in the response viewer opens a tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Ark0N pushed a commit that referenced this pull request Oct 22, 2026
… file paths in the preview, not as a same-origin URL

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

Ark0N commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Merged and shipped in 1.44.0. Thank you @JDProfresh! Codex's [label](/abs/path) links opening the file instead of a 404 tab is one of those fixes people notice right away.

The four items, applied at merge:

  1. Converted links carry rv-path rv-path-link, and a rule resets the font and word-break, so a label reads as prose while a bare path keeps the monospace style.
  2. The test covers /tmp/a.json?raw=true and a /tmp/ folder link. Each one fails when the code it pins is removed.
  3. The _linkifyFilePaths JSDoc and the invariants say the function also rewrites anchors with a scheme-less path.
  4. The Mobile Guide says "a web link".

@JDProfresh
JDProfresh deleted the fix/response-viewer-path-links branch October 22, 2026 19:20
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