Skill: steipete/brave-search (version 1.0.1)

--- name: brave-search description: Web search and content extraction via Brave Search API. Use for searching documentation, facts, or any web content. Lightweight, no browser required. --- # Brave Search Headless web search and content extraction using Brave Search. No browser required. ## Setup Run once before first use: ```bash cd ~/Projects/agent-scripts/skills/brave-search npm ci ``` Needs env: `BRAVE_API_KEY`. ## Search ```bash ./search.js "query" # Basic search (5 results) ./search.js "query" -n 10 # More results ./search.js "query" --content # Include page content as markdown ./search.js "query" -n 3 --content # Combined ``` ## Extract Page Content ```bash ./content.js https://example.com/article ``` Fetches a URL and extracts readable content as markdown. ## Output Format ``` --- Result 1 --- Title: Page Title Link: https://example.com/page Snippet: Description from search results Content: (if --content flag used) Markdown content extracted from the page... --- Result 2 --- ... ``` ## When to Use - Searching for documentation or API references - Looking up facts or current information - Fetching content from specific URLs - Any task requiring web search without interactive browsing

path: content.js
content: #!/usr/bin/env node

import { Readability } from "@mozilla/readability";
import { JSDOM } from "jsdom";
import TurndownService from "turndown";
import { gfm } from "turndown-plugin-gfm";

const url = process.argv[2];

if (!url) {
	console.log("Usage: content.js <url>");
	console.log("\nExtracts readable content from a webpage as markdown.");
	console.log("\nExamples:");
	console.log("  content.js https://example.com/article");
	console.log("  content.js https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html");
	process.exit(1);
}

function htmlToMarkdown(html) {
	const turndown = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
	turndown.use(gfm);
	turndown.addRule("removeEmptyLinks", {
		filter: (node) => node.nodeName === "A" && !node.textContent?.trim(),
		replacement: () => "",
	});
	return turndown
		.turndown(html)
		.replace(/\[\\?\[\s*\\?\]\]\([^)]*\)/g, "")
		.replace(/ +/g, " ")
		.replace(/\s+,/g, ",")
		.replace(/\s+\./g, ".")
		.replace(/\n{3,}/g, "\n\n")
		.trim();
}

try {
	const response = await fetch(url, {
		headers: {
			"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
			"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			"Accept-Language": "en-US,en;q=0.9",
		},
		signal: AbortSignal.timeout(15000),
	});
	
	if (!response.ok) {
		console.error(`HTTP ${response.status}: ${response.statusText}`);
		process.exit(1);
	}
	
	const html = await response.text();
	const dom = new JSDOM(html, { url });
	const reader = new Readability(dom.window.document);
	const article = reader.parse();
	
	if (article && article.content) {
		if (article.title) {
			console.log(`# ${article.title}\n`);
		}
		console.log(htmlToMarkdown(article.content));
		process.exit(0);
	}
	
	// Fallback: try to extract main content
	const fallbackDoc = new JSDOM(html, { url });
	const body = fallbackDoc.window.document;
	body.querySelectorAll("script, style, noscript, nav, header, footer, aside").forEach(el => el.remove());
	
	const title = body.querySelector("title")?.textContent?.trim();
	const main = body.querySelector("main, article, [role='main'], .content, #content") || body.body;
	
	if (title) {
		console.log(`# ${title}\n`);
	}
	
	const text = main?.innerHTML || "";
	if (text.trim().length > 100) {
		console.log(htmlToMarkdown(text));
	} else {
		console.error("Could not extract readable content from this page.");
		process.exit(1);
	}
} catch (e) {
	console.error(`Error: ${e.message}`);
	process.exit(1);
}


path: package-lock.json
content: {
	"name": "brave-search",
	"version": "1.0.0",
	"lockfileVersion": 3,
	"requires": true,
	"packages": {
		"": {
			"name": "brave-search",
			"version": "1.0.0",
			"license": "MIT",
			"dependencies": {
				"@mozilla/readability": "^0.6.0",
				"jsdom": "^27.0.1",
				"turndown": "^7.2.2",
				"turndown-plugin-gfm": "^1.0.2"
			}
		},
		"node_modules/@asamuzakjp/css-color": {
			"version": "4.1.0",
			"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"@csstools/css-calc": "^2.1.4",
				"@csstools/css-color-parser": "^3.1.0",
				"@csstools/css-parser-algorithms": "^3.0.5",
				"@csstools/css-tokenizer": "^3.0.4",
				"lru-cache": "^11.2.2"
			}
		},
		"node_modules/@asamuzakjp/dom-selector": {
			"version": "6.7.5",
			"resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.5.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"@asamuzakjp/nwsapi": "^2.3.9",
				"bidi-js": "^1.0.3",
				"css-tree": "^3.1.0",
				"is-potential-custom-element-name": "^1.0.1",
				"lru-cache": "^11.2.2"
			}
		},
		"node_modules/@asamuzakjp/nwsapi": {
			"version": "2.3.9",
			"resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/@csstools/color-helpers": {
			"version": "5.1.0",
			"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT-0",
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/@csstools/css-calc": {
			"version": "2.1.4",
			"resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT",
			"engines": {
				"node": ">=18"
			},
			"peerDependencies": {
				"@csstools/css-parser-algorithms": "^3.0.5",
				"@csstools/css-tokenizer": "^3.0.4"
			}
		},
		"node_modules/@csstools/css-color-parser": {
			"version": "3.1.0",
			"resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT",
			"dependencies": {
				"@csstools/color-helpers": "^5.1.0",
				"@csstools/css-calc": "^2.1.4"
			},
			"engines": {
				"node": ">=18"
			},
			"peerDependencies": {
				"@csstools/css-parser-algorithms": "^3.0.5",
				"@csstools/css-tokenizer": "^3.0.4"
			}
		},
		"node_modules/@csstools/css-parser-algorithms": {
			"version": "3.0.5",
			"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT",
			"engines": {
				"node": ">=18"
			},
			"peerDependencies": {
				"@csstools/css-tokenizer": "^3.0.4"
			}
		},
		"node_modules/@csstools/css-syntax-patches-for-csstree": {
			"version": "1.0.20",
			"resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.20.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT-0",
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/@csstools/css-tokenizer": {
			"version": "3.0.4",
			"resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
			"integrity": [REDACTED_SECRET],
			"funding": [
				{
					"type": "github",
					"url": "https://github.com/sponsors/csstools"
				},
				{
					"type": "opencollective",
					"url": "https://opencollective.com/csstools"
				}
			],
			"license": "MIT",
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/@mixmark-io/domino": {
			"version": "2.2.0",
			"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BSD-2-Clause"
		},
		"node_modules/@mozilla/readability": {
			"version": "0.6.0",
			"resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "Apache-2.0",
			"engines": {
				"node": ">=14.0.0"
			}
		},
		"node_modules/agent-base": {
			"version": "7.1.4",
			"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"engines": {
				"node": ">= 14"
			}
		},
		"node_modules/bidi-js": {
			"version": "1.0.3",
			"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"require-from-string": "^2.0.2"
			}
		},
		"node_modules/css-tree": {
			"version": "3.1.0",
			"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"mdn-data": "2.12.2",
				"source-map-js": "^1.0.1"
			},
			"engines": {
				"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
			}
		},
		"node_modules/cssstyle": {
			"version": "5.3.3",
			"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"@asamuzakjp/css-color": "^4.0.3",
				"@csstools/css-syntax-patches-for-csstree": "^1.0.14",
				"css-tree": "^3.1.0"
			},
			"engines": {
				"node": ">=20"
			}
		},
		"node_modules/data-urls": {
			"version": "6.0.0",
			"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"whatwg-mimetype": "^4.0.0",
				"whatwg-url": "^15.0.0"
			},
			"engines": {
				"node": ">=20"
			}
		},
		"node_modules/debug": {
			"version": "4.4.3",
			"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"ms": "^2.1.3"
			},
			"engines": {
				"node": ">=6.0"
			},
			"peerDependenciesMeta": {
				"supports-color": {
					"optional": true
				}
			}
		},
		"node_modules/decimal.js": {
			"version": "10.6.0",
			"resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/entities": {
			"version": "6.0.1",
			"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BSD-2-Clause",
			"engines": {
				"node": ">=0.12"
			},
			"funding": {
				"url": "https://github.com/fb55/entities?sponsor=1"
			}
		},
		"node_modules/html-encoding-sniffer": {
			"version": "4.0.0",
			"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"whatwg-encoding": "^3.1.1"
			},
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/http-proxy-agent": {
			"version": "7.0.2",
			"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"agent-base": "^7.1.0",
				"debug": "^4.3.4"
			},
			"engines": {
				"node": ">= 14"
			}
		},
		"node_modules/https-proxy-agent": {
			"version": "7.0.6",
			"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"agent-base": "^7.1.2",
				"debug": "4"
			},
			"engines": {
				"node": ">= 14"
			}
		},
		"node_modules/iconv-lite": {
			"version": "0.6.3",
			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"safer-buffer": ">= 2.1.2 < 3.0.0"
			},
			"engines": {
				"node": ">=0.10.0"
			}
		},
		"node_modules/is-potential-custom-element-name": {
			"version": "1.0.1",
			"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/jsdom": {
			"version": "27.0.1",
			"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.0.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"@asamuzakjp/dom-selector": "^6.7.2",
				"cssstyle": "^5.3.1",
				"data-urls": "^6.0.0",
				"decimal.js": "^10.6.0",
				"html-encoding-sniffer": "^4.0.0",
				"http-proxy-agent": "^7.0.2",
				"https-proxy-agent": "^7.0.6",
				"is-potential-custom-element-name": "^1.0.1",
				"parse5": "^8.0.0",
				"rrweb-cssom": "^0.8.0",
				"saxes": "^6.0.0",
				"symbol-tree": "^3.2.4",
				"tough-cookie": "^6.0.0",
				"w3c-xmlserializer": "^5.0.0",
				"webidl-conversions": "^8.0.0",
				"whatwg-encoding": "^3.1.1",
				"whatwg-mimetype": "^4.0.0",
				"whatwg-url": "^15.1.0",
				"ws": "^8.18.3",
				"xml-name-validator": "^5.0.0"
			},
			"engines": {
				"node": ">=20"
			},
			"peerDependencies": {
				"canvas": "^3.0.0"
			},
			"peerDependenciesMeta": {
				"canvas": {
					"optional": true
				}
			}
		},
		"node_modules/lru-cache": {
			"version": "11.2.4",
			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BlueOak-1.0.0",
			"engines": {
				"node": "20 || >=22"
			}
		},
		"node_modules/mdn-data": {
			"version": "2.12.2",
			"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "CC0-1.0"
		},
		"node_modules/ms": {
			"version": "2.1.3",
			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/parse5": {
			"version": "8.0.0",
			"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"entities": "^6.0.0"
			},
			"funding": {
				"url": "https://github.com/inikulin/parse5?sponsor=1"
			}
		},
		"node_modules/punycode": {
			"version": "2.3.1",
			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"engines": {
				"node": ">=6"
			}
		},
		"node_modules/require-from-string": {
			"version": "2.0.2",
			"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"engines": {
				"node": ">=0.10.0"
			}
		},
		"node_modules/rrweb-cssom": {
			"version": "0.8.0",
			"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/safer-buffer": {
			"version": "2.1.2",
			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/saxes": {
			"version": "6.0.0",
			"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "ISC",
			"dependencies": {
				"xmlchars": "^2.2.0"
			},
			"engines": {
				"node": ">=v12.22.7"
			}
		},
		"node_modules/source-map-js": {
			"version": "1.2.1",
			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BSD-3-Clause",
			"engines": {
				"node": ">=0.10.0"
			}
		},
		"node_modules/symbol-tree": {
			"version": "3.2.4",
			"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/tldts": {
			"version": "7.0.19",
			"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"tldts-core": "^7.0.19"
			},
			"bin": {
				"tldts": "bin/cli.js"
			}
		},
		"node_modules/tldts-core": {
			"version": "7.0.19",
			"resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/tough-cookie": {
			"version": "6.0.0",
			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BSD-3-Clause",
			"dependencies": {
				"tldts": "^7.0.5"
			},
			"engines": {
				"node": ">=16"
			}
		},
		"node_modules/tr46": {
			"version": "6.0.0",
			"resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"punycode": "^2.3.1"
			},
			"engines": {
				"node": ">=20"
			}
		},
		"node_modules/turndown": {
			"version": "7.2.2",
			"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"@mixmark-io/domino": "^2.2.0"
			}
		},
		"node_modules/turndown-plugin-gfm": {
			"version": "1.0.2",
			"resolved": "https://registry.npmjs.org/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.2.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		},
		"node_modules/w3c-xmlserializer": {
			"version": "5.0.0",
			"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"xml-name-validator": "^5.0.0"
			},
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/webidl-conversions": {
			"version": "8.0.0",
			"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "BSD-2-Clause",
			"engines": {
				"node": ">=20"
			}
		},
		"node_modules/whatwg-encoding": {
			"version": "3.1.1",
			"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"iconv-lite": "0.6.3"
			},
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/whatwg-mimetype": {
			"version": "4.0.0",
			"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/whatwg-url": {
			"version": "15.1.0",
			"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"dependencies": {
				"tr46": "^6.0.0",
				"webidl-conversions": "^8.0.0"
			},
			"engines": {
				"node": ">=20"
			}
		},
		"node_modules/ws": {
			"version": "8.18.3",
			"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT",
			"engines": {
				"node": ">=10.0.0"
			},
			"peerDependencies": {
				"bufferutil": "^4.0.1",
				"utf-8-validate": ">=5.0.2"
			},
			"peerDependenciesMeta": {
				"bufferutil": {
					"optional": true
				},
				"utf-8-validate": {
					"optional": true
				}
			}
		},
		"node_modules/xml-name-validator": {
			"version": "5.0.0",
			"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "Apache-2.0",
			"engines": {
				"node": ">=18"
			}
		},
		"node_modules/xmlchars": {
			"version": "2.2.0",
			"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
			"integrity": [REDACTED_SECRET],
			"license": "MIT"
		}
	}
}


path: package.json
content: {
	"name": "brave-search",
	"version": "1.0.0",
	"type": "module",
	"description": "Headless web search via Brave Search - no browser required",
	"author": "Mario Zechner",
	"license": "MIT",
	"dependencies": {
		"@mozilla/readability": "^0.6.0",
		"jsdom": "^27.0.1",
		"turndown": "^7.2.2",
		"turndown-plugin-gfm": "^1.0.2"
	}
}


path: search.js
content: #!/usr/bin/env node

import { Readability } from "@mozilla/readability";
import { JSDOM } from "jsdom";
import TurndownService from "turndown";
import { gfm } from "turndown-plugin-gfm";

const args = process.argv.slice(2);

const contentIndex = args.indexOf("--content");
const fetchContent = contentIndex !== -1;
if (fetchContent) args.splice(contentIndex, 1);

let numResults = 5;
const nIndex = args.indexOf("-n");
if (nIndex !== -1 && args[nIndex + 1]) {
	numResults = parseInt(args[nIndex + 1], 10);
	args.splice(nIndex, 2);
}

const query = args.join(" ");

if (!query) {
	console.log("Usage: search.js <query> [-n <num>] [--content]");
	console.log("\nOptions:");
	console.log("  -n <num>    Number of results (default: 5)");
	console.log("  --content   Fetch readable content as markdown");
	console.log("\nExamples:");
	console.log('  search.js "javascript async await"');
	console.log('  search.js "rust programming" -n 10');
	console.log('  search.js "climate change" --content');
	process.exit(1);
}

async function fetchBraveResults(query, numResults) {
	const url = `https://search.brave.com/search?q=${encodeURIComponent(query)}`;
	
	const response = await fetch(url, {
		headers: {
			"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
			"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
			"Accept-Language": "en-US,en;q=0.9",
			"sec-ch-ua": '"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
			"sec-ch-ua-mobile": "?0",
			"sec-ch-ua-platform": '"macOS"',
			"sec-fetch-dest": "document",
			"sec-fetch-mode": "navigate",
			"sec-fetch-site": "none",
			"sec-fetch-user": "?1",
		}
	});
	
	if (!response.ok) {
		throw new Error(`HTTP ${response.status}: ${response.statusText}`);
	}
	
	const html = await response.text();
	const dom = new JSDOM(html);
	const doc = dom.window.document;
	
	const results = [];
	
	// Find all search result snippets with data-type="web"
	const snippets = doc.querySelectorAll('div.snippet[data-type="web"]');
	
	for (const snippet of snippets) {
		if (results.length >= numResults) break;
		
		// Get the main link and title
		const titleLink = snippet.querySelector('a.svelte-14r20fy');
		if (!titleLink) continue;
		
		const link = titleLink.getAttribute('href');
		if (!link || link.includes('brave.com')) continue;
		
		const titleEl = titleLink.querySelector('.title');
		const title = titleEl?.textContent?.trim() || titleLink.textContent?.trim() || '';
		
		// Get the snippet/description
		const descEl = snippet.querySelector('.generic-snippet .content');
		let snippetText = descEl?.textContent?.trim() || '';
		// Remove date prefix if present
		snippetText = snippetText.replace(/^[A-Z][a-z]+ \d+, \d{4} -\s*/, '');
		
		if (title && link) {
			results.push({ title, link, snippet: snippetText });
		}
	}
	
	return results;
}

function htmlToMarkdown(html) {
	const turndown = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
	turndown.use(gfm);
	turndown.addRule("removeEmptyLinks", {
		filter: (node) => node.nodeName === "A" && !node.textContent?.trim(),
		replacement: () => "",
	});
	return turndown
		.turndown(html)
		.replace(/\[\\?\[\s*\\?\]\]\([^)]*\)/g, "")
		.replace(/ +/g, " ")
		.replace(/\s+,/g, ",")
		.replace(/\s+\./g, ".")
		.replace(/\n{3,}/g, "\n\n")
		.trim();
}

async function fetchPageContent(url) {
	try {
		const response = await fetch(url, {
			headers: {
				"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
				"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
			},
			signal: AbortSignal.timeout(10000),
		});
		
		if (!response.ok) {
			return `(HTTP ${response.status})`;
		}
		
		const html = await response.text();
		const dom = new JSDOM(html, { url });
		const reader = new Readability(dom.window.document);
		const article = reader.parse();
		
		if (article && article.content) {
			return htmlToMarkdown(article.content).substring(0, 5000);
		}
		
		// Fallback: try to get main content
		const fallbackDoc = new JSDOM(html, { url });
		const body = fallbackDoc.window.document;
		body.querySelectorAll("script, style, noscript, nav, header, footer, aside").forEach(el => el.remove());
		const main = body.querySelector("main, article, [role='main'], .content, #content") || body.body;
		const text = main?.textContent || "";
		
		if (text.trim().length > 100) {
			return text.trim().substring(0, 5000);
		}
		
		return "(Could not extract content)";
	} catch (e) {
		return `(Error: ${e.message})`;
	}
}

// Main
try {
	const results = await fetchBraveResults(query, numResults);
	
	if (results.length === 0) {
		console.error("No results found.");
		process.exit(0);
	}
	
	if (fetchContent) {
		for (const result of results) {
			result.content = await fetchPageContent(result.link);
		}
	}
	
	for (let i = 0; i < results.length; i++) {
		const r = results[i];
		console.log(`--- Result ${i + 1} ---`);
		console.log(`Title: ${r.title}`);
		console.log(`Link: ${r.link}`);
		console.log(`Snippet: ${r.snippet}`);
		if (r.content) {
			console.log(`Content:\n${r.content}`);
		}
		console.log("");
	}
} catch (e) {
	console.error(`Error: ${e.message}`);
	process.exit(1);
}


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)