#!/usr/bin/env node /** * SearXNG Search Tool * * Provides web search via local SearXNG instance at http://10.0.0.8:8888/ */ const SEARXNG_BASE_URL = process.env.SEARXNG_URL || 'http://10.0.0.8:8888'; async function searxSearch(args) { const { query, count = 5, lang = 'en', safesearch = 0 } = args; if (!query || typeof query !== 'string') { throw new Error('Missing required parameter: query'); } // Build the search URL const searchParams = new URLSearchParams({ q: query, format: 'json', language: lang, safesearch: String(safesearch), }); const url = `${SEARXNG_BASE_URL}/search?${searchParams.toString()}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Accept': 'application/json', 'User-Agent': 'OpenClaw-SearXNG-Skill/1.0', }, }); if (!response.ok) { throw new Error(`SearXNG returned HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); // Transform SearXNG results to a standard format const results = (data.results || []).slice(0, Math.min(count, 20)).map(result => ({ title: result.title || '', url: result.url || '', snippet: result.content || '', engine: result.engine || 'unknown', engines: result.engines || [], thumbnail: result.thumbnail || null, publishedDate: result.publishedDate || null, })); // Include infoboxes if available const infoboxes = (data.infoboxes || []).map(box => ({ title: box.infobox || box.title || '', content: box.content || '', image: box.img_src || null, urls: box.urls || [], engine: box.engine || 'wikipedia', })); return { success: true, query: data.query || query, resultCount: results.length, totalResults: data.number_of_results || results.length, results, infoboxes: infoboxes.length > 0 ? infoboxes : undefined, unresponsiveEngines: data.unresponsive_engines || [], }; } catch (error) { return { success: false, error: error.message, query, }; } } // CLI execution if (require.main === module) { const args = JSON.parse(process.argv[2] || '{}'); searxSearch(args).then(result => { console.log(JSON.stringify(result, null, 2)); }).catch(error => { console.error(JSON.stringify({ success: false, error: error.message })); process.exit(1); }); } module.exports = { searxSearch };