Skip to content

feat(fetch): add --raw to web fetch for selector discovery - #419

Open
ankitranjan7 wants to merge 1 commit into
mainfrom
feat/web-fetch-raw
Open

feat(fetch): add --raw to web fetch for selector discovery#419
ankitranjan7 wants to merge 1 commit into
mainfrom
feat/web-fetch-raw

Conversation

@ankitranjan7

Copy link
Copy Markdown
Contributor

webcmd web fetch could only ever return readability-extracted article text, so an agent hunting for a CSS selector, a meta tag, or an inline <script> payload had no way to see the HTML — two recent eval scenarios abandoned webcmd here and fell back to curl | grep -P, which does not exist on macOS, losing the task.

What changed

  1. --raw (boolean, default false) on web fetch: returns the response body verbatim — no readability, no markdown conversion.
  2. Raw bodies honour --max-chars with a hard cut at the limit plus the existing [webcmd: truncated at N characters; rerun with --max-chars 0] marker, and truncated: true. Never a silent cut.
  3. Raw results carry bytes (body byte length) alongside the existing status, finalUrl, contentType, truncated fields; markdown output gains Bytes:/Truncated: lines. Non-raw results are byte-identical to before — no new fields.
  4. Help text names the use case ("CSS selector discovery, meta tags, and inline script payloads") and the command example now shows --raw; cli-manifest.json regenerated.
  5. Untouched: safe proxy / --allow-private gating, timeouts, the challenge ladder, FETCH_BLOCKED, FETCH_REQUIRES_BROWSER, and the 10 MiB body cap.

Before / After

Before — no way to get HTML:

$ webcmd web fetch --url https://example.com --raw
error: unknown option '--raw'

After:

$ node dist/src/main.js web fetch --url https://example.com --raw --json
{
  "status": 200,
  "requestedUrl": "https://example.com",
  "finalUrl": "https://example.com/",
  "contentType": "text/html",
  "tier": "impit",
  "profile": "chrome",
  "title": "",
  "extractionSource": "raw",
  "truncated": false,
  "content": "<!doctype html><html lang=\"en\"><head><title>Example Domain</title><link rel=\"icon\" href=\"data:,\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style></head><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.</p><p><a href=\"https://iana.org/domains/example\">Learn more</a></p></div></body></html>\n",
  "bytes": 559
}

Default path, unchanged:

$ node dist/src/main.js web fetch --url https://example.com
# Example Domain

Source: https://example.com
Final URL: https://example.com/
Content type: text/html
Extraction: readability

This domain is for use in documentation examples without needing permission. Avoid use in operations.

[Learn more](https://iana.org/domains/example)

Truncation is announced, not silent:

$ node dist/src/main.js web fetch --url https://example.com --raw --max-chars 120
# Fetched content

Source: https://example.com
Final URL: https://example.com/
Content type: text/html
Extraction: raw
Bytes: 559
Truncated: true

<!doctype html><html lang="en"><head><title>Example Domain</title><link rel="icon" href="data:,"><meta name="viewport" c

[webcmd: truncated at 120 characters; rerun with --max-chars 0]

Tests

npm run typecheck clean. npx vitest run --project unit src/fetch src/hosted/manifest.test.ts src/check-hosted-contract.test.ts — 82 passed. New cases: raw returns the unprocessed body with metadata; non-raw still extracts and omits bytes; raw truncation is reported; a Cloudflare challenge with --raw still ends in FETCH_BLOCKED; --raw reaches the client and markdown metadata renders.

Full --project unit run: 123 failures with this change vs 122 on origin/main — the one delta was the hosted-contract byte check, fixed by regenerating cli-manifest.json (now committed); the remaining 122 are pre-existing on main in this environment (hosted lifecycle, playwright sandbox provenance, plugin manifest) and untouched here.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

Limitations

  • The automated review returned an invalid structured result.

This review is advisory and does not block merging.

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.

1 participant