Repository navigation
feat: fetch_page returns Markdown, links and tables kept - #7
Merged
Merged
Conversation
fetch_page and refetch get now return the page as Markdown by default: headings, lists, links, tables and code blocks kept, scripts and hidden elements dropped. format: "text" (get --format text) gives the plain text as before, and the JavaScript and empty-page detection keeps measuring plain text. - Links are absolute, resolved against the address after redirects (or <base href>). Search engines' click-through links (DuckDuckGo's uddg, Google's /url?q=) point at their targets, tracking parameters are dropped, and a target repeated right after itself shows only its text. Only http, https and mailto links keep a target. - A data table becomes a pipe table, without rows and columns that are empty throughout; a layout table becomes its cells' text. - Code blocks keep their whitespace and language, fenced longer than any backtick run inside them. - An element with a block inside (a custom element, a span around a div) is laid out as a block, as a browser does; a link stays one line. - save: true writes a .md file (.txt with format: "text"). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
/links names three notes pages by link text only and refuses plain clients; the word is on the page its release-notes link leads to, under a path that cannot be guessed. A session passes only if fetch_page's result carries the link's URL. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7 +/- ##
==========================================
+ Coverage 89.75% 90.47% +0.71%
==========================================
Files 18 19 +1
Lines 1689 2015 +326
==========================================
+ Hits 1516 1823 +307
- Misses 172 191 +19
Partials 1 1
🚀 New features to boost your workflow:
|
From a review of the Markdown converter: - A crafted table could make the output grow with the square of the page (one 4,000-cell row padded every other row: 280 KB of HTML gave 225 MB of Markdown), and so could deep quotes and lists, which prefixed every line once per level. A table wider than 64 columns or with more than 20,000 cells is now laid out as its cells' text, and quotes and lists stop adding prefixes after six levels. At 2 MB, the largest page refetch reads, every probed shape now converts in under 0.2 s to at most three times its size. - Links in a layout table lost their target: the cells were rendered twice and the second pass took each link for a repeat. - Code blocks lost blank lines to a pass over the whole document. - Hidden table rows and cells were shown; a code block's Copy button and other skipped elements reached its text, which is now gathered in one pass without recursion. - Dropping a tracking parameter re-sorted and re-encoded the rest of the query; the other pairs now keep their order and encoding. - A saved page that is not HTML is .txt, not .md. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
From a security review of the Markdown converter: - A list item outside a list (<li> inside <section>, nested about 95 deep) indented every line of its content once per level, past the six-level cap that counted only <ul>/<ol>: 1 MB of HTML gave 40 MB of Markdown in 1.2 s. List items now count their own nesting. - <ol start="-9223372036854775808"> made 22-character markers on every line; a start outside 0 to 999,999 is ignored. - A link target keeps no userinfo, so https://good.example@evil.example/ shows as https://evil.example/. - Clip walks the text up to its limit instead of converting the whole of it to runes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fetch_pageandrefetch getnow return the page as Markdown by default. Before, a page came back as one flat run of text: links lost their URLs, tables lost their columns, and code lost its whitespace. Claude could see a search result or a "next page" link but couldn't follow it.format: "text"(CLI:--format text) gives the old plain text.What the Markdown keeps
<base href>).uddg, Google's/url?q=) point at their real targets.utm_*,fbclid,gclidand so on) are dropped.javascript:anddata:links show only their text.<react-app>, or a span around a div) is a block. Without this, GitHub's releases page came out as one line. A link stays one line, which keeps a card as one link.hidden,aria-hidden,display:none).save: truewrites.md, or.txtwithformat: "text".Real pages (Markdown vs plain text size)
Links cost space. A link-heavy page is two to four times its plain-text size, so it reaches the default
max_chars(20,000) sooner.Sessions (
e2e/run.py, Sonnet)There's a new case,
links: an index page that refuses plain clients and names its notes pages only by link text. The secret word is on the page behind one link, under a path that can't be guessed.linksfails: Claude guessed paths with 2 morefetch_pagecalls and Bash, and gave no answerThe other seven cases (ok, 403, challenge, challenge-403, challenge-js, js, slow) pass in every run.
Checks
make testmake lint, on macOS and withGOOS=linuxmake cover-check: 89.7%claude plugin validate . --strictReview fixes (6dfc0fa)
A code review found one critical issue: crafted markup could make the output grow with the square of the page. A 280 KB table with one 4,000-cell row gave 225 MB of Markdown. Deep quotes and lists grew the same way, because each level prefixed every line again.
Smaller fixes from the same review:
.txt.One known limit: when headless Chrome reads a page after the HTTP fetch failed, links resolve against the URL that was asked for, not the address Chrome ended up on after redirects.
--dump-domdoesn't report that address.🤖 Generated with Claude Code