import { z } from "zod"; import type { McpTool } from "../tool.js"; declare const inputSchema: z.ZodObject<{ url: z.ZodString; /** Project slug. Optional — defaults to the sentinel "default" project, * the same Phase 1D-friendly fallback that ingest_content uses. */ project: z.ZodDefault; /** * Page title override (single-page mode only — when crawling, each * page uses its own ). Falls back to the parsed <title> or * the URL itself. */ title: z.ZodDefault<z.ZodString>; tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>; /** Hard cap on response body PER PAGE. Default 2 MiB. */ maxBytes: z.ZodDefault<z.ZodNumber>; /** Per-fetch timeout in milliseconds. Default 30s. */ timeoutMs: z.ZodDefault<z.ZodNumber>; /** * Crawl depth. 0 (default) = ingest just `url`. 1 = also follow * every same-host link found on the seed page. 2 = follow links on * the pages found at depth 1, etc. Capped at 5 to keep a runaway * crawl bounded. Combined with `maxPages` (the absolute hard cap) * this gives the caller two orthogonal levers. */ crawlDepth: z.ZodDefault<z.ZodNumber>; /** * Absolute hard ceiling on pages fetched per call. Includes the seed * page. Default 50 — enough for a typical docs section, small enough * that a misconfigured crawl won't blow the chunk budget. Set lower * for "test the crawl" runs; higher for full sites (consider an * async job runner before going past a few hundred). */ maxPages: z.ZodDefault<z.ZodNumber>; /** * When true (default), crawls only URLs whose path starts with the * seed URL's directory. Example: seed "https://docs.example.com/v2/api/intro" * → only crawls "/v2/api/...". Stops the crawl from wandering into * "/blog/" or the marketing site root. Set false to crawl any * same-host URL. */ samePathPrefixOnly: z.ZodDefault<z.ZodBoolean>; /** * Run the crawl in the background and return a jobId immediately. * Default true — even single-page fetches can stall behind a slow * upstream and trip the MCP transport timeout, and crawls past a * few pages routinely do. Async returns `{ jobId, queued: true }`; * caller polls `kb_job_status({ jobId })`. Set false ONLY for a * single-page fetch the caller knows will be fast and wants inline. */ async: z.ZodDefault<z.ZodBoolean>; }, "strip", z.ZodTypeAny, { project: string; title: string; tags: string[]; timeoutMs: number; url: string; maxBytes: number; crawlDepth: number; maxPages: number; samePathPrefixOnly: boolean; async: boolean; }, { url: string; project?: string | undefined; title?: string | undefined; tags?: string[] | undefined; timeoutMs?: number | undefined; maxBytes?: number | undefined; crawlDepth?: number | undefined; maxPages?: number | undefined; samePathPrefixOnly?: boolean | undefined; async?: boolean | undefined; }>; interface PageResult { url: string; title: string; bytes: number; ingested: number; /** Depth at which this page was discovered (0 = seed). */ depth: number; } interface Output { /** True for backwards compat with the single-page caller — sums chunks across all pages. */ ingested: number; project: string; /** First page's URL — kept as `url` for back-compat with single-page callers. */ url: string; /** First page's title — same back-compat reason. */ title: string; /** Total bytes fetched across every page. */ bytes: number; /** Per-page summary. Capped at 50 entries to keep payloads bounded. */ pages: PageResult[]; /** Number of pages successfully ingested. */ pagesIngested: number; /** Number of pages skipped (off-host, off-prefix, dedup, parse failure). */ pagesSkipped: number; /** True when the crawl stopped because maxPages was hit before the queue drained. */ truncated: boolean; /** Per-page errors. Capped at 50 entries. */ errors: Array<{ source_id: string; error: string; }>; } /** * Fetch a URL (and optionally its linked pages on the same host), * extract readable text, ingest into Cortex. * * Default behavior (crawlDepth=0): single-page mode — same as the * Phase 2 implementation. Set crawlDepth >= 1 to follow links. * * The crawler is BFS, deduplicated by absolute URL, scoped to the * seed URL's host, and (when `samePathPrefixOnly` is true, the * default) restricted to URLs whose path starts with the seed's * directory. `maxPages` is the absolute ceiling, applied across the * whole crawl regardless of depth. * * NOT suitable for SPAs — no JavaScript rendering. Use ingest_content * with the rendered text for those. */ export declare const ingestUrl: McpTool<typeof inputSchema, Output>; /** * Trim trailing slash + drop fragment + lowercase the host for stable * dedup. Query strings are preserved (they often differentiate * legitimately-distinct content like ?lang=en vs ?lang=ja). */ export declare function normalizeUrl(raw: string): string; /** * Compute the directory portion of a path. Used for the * `samePathPrefixOnly` filter so a seed at /docs/v2/api/intro * crawls only /docs/v2/api/*, not the whole site. * * Path "/docs/v2/api/intro" → "/docs/v2/api/" * Path "/docs/v2/api/intro.html" → "/docs/v2/api/" * Path "/docs/v2/api/" → "/docs/v2/api/" * Path "/" → "/" */ export declare function deriveDirectoryPrefix(pathname: string): string; /** * Pull every <a href="..."> out of the HTML, resolve it against the * page URL, then filter to: * - same host (case-insensitive) * - http/https scheme only * - path starts with `pathPrefix` * - not a fragment-only link to the same page * Returns deduplicated, normalized URLs. */ export declare function extractSameHostLinks(html: string, pageUrl: string, expectedHost: string, pathPrefix: string): string[]; /** * Cheap HTML→text extraction. Sufficient for the first cut. * * Strategy: * 1. Pull <title> out before stripping (so we keep page metadata). * 2. Drop `<script>`, `<style>`, `<noscript>`, `<svg>`, `<head>` blocks * including their content. * 3. Drop HTML comments. * 4. Strip remaining tags but preserve their inner text. * 5. Decode the few HTML entities that show up most often in plain * prose. Full entity decoding would need a parser; this is the * 90/10 cut for English/Latin-script content. * 6. Collapse whitespace runs to single spaces; preserve paragraph * breaks (double-newline) where possible. */ export declare function stripHtml(html: string): { text: string; parsedTitle: string; }; export {}; //# sourceMappingURL=ingest-url.d.ts.map