@agentproto/corpus-cli 0.1.0-alpha.4 → 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ports/local-fs.adapter.ts","../../src/ports/os-identity.adapter.ts","../../src/ports/video-hosts.ts","../../src/ports/browser-fetcher.adapter.ts","../../src/ports/scrape-mcp-fetcher.adapter.ts","../../src/ports/ytdlp-whisper-fetcher.adapter.ts","../../src/ports/stt.port.ts","../../src/ports/assemblyai-stt.adapter.ts","../../src/ports/chunked-stt.adapter.ts","../../src/ports/composite-fetcher.ts","../../src/ports/throttle-fetcher.adapter.ts","../../src/ports/http-readability-fetcher.adapter.ts","../../src/ports/anthropic-distiller.ts","../../src/ports/cli-agent-distiller.ts","../../src/ports/cli-engines.ts","../../src/ports/mcp-http-client.ts","../../src/ports/mcp-sink.adapter.ts"],"names":["path","z","MCP_TEXT_BLOCK","rm","readdir","readFile","execFileAsync","promisify","execFile","stat","mkdtemp","join","tmpdir","msg"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * NodeFsAdapter — `FsPort` implementation backed by node:fs.\n *\n * Atomic writes via temp + rename (the same posix pattern every\n * mature tool uses). Recursive `walk` skips hidden segments\n * (anything beginning with `.`). Advisory locks via lockfiles in\n * `.corpus-locks/` next to the target — single-process safe; for\n * multi-process the lockfile owner pid is recorded so callers can\n * see who holds the lock.\n */\n\nimport { randomBytes } from \"node:crypto\"\nimport {\n appendFile,\n mkdir,\n readFile,\n readdir,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { existsSync } from \"node:fs\"\nimport type {\n FsPort,\n FsLockHandle,\n FsStat,\n} from \"@agentproto/corpus\"\n\nexport interface NodeFsAdapterOptions {\n /**\n * Absolute path to the workspace root. All FsPort paths are\n * resolved relative to this — the kit never sees host filesystem\n * paths.\n */\n readonly root: string\n}\n\nexport class NodeFsAdapter implements FsPort {\n private readonly root: string\n\n constructor(opts: NodeFsAdapterOptions) {\n this.root = opts.root\n }\n\n async exists(p: string): Promise<boolean> {\n try {\n await stat(this.resolve(p))\n return true\n } catch {\n return false\n }\n }\n\n async readFile(p: string): Promise<string> {\n return await readFile(this.resolve(p), \"utf8\")\n }\n\n /**\n * Atomic write: write to `${target}.tmp-{nonce}`, fsync, rename.\n * Rename is atomic on the same filesystem. Creates parent dirs as\n * needed (most callers expect mkdir -p semantics).\n */\n async writeFile(p: string, content: string): Promise<void> {\n const target = this.resolve(p)\n await mkdir(path.dirname(target), { recursive: true })\n const tmp = `${target}.tmp-${randomBytes(8).toString(\"hex\")}`\n await writeFile(tmp, content, \"utf8\")\n await rename(tmp, target)\n }\n\n async appendFile(p: string, content: string): Promise<void> {\n const target = this.resolve(p)\n await mkdir(path.dirname(target), { recursive: true })\n await appendFile(target, content, \"utf8\")\n }\n\n async readdir(p: string): Promise<readonly string[]> {\n const target = this.resolve(p)\n const entries = await readdir(target)\n return entries\n }\n\n async walk(p: string): Promise<readonly string[]> {\n const out: string[] = []\n const start = this.resolve(p)\n const rootForRelative = start\n const visit = async (dir: string): Promise<void> => {\n let entries: string[] = []\n try {\n entries = await readdir(dir)\n } catch {\n return\n }\n for (const ent of entries) {\n // Skip hidden segments — matches the FsPort contract.\n if (ent.startsWith(\".\")) continue\n const full = path.join(dir, ent)\n const s = await stat(full)\n if (s.isDirectory()) {\n await visit(full)\n } else if (s.isFile()) {\n const rel = path.relative(rootForRelative, full).split(path.sep).join(\"/\")\n out.push(rel)\n }\n }\n }\n await visit(start)\n return out\n }\n\n async stat(p: string): Promise<FsStat | null> {\n try {\n const s = await stat(this.resolve(p))\n return {\n kind: s.isDirectory() ? \"directory\" : \"file\",\n bytes: s.isFile() ? s.size : undefined,\n modifiedAt: s.mtime,\n }\n } catch {\n return null\n }\n }\n\n /**\n * Advisory lock via a lockfile. Spins waiting for the lockfile to\n * disappear, then creates it with exclusive flag. Released by\n * deleting it. Single-process safe; multi-process semi-safe (the\n * write is best-effort exclusive — adequate for the corpus's\n * promote-entry transaction which is rare and short-lived).\n */\n async lock(p: string): Promise<FsLockHandle> {\n const target = this.resolve(p)\n const lockDir = path.join(path.dirname(target), \".corpus-locks\")\n await mkdir(lockDir, { recursive: true })\n const lockFile = path.join(lockDir, path.basename(target) + \".lock\")\n const myToken = `${process.pid}-${randomBytes(4).toString(\"hex\")}`\n\n // Spin until we acquire. Cheap polling is fine for corpus\n // workloads — transactions are < 1s.\n while (true) {\n if (!existsSync(lockFile)) {\n try {\n await writeFile(lockFile, myToken, { encoding: \"utf8\", flag: \"wx\" })\n // Race: verify our token is the one that landed.\n const written = await readFile(lockFile, \"utf8\").catch(() => \"\")\n if (written === myToken) break\n } catch {\n // Lost the race — fall through and retry.\n }\n }\n await new Promise((r) => setTimeout(r, 25))\n }\n return {\n release: async () => {\n try {\n await rm(lockFile, { force: true })\n } catch {\n // Lockfile already gone — no-op.\n }\n },\n }\n }\n\n // ── Helpers ────────────────────────────────────────────────────\n\n /**\n * Resolve a workspace-relative path to an absolute host path.\n * Refuses to climb out of the workspace root (defense against\n * `../../etc/passwd`-style abuse) — the corpus kit's paths must\n * stay inside the workspace.\n */\n private resolve(p: string): string {\n const normalized = path.posix.normalize(\"/\" + p.replace(/^\\/+/, \"\"))\n // Drop the leading \"/\" so path.join joins correctly under root.\n const rel = normalized.slice(1)\n if (rel.startsWith(\"..\")) {\n throw new Error(\n `NodeFsAdapter: path \"${p}\" escapes the workspace root \"${this.root}\"`\n )\n }\n return path.join(this.root, rel)\n }\n}\n","/**\n * OsIdentityAdapter — `IdentityPort` resolved from OS user + cwd.\n *\n * Local-topology identity model:\n * - principal = `ws://users/{os-user}`\n * - identityTree = [\n * `ws://users/{os-user}`,\n * `ws://workspaces/{workspace-dir-name}`,\n * ]\n *\n * Roles + guilds + orgs don't exist locally — single-user, single-\n * workspace machine. Scope-policy in the corpus adapter matches\n * against this minimal tree, so AIP-10 `appliesTo` entries scoped\n * narrower than `ws://users/...` or `ws://workspaces/...` are\n * invisible to the local user. That's the intended local-topology\n * semantics: you only see what's scoped to you or your workspace.\n */\n\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport type {\n CallerIdentity,\n IdentityPort,\n} from \"@agentproto/corpus\"\n\nexport interface OsIdentityAdapterOptions {\n readonly workspaceRoot: string\n /** Override the OS user (useful for tests). Falls back to os.userInfo(). */\n readonly userOverride?: string\n}\n\nexport class OsIdentityAdapter implements IdentityPort {\n private readonly cached: CallerIdentity\n\n constructor(opts: OsIdentityAdapterOptions) {\n // Env vars win over os.userInfo() — matches Unix convention (env is\n // explicit intent, OS detection is fallback). Also keeps tests\n // deterministic across CI environments where the OS user differs.\n const user =\n opts.userOverride ??\n process.env.USER ??\n process.env.USERNAME ??\n safeGetUser() ??\n \"anonymous\"\n const wsName = path.basename(opts.workspaceRoot) || \"default\"\n this.cached = Object.freeze({\n principal: `ws://users/${slugify(user)}`,\n identityTree: Object.freeze([\n `ws://users/${slugify(user)}`,\n `ws://workspaces/${slugify(wsName)}`,\n ]),\n displayName: user,\n })\n }\n\n async resolve(): Promise<CallerIdentity> {\n return this.cached\n }\n}\n\nfunction safeGetUser(): string | undefined {\n try {\n return os.userInfo().username\n } catch {\n return undefined\n }\n}\n\nfunction slugify(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\")\n .slice(0, 64) || \"anonymous\"\n}\n","/**\n * Shared video-host detection. Video URLs belong to the transcription\n * fetcher (yt-dlp → STT); the readability fetchers MUST refuse them, so a\n * failed transcription is skipped-and-retried rather than silently\n * falling through to scrape a JS-rendered watch page (which yields the\n * page chrome — \"About Press Copyright…\" — not the talk).\n */\n\nexport const VIDEO_HOSTS: ReadonlySet<string> = new Set([\n \"youtube.com\",\n \"www.youtube.com\",\n \"m.youtube.com\",\n \"music.youtube.com\",\n \"youtu.be\",\n \"vimeo.com\",\n])\n\nexport function isVideoUrl(\n url: string,\n extraHosts?: ReadonlySet<string>\n): boolean {\n let host: string\n try {\n host = new URL(url).hostname\n } catch {\n return false\n }\n const bare = host.replace(/^www\\./, \"\")\n return (\n VIDEO_HOSTS.has(host) ||\n VIDEO_HOSTS.has(bare) ||\n (extraHosts?.has(host) ?? false) ||\n (extraHosts?.has(bare) ?? false)\n )\n}\n","/**\n * BrowserMcpFetcher — a FetcherPort that extracts ARTICLE text through\n * the user's authenticated browser (chrome-devtools-mcp). Use it for\n * pages that a plain HTTP fetch can't read: login-walled, consent-walled,\n * or JS-rendered (SPA) content. For public static articles the cheaper\n * HttpReadabilityFetcher suffices; for video, YtDlpWhisperFetcher handles\n * transcription — this fetcher does NOT touch video.\n *\n * navigate_page(url) → evaluate_script(readability) → { title, text }\n *\n * (It used to also scrape YouTube captions, but YouTube's caption APIs\n * are pot/SABR-gated and unreliable; transcription via YtDlpWhisperFetcher\n * replaced that path entirely.)\n *\n * The browser is injected as a minimal structural `BrowserMcpLike` (just\n * `callTool`, matching `@agentproto/driver-mcp`'s `McpClient`), so this\n * adapter has no hard MCP-SDK dependency and is unit-testable with a fake\n * client. The CLI wires the real chrome-devtools-mcp client.\n */\n\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\n/** The fetched-source payload the in-browser script returns. */\nconst FETCHED_PAYLOAD = z\n .object({\n title: z.string(),\n text: z.string(),\n kind: z.enum([\"video\", \"article\", \"page\", \"unknown\"]).catch(\"unknown\"),\n language: z.string().optional().catch(undefined),\n via: z.string().optional().catch(undefined),\n })\n .loose()\n\n/** An MCP `content` text block. */\nconst MCP_TEXT_BLOCK = z.object({ type: z.literal(\"text\"), text: z.string() }).loose()\n\n/** Minimal MCP client surface — matches `@agentproto/driver-mcp`'s `McpClient`. */\nexport interface BrowserMcpLike {\n callTool(args: {\n name: string\n arguments: Record<string, unknown>\n }): Promise<{ content?: unknown; structuredContent?: unknown; isError?: boolean }>\n}\n\nexport interface BrowserMcpFetcherOptions {\n readonly browser: BrowserMcpLike\n /** chrome-devtools-mcp tool names — overridable if a host renames them. */\n readonly navigateToolName?: string\n readonly evaluateToolName?: string\n}\n\n// In-page readability extraction, serialised for evaluate_script. Runs in\n// the navigated page's context (cookies/session apply).\nconst READABILITY_FN = `() => {\n const title = document.title || \"\";\n const article = document.querySelector(\"article\") || document.querySelector(\"main\");\n const root = article || document.body;\n const text = (root?.innerText || \"\").replace(/\\\\n{3,}/g, \"\\\\n\\\\n\").trim().slice(0, 200000);\n const lang = document.documentElement.getAttribute(\"lang\") || undefined;\n return { title, text, kind: \"article\", language: lang, via: \"readability\" };\n}`\n\nexport class BrowserMcpFetcher implements FetcherPort {\n private readonly browser: BrowserMcpLike\n private readonly navigateTool: string\n private readonly evaluateTool: string\n\n constructor(opts: BrowserMcpFetcherOptions) {\n this.browser = opts.browser\n this.navigateTool = opts.navigateToolName ?? \"navigate_page\"\n this.evaluateTool = opts.evaluateToolName ?? \"evaluate_script\"\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (isVideoUrl(url)) return null // videos → transcription, not page scrape\n\n await this.browser.callTool({\n name: this.navigateTool,\n arguments: { url },\n })\n const result = await this.browser.callTool({\n name: this.evaluateTool,\n arguments: { function: READABILITY_FN },\n })\n const extracted = parseEvaluateResult(result)\n if (!extracted || !extracted.text.trim()) return null\n return extracted\n }\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\n/**\n * chrome-devtools-mcp returns the script's return value either as\n * `structuredContent`, or serialised inside a `content` text block.\n * Parse defensively across both shapes.\n */\nfunction parseEvaluateResult(result: {\n content?: unknown\n structuredContent?: unknown\n}): FetchedSource | null {\n return (\n coerceFetched(result.structuredContent) ??\n coerceFetched(extractText(result.content))\n )\n}\n\nfunction coerceFetched(value: unknown): FetchedSource | null {\n let obj = value\n if (typeof obj === \"string\") {\n try {\n obj = JSON.parse(obj)\n } catch {\n return null\n }\n }\n const parsed = FETCHED_PAYLOAD.safeParse(obj)\n if (!parsed.success) return null\n const { title, text, kind, language, via } = parsed.data\n return {\n title,\n text,\n kind,\n ...(language ? { language } : {}),\n ...(via ? { via } : {}),\n }\n}\n\n/** Pull a text payload out of an MCP `content` array (or string). */\nfunction extractText(content: unknown): string | null {\n if (typeof content === \"string\") return content\n if (Array.isArray(content)) {\n for (const block of content) {\n const parsed = MCP_TEXT_BLOCK.safeParse(block)\n if (parsed.success) return parsed.data.text\n }\n }\n return null\n}\n","/**\n * ScrapeMcpFetcher — a FetcherPort that delegates article/page fetching to\n * any MCP server exposing a `scrape(url)` tool (e.g. the browser project's\n * tiered router: HTTP → Chromium → Camofox stealth → agent, with cookie\n * injection and auto-escalation on bot-walls). The browser stack is reached\n * over MCP, so this stays vendor-neutral — corpus-cli never imports it.\n *\n * scrape(url) → { title, markdown } → FetchedSource\n *\n * It does NOT touch video URLs (YtDlpWhisperFetcher owns those) and returns\n * `null` for a blocked / empty page so the importer skips-with-warning\n * rather than aborting the batch.\n *\n * The MCP client is injected as the minimal structural `BrowserMcpLike`\n * (just `callTool`), the same surface `BrowserMcpFetcher` consumes — so this\n * adapter has no MCP-SDK dependency and is unit-testable with a fake client.\n */\n\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport type { BrowserMcpLike } from \"./browser-fetcher.adapter.js\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\n/**\n * The fields we read off the `scrape` tool's result. A purifying scrape\n * server returns `title` + `markdown`; we tolerate a raw-`html`-only server\n * by stripping tags as a last resort. Everything else is left opaque.\n */\nconst SCRAPE_PAYLOAD = z\n .object({\n title: z.string().optional().catch(undefined),\n markdown: z.string().optional().catch(undefined),\n html: z.string().optional().catch(undefined),\n language: z.string().optional().catch(undefined),\n tierUsed: z.union([z.string(), z.number()]).optional().catch(undefined),\n })\n .loose()\n\nconst MCP_TEXT_BLOCK = z\n .object({ type: z.literal(\"text\"), text: z.string() })\n .loose()\n\nexport interface ScrapeMcpFetcherOptions {\n readonly client: BrowserMcpLike\n /** Tool name on the MCP server — overridable if a host renames it. */\n readonly scrapeToolName?: string\n}\n\nexport class ScrapeMcpFetcher implements FetcherPort {\n private readonly client: BrowserMcpLike\n private readonly toolName: string\n\n constructor(opts: ScrapeMcpFetcherOptions) {\n this.client = opts.client\n this.toolName = opts.scrapeToolName ?? \"scrape\"\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (isVideoUrl(url)) return null // let the transcription fetcher handle video\n\n let res: Awaited<ReturnType<BrowserMcpLike[\"callTool\"]>>\n try {\n res = await this.client.callTool({\n name: this.toolName,\n arguments: { url },\n })\n } catch {\n // Transient MCP/transport failure → skip this URL (resumable re-run\n // retries it), don't abort the whole batch.\n return null\n }\n if (res.isError) return null\n\n const payload = extractPayload(res)\n if (!payload) return null\n\n const text = (payload.markdown?.trim() || stripTags(payload.html)).trim()\n if (!text) return null // blocked / empty page → skip\n\n return {\n title: payload.title?.trim() || url,\n text,\n kind: \"article\",\n ...(payload.language ? { language: payload.language } : {}),\n via: payload.tierUsed ? `scrape:${payload.tierUsed}` : \"scrape\",\n }\n }\n}\n\n/** Read the scrape result from `structuredContent`, else a JSON text block. */\nfunction extractPayload(res: {\n content?: unknown\n structuredContent?: unknown\n}): z.infer<typeof SCRAPE_PAYLOAD> | null {\n if (res.structuredContent && typeof res.structuredContent === \"object\") {\n const parsed = SCRAPE_PAYLOAD.safeParse(res.structuredContent)\n if (parsed.success) return parsed.data\n }\n if (Array.isArray(res.content)) {\n for (const block of res.content) {\n const text = MCP_TEXT_BLOCK.safeParse(block)\n if (!text.success) continue\n try {\n const parsed = SCRAPE_PAYLOAD.safeParse(JSON.parse(text.data.text))\n if (parsed.success) return parsed.data\n } catch {\n // Non-JSON text block — treat the raw text as the content itself.\n return { markdown: text.data.text }\n }\n }\n }\n return null\n}\n\n/** Last-resort tag strip for a server that returns only raw HTML. */\nfunction stripTags(html: string | undefined): string {\n if (!html) return \"\"\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<[^>]+>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n}\n","/**\n * YtDlpWhisperFetcher — a FetcherPort for video URLs that does NOT rely\n * on captions (YouTube's caption/transcript APIs are pot/SABR-gated and\n * frequently unavailable). Instead it pulls the audio with yt-dlp and\n * transcribes it with an injected SttPort (Whisper). Captions-independent\n * and robust: works whether or not the video has subtitles.\n *\n * video URL → yt-dlp -f bestaudio -x (mp3) → SttPort.transcribe → text\n *\n * yt-dlp handles the pot token / SABR negotiation / signature itself, so\n * no browser or cookies are needed for public videos. Non-video URLs\n * resolve to `null` so this fetcher composes ahead of a readability\n * fetcher (see CompositeFetcher).\n *\n * The yt-dlp invocation is injected as `download` so the adapter is unit-\n * testable with a fake downloader + fake SttPort — no binary, no network.\n */\n\nimport { execFile } from \"node:child_process\"\nimport { mkdtemp, readdir, readFile, rm } from \"node:fs/promises\"\nimport { tmpdir } from \"node:os\"\nimport { join } from \"node:path\"\nimport { promisify } from \"node:util\"\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport type { SttPort } from \"./stt.port.js\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\nconst execFileAsync = promisify(execFile)\n\n/** yt-dlp's `.info.json` — only the fields we use. */\nconst YTDLP_INFO = z\n .object({ title: z.string().optional(), language: z.string().optional() })\n .loose()\n\nexport interface AudioDownload {\n readonly audioPath: string\n readonly title: string\n readonly language?: string\n /** Remove the temp working dir. Always called by the fetcher. */\n cleanup(): Promise<void>\n}\n\n/** Pull a URL's audio to a local file. Injectable for tests. */\nexport type AudioDownloader = (url: string) => Promise<AudioDownload>\n\nexport interface YtDlpWhisperFetcherOptions {\n readonly stt: SttPort\n /** Defaults to a yt-dlp subprocess downloader. */\n readonly download?: AudioDownloader\n /** Path to the yt-dlp binary (default: \"yt-dlp\" on PATH). */\n readonly ytDlpBin?: string\n /** Treat these hostnames as video (in addition to the YouTube/Vimeo set). */\n readonly extraVideoHosts?: readonly string[]\n /**\n * Skip videos longer than this many seconds, BEFORE downloading\n * (yt-dlp `--match-filter \"duration <= N\"`). A filtered video pulls no\n * bytes and resolves to `null` (skipped), so a stray 40-hour stream\n * can't blow up the batch. Omit for no cap — long media is segmented by\n * `ChunkedStt`, so length alone is not a blocker.\n */\n readonly maxDurationSec?: number\n /**\n * Read cookies from a local browser (`chrome`, `firefox`, `chrome:Profile 1`)\n * — passed to yt-dlp as `--cookies-from-browser`. Authenticated requests\n * sidestep YouTube's \"confirm you're not a bot\" rate-limit that public\n * fetches hit after a burst of downloads.\n */\n readonly cookiesFromBrowser?: string\n /** Path to a Netscape cookies.txt — passed to yt-dlp as `--cookies`. */\n readonly cookiesFile?: string\n}\n\nexport class YtDlpWhisperFetcher implements FetcherPort {\n private readonly stt: SttPort\n private readonly download: AudioDownloader\n private readonly extraHosts: ReadonlySet<string> | undefined\n\n constructor(opts: YtDlpWhisperFetcherOptions) {\n this.stt = opts.stt\n this.download =\n opts.download ??\n defaultYtDlpDownloader(opts.ytDlpBin ?? \"yt-dlp\", {\n maxDurationSec: opts.maxDurationSec,\n cookiesFromBrowser: opts.cookiesFromBrowser,\n cookiesFile: opts.cookiesFile,\n })\n this.extraHosts = opts.extraVideoHosts\n ? new Set(opts.extraVideoHosts)\n : undefined\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (!isVideoUrl(url, this.extraHosts)) return null // let a readability fetcher handle it\n\n let dl: AudioDownload\n try {\n dl = await this.download(url)\n } catch (e) {\n // Per-video download failure (geo-block, private, removed, or a\n // YouTube bot-check) → skip, don't abort the batch. Surface it so a\n // run that silently downloads nothing is diagnosable (e.g. the\n // bot-check that --cookies-from-browser fixes) rather than looking\n // like \"0 videos found\".\n process.stderr.write(`corpus: download failed for ${url} — skipped (${msg(e)})\\n`)\n return null\n }\n try {\n const t = await this.stt.transcribe(dl.audioPath)\n if (!t.text.trim()) return null\n return {\n title: dl.title || url,\n text: t.text,\n kind: \"video\",\n ...(t.language ?? dl.language\n ? { language: t.language ?? dl.language }\n : {}),\n via: \"transcription\",\n }\n } catch (e) {\n // A transcription failure on ONE video must not abort the whole\n // batch (the STT layer already retries transient blips). Skip it and\n // let the resumable importer retry on the next run — EXCEPT for an\n // auth/config error, which would fail every video, so we surface it\n // loudly rather than silently dropping the entire run.\n if (isAuthError(e)) throw e\n process.stderr.write(\n `corpus: transcription failed for ${url} — skipped (${msg(e)})\\n`\n )\n return null\n } finally {\n await dl.cleanup().catch(() => {})\n }\n }\n}\n\nfunction msg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n\n/** A 401/403 or \"api key\" error fails every video — abort, don't skip. */\nfunction isAuthError(e: unknown): boolean {\n const m = msg(e).toLowerCase()\n return (\n m.includes(\" 401\") ||\n m.includes(\" 403\") ||\n m.includes(\"unauthorized\") ||\n m.includes(\"forbidden\") ||\n m.includes(\"api key\") ||\n m.includes(\"api_key\")\n )\n}\n\n// ── Default yt-dlp subprocess downloader ────────────────────────────\n\nfunction defaultYtDlpDownloader(\n bin: string,\n opts?: {\n readonly maxDurationSec?: number\n readonly cookiesFromBrowser?: string\n readonly cookiesFile?: string\n }\n): AudioDownloader {\n return async (url: string): Promise<AudioDownload> => {\n const dir = await mkdtemp(join(tmpdir(), \"corpus-ytdlp-\"))\n const cleanup = () => rm(dir, { recursive: true, force: true })\n try {\n // `--match-filter` is evaluated before the media is fetched, so an\n // over-length video pulls zero bytes — it just yields no output file,\n // which the caller treats as a skip.\n const durationGuard =\n opts?.maxDurationSec && opts.maxDurationSec > 0\n ? [\"--match-filter\", `duration <= ${Math.floor(opts.maxDurationSec)}`]\n : []\n // Authenticate via local browser cookies (or a cookies.txt) to dodge\n // YouTube's bot-check rate-limit on bursts of public downloads.\n const cookieArgs = opts?.cookiesFromBrowser\n ? [\"--cookies-from-browser\", opts.cookiesFromBrowser]\n : opts?.cookiesFile\n ? [\"--cookies\", opts.cookiesFile]\n : []\n await execFileAsync(\n bin,\n [\n \"-f\", \"bestaudio\",\n \"-x\", \"--audio-format\", \"mp3\", \"--audio-quality\", \"64K\",\n \"--no-playlist\", \"--no-progress\",\n ...durationGuard,\n ...cookieArgs,\n \"--write-info-json\",\n \"-o\", join(dir, \"track.%(ext)s\"),\n url,\n ],\n { maxBuffer: 16 * 1024 * 1024 }\n )\n const files = await readdir(dir)\n const audio = files.find(f => f === \"track.mp3\") ??\n files.find(f => /\\.(mp3|m4a|opus|webm|ogg|wav)$/i.test(f))\n if (!audio) throw new Error(\"yt-dlp produced no audio file\")\n\n let title = url\n let language: string | undefined\n const infoName = files.find(f => f.endsWith(\".info.json\"))\n if (infoName) {\n try {\n const info = YTDLP_INFO.parse(\n JSON.parse(await readFile(join(dir, infoName), \"utf-8\"))\n )\n if (info.title) title = info.title\n if (info.language) language = info.language\n } catch {\n // info json optional — fall back to url as title\n }\n }\n return {\n audioPath: join(dir, audio),\n title,\n ...(language ? { language } : {}),\n cleanup,\n }\n } catch (e) {\n await cleanup().catch(() => {})\n throw e\n }\n }\n}\n","/**\n * SttPort — speech-to-text boundary the YtDlpWhisperFetcher consumes.\n *\n * Keeps the fetcher pure of any STT-vendor specifics: it hands a local\n * audio file path to `transcribe()` and gets back text. The CLI wires a\n * concrete impl (OpenAI Whisper here; swap for a self-hosted whisper.cpp\n * or Deepgram impl without touching the fetcher).\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { basename } from \"node:path\"\nimport { normalizeLanguageTag } from \"@agentproto/corpus\"\nimport { z } from \"zod\"\n\n/** The Whisper verbose_json fields we read. */\nconst WHISPER_RESPONSE = z\n .object({ text: z.string().optional(), language: z.string().optional() })\n .loose()\n\nexport interface Transcript {\n readonly text: string\n /** BCP-47 language, when the engine detects it. */\n readonly language?: string\n}\n\nexport interface SttPort {\n transcribe(audioPath: string): Promise<Transcript>\n}\n\nconst WHISPER_MAX_BYTES = 25 * 1024 * 1024 // OpenAI hard cap\n\nexport interface OpenAiWhisperSttOptions {\n readonly apiKey: string\n /** Default \"whisper-1\". */\n readonly model?: string\n /** Override base URL (proxy / Azure). Default OpenAI. */\n readonly baseUrl?: string\n}\n\n/**\n * OpenAI Whisper STT. Posts the audio file to /audio/transcriptions with\n * `response_format=verbose_json` so we recover the detected language.\n *\n * Files above OpenAI's 25 MB cap throw a clear error — the caller should\n * have downloaded at a lower bitrate (the fetcher uses 64 kbps mono) or\n * chunk long media. We surface the size rather than letting the API 413.\n */\nexport class OpenAiWhisperStt implements SttPort {\n private readonly apiKey: string\n private readonly model: string\n private readonly baseUrl: string\n\n constructor(opts: OpenAiWhisperSttOptions) {\n this.apiKey = opts.apiKey\n this.model = opts.model ?? \"whisper-1\"\n this.baseUrl = (opts.baseUrl ?? \"https://api.openai.com/v1\").replace(/\\/+$/, \"\")\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const bytes = await readFile(audioPath)\n if (bytes.byteLength > WHISPER_MAX_BYTES) {\n throw new Error(\n `audio ${basename(audioPath)} is ${(bytes.byteLength / 1024 / 1024).toFixed(1)} MB — over Whisper's 25 MB cap. Lower the bitrate or chunk the media.`\n )\n }\n const form = new FormData()\n form.append(\"file\", new Blob([bytes]), basename(audioPath))\n form.append(\"model\", this.model)\n form.append(\"response_format\", \"verbose_json\")\n\n const res = await this.postWithRetry(form)\n if (!res.ok) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`Whisper STT ${res.status} ${res.statusText}: ${body.slice(0, 200)}`)\n }\n const data = WHISPER_RESPONSE.parse(await res.json())\n const language = normalizeLanguageTag(data.language)\n return {\n text: (data.text ?? \"\").trim(),\n ...(language ? { language } : {}),\n }\n }\n\n /**\n * POST the audio with bounded retry. Transcribing a long talk fans out\n * into many segment uploads (see ChunkedStt), so a single transient\n * network blip (\"fetch failed\") or a 429 / 5xx must not abort the whole\n * batch. Network errors and retryable statuses back off and retry;\n * client errors (401 auth, 400 bad request) return immediately so a real\n * misconfiguration still surfaces loudly.\n */\n private async postWithRetry(form: FormData, attempts = 4): Promise<Response> {\n const url = `${this.baseUrl}/audio/transcriptions`\n let lastErr: unknown\n for (let i = 0; i < attempts; i++) {\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${this.apiKey}` },\n body: form,\n })\n if (res.status !== 429 && res.status < 500) return res\n lastErr = new Error(`Whisper STT ${res.status} ${res.statusText}`)\n } catch (e) {\n lastErr = e // network-level failure (undici \"fetch failed\", reset, timeout)\n }\n if (i < attempts - 1) await delay(500 * 2 ** i) // 0.5s, 1s, 2s\n }\n throw lastErr instanceof Error ? lastErr : new Error(String(lastErr))\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","/**\n * AssemblyAiStt — a diarizing SttPort. Where OpenAiWhisperStt returns a\n * flat transcript, this returns SPEAKER-LABELLED text (`Speaker A: … /\n * Speaker B: …`) via AssemblyAI's `speaker_labels`. Use it ad-hoc for\n * multi-speaker videos (interviews, mock interviews, panels, \"day in the\n * life\") where the content only makes sense if you know who said what.\n *\n * Same `SttPort` contract — the diarized layout lives in `text`, so it\n * drops straight into YtDlpWhisperFetcher without any other change.\n *\n * Flow: upload audio → create transcript(speaker_labels) → poll → format\n * utterances. No 25 MB cap (unlike Whisper), so long videos are fine; the\n * trade-off is latency (~a third of audio duration) — slower than Whisper.\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { z } from \"zod\"\nimport type { SttPort, Transcript } from \"./stt.port.js\"\n\nexport interface AssemblyAiSttOptions {\n readonly apiKey: string\n readonly baseUrl?: string\n readonly pollIntervalMs?: number\n readonly maxWaitMs?: number\n readonly sleep?: (ms: number) => Promise<void>\n}\n\nconst UPLOAD_RESPONSE = z.object({ upload_url: z.string() })\n\nconst AAI_TRANSCRIPT = z\n .object({\n id: z.string(),\n status: z.enum([\"queued\", \"processing\", \"completed\", \"error\"]),\n text: z.string().optional(),\n language_code: z.string().optional(),\n error: z.string().optional(),\n utterances: z\n .array(z.object({ speaker: z.string(), text: z.string() }))\n .nullish(),\n })\n .loose()\n\ntype AaiTranscript = z.infer<typeof AAI_TRANSCRIPT>\n\nexport class AssemblyAiStt implements SttPort {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly pollIntervalMs: number\n private readonly maxWaitMs: number\n private readonly sleep: (ms: number) => Promise<void>\n\n constructor(opts: AssemblyAiSttOptions) {\n this.apiKey = opts.apiKey\n this.baseUrl = (opts.baseUrl ?? \"https://api.assemblyai.com/v2\").replace(/\\/+$/, \"\")\n this.pollIntervalMs = opts.pollIntervalMs ?? 3000\n this.maxWaitMs = opts.maxWaitMs ?? 15 * 60 * 1000\n this.sleep = opts.sleep ?? ((ms: number) => new Promise(r => setTimeout(r, ms)))\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const bytes = await readFile(audioPath)\n\n // 1. Upload the audio bytes.\n const up = await fetch(`${this.baseUrl}/upload`, {\n method: \"POST\",\n headers: { authorization: this.apiKey, \"content-type\": \"application/octet-stream\" },\n body: bytes,\n })\n if (!up.ok) throw new Error(`AssemblyAI upload ${up.status}: ${(await up.text()).slice(0, 200)}`)\n const { upload_url } = UPLOAD_RESPONSE.parse(await up.json())\n\n // 2. Create a diarized transcript job.\n const created = await this.post(\"/transcript\", {\n audio_url: upload_url,\n speaker_labels: true,\n language_detection: true,\n })\n const id = created.id\n\n // 3. Poll until done.\n const deadline = this.maxWaitMs\n let waited = 0\n let job = created\n while (job.status !== \"completed\" && job.status !== \"error\") {\n if (waited >= deadline) throw new Error(`AssemblyAI transcript ${id} timed out after ${deadline} ms`)\n await this.sleep(this.pollIntervalMs)\n waited += this.pollIntervalMs\n job = await this.get(`/transcript/${id}`)\n }\n if (job.status === \"error\") throw new Error(`AssemblyAI transcript failed: ${job.error ?? \"unknown\"}`)\n\n return {\n text: formatDiarized(job),\n ...(job.language_code ? { language: job.language_code } : {}),\n }\n }\n\n private async post(path: string, body: unknown): Promise<AaiTranscript> {\n const r = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: { authorization: this.apiKey, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n })\n if (!r.ok) throw new Error(`AssemblyAI POST ${path} ${r.status}: ${(await r.text()).slice(0, 200)}`)\n return AAI_TRANSCRIPT.parse(await r.json())\n }\n\n private async get(path: string): Promise<AaiTranscript> {\n const r = await fetch(`${this.baseUrl}${path}`, { headers: { authorization: this.apiKey } })\n if (!r.ok) throw new Error(`AssemblyAI GET ${path} ${r.status}: ${(await r.text()).slice(0, 200)}`)\n return AAI_TRANSCRIPT.parse(await r.json())\n }\n}\n\n/** Join utterances as `Speaker A: …` blocks; fall back to flat text. */\nfunction formatDiarized(job: AaiTranscript): string {\n if (job.utterances && job.utterances.length > 0) {\n return job.utterances\n .map(u => `Speaker ${u.speaker}: ${u.text.trim()}`)\n .join(\"\\n\\n\")\n .trim()\n }\n return (job.text ?? \"\").trim()\n}\n","/**\n * ChunkedStt — a SttPort decorator that makes a capped engine handle\n * arbitrarily long audio. Whisper rejects files over 25 MB, so a\n * multi-hour talk (full course, masterclass, panel) can't be sent in one\n * request. This wrapper splits oversized audio into time segments with\n * ffmpeg, transcribes each through the wrapped engine, and concatenates\n * the text back into a single transcript.\n *\n * transcribe(path) → ≤cap ? base.transcribe(path)\n * : ffmpeg segment → base.transcribe(eachPart) → join\n *\n * The cap is a vendor concern (Whisper's limit), so handling it belongs in\n * the STT layer rather than the fetcher — the fetcher stays pure and the\n * concrete `OpenAiWhisperStt` stays a single-request transcriber. Splitting\n * is injected as `split` so the decorator is unit-testable with a fake\n * splitter + fake base engine — no ffmpeg, no network.\n *\n * Segmenting uses `-c copy` (stream copy, no re-encode): fast, and each\n * segment is a self-contained valid file. At the fetcher's 64 kbps a 20-min\n * segment is ~9.6 MB — comfortably under the 25 MB cap with margin for\n * VBR drift.\n */\n\nimport { execFile } from \"node:child_process\"\nimport { mkdtemp, readdir, rm, stat } from \"node:fs/promises\"\nimport { tmpdir } from \"node:os\"\nimport { extname, join } from \"node:path\"\nimport { promisify } from \"node:util\"\nimport type { SttPort, Transcript } from \"./stt.port.js\"\n\nconst execFileAsync = promisify(execFile)\n\n/**\n * Split a local audio file into ≤`segmentSeconds` parts inside `outDir`,\n * returning the segment paths in playback order. Injectable for tests.\n */\nexport type AudioSplitter = (\n audioPath: string,\n segmentSeconds: number,\n outDir: string\n) => Promise<string[]>\n\nexport interface ChunkedSttOptions {\n /** The engine each (sub-cap) part is transcribed through. */\n readonly base: SttPort\n /**\n * Split anything strictly larger than this. Default 24 MB — just under\n * Whisper's 25 MB hard cap so VBR drift never pushes a part over.\n */\n readonly maxBytes?: number\n /** Segment length when splitting. Default 1200 s (20 min). */\n readonly segmentSeconds?: number\n /** Defaults to an ffmpeg segment-muxer splitter. */\n readonly split?: AudioSplitter\n /** Path to the ffmpeg binary (default: \"ffmpeg\" on PATH). */\n readonly ffmpegBin?: string\n}\n\nconst DEFAULT_MAX_BYTES = 24 * 1024 * 1024\nconst DEFAULT_SEGMENT_SECONDS = 1200\n\nexport class ChunkedStt implements SttPort {\n private readonly base: SttPort\n private readonly maxBytes: number\n private readonly segmentSeconds: number\n private readonly split: AudioSplitter\n\n constructor(opts: ChunkedSttOptions) {\n this.base = opts.base\n this.maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES\n this.segmentSeconds = opts.segmentSeconds ?? DEFAULT_SEGMENT_SECONDS\n this.split = opts.split ?? defaultFfmpegSplitter(opts.ffmpegBin ?? \"ffmpeg\")\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const { size } = await stat(audioPath)\n if (size <= this.maxBytes) return this.base.transcribe(audioPath)\n\n const dir = await mkdtemp(join(tmpdir(), \"corpus-stt-chunk-\"))\n try {\n const parts = await this.split(audioPath, this.segmentSeconds, dir)\n if (parts.length === 0) {\n // Splitter produced nothing — fall back to a single attempt so the\n // base engine surfaces its own (clear) over-cap error rather than\n // us silently dropping the source.\n return this.base.transcribe(audioPath)\n }\n const texts: string[] = []\n let language: string | undefined\n let failed = 0\n let firstErr: unknown\n for (const part of parts) {\n try {\n const t = await this.base.transcribe(part)\n if (t.text.trim()) texts.push(t.text.trim())\n language ??= t.language\n } catch (e) {\n // One segment failing (after the base engine's own retries) must\n // not discard the whole multi-hour transcript — keep the rest.\n failed++\n firstErr ??= e\n }\n }\n // Every segment failing usually means a systemic error (auth, quota) —\n // rethrow so the caller can surface/skip it, rather than silently\n // writing an empty transcript.\n if (texts.length === 0) {\n throw firstErr ?? new Error(\"all audio segments failed transcription\")\n }\n if (failed > 0) {\n process.stderr.write(\n `corpus: ${failed}/${parts.length} audio segments failed — partial transcript\\n`\n )\n }\n return {\n text: texts.join(\"\\n\\n\"),\n ...(language ? { language } : {}),\n }\n } finally {\n await rm(dir, { recursive: true, force: true }).catch(() => {})\n }\n }\n}\n\n// ── Default ffmpeg segment-muxer splitter ───────────────────────────\n\nfunction defaultFfmpegSplitter(bin: string): AudioSplitter {\n return async (audioPath, segmentSeconds, outDir) => {\n const ext = extname(audioPath) || \".mp3\"\n await execFileAsync(\n bin,\n [\n \"-hide_banner\", \"-loglevel\", \"error\",\n \"-i\", audioPath,\n \"-f\", \"segment\",\n \"-segment_time\", String(segmentSeconds),\n \"-c\", \"copy\",\n join(outDir, `part%03d${ext}`),\n ],\n { maxBuffer: 16 * 1024 * 1024 }\n )\n // ffmpeg names parts part000, part001, … — lexical sort = playback order.\n const files = (await readdir(outDir))\n .filter(f => f.startsWith(\"part\") && f.endsWith(ext))\n .sort()\n return files.map(f => join(outDir, f))\n }\n}\n","/**\n * CompositeFetcher — tries child fetchers in order, first non-null wins.\n *\n * Lets the importer route by URL without itself knowing the routing:\n * new CompositeFetcher([ ytDlpWhisper, browserReadability ])\n * sends videos to whisper (the readability one returns null for them is\n * never reached because whisper handled it) and everything else falls\n * through to readability. A child that THROWS aborts (hard failure);\n * a child that returns null means \"not mine, try the next\".\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\n\nexport class CompositeFetcher implements FetcherPort {\n private readonly children: readonly FetcherPort[]\n\n constructor(children: readonly FetcherPort[]) {\n this.children = children\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n for (const child of this.children) {\n const result = await child.fetch(url)\n if (result) return result\n }\n return null\n }\n}\n","/**\n * ThrottleFetcher — wraps a FetcherPort to enforce a minimum interval\n * between fetches (rate limiting). The importer already calls fetch\n * serially (one URL at a time), so this adds the *pacing* that protects\n * against YouTube anti-abuse blocks and Whisper RPM limits when running\n * a large batch.\n *\n * `now` + `sleep` are injectable so the throttle is unit-testable without\n * real timers.\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\n\nexport interface ThrottleFetcherOptions {\n /** Minimum milliseconds between the START of consecutive fetches. */\n readonly minIntervalMs: number\n readonly now?: () => number\n readonly sleep?: (ms: number) => Promise<void>\n}\n\nexport class ThrottleFetcher implements FetcherPort {\n private readonly inner: FetcherPort\n private readonly minIntervalMs: number\n private readonly now: () => number\n private readonly sleep: (ms: number) => Promise<void>\n private lastStart = 0\n private started = false\n\n constructor(inner: FetcherPort, opts: ThrottleFetcherOptions) {\n this.inner = inner\n this.minIntervalMs = Math.max(0, opts.minIntervalMs)\n this.now = opts.now ?? (() => Date.now())\n this.sleep =\n opts.sleep ?? ((ms: number) => new Promise(r => setTimeout(r, ms)))\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (this.minIntervalMs > 0 && this.started) {\n const wait = this.minIntervalMs - (this.now() - this.lastStart)\n if (wait > 0) await this.sleep(wait)\n }\n this.started = true\n this.lastStart = this.now()\n return this.inner.fetch(url)\n }\n}\n","/**\n * HttpReadabilityFetcher — a browser-free FetcherPort for articles:\n * plain `fetch` + a lightweight readability extraction (prefer\n * <article>/<main>, strip chrome). Validated to pull ~35k chars from a\n * real corpus article. Returns `null` for non-HTML or empty bodies so a\n * video or authed-browser fetcher can take those.\n *\n * No JS execution — so it won't get SPA-only content; for login-walled\n * or JS-rendered pages, compose a BrowserMcpFetcher ahead of/after this.\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\nexport interface HttpReadabilityFetcherOptions {\n readonly userAgent?: string\n readonly maxChars?: number\n}\n\nconst DEFAULT_UA =\n \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0 Safari/537.36\"\n\nexport class HttpReadabilityFetcher implements FetcherPort {\n private readonly ua: string\n private readonly maxChars: number\n\n constructor(opts: HttpReadabilityFetcherOptions = {}) {\n this.ua = opts.userAgent ?? DEFAULT_UA\n this.maxChars = opts.maxChars ?? 200_000\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n // Video URLs belong to the transcription fetcher. Never scrape a\n // watch page here — a failed transcription must skip, not fall\n // through to YouTube's page chrome.\n if (isVideoUrl(url)) return null\n\n let res: Response\n try {\n res = await fetch(url, {\n headers: { \"user-agent\": this.ua, \"accept-language\": \"en,fr;q=0.8\" },\n redirect: \"follow\",\n })\n } catch {\n return null\n }\n if (!res.ok) return null\n const ct = res.headers.get(\"content-type\") ?? \"\"\n if (!ct.includes(\"text/html\") && !ct.includes(\"application/xhtml\")) return null\n\n const html = await res.text()\n const title = decodeEntities(\n (html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i)?.[1] ?? \"\").trim()\n )\n const lang = html.match(/<html[^>]*\\blang=[\"']?([a-zA-Z-]+)/i)?.[1]\n const text = extractReadable(html).slice(0, this.maxChars)\n if (!text.trim()) return null\n\n return {\n title: title || url,\n text,\n kind: \"article\",\n ...(lang ? { language: lang } : {}),\n via: \"readability\",\n }\n }\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nfunction extractReadable(html: string): string {\n // Prefer the main content region; fall back to <body>.\n const region =\n html.match(/<article[\\s\\S]*?<\\/article>/i)?.[0] ??\n html.match(/<main[\\s\\S]*?<\\/main>/i)?.[0] ??\n html.match(/<body[\\s\\S]*?<\\/body>/i)?.[0] ??\n html\n return decodeEntities(\n region\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<(nav|header|footer|aside|form)[\\s\\S]*?<\\/\\1>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/[ \\t]+/g, \" \")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n ).trim()\n}\n\nfunction decodeEntities(s: string): string {\n return s\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&#(\\d+);/g, (_, n) => String.fromCharCode(Number(n)))\n}\n","/**\n * AnthropicDistiller — a DistillPort backed by Claude over the Messages API.\n * Extracts refined AIP-10 items (principle/pattern/critique/summary/example)\n * from a raw source. Returns self-contained insights, not quote dumps.\n *\n * Hand-rolled over the HTTP API (no SDK dep), mirroring the other corpus-cli\n * port adapters. Prompt + parse are the shared `distill-prompt` core; this\n * adapter owns only the metered-API transport. For the subscription-billed\n * alternative see CliAgentDistiller + the `claude-code` engine.\n */\n\nimport { z } from \"zod\"\nimport type { DistillPort, DistillInput, DistilledItem } from \"@agentproto/corpus\"\nimport { buildDistillPrompt, parseItems } from \"./distill-prompt.js\"\nimport type { DistillUsage } from \"./usage-telemetry.js\"\n\n/** The Messages API response — text content blocks plus model + token usage. */\nconst ANTHROPIC_RESPONSE = z\n .object({\n model: z.string().optional(),\n content: z\n .array(z.object({ type: z.string(), text: z.string().optional() }).loose())\n .optional(),\n usage: z\n .object({ input_tokens: z.number(), output_tokens: z.number() })\n .loose()\n .optional(),\n })\n .loose()\n\nexport interface AnthropicDistillerOptions {\n readonly apiKey: string\n /** Default a current Claude model id. */\n readonly model?: string\n readonly baseUrl?: string\n /** Max refined items to extract per source. */\n readonly maxItems?: number\n /** Optional sink for per-call token usage (cost + Langfuse export). */\n readonly onUsage?: (usage: DistillUsage) => void\n}\n\nexport class AnthropicDistiller implements DistillPort {\n private readonly apiKey: string\n private readonly model: string\n private readonly baseUrl: string\n private readonly maxItems: number\n private readonly onUsage: ((usage: DistillUsage) => void) | undefined\n\n constructor(opts: AnthropicDistillerOptions) {\n this.apiKey = opts.apiKey\n this.model = opts.model ?? \"claude-sonnet-4-6\"\n this.baseUrl = (opts.baseUrl ?? \"https://api.anthropic.com/v1\").replace(/\\/+$/, \"\")\n this.maxItems = opts.maxItems ?? 8\n this.onUsage = opts.onUsage\n }\n\n async distill(input: DistillInput): Promise<readonly DistilledItem[]> {\n const prompt = buildDistillPrompt(input, this.maxItems)\n const startedAt = new Date().toISOString()\n const res = await fetch(`${this.baseUrl}/messages`, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 4096,\n messages: [{ role: \"user\", content: prompt }],\n }),\n })\n if (!res.ok) {\n throw new Error(`Anthropic distill ${res.status}: ${(await res.text()).slice(0, 200)}`)\n }\n const parsed = ANTHROPIC_RESPONSE.safeParse(await res.json())\n const text = parsed.success\n ? (parsed.data.content ?? []).find(c => c.type === \"text\")?.text ?? \"\"\n : \"\"\n if (parsed.success && parsed.data.usage && this.onUsage) {\n this.onUsage({\n model: parsed.data.model ?? this.model,\n inputTokens: parsed.data.usage.input_tokens,\n outputTokens: parsed.data.usage.output_tokens,\n label: input.title,\n startedAt,\n endedAt: new Date().toISOString(),\n })\n }\n return parseItems(text)\n }\n}\n","/**\n * CliAgentDistiller — a DistillPort backed by any local agent CLI running in\n * one-shot mode (prompt on stdin, response on stdout). The transport is generic;\n * the per-CLI specifics (command, argv, output parse) come from a CliEngine\n * descriptor, so claude / gemini / goose / … are one descriptor each.\n *\n * Same DistillPort contract + same prompt/parse as AnthropicDistiller (both use\n * the shared `distill-prompt` core), so the two are drop-in swappable behind the\n * `corpus distill --engine` flag.\n *\n * TRADE-OFFS vs the metered API:\n * - Subscription rate caps — slower for big batches; pace with --throttle and\n * let the runner skip+retry on non-zero exits.\n * - Output is CLI text, not API structured output — same tolerant parse.\n * - One process spawn per source — higher per-call overhead than fetch().\n */\n\nimport { tmpdir } from \"node:os\"\nimport { spawnWithStdin } from \"@agentproto/cli-exec\"\nimport type { DistillPort, DistillInput, DistilledItem } from \"@agentproto/corpus\"\nimport { buildDistillPrompt, parseItems } from \"./distill-prompt.js\"\nimport type { CliEngine } from \"./cli-engines.js\"\n\nexport interface CliAgentDistillerOptions {\n /** The CLI engine descriptor (command + argv + output parse). */\n readonly engine: CliEngine\n /** Optional model override passed to the engine, e.g. \"haiku\" to spend less quota. */\n readonly model?: string\n /** Max refined items per source (feeds the shared prompt). */\n readonly maxItems?: number\n /** Hard per-source timeout; kills a wedged CLI call. Default 120s. */\n readonly timeoutMs?: number\n /** Working dir. Default os.tmpdir() — neutral, no project CLAUDE.md / repo. */\n readonly cwd?: string\n}\n\nexport class CliAgentDistiller implements DistillPort {\n private readonly engine: CliEngine\n private readonly model?: string\n private readonly maxItems: number\n private readonly timeoutMs: number\n private readonly cwd: string\n\n constructor(opts: CliAgentDistillerOptions) {\n this.engine = opts.engine\n this.model = opts.model\n this.maxItems = opts.maxItems ?? 8\n this.timeoutMs = opts.timeoutMs ?? 120_000\n this.cwd = opts.cwd ?? tmpdir()\n }\n\n async distill(input: DistillInput): Promise<readonly DistilledItem[]> {\n const prompt = buildDistillPrompt(input, this.maxItems)\n // A non-zero exit (often a rate cap) rejects here; the runner skips + retries\n // the source on the next pass.\n const stdout = await spawnWithStdin({\n command: this.engine.command,\n args: this.engine.buildArgs({ ...(this.model ? { model: this.model } : {}) }),\n stdin: prompt,\n cwd: this.cwd,\n timeoutMs: this.timeoutMs,\n })\n const text = this.engine.parseOutput(stdout) ?? stdout\n return parseItems(text)\n }\n}\n","/**\n * CLI agent engines — descriptors for distilling through a local agent CLI in\n * headless one-shot mode (prompt on stdin, response on stdout), instead of a\n * metered API. Each engine declares its `command`, how to `buildArgs` (model\n * injection, output format, tool/MCP lockdown), and how to `parseOutput` of the\n * captured stdout into the model's text.\n *\n * WHY: distillation is a high-volume batch (hundreds of sources × ~8 items). On\n * the API that bills per token; routed through an authenticated agent-CLI\n * subscription (e.g. Claude Max) it draws on a flat monthly plan — ~$0 marginal\n * cost. Same DistillPort contract + same prompt/parse, swappable transport.\n *\n * Engines register full descriptors and are dispatched by id (no `engineId ===`\n * branching at the call site). Add a CLI by adding a descriptor below; gemini /\n * goose / codex etc. each become one entry.\n */\n\nimport { parseClaudeJsonOutput } from \"@agentproto/cli-exec\"\n\n/** What a CLI engine needs to drive one stdin→stdout completion. */\nexport interface CliEngine {\n /** Stable id, used by `corpus distill --engine <id>`. */\n readonly id: string\n /** Whether this engine bills a subscription (no API key needed). Surfaced in help. */\n readonly subscriptionBilled: boolean\n /** Executable to invoke — must be on PATH and logged in. */\n readonly command: string\n /** Build the argv for one completion. The prompt is fed over stdin, not argv. */\n buildArgs(opts: { readonly model?: string }): string[]\n /** Extract the model's text from captured stdout; null → fall back to raw stdout. */\n parseOutput(stdout: string): string | null\n}\n\n/**\n * Claude Code in headless print mode, billed against the logged-in subscription.\n *\n * Flags (verified against `claude -p --help`):\n * -p non-interactive print mode\n * --output-format json single-result JSON envelope ({ result, is_error, … })\n * --strict-mcp-config ignore all MCP servers (no --mcp-config ⇒ none load)\n * --model <m> optional alias (\"haiku\"/\"sonnet\") or full id\n * Deliberately NOT --bare: that flag forces ANTHROPIC_API_KEY auth and never\n * reads OAuth/keychain — which would bypass the subscription we're here to use.\n * Pair with cwd=os.tmpdir() (CliAgentDistiller default) so no project CLAUDE.md\n * is auto-discovered and the agent can't wander a repo.\n */\nconst CLAUDE_CODE: CliEngine = {\n id: \"claude-code\",\n subscriptionBilled: true,\n command: \"claude\",\n buildArgs: ({ model }) => [\n \"-p\",\n \"--output-format\",\n \"json\",\n \"--strict-mcp-config\",\n ...(model ? [\"--model\", model] : []),\n ],\n parseOutput: parseClaudeJsonOutput,\n}\n\n/** Registry of CLI engines, keyed by id. */\nexport const CLI_ENGINES: Readonly<Record<string, CliEngine>> = {\n [CLAUDE_CODE.id]: CLAUDE_CODE,\n}\n","/**\n * Minimal streamable-HTTP MCP client (host-agnostic). Used by config-driven\n * sinks/sources to call ANY MCP server's tools — the corpus never names a\n * specific host; the endpoint + tool come from a manifest.\n *\n * Handles both JSON and SSE (`text/event-stream`) responses, optional\n * `Mcp-Session-Id`, and the initialize handshake.\n */\n\nimport { z } from \"zod\"\n\n/** JSON-RPC envelope (result/error opaque). */\nconst RPC_RESPONSE = z\n .object({ result: z.unknown().optional(), error: z.unknown().optional() })\n .loose()\n\n/** A JSON-RPC message with an id (SSE-delivered responses). */\nconst RPC_MESSAGE = z\n .object({\n id: z.number().optional(),\n result: z.unknown().optional(),\n error: z.unknown().optional(),\n })\n .loose()\n\n/** An MCP `tools/call` result (content blocks left opaque). */\nconst CALL_RESULT = z\n .object({\n content: z.unknown().optional(),\n structuredContent: z.unknown().optional(),\n isError: z.boolean().optional(),\n })\n .loose()\n\nexport interface McpClientLike {\n callTool(name: string, args: Record<string, unknown>): Promise<{\n content?: unknown\n structuredContent?: unknown\n isError?: boolean\n }>\n}\n\nexport interface ConnectMcpHttpOptions {\n readonly endpoint: string\n readonly headers?: Record<string, string>\n readonly protocolVersion?: string\n /** \"streamable-http\" (POST, default) or \"sse\" (legacy GET stream + POST messages). */\n readonly transport?: \"streamable-http\" | \"sse\"\n}\n\nexport async function connectMcpHttp(\n opts: ConnectMcpHttpOptions\n): Promise<McpClientLike> {\n if (opts.transport === \"sse\") {\n const sse = new SseMcpClient(opts)\n await sse.connect()\n return sse\n }\n const client = new StreamableHttpMcpClient(opts)\n await client.initialize()\n return client\n}\n\nclass StreamableHttpMcpClient implements McpClientLike {\n private id = 0\n private sessionId: string | undefined\n private readonly endpoint: string\n private readonly headers: Record<string, string>\n private readonly protocolVersion: string\n\n constructor(opts: ConnectMcpHttpOptions) {\n this.endpoint = opts.endpoint\n this.headers = opts.headers ?? {}\n this.protocolVersion = opts.protocolVersion ?? \"2025-06-18\"\n }\n\n async initialize(): Promise<void> {\n const res = await this.rpc({\n jsonrpc: \"2.0\",\n id: ++this.id,\n method: \"initialize\",\n params: {\n protocolVersion: this.protocolVersion,\n capabilities: {},\n clientInfo: { name: \"corpus-cli\", version: \"0.1.0\" },\n },\n })\n await this.rpc({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} }, false)\n if (res?.error) throw new Error(`initialize failed: ${JSON.stringify(res.error)}`)\n }\n\n async callTool(name: string, args: Record<string, unknown>) {\n const res = await this.rpc({\n jsonrpc: \"2.0\",\n id: ++this.id,\n method: \"tools/call\",\n params: { name, arguments: args },\n })\n if (res?.error) throw new Error(`tools/call ${name}: ${JSON.stringify(res.error)}`)\n const parsed = CALL_RESULT.safeParse(res?.result ?? {})\n return parsed.success ? parsed.data : {}\n }\n\n private async rpc(\n body: Record<string, unknown>,\n expectResponse = true\n ): Promise<{ result?: unknown; error?: unknown } | null> {\n const res = await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json, text/event-stream\",\n ...(this.sessionId ? { \"mcp-session-id\": this.sessionId } : {}),\n ...this.headers,\n },\n body: JSON.stringify(body),\n })\n const sid = res.headers.get(\"mcp-session-id\")\n if (sid) this.sessionId = sid\n if (!expectResponse) return null\n if (!res.ok) throw new Error(`MCP HTTP ${res.status} ${res.statusText}`)\n return parseRpc(await res.text(), res.headers.get(\"content-type\"))\n }\n}\n\n/**\n * Legacy HTTP+SSE MCP transport: GET the stream → first `endpoint` event gives\n * the POST URL → POST JSON-RPC requests there; responses arrive back on the\n * stream (correlated by id). Used for servers like Guilde's `/guilde/mcp/sse`.\n */\nclass SseMcpClient implements McpClientLike {\n private id = 0\n private messagesUrl: string | undefined\n private readonly pending = new Map<number, (msg: { result?: unknown; error?: unknown }) => void>()\n private readyResolve!: () => void\n private readonly ready = new Promise<void>(r => (this.readyResolve = r))\n private readonly base: URL\n\n constructor(private readonly opts: ConnectMcpHttpOptions) {\n this.base = new URL(opts.endpoint)\n }\n\n async connect(): Promise<void> {\n const res = await fetch(this.opts.endpoint, {\n headers: { accept: \"text/event-stream\", ...(this.opts.headers ?? {}) },\n })\n if (!res.ok || !res.body) throw new Error(`SSE connect ${res.status} ${res.statusText}`)\n void this.readLoop(res.body.getReader())\n // Wait for the endpoint event (POST url), then initialize.\n await withTimeout(this.ready, 10_000, \"SSE endpoint event\")\n const init = await this.send(\"initialize\", {\n protocolVersion: this.opts.protocolVersion ?? \"2025-06-18\",\n capabilities: {},\n clientInfo: { name: \"corpus-cli\", version: \"0.1.0\" },\n })\n if (init?.error) throw new Error(`initialize failed: ${JSON.stringify(init.error)}`)\n await this.post({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} })\n }\n\n async callTool(name: string, args: Record<string, unknown>) {\n const res = await this.send(\"tools/call\", { name, arguments: args })\n if (res?.error) throw new Error(`tools/call ${name}: ${JSON.stringify(res.error)}`)\n const parsed = CALL_RESULT.safeParse(res?.result ?? {})\n return parsed.success ? parsed.data : {}\n }\n\n private async send(method: string, params: unknown) {\n const id = ++this.id\n const wait = new Promise<{ result?: unknown; error?: unknown }>(resolve => this.pending.set(id, resolve))\n await this.post({ jsonrpc: \"2.0\", id, method, params })\n return withTimeout(wait, 60_000, `${method} response`)\n }\n\n private async post(body: Record<string, unknown>): Promise<void> {\n if (!this.messagesUrl) throw new Error(\"SSE messages endpoint not ready\")\n const res = await fetch(this.messagesUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...(this.opts.headers ?? {}) },\n body: JSON.stringify(body),\n })\n if (!res.ok && res.status !== 202) throw new Error(`SSE POST ${res.status}`)\n }\n\n private async readLoop(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n const dec = new TextDecoder()\n let buf = \"\"\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let nl: number\n while ((nl = buf.indexOf(\"\\n\\n\")) >= 0) {\n const raw = buf.slice(0, nl)\n buf = buf.slice(nl + 2)\n this.handleEvent(raw)\n }\n }\n }\n\n private handleEvent(raw: string): void {\n let event = \"message\"\n const data: string[] = []\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) event = line.slice(6).trim()\n else if (line.startsWith(\"data:\")) data.push(line.slice(5).trim())\n }\n const payload = data.join(\"\\n\")\n if (event === \"endpoint\") {\n this.messagesUrl = new URL(payload, this.base).toString()\n this.readyResolve()\n return\n }\n if (!payload) return\n try {\n const parsed = RPC_MESSAGE.safeParse(JSON.parse(payload))\n if (!parsed.success) return\n const msg = parsed.data\n if (typeof msg.id === \"number\" && this.pending.has(msg.id)) {\n this.pending.get(msg.id)!(msg)\n this.pending.delete(msg.id)\n }\n } catch {\n /* skip non-JSON */\n }\n }\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, what: string): Promise<T> {\n return Promise.race([\n p,\n new Promise<T>((_, rej) => setTimeout(() => rej(new Error(`timeout waiting for ${what}`)), ms)),\n ])\n}\n\nfunction parseRpc(\n text: string,\n contentType: string | null\n): { result?: unknown; error?: unknown } | null {\n if (!text.trim()) return null\n if (!(contentType ?? \"\").includes(\"text/event-stream\")) {\n const parsed = RPC_RESPONSE.safeParse(JSON.parse(text))\n return parsed.success ? parsed.data : null\n }\n let last: { result?: unknown; error?: unknown } | null = null\n for (const line of text.split(\"\\n\")) {\n const t = line.trim()\n if (!t.startsWith(\"data:\")) continue\n const p = t.slice(5).trim()\n if (!p || p === \"[DONE]\") continue\n try {\n last = JSON.parse(p)\n } catch {\n /* skip non-JSON frames */\n }\n }\n return last\n}\n","/**\n * McpSink — a config-driven SinkPort that pushes each refined entry by calling\n * a configured MCP tool. Host-agnostic: the endpoint, tool name, and the\n * entry→args mapping all come from a sink manifest, so the corpus links to ANY\n * host (a Guilde guild KB, a Notion db, a vector store) without naming it.\n *\n * The manifest's `args` is a template: string values containing `${slug}`,\n * `${title}`, `${body}`, `${sources}`, `${tags}`, `${access}`, `${uri}`,\n * `${kind}`, `${confidence}` are substituted per entry. A value that is exactly\n * one placeholder (e.g. `\"${sources}\"`) is replaced with the typed value (array\n * / number), not a string.\n */\n\nimport { z } from \"zod\"\nimport type { SinkPort, SinkItem, SinkPushResult } from \"@agentproto/corpus\"\nimport { connectMcpHttp, type McpClientLike } from \"./mcp-http-client.js\"\n\n/** Validates a sink manifest (the `--config` JSON) — single source for the type. */\nexport const SINK_CONFIG_SCHEMA = z.object({\n endpoint: z.string().min(1),\n tool: z.string().min(1),\n /** Arg template — substituted per entry. */\n args: z.record(z.string(), z.unknown()),\n headers: z.record(z.string(), z.string()).optional(),\n /** MCP transport: \"streamable-http\" (default) or \"sse\". */\n transport: z.enum([\"streamable-http\", \"sse\"]).optional(),\n /**\n * If set, calls go through `mcp_imported_call({ alias, toolName, args })`\n * (the agentproto daemon's imported-MCP proxy) instead of the tool directly.\n */\n importedAlias: z.string().optional(),\n})\n\nexport type McpSinkConfig = z.infer<typeof SINK_CONFIG_SCHEMA>\n\nexport class McpSink implements SinkPort {\n private client: McpClientLike | undefined\n constructor(\n private readonly config: McpSinkConfig,\n client?: McpClientLike // injectable for tests\n ) {\n this.client = client\n }\n\n private async ensure(): Promise<McpClientLike> {\n if (!this.client) {\n this.client = await connectMcpHttp({\n endpoint: this.config.endpoint,\n ...(this.config.headers ? { headers: this.config.headers } : {}),\n ...(this.config.transport ? { transport: this.config.transport } : {}),\n })\n }\n return this.client\n }\n\n async push(item: SinkItem): Promise<SinkPushResult> {\n let client: McpClientLike\n try {\n client = await this.ensure()\n } catch (e) {\n return { uri: item.uri, ok: false, error: `connect: ${msg(e)}` }\n }\n const args = template(this.config.args, item)\n const call = this.config.importedAlias\n ? { name: \"mcp_imported_call\", args: { alias: this.config.importedAlias, toolName: this.config.tool, args } }\n : { name: this.config.tool, args }\n try {\n const res = await client.callTool(call.name, call.args)\n if (res.isError) return { uri: item.uri, ok: false, error: \"tool returned isError\" }\n return { uri: item.uri, ok: true }\n } catch (e) {\n return { uri: item.uri, ok: false, error: msg(e) }\n }\n }\n}\n\n// ── templating ──────────────────────────────────────────────────────\n\nconst PLACEHOLDER_RE = /\\$\\{(\\w+)\\}/g\n\nfunction template(args: Record<string, unknown>, item: SinkItem): Record<string, unknown> {\n const fields: Record<string, unknown> = {\n slug: item.slug,\n title: item.title,\n body: item.body,\n sources: item.sources,\n tags: item.tags,\n access: item.access ?? \"\",\n uri: item.uri,\n kind: item.kind,\n confidence: item.confidence,\n }\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(args)) {\n out[key] = substitute(value, fields)\n }\n return out\n}\n\nfunction substitute(value: unknown, fields: Record<string, unknown>): unknown {\n if (typeof value === \"string\") {\n // Whole-value placeholder → typed substitution.\n const whole = value.match(/^\\$\\{(\\w+)\\}$/)\n if (whole && whole[1]! in fields) return fields[whole[1]!]\n // Otherwise string interpolation.\n return value.replace(PLACEHOLDER_RE, (_, k) =>\n k in fields ? stringify(fields[k]) : `\\${${k}}`\n )\n }\n if (Array.isArray(value)) return value.map(v => substitute(v, fields))\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) out[k] = substitute(v, fields)\n return out\n }\n return value\n}\n\nfunction stringify(v: unknown): string {\n if (Array.isArray(v)) return v.join(\", \")\n return v == null ? \"\" : String(v)\n}\n\nfunction msg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n"]}
1
+ {"version":3,"sources":["../../src/ports/local-fs.adapter.ts","../../src/ports/os-identity.adapter.ts","../../src/ports/video-hosts.ts","../../src/ports/browser-fetcher.adapter.ts","../../src/ports/scrape-mcp-fetcher.adapter.ts","../../src/ports/ytdlp-whisper-fetcher.adapter.ts","../../src/ports/stt.port.ts","../../src/ports/assemblyai-stt.adapter.ts","../../src/ports/chunked-stt.adapter.ts","../../src/ports/composite-fetcher.ts","../../src/ports/throttle-fetcher.adapter.ts","../../src/ports/http-readability-fetcher.adapter.ts","../../src/ports/anthropic-distiller.ts","../../src/ports/cli-agent-distiller.ts","../../src/ports/cli-engines.ts","../../src/ports/mcp-http-client.ts","../../src/ports/mcp-sink.adapter.ts"],"names":["path","z","MCP_TEXT_BLOCK","rm","readdir","readFile","execFileAsync","promisify","execFile","stat","mkdtemp","join","tmpdir","msg"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * NodeFsAdapter — `FsPort` implementation backed by node:fs.\n *\n * Atomic writes via temp + rename (the same posix pattern every\n * mature tool uses). Recursive `walk` skips hidden segments\n * (anything beginning with `.`). Advisory locks via lockfiles in\n * `.corpus-locks/` next to the target — single-process safe; for\n * multi-process the lockfile owner pid is recorded so callers can\n * see who holds the lock.\n */\n\nimport { randomBytes } from \"node:crypto\"\nimport {\n appendFile,\n mkdir,\n readFile,\n readdir,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { existsSync } from \"node:fs\"\nimport type {\n FsPort,\n FsLockHandle,\n FsStat,\n} from \"@agentproto/corpus\"\n\nexport interface NodeFsAdapterOptions {\n /**\n * Absolute path to the workspace root. All FsPort paths are\n * resolved relative to this — the kit never sees host filesystem\n * paths.\n */\n readonly root: string\n}\n\nexport class NodeFsAdapter implements FsPort {\n private readonly root: string\n\n constructor(opts: NodeFsAdapterOptions) {\n this.root = opts.root\n }\n\n async exists(p: string): Promise<boolean> {\n try {\n await stat(this.resolve(p))\n return true\n } catch {\n return false\n }\n }\n\n async readFile(p: string): Promise<string> {\n return await readFile(this.resolve(p), \"utf8\")\n }\n\n /**\n * Atomic write: write to `${target}.tmp-{nonce}`, fsync, rename.\n * Rename is atomic on the same filesystem. Creates parent dirs as\n * needed (most callers expect mkdir -p semantics).\n */\n async writeFile(p: string, content: string): Promise<void> {\n const target = this.resolve(p)\n await mkdir(path.dirname(target), { recursive: true })\n const tmp = `${target}.tmp-${randomBytes(8).toString(\"hex\")}`\n await writeFile(tmp, content, \"utf8\")\n await rename(tmp, target)\n }\n\n async appendFile(p: string, content: string): Promise<void> {\n const target = this.resolve(p)\n await mkdir(path.dirname(target), { recursive: true })\n await appendFile(target, content, \"utf8\")\n }\n\n async readdir(p: string): Promise<readonly string[]> {\n const target = this.resolve(p)\n const entries = await readdir(target)\n return entries\n }\n\n async walk(p: string): Promise<readonly string[]> {\n const out: string[] = []\n const start = this.resolve(p)\n const rootForRelative = start\n const visit = async (dir: string): Promise<void> => {\n let entries: string[] = []\n try {\n entries = await readdir(dir)\n } catch {\n return\n }\n for (const ent of entries) {\n // Skip hidden segments — matches the FsPort contract.\n if (ent.startsWith(\".\")) continue\n const full = path.join(dir, ent)\n const s = await stat(full)\n if (s.isDirectory()) {\n await visit(full)\n } else if (s.isFile()) {\n const rel = path.relative(rootForRelative, full).split(path.sep).join(\"/\")\n out.push(rel)\n }\n }\n }\n await visit(start)\n return out\n }\n\n async stat(p: string): Promise<FsStat | null> {\n try {\n const s = await stat(this.resolve(p))\n return {\n kind: s.isDirectory() ? \"directory\" : \"file\",\n bytes: s.isFile() ? s.size : undefined,\n modifiedAt: s.mtime,\n }\n } catch {\n return null\n }\n }\n\n /**\n * Advisory lock via a lockfile. Spins waiting for the lockfile to\n * disappear, then creates it with exclusive flag. Released by\n * deleting it. Single-process safe; multi-process semi-safe (the\n * write is best-effort exclusive — adequate for the corpus's\n * promote-entry transaction which is rare and short-lived).\n */\n async lock(p: string): Promise<FsLockHandle> {\n const target = this.resolve(p)\n const lockDir = path.join(path.dirname(target), \".corpus-locks\")\n await mkdir(lockDir, { recursive: true })\n const lockFile = path.join(lockDir, path.basename(target) + \".lock\")\n const myToken = `${process.pid}-${randomBytes(4).toString(\"hex\")}`\n\n // Spin until we acquire. Cheap polling is fine for corpus\n // workloads — transactions are < 1s.\n while (true) {\n if (!existsSync(lockFile)) {\n try {\n await writeFile(lockFile, myToken, { encoding: \"utf8\", flag: \"wx\" })\n // Race: verify our token is the one that landed.\n const written = await readFile(lockFile, \"utf8\").catch(() => \"\")\n if (written === myToken) break\n } catch {\n // Lost the race — fall through and retry.\n }\n }\n await new Promise((r) => setTimeout(r, 25))\n }\n return {\n release: async () => {\n try {\n await rm(lockFile, { force: true })\n } catch {\n // Lockfile already gone — no-op.\n }\n },\n }\n }\n\n // ── Helpers ────────────────────────────────────────────────────\n\n /**\n * Resolve a workspace-relative path to an absolute host path.\n * Refuses to climb out of the workspace root (defense against\n * `../../etc/passwd`-style abuse) — the corpus kit's paths must\n * stay inside the workspace.\n */\n private resolve(p: string): string {\n const normalized = path.posix.normalize(\"/\" + p.replace(/^\\/+/, \"\"))\n // Drop the leading \"/\" so path.join joins correctly under root.\n const rel = normalized.slice(1)\n if (rel.startsWith(\"..\")) {\n throw new Error(\n `NodeFsAdapter: path \"${p}\" escapes the workspace root \"${this.root}\"`\n )\n }\n return path.join(this.root, rel)\n }\n}\n","/**\n * OsIdentityAdapter — `IdentityPort` resolved from OS user + cwd.\n *\n * Local-topology identity model:\n * - principal = `ws://users/{os-user}`\n * - identityTree = [\n * `ws://users/{os-user}`,\n * `ws://workspaces/{workspace-dir-name}`,\n * ]\n *\n * Roles + guilds + orgs don't exist locally — single-user, single-\n * workspace machine. Scope-policy in the corpus adapter matches\n * against this minimal tree, so AIP-10 `appliesTo` entries scoped\n * narrower than `ws://users/...` or `ws://workspaces/...` are\n * invisible to the local user. That's the intended local-topology\n * semantics: you only see what's scoped to you or your workspace.\n */\n\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport type {\n CallerIdentity,\n IdentityPort,\n} from \"@agentproto/corpus\"\n\nexport interface OsIdentityAdapterOptions {\n readonly workspaceRoot: string\n /** Override the OS user (useful for tests). Falls back to os.userInfo(). */\n readonly userOverride?: string\n}\n\nexport class OsIdentityAdapter implements IdentityPort {\n private readonly cached: CallerIdentity\n\n constructor(opts: OsIdentityAdapterOptions) {\n // Env vars win over os.userInfo() — matches Unix convention (env is\n // explicit intent, OS detection is fallback). Also keeps tests\n // deterministic across CI environments where the OS user differs.\n const user =\n opts.userOverride ??\n process.env.USER ??\n process.env.USERNAME ??\n safeGetUser() ??\n \"anonymous\"\n const wsName = path.basename(opts.workspaceRoot) || \"default\"\n this.cached = Object.freeze({\n principal: `ws://users/${slugify(user)}`,\n identityTree: Object.freeze([\n `ws://users/${slugify(user)}`,\n `ws://workspaces/${slugify(wsName)}`,\n ]),\n displayName: user,\n })\n }\n\n async resolve(): Promise<CallerIdentity> {\n return this.cached\n }\n}\n\nfunction safeGetUser(): string | undefined {\n try {\n return os.userInfo().username\n } catch {\n return undefined\n }\n}\n\nfunction slugify(s: string): string {\n return s\n .toLowerCase()\n .replace(/[^a-z0-9-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\")\n .slice(0, 64) || \"anonymous\"\n}\n","/**\n * Shared video-host detection. Video URLs belong to the transcription\n * fetcher (yt-dlp → STT); the readability fetchers MUST refuse them, so a\n * failed transcription is skipped-and-retried rather than silently\n * falling through to scrape a JS-rendered watch page (which yields the\n * page chrome — \"About Press Copyright…\" — not the talk).\n */\n\nexport const VIDEO_HOSTS: ReadonlySet<string> = new Set([\n \"youtube.com\",\n \"www.youtube.com\",\n \"m.youtube.com\",\n \"music.youtube.com\",\n \"youtu.be\",\n \"vimeo.com\",\n])\n\nexport function isVideoUrl(\n url: string,\n extraHosts?: ReadonlySet<string>\n): boolean {\n let host: string\n try {\n host = new URL(url).hostname\n } catch {\n return false\n }\n const bare = host.replace(/^www\\./, \"\")\n return (\n VIDEO_HOSTS.has(host) ||\n VIDEO_HOSTS.has(bare) ||\n (extraHosts?.has(host) ?? false) ||\n (extraHosts?.has(bare) ?? false)\n )\n}\n","/**\n * BrowserMcpFetcher — a FetcherPort that extracts ARTICLE text through\n * the user's authenticated browser (chrome-devtools-mcp). Use it for\n * pages that a plain HTTP fetch can't read: login-walled, consent-walled,\n * or JS-rendered (SPA) content. For public static articles the cheaper\n * HttpReadabilityFetcher suffices; for video, YtDlpWhisperFetcher handles\n * transcription — this fetcher does NOT touch video.\n *\n * navigate_page(url) → evaluate_script(readability) → { title, text }\n *\n * (It used to also scrape YouTube captions, but YouTube's caption APIs\n * are pot/SABR-gated and unreliable; transcription via YtDlpWhisperFetcher\n * replaced that path entirely.)\n *\n * The browser is injected as a minimal structural `BrowserMcpLike` (just\n * `callTool`, matching `@agentproto/driver-mcp`'s `McpClient`), so this\n * adapter has no hard MCP-SDK dependency and is unit-testable with a fake\n * client. The CLI wires the real chrome-devtools-mcp client.\n */\n\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\n/** The fetched-source payload the in-browser script returns. */\nconst FETCHED_PAYLOAD = z\n .object({\n title: z.string(),\n text: z.string(),\n kind: z.enum([\"video\", \"article\", \"page\", \"unknown\"]).catch(\"unknown\"),\n language: z.string().optional().catch(undefined),\n via: z.string().optional().catch(undefined),\n })\n .loose()\n\n/** An MCP `content` text block. */\nconst MCP_TEXT_BLOCK = z.object({ type: z.literal(\"text\"), text: z.string() }).loose()\n\n/** Minimal MCP client surface — matches `@agentproto/driver-mcp`'s `McpClient`. */\nexport interface BrowserMcpLike {\n callTool(args: {\n name: string\n arguments: Record<string, unknown>\n }): Promise<{ content?: unknown; structuredContent?: unknown; isError?: boolean }>\n}\n\nexport interface BrowserMcpFetcherOptions {\n readonly browser: BrowserMcpLike\n /** chrome-devtools-mcp tool names — overridable if a host renames them. */\n readonly navigateToolName?: string\n readonly evaluateToolName?: string\n}\n\n// In-page readability extraction, serialised for evaluate_script. Runs in\n// the navigated page's context (cookies/session apply).\nconst READABILITY_FN = `() => {\n const title = document.title || \"\";\n const article = document.querySelector(\"article\") || document.querySelector(\"main\");\n const root = article || document.body;\n const text = (root?.innerText || \"\").replace(/\\\\n{3,}/g, \"\\\\n\\\\n\").trim().slice(0, 200000);\n const lang = document.documentElement.getAttribute(\"lang\") || undefined;\n return { title, text, kind: \"article\", language: lang, via: \"readability\" };\n}`\n\nexport class BrowserMcpFetcher implements FetcherPort {\n private readonly browser: BrowserMcpLike\n private readonly navigateTool: string\n private readonly evaluateTool: string\n\n constructor(opts: BrowserMcpFetcherOptions) {\n this.browser = opts.browser\n this.navigateTool = opts.navigateToolName ?? \"navigate_page\"\n this.evaluateTool = opts.evaluateToolName ?? \"evaluate_script\"\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (isVideoUrl(url)) return null // videos → transcription, not page scrape\n\n await this.browser.callTool({\n name: this.navigateTool,\n arguments: { url },\n })\n const result = await this.browser.callTool({\n name: this.evaluateTool,\n arguments: { function: READABILITY_FN },\n })\n const extracted = parseEvaluateResult(result)\n if (!extracted || !extracted.text.trim()) return null\n return extracted\n }\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\n/**\n * chrome-devtools-mcp returns the script's return value either as\n * `structuredContent`, or serialised inside a `content` text block.\n * Parse defensively across both shapes.\n */\nfunction parseEvaluateResult(result: {\n content?: unknown\n structuredContent?: unknown\n}): FetchedSource | null {\n return (\n coerceFetched(result.structuredContent) ??\n coerceFetched(extractText(result.content))\n )\n}\n\nfunction coerceFetched(value: unknown): FetchedSource | null {\n let obj = value\n if (typeof obj === \"string\") {\n try {\n obj = JSON.parse(obj)\n } catch {\n return null\n }\n }\n const parsed = FETCHED_PAYLOAD.safeParse(obj)\n if (!parsed.success) return null\n const { title, text, kind, language, via } = parsed.data\n return {\n title,\n text,\n kind,\n ...(language ? { language } : {}),\n ...(via ? { via } : {}),\n }\n}\n\n/** Pull a text payload out of an MCP `content` array (or string). */\nfunction extractText(content: unknown): string | null {\n if (typeof content === \"string\") return content\n if (Array.isArray(content)) {\n for (const block of content) {\n const parsed = MCP_TEXT_BLOCK.safeParse(block)\n if (parsed.success) return parsed.data.text\n }\n }\n return null\n}\n","/**\n * ScrapeMcpFetcher — a FetcherPort that delegates article/page fetching to\n * any MCP server exposing a `scrape(url)` tool (e.g. the browser project's\n * tiered router: HTTP → Chromium → Camofox stealth → agent, with cookie\n * injection and auto-escalation on bot-walls). The browser stack is reached\n * over MCP, so this stays vendor-neutral — corpus-cli never imports it.\n *\n * scrape(url) → { title, markdown } → FetchedSource\n *\n * It does NOT touch video URLs (YtDlpWhisperFetcher owns those) and returns\n * `null` for a blocked / empty page so the importer skips-with-warning\n * rather than aborting the batch.\n *\n * The MCP client is injected as the minimal structural `BrowserMcpLike`\n * (just `callTool`), the same surface `BrowserMcpFetcher` consumes — so this\n * adapter has no MCP-SDK dependency and is unit-testable with a fake client.\n */\n\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport type { BrowserMcpLike } from \"./browser-fetcher.adapter.js\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\n/**\n * The fields we read off the `scrape` tool's result. A purifying scrape\n * server returns `title` + `markdown`; we tolerate a raw-`html`-only server\n * by stripping tags as a last resort. Everything else is left opaque.\n */\nconst SCRAPE_PAYLOAD = z\n .object({\n title: z.string().optional().catch(undefined),\n markdown: z.string().optional().catch(undefined),\n html: z.string().optional().catch(undefined),\n language: z.string().optional().catch(undefined),\n tierUsed: z.union([z.string(), z.number()]).optional().catch(undefined),\n })\n .loose()\n\nconst MCP_TEXT_BLOCK = z\n .object({ type: z.literal(\"text\"), text: z.string() })\n .loose()\n\nexport interface ScrapeMcpFetcherOptions {\n readonly client: BrowserMcpLike\n /** Tool name on the MCP server — overridable if a host renames it. */\n readonly scrapeToolName?: string\n}\n\nexport class ScrapeMcpFetcher implements FetcherPort {\n private readonly client: BrowserMcpLike\n private readonly toolName: string\n\n constructor(opts: ScrapeMcpFetcherOptions) {\n this.client = opts.client\n this.toolName = opts.scrapeToolName ?? \"scrape\"\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (isVideoUrl(url)) return null // let the transcription fetcher handle video\n\n let res: Awaited<ReturnType<BrowserMcpLike[\"callTool\"]>>\n try {\n res = await this.client.callTool({\n name: this.toolName,\n arguments: { url },\n })\n } catch {\n // Transient MCP/transport failure → skip this URL (resumable re-run\n // retries it), don't abort the whole batch.\n return null\n }\n if (res.isError) return null\n\n const payload = extractPayload(res)\n if (!payload) return null\n\n const text = (payload.markdown?.trim() || stripTags(payload.html)).trim()\n if (!text) return null // blocked / empty page → skip\n\n return {\n title: payload.title?.trim() || url,\n text,\n kind: \"article\",\n ...(payload.language ? { language: payload.language } : {}),\n via: payload.tierUsed ? `scrape:${payload.tierUsed}` : \"scrape\",\n }\n }\n}\n\n/** Read the scrape result from `structuredContent`, else a JSON text block. */\nfunction extractPayload(res: {\n content?: unknown\n structuredContent?: unknown\n}): z.infer<typeof SCRAPE_PAYLOAD> | null {\n if (res.structuredContent && typeof res.structuredContent === \"object\") {\n const parsed = SCRAPE_PAYLOAD.safeParse(res.structuredContent)\n if (parsed.success) return parsed.data\n }\n if (Array.isArray(res.content)) {\n for (const block of res.content) {\n const text = MCP_TEXT_BLOCK.safeParse(block)\n if (!text.success) continue\n try {\n const parsed = SCRAPE_PAYLOAD.safeParse(JSON.parse(text.data.text))\n if (parsed.success) return parsed.data\n } catch {\n // Non-JSON text block — treat the raw text as the content itself.\n return { markdown: text.data.text }\n }\n }\n }\n return null\n}\n\n/** Last-resort tag strip for a server that returns only raw HTML. */\nfunction stripTags(html: string | undefined): string {\n if (!html) return \"\"\n return html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \"\")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \"\")\n .replace(/<[^>]+>/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n}\n","/**\n * YtDlpWhisperFetcher — a FetcherPort for video URLs that does NOT rely\n * on captions (YouTube's caption/transcript APIs are pot/SABR-gated and\n * frequently unavailable). Instead it pulls the audio with yt-dlp and\n * transcribes it with an injected SttPort (Whisper). Captions-independent\n * and robust: works whether or not the video has subtitles.\n *\n * video URL → yt-dlp -f bestaudio -x (mp3) → SttPort.transcribe → text\n *\n * yt-dlp handles the pot token / SABR negotiation / signature itself, so\n * no browser or cookies are needed for public videos. Non-video URLs\n * resolve to `null` so this fetcher composes ahead of a readability\n * fetcher (see CompositeFetcher).\n *\n * The yt-dlp invocation is injected as `download` so the adapter is unit-\n * testable with a fake downloader + fake SttPort — no binary, no network.\n */\n\nimport { execFile } from \"node:child_process\"\nimport { mkdtemp, readdir, readFile, rm } from \"node:fs/promises\"\nimport { tmpdir } from \"node:os\"\nimport { join } from \"node:path\"\nimport { promisify } from \"node:util\"\nimport { z } from \"zod\"\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport type { SttPort } from \"./stt.port.js\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\nconst execFileAsync = promisify(execFile)\n\n/** yt-dlp's `.info.json` — only the fields we use. */\nconst YTDLP_INFO = z\n .object({ title: z.string().optional(), language: z.string().optional() })\n .loose()\n\nexport interface AudioDownload {\n readonly audioPath: string\n readonly title: string\n readonly language?: string\n /** Remove the temp working dir. Always called by the fetcher. */\n cleanup(): Promise<void>\n}\n\n/** Pull a URL's audio to a local file. Injectable for tests. */\nexport type AudioDownloader = (url: string) => Promise<AudioDownload>\n\nexport interface YtDlpWhisperFetcherOptions {\n readonly stt: SttPort\n /** Defaults to a yt-dlp subprocess downloader. */\n readonly download?: AudioDownloader\n /** Path to the yt-dlp binary (default: \"yt-dlp\" on PATH). */\n readonly ytDlpBin?: string\n /** Treat these hostnames as video (in addition to the YouTube/Vimeo set). */\n readonly extraVideoHosts?: readonly string[]\n /**\n * Skip videos longer than this many seconds, BEFORE downloading\n * (yt-dlp `--match-filter \"duration <= N\"`). A filtered video pulls no\n * bytes and resolves to `null` (skipped), so a stray 40-hour stream\n * can't blow up the batch. Omit for no cap — long media is segmented by\n * `ChunkedStt`, so length alone is not a blocker.\n */\n readonly maxDurationSec?: number\n /**\n * Read cookies from a local browser (`chrome`, `firefox`, `chrome:Profile 1`)\n * — passed to yt-dlp as `--cookies-from-browser`. Authenticated requests\n * sidestep YouTube's \"confirm you're not a bot\" rate-limit that public\n * fetches hit after a burst of downloads.\n */\n readonly cookiesFromBrowser?: string\n /** Path to a Netscape cookies.txt — passed to yt-dlp as `--cookies`. */\n readonly cookiesFile?: string\n}\n\nexport class YtDlpWhisperFetcher implements FetcherPort {\n private readonly stt: SttPort\n private readonly download: AudioDownloader\n private readonly extraHosts: ReadonlySet<string> | undefined\n\n constructor(opts: YtDlpWhisperFetcherOptions) {\n this.stt = opts.stt\n this.download =\n opts.download ??\n defaultYtDlpDownloader(opts.ytDlpBin ?? \"yt-dlp\", {\n maxDurationSec: opts.maxDurationSec,\n cookiesFromBrowser: opts.cookiesFromBrowser,\n cookiesFile: opts.cookiesFile,\n })\n this.extraHosts = opts.extraVideoHosts\n ? new Set(opts.extraVideoHosts)\n : undefined\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (!isVideoUrl(url, this.extraHosts)) return null // let a readability fetcher handle it\n\n let dl: AudioDownload\n try {\n dl = await this.download(url)\n } catch (e) {\n // Per-video download failure (geo-block, private, removed, or a\n // YouTube bot-check) → skip, don't abort the batch. Surface it so a\n // run that silently downloads nothing is diagnosable (e.g. the\n // bot-check that --cookies-from-browser fixes) rather than looking\n // like \"0 videos found\".\n process.stderr.write(`corpus: download failed for ${url} — skipped (${msg(e)})\\n`)\n return null\n }\n try {\n const t = await this.stt.transcribe(dl.audioPath)\n if (!t.text.trim()) return null\n return {\n title: dl.title || url,\n text: t.text,\n kind: \"video\",\n ...(t.language ?? dl.language\n ? { language: t.language ?? dl.language }\n : {}),\n via: \"transcription\",\n }\n } catch (e) {\n // A transcription failure on ONE video must not abort the whole\n // batch (the STT layer already retries transient blips). Skip it and\n // let the resumable importer retry on the next run — EXCEPT for an\n // auth/config error, which would fail every video, so we surface it\n // loudly rather than silently dropping the entire run.\n if (isAuthError(e)) throw e\n process.stderr.write(\n `corpus: transcription failed for ${url} — skipped (${msg(e)})\\n`\n )\n return null\n } finally {\n await dl.cleanup().catch(() => {})\n }\n }\n}\n\nfunction msg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n\n/** A 401/403 or \"api key\" error fails every video — abort, don't skip. */\nfunction isAuthError(e: unknown): boolean {\n const m = msg(e).toLowerCase()\n return (\n m.includes(\" 401\") ||\n m.includes(\" 403\") ||\n m.includes(\"unauthorized\") ||\n m.includes(\"forbidden\") ||\n m.includes(\"api key\") ||\n m.includes(\"api_key\")\n )\n}\n\n// ── Default yt-dlp subprocess downloader ────────────────────────────\n\nfunction defaultYtDlpDownloader(\n bin: string,\n opts?: {\n readonly maxDurationSec?: number\n readonly cookiesFromBrowser?: string\n readonly cookiesFile?: string\n }\n): AudioDownloader {\n return async (url: string): Promise<AudioDownload> => {\n const dir = await mkdtemp(join(tmpdir(), \"corpus-ytdlp-\"))\n const cleanup = () => rm(dir, { recursive: true, force: true })\n try {\n // `--match-filter` is evaluated before the media is fetched, so an\n // over-length video pulls zero bytes — it just yields no output file,\n // which the caller treats as a skip.\n const durationGuard =\n opts?.maxDurationSec && opts.maxDurationSec > 0\n ? [\"--match-filter\", `duration <= ${Math.floor(opts.maxDurationSec)}`]\n : []\n // Authenticate via local browser cookies (or a cookies.txt) to dodge\n // YouTube's bot-check rate-limit on bursts of public downloads.\n const cookieArgs = opts?.cookiesFromBrowser\n ? [\"--cookies-from-browser\", opts.cookiesFromBrowser]\n : opts?.cookiesFile\n ? [\"--cookies\", opts.cookiesFile]\n : []\n await execFileAsync(\n bin,\n [\n \"-f\", \"bestaudio\",\n \"-x\", \"--audio-format\", \"mp3\", \"--audio-quality\", \"64K\",\n \"--no-playlist\", \"--no-progress\",\n ...durationGuard,\n ...cookieArgs,\n \"--write-info-json\",\n \"-o\", join(dir, \"track.%(ext)s\"),\n url,\n ],\n { maxBuffer: 16 * 1024 * 1024 }\n )\n const files = await readdir(dir)\n const audio = files.find(f => f === \"track.mp3\") ??\n files.find(f => /\\.(mp3|m4a|opus|webm|ogg|wav)$/i.test(f))\n if (!audio) throw new Error(\"yt-dlp produced no audio file\")\n\n let title = url\n let language: string | undefined\n const infoName = files.find(f => f.endsWith(\".info.json\"))\n if (infoName) {\n try {\n const info = YTDLP_INFO.parse(\n JSON.parse(await readFile(join(dir, infoName), \"utf-8\"))\n )\n if (info.title) title = info.title\n if (info.language) language = info.language\n } catch {\n // info json optional — fall back to url as title\n }\n }\n return {\n audioPath: join(dir, audio),\n title,\n ...(language ? { language } : {}),\n cleanup,\n }\n } catch (e) {\n await cleanup().catch(() => {})\n throw e\n }\n }\n}\n","/**\n * SttPort — speech-to-text boundary the YtDlpWhisperFetcher consumes.\n *\n * Keeps the fetcher pure of any STT-vendor specifics: it hands a local\n * audio file path to `transcribe()` and gets back text. The CLI wires a\n * concrete impl (OpenAI Whisper here; swap for a self-hosted whisper.cpp\n * or Deepgram impl without touching the fetcher).\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { basename } from \"node:path\"\nimport { normalizeLanguageTag } from \"@agentproto/corpus\"\nimport { z } from \"zod\"\n\n/** The Whisper verbose_json fields we read. */\nconst WHISPER_RESPONSE = z\n .object({ text: z.string().optional(), language: z.string().optional() })\n .loose()\n\nexport interface Transcript {\n readonly text: string\n /** BCP-47 language, when the engine detects it. */\n readonly language?: string\n}\n\nexport interface SttPort {\n transcribe(audioPath: string): Promise<Transcript>\n}\n\nconst WHISPER_MAX_BYTES = 25 * 1024 * 1024 // OpenAI hard cap\n\nexport interface OpenAiWhisperSttOptions {\n readonly apiKey: string\n /** Default \"whisper-1\". */\n readonly model?: string\n /** Override base URL (proxy / Azure). Default OpenAI. */\n readonly baseUrl?: string\n}\n\n/**\n * OpenAI Whisper STT. Posts the audio file to /audio/transcriptions with\n * `response_format=verbose_json` so we recover the detected language.\n *\n * Files above OpenAI's 25 MB cap throw a clear error — the caller should\n * have downloaded at a lower bitrate (the fetcher uses 64 kbps mono) or\n * chunk long media. We surface the size rather than letting the API 413.\n */\nexport class OpenAiWhisperStt implements SttPort {\n private readonly apiKey: string\n private readonly model: string\n private readonly baseUrl: string\n\n constructor(opts: OpenAiWhisperSttOptions) {\n this.apiKey = opts.apiKey\n this.model = opts.model ?? \"whisper-1\"\n this.baseUrl = (opts.baseUrl ?? \"https://api.openai.com/v1\").replace(/\\/+$/, \"\")\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const bytes = await readFile(audioPath)\n if (bytes.byteLength > WHISPER_MAX_BYTES) {\n throw new Error(\n `audio ${basename(audioPath)} is ${(bytes.byteLength / 1024 / 1024).toFixed(1)} MB — over Whisper's 25 MB cap. Lower the bitrate or chunk the media.`\n )\n }\n const form = new FormData()\n form.append(\"file\", new Blob([bytes]), basename(audioPath))\n form.append(\"model\", this.model)\n form.append(\"response_format\", \"verbose_json\")\n\n const res = await this.postWithRetry(form)\n if (!res.ok) {\n const body = await res.text().catch(() => \"\")\n throw new Error(`Whisper STT ${res.status} ${res.statusText}: ${body.slice(0, 200)}`)\n }\n const data = WHISPER_RESPONSE.parse(await res.json())\n const language = normalizeLanguageTag(data.language)\n return {\n text: (data.text ?? \"\").trim(),\n ...(language ? { language } : {}),\n }\n }\n\n /**\n * POST the audio with bounded retry. Transcribing a long talk fans out\n * into many segment uploads (see ChunkedStt), so a single transient\n * network blip (\"fetch failed\") or a 429 / 5xx must not abort the whole\n * batch. Network errors and retryable statuses back off and retry;\n * client errors (401 auth, 400 bad request) return immediately so a real\n * misconfiguration still surfaces loudly.\n */\n private async postWithRetry(form: FormData, attempts = 4): Promise<Response> {\n const url = `${this.baseUrl}/audio/transcriptions`\n let lastErr: unknown\n for (let i = 0; i < attempts; i++) {\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { authorization: `Bearer ${this.apiKey}` },\n body: form,\n })\n if (res.status !== 429 && res.status < 500) return res\n lastErr = new Error(`Whisper STT ${res.status} ${res.statusText}`)\n } catch (e) {\n lastErr = e // network-level failure (undici \"fetch failed\", reset, timeout)\n }\n if (i < attempts - 1) await delay(500 * 2 ** i) // 0.5s, 1s, 2s\n }\n throw lastErr instanceof Error ? lastErr : new Error(String(lastErr))\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","/**\n * AssemblyAiStt — a diarizing SttPort. Where OpenAiWhisperStt returns a\n * flat transcript, this returns SPEAKER-LABELLED text (`Speaker A: … /\n * Speaker B: …`) via AssemblyAI's `speaker_labels`. Use it ad-hoc for\n * multi-speaker videos (interviews, mock interviews, panels, \"day in the\n * life\") where the content only makes sense if you know who said what.\n *\n * Same `SttPort` contract — the diarized layout lives in `text`, so it\n * drops straight into YtDlpWhisperFetcher without any other change.\n *\n * Flow: upload audio → create transcript(speaker_labels) → poll → format\n * utterances. No 25 MB cap (unlike Whisper), so long videos are fine; the\n * trade-off is latency (~a third of audio duration) — slower than Whisper.\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { z } from \"zod\"\nimport type { SttPort, Transcript } from \"./stt.port.js\"\n\nexport interface AssemblyAiSttOptions {\n readonly apiKey: string\n readonly baseUrl?: string\n readonly pollIntervalMs?: number\n readonly maxWaitMs?: number\n readonly sleep?: (ms: number) => Promise<void>\n}\n\nconst UPLOAD_RESPONSE = z.object({ upload_url: z.string() })\n\nconst AAI_TRANSCRIPT = z\n .object({\n id: z.string(),\n status: z.enum([\"queued\", \"processing\", \"completed\", \"error\"]),\n text: z.string().optional(),\n language_code: z.string().optional(),\n error: z.string().optional(),\n utterances: z\n .array(z.object({ speaker: z.string(), text: z.string() }))\n .nullish(),\n })\n .loose()\n\ntype AaiTranscript = z.infer<typeof AAI_TRANSCRIPT>\n\nexport class AssemblyAiStt implements SttPort {\n private readonly apiKey: string\n private readonly baseUrl: string\n private readonly pollIntervalMs: number\n private readonly maxWaitMs: number\n private readonly sleep: (ms: number) => Promise<void>\n\n constructor(opts: AssemblyAiSttOptions) {\n this.apiKey = opts.apiKey\n this.baseUrl = (opts.baseUrl ?? \"https://api.assemblyai.com/v2\").replace(/\\/+$/, \"\")\n this.pollIntervalMs = opts.pollIntervalMs ?? 3000\n this.maxWaitMs = opts.maxWaitMs ?? 15 * 60 * 1000\n this.sleep = opts.sleep ?? ((ms: number) => new Promise(r => setTimeout(r, ms)))\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const bytes = await readFile(audioPath)\n\n // 1. Upload the audio bytes.\n const up = await fetch(`${this.baseUrl}/upload`, {\n method: \"POST\",\n headers: { authorization: this.apiKey, \"content-type\": \"application/octet-stream\" },\n body: bytes,\n })\n if (!up.ok) throw new Error(`AssemblyAI upload ${up.status}: ${(await up.text()).slice(0, 200)}`)\n const { upload_url } = UPLOAD_RESPONSE.parse(await up.json())\n\n // 2. Create a diarized transcript job.\n const created = await this.post(\"/transcript\", {\n audio_url: upload_url,\n speaker_labels: true,\n language_detection: true,\n })\n const id = created.id\n\n // 3. Poll until done.\n const deadline = this.maxWaitMs\n let waited = 0\n let job = created\n while (job.status !== \"completed\" && job.status !== \"error\") {\n if (waited >= deadline) throw new Error(`AssemblyAI transcript ${id} timed out after ${deadline} ms`)\n await this.sleep(this.pollIntervalMs)\n waited += this.pollIntervalMs\n job = await this.get(`/transcript/${id}`)\n }\n if (job.status === \"error\") throw new Error(`AssemblyAI transcript failed: ${job.error ?? \"unknown\"}`)\n\n return {\n text: formatDiarized(job),\n ...(job.language_code ? { language: job.language_code } : {}),\n }\n }\n\n private async post(path: string, body: unknown): Promise<AaiTranscript> {\n const r = await fetch(`${this.baseUrl}${path}`, {\n method: \"POST\",\n headers: { authorization: this.apiKey, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n })\n if (!r.ok) throw new Error(`AssemblyAI POST ${path} ${r.status}: ${(await r.text()).slice(0, 200)}`)\n return AAI_TRANSCRIPT.parse(await r.json())\n }\n\n private async get(path: string): Promise<AaiTranscript> {\n const r = await fetch(`${this.baseUrl}${path}`, { headers: { authorization: this.apiKey } })\n if (!r.ok) throw new Error(`AssemblyAI GET ${path} ${r.status}: ${(await r.text()).slice(0, 200)}`)\n return AAI_TRANSCRIPT.parse(await r.json())\n }\n}\n\n/** Join utterances as `Speaker A: …` blocks; fall back to flat text. */\nfunction formatDiarized(job: AaiTranscript): string {\n if (job.utterances && job.utterances.length > 0) {\n return job.utterances\n .map(u => `Speaker ${u.speaker}: ${u.text.trim()}`)\n .join(\"\\n\\n\")\n .trim()\n }\n return (job.text ?? \"\").trim()\n}\n","/**\n * ChunkedStt — a SttPort decorator that makes a capped engine handle\n * arbitrarily long audio. Whisper rejects files over 25 MB, so a\n * multi-hour talk (full course, masterclass, panel) can't be sent in one\n * request. This wrapper splits oversized audio into time segments with\n * ffmpeg, transcribes each through the wrapped engine, and concatenates\n * the text back into a single transcript.\n *\n * transcribe(path) → ≤cap ? base.transcribe(path)\n * : ffmpeg segment → base.transcribe(eachPart) → join\n *\n * The cap is a vendor concern (Whisper's limit), so handling it belongs in\n * the STT layer rather than the fetcher — the fetcher stays pure and the\n * concrete `OpenAiWhisperStt` stays a single-request transcriber. Splitting\n * is injected as `split` so the decorator is unit-testable with a fake\n * splitter + fake base engine — no ffmpeg, no network.\n *\n * Segmenting uses `-c copy` (stream copy, no re-encode): fast, and each\n * segment is a self-contained valid file. At the fetcher's 64 kbps a 20-min\n * segment is ~9.6 MB — comfortably under the 25 MB cap with margin for\n * VBR drift.\n */\n\nimport { execFile } from \"node:child_process\"\nimport { mkdtemp, readdir, rm, stat } from \"node:fs/promises\"\nimport { tmpdir } from \"node:os\"\nimport { extname, join } from \"node:path\"\nimport { promisify } from \"node:util\"\nimport type { SttPort, Transcript } from \"./stt.port.js\"\n\nconst execFileAsync = promisify(execFile)\n\n/**\n * Split a local audio file into ≤`segmentSeconds` parts inside `outDir`,\n * returning the segment paths in playback order. Injectable for tests.\n */\nexport type AudioSplitter = (\n audioPath: string,\n segmentSeconds: number,\n outDir: string\n) => Promise<string[]>\n\nexport interface ChunkedSttOptions {\n /** The engine each (sub-cap) part is transcribed through. */\n readonly base: SttPort\n /**\n * Split anything strictly larger than this. Default 24 MB — just under\n * Whisper's 25 MB hard cap so VBR drift never pushes a part over.\n */\n readonly maxBytes?: number\n /** Segment length when splitting. Default 1200 s (20 min). */\n readonly segmentSeconds?: number\n /** Defaults to an ffmpeg segment-muxer splitter. */\n readonly split?: AudioSplitter\n /** Path to the ffmpeg binary (default: \"ffmpeg\" on PATH). */\n readonly ffmpegBin?: string\n}\n\nconst DEFAULT_MAX_BYTES = 24 * 1024 * 1024\nconst DEFAULT_SEGMENT_SECONDS = 1200\n\nexport class ChunkedStt implements SttPort {\n private readonly base: SttPort\n private readonly maxBytes: number\n private readonly segmentSeconds: number\n private readonly split: AudioSplitter\n\n constructor(opts: ChunkedSttOptions) {\n this.base = opts.base\n this.maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES\n this.segmentSeconds = opts.segmentSeconds ?? DEFAULT_SEGMENT_SECONDS\n this.split = opts.split ?? defaultFfmpegSplitter(opts.ffmpegBin ?? \"ffmpeg\")\n }\n\n async transcribe(audioPath: string): Promise<Transcript> {\n const { size } = await stat(audioPath)\n if (size <= this.maxBytes) return this.base.transcribe(audioPath)\n\n const dir = await mkdtemp(join(tmpdir(), \"corpus-stt-chunk-\"))\n try {\n const parts = await this.split(audioPath, this.segmentSeconds, dir)\n if (parts.length === 0) {\n // Splitter produced nothing — fall back to a single attempt so the\n // base engine surfaces its own (clear) over-cap error rather than\n // us silently dropping the source.\n return this.base.transcribe(audioPath)\n }\n const texts: string[] = []\n let language: string | undefined\n let failed = 0\n let firstErr: unknown\n for (const part of parts) {\n try {\n const t = await this.base.transcribe(part)\n if (t.text.trim()) texts.push(t.text.trim())\n language ??= t.language\n } catch (e) {\n // One segment failing (after the base engine's own retries) must\n // not discard the whole multi-hour transcript — keep the rest.\n failed++\n firstErr ??= e\n }\n }\n // Every segment failing usually means a systemic error (auth, quota) —\n // rethrow so the caller can surface/skip it, rather than silently\n // writing an empty transcript.\n if (texts.length === 0) {\n throw firstErr ?? new Error(\"all audio segments failed transcription\")\n }\n if (failed > 0) {\n process.stderr.write(\n `corpus: ${failed}/${parts.length} audio segments failed — partial transcript\\n`\n )\n }\n return {\n text: texts.join(\"\\n\\n\"),\n ...(language ? { language } : {}),\n }\n } finally {\n await rm(dir, { recursive: true, force: true }).catch(() => {})\n }\n }\n}\n\n// ── Default ffmpeg segment-muxer splitter ───────────────────────────\n\nfunction defaultFfmpegSplitter(bin: string): AudioSplitter {\n return async (audioPath, segmentSeconds, outDir) => {\n const ext = extname(audioPath) || \".mp3\"\n await execFileAsync(\n bin,\n [\n \"-hide_banner\", \"-loglevel\", \"error\",\n \"-i\", audioPath,\n \"-f\", \"segment\",\n \"-segment_time\", String(segmentSeconds),\n \"-c\", \"copy\",\n join(outDir, `part%03d${ext}`),\n ],\n { maxBuffer: 16 * 1024 * 1024 }\n )\n // ffmpeg names parts part000, part001, … — lexical sort = playback order.\n const files = (await readdir(outDir))\n .filter(f => f.startsWith(\"part\") && f.endsWith(ext))\n .sort()\n return files.map(f => join(outDir, f))\n }\n}\n","/**\n * CompositeFetcher — tries child fetchers in order, first non-null wins.\n *\n * Lets the importer route by URL without itself knowing the routing:\n * new CompositeFetcher([ ytDlpWhisper, browserReadability ])\n * sends videos to whisper (the readability one returns null for them is\n * never reached because whisper handled it) and everything else falls\n * through to readability. A child that THROWS aborts (hard failure);\n * a child that returns null means \"not mine, try the next\".\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\n\nexport class CompositeFetcher implements FetcherPort {\n private readonly children: readonly FetcherPort[]\n\n constructor(children: readonly FetcherPort[]) {\n this.children = children\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n for (const child of this.children) {\n const result = await child.fetch(url)\n if (result) return result\n }\n return null\n }\n}\n","/**\n * ThrottleFetcher — wraps a FetcherPort to enforce a minimum interval\n * between fetches (rate limiting). The importer already calls fetch\n * serially (one URL at a time), so this adds the *pacing* that protects\n * against YouTube anti-abuse blocks and Whisper RPM limits when running\n * a large batch.\n *\n * `now` + `sleep` are injectable so the throttle is unit-testable without\n * real timers.\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\n\nexport interface ThrottleFetcherOptions {\n /** Minimum milliseconds between the START of consecutive fetches. */\n readonly minIntervalMs: number\n readonly now?: () => number\n readonly sleep?: (ms: number) => Promise<void>\n}\n\nexport class ThrottleFetcher implements FetcherPort {\n private readonly inner: FetcherPort\n private readonly minIntervalMs: number\n private readonly now: () => number\n private readonly sleep: (ms: number) => Promise<void>\n private lastStart = 0\n private started = false\n\n constructor(inner: FetcherPort, opts: ThrottleFetcherOptions) {\n this.inner = inner\n this.minIntervalMs = Math.max(0, opts.minIntervalMs)\n this.now = opts.now ?? (() => Date.now())\n this.sleep =\n opts.sleep ?? ((ms: number) => new Promise(r => setTimeout(r, ms)))\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n if (this.minIntervalMs > 0 && this.started) {\n const wait = this.minIntervalMs - (this.now() - this.lastStart)\n if (wait > 0) await this.sleep(wait)\n }\n this.started = true\n this.lastStart = this.now()\n return this.inner.fetch(url)\n }\n}\n","/**\n * HttpReadabilityFetcher — a browser-free FetcherPort for articles:\n * plain `fetch` + a lightweight readability extraction (prefer\n * <article>/<main>, strip chrome). Validated to pull ~35k chars from a\n * real corpus article. Returns `null` for non-HTML or empty bodies so a\n * video or authed-browser fetcher can take those.\n *\n * No JS execution — so it won't get SPA-only content; for login-walled\n * or JS-rendered pages, compose a BrowserMcpFetcher ahead of/after this.\n */\n\nimport type { FetcherPort, FetchedSource } from \"@agentproto/corpus\"\nimport { isVideoUrl } from \"./video-hosts.js\"\n\nexport interface HttpReadabilityFetcherOptions {\n readonly userAgent?: string\n readonly maxChars?: number\n}\n\nconst DEFAULT_UA =\n \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0 Safari/537.36\"\n\nexport class HttpReadabilityFetcher implements FetcherPort {\n private readonly ua: string\n private readonly maxChars: number\n\n constructor(opts: HttpReadabilityFetcherOptions = {}) {\n this.ua = opts.userAgent ?? DEFAULT_UA\n this.maxChars = opts.maxChars ?? 200_000\n }\n\n async fetch(url: string): Promise<FetchedSource | null> {\n // Video URLs belong to the transcription fetcher. Never scrape a\n // watch page here — a failed transcription must skip, not fall\n // through to YouTube's page chrome.\n if (isVideoUrl(url)) return null\n\n let res: Response\n try {\n res = await fetch(url, {\n headers: { \"user-agent\": this.ua, \"accept-language\": \"en,fr;q=0.8\" },\n redirect: \"follow\",\n })\n } catch {\n return null\n }\n if (!res.ok) return null\n const ct = res.headers.get(\"content-type\") ?? \"\"\n if (!ct.includes(\"text/html\") && !ct.includes(\"application/xhtml\")) return null\n\n const html = await res.text()\n const title = decodeEntities(\n (html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i)?.[1] ?? \"\").trim()\n )\n const lang = html.match(/<html[^>]*\\blang=[\"']?([a-zA-Z-]+)/i)?.[1]\n const text = extractReadable(html).slice(0, this.maxChars)\n if (!text.trim()) return null\n\n return {\n title: title || url,\n text,\n kind: \"article\",\n ...(lang ? { language: lang } : {}),\n via: \"readability\",\n }\n }\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nfunction extractReadable(html: string): string {\n // Prefer the main content region; fall back to <body>.\n const region =\n html.match(/<article[\\s\\S]*?<\\/article>/i)?.[0] ??\n html.match(/<main[\\s\\S]*?<\\/main>/i)?.[0] ??\n html.match(/<body[\\s\\S]*?<\\/body>/i)?.[0] ??\n html\n return decodeEntities(\n region\n .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n .replace(/<(nav|header|footer|aside|form)[\\s\\S]*?<\\/\\1>/gi, \" \")\n .replace(/<[^>]+>/g, \" \")\n .replace(/[ \\t]+/g, \" \")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n ).trim()\n}\n\nfunction decodeEntities(s: string): string {\n return s\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&nbsp;/g, \" \")\n .replace(/&#(\\d+);/g, (_, n) => String.fromCharCode(Number(n)))\n}\n","/**\n * AnthropicDistiller — a DistillPort backed by Claude over the Messages API.\n * Extracts refined AIP-10 items (principle/pattern/critique/summary/example)\n * from a raw source. Returns self-contained insights, not quote dumps.\n *\n * Hand-rolled over the HTTP API (no SDK dep), mirroring the other corpus-cli\n * port adapters. Prompt + parse are the shared `distill-prompt` core; this\n * adapter owns only the metered-API transport. For the subscription-billed\n * alternative see CliAgentDistiller + the `claude-code` engine.\n */\n\nimport { z } from \"zod\"\nimport type { DistillPort, DistillInput, DistilledItem } from \"@agentproto/corpus\"\nimport { buildDistillPrompt, parseItems } from \"./distill-prompt.js\"\nimport type { DistillUsage } from \"./usage-telemetry.js\"\n\n/** The Messages API response — text content blocks plus model + token usage. */\nconst ANTHROPIC_RESPONSE = z\n .object({\n model: z.string().optional(),\n content: z\n .array(z.object({ type: z.string(), text: z.string().optional() }).loose())\n .optional(),\n usage: z\n .object({ input_tokens: z.number(), output_tokens: z.number() })\n .loose()\n .optional(),\n })\n .loose()\n\nexport interface AnthropicDistillerOptions {\n readonly apiKey: string\n /** Default a current Claude model id. */\n readonly model?: string\n readonly baseUrl?: string\n /** Max refined items to extract per source. */\n readonly maxItems?: number\n /** Optional sink for per-call token usage (cost + Langfuse export). */\n readonly onUsage?: (usage: DistillUsage) => void\n}\n\nexport class AnthropicDistiller implements DistillPort {\n private readonly apiKey: string\n private readonly model: string\n private readonly baseUrl: string\n private readonly maxItems: number\n private readonly onUsage: ((usage: DistillUsage) => void) | undefined\n\n constructor(opts: AnthropicDistillerOptions) {\n this.apiKey = opts.apiKey\n this.model = opts.model ?? \"claude-sonnet-4-6\"\n this.baseUrl = (opts.baseUrl ?? \"https://api.anthropic.com/v1\").replace(/\\/+$/, \"\")\n this.maxItems = opts.maxItems ?? 8\n this.onUsage = opts.onUsage\n }\n\n async distill(input: DistillInput): Promise<readonly DistilledItem[]> {\n const prompt = buildDistillPrompt(input, this.maxItems)\n const startedAt = new Date().toISOString()\n const res = await fetch(`${this.baseUrl}/messages`, {\n method: \"POST\",\n headers: {\n \"x-api-key\": this.apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 4096,\n messages: [{ role: \"user\", content: prompt }],\n }),\n })\n if (!res.ok) {\n throw new Error(`Anthropic distill ${res.status}: ${(await res.text()).slice(0, 200)}`)\n }\n const parsed = ANTHROPIC_RESPONSE.safeParse(await res.json())\n const text = parsed.success\n ? (parsed.data.content ?? []).find(c => c.type === \"text\")?.text ?? \"\"\n : \"\"\n if (parsed.success && parsed.data.usage && this.onUsage) {\n this.onUsage({\n model: parsed.data.model ?? this.model,\n inputTokens: parsed.data.usage.input_tokens,\n outputTokens: parsed.data.usage.output_tokens,\n label: input.title,\n startedAt,\n endedAt: new Date().toISOString(),\n })\n }\n return parseItems(text)\n }\n}\n","/**\n * CliAgentDistiller — a DistillPort backed by any local agent CLI running in\n * one-shot mode (prompt on stdin, response on stdout). The transport is generic;\n * the per-CLI specifics (command, argv, output parse) come from a CliEngine\n * descriptor, so claude / gemini / goose / … are one descriptor each.\n *\n * Same DistillPort contract + same prompt/parse as AnthropicDistiller (both use\n * the shared `distill-prompt` core), so the two are drop-in swappable behind the\n * `corpus distill --engine` flag.\n *\n * TRADE-OFFS vs the metered API:\n * - Subscription rate caps — slower for big batches; pace with --throttle and\n * let the runner skip+retry on non-zero exits.\n * - Output is CLI text, not API structured output — same tolerant parse.\n * - One process spawn per source — higher per-call overhead than fetch().\n */\n\nimport { tmpdir } from \"node:os\"\nimport { spawnWithStdin } from \"@agentproto/cli-exec\"\nimport type { DistillPort, DistillInput, DistilledItem } from \"@agentproto/corpus\"\nimport { buildDistillPrompt, parseItems } from \"./distill-prompt.js\"\nimport type { CliEngine } from \"./cli-engines.js\"\n\nexport interface CliAgentDistillerOptions {\n /** The CLI engine descriptor (command + argv + output parse). */\n readonly engine: CliEngine\n /** Optional model override passed to the engine, e.g. \"haiku\" to spend less quota. */\n readonly model?: string\n /** Max refined items per source (feeds the shared prompt). */\n readonly maxItems?: number\n /** Hard per-source timeout; kills a wedged CLI call. Default 120s. */\n readonly timeoutMs?: number\n /** Working dir. Default os.tmpdir() — neutral, no project CLAUDE.md / repo. */\n readonly cwd?: string\n}\n\nexport class CliAgentDistiller implements DistillPort {\n private readonly engine: CliEngine\n private readonly model?: string\n private readonly maxItems: number\n private readonly timeoutMs: number\n private readonly cwd: string\n\n constructor(opts: CliAgentDistillerOptions) {\n this.engine = opts.engine\n this.model = opts.model\n this.maxItems = opts.maxItems ?? 8\n this.timeoutMs = opts.timeoutMs ?? 120_000\n this.cwd = opts.cwd ?? tmpdir()\n }\n\n async distill(input: DistillInput): Promise<readonly DistilledItem[]> {\n const prompt = buildDistillPrompt(input, this.maxItems)\n // A non-zero exit (often a rate cap) rejects here; the runner skips + retries\n // the source on the next pass.\n const stdout = await spawnWithStdin({\n command: this.engine.command,\n args: this.engine.buildArgs({ ...(this.model ? { model: this.model } : {}) }),\n stdin: prompt,\n cwd: this.cwd,\n timeoutMs: this.timeoutMs,\n })\n const text = this.engine.parseOutput(stdout) ?? stdout\n return parseItems(text)\n }\n}\n","/**\n * CLI agent engines — descriptors for distilling through a local agent CLI in\n * headless one-shot mode (prompt on stdin, response on stdout), instead of a\n * metered API. Each engine declares its `command`, how to `buildArgs` (model\n * injection, output format, tool/MCP lockdown), and how to `parseOutput` of the\n * captured stdout into the model's text.\n *\n * WHY: distillation is a high-volume batch (hundreds of sources × ~8 items). On\n * the API that bills per token; routed through an authenticated agent-CLI\n * subscription (e.g. Claude Max) it draws on a flat monthly plan — ~$0 marginal\n * cost. Same DistillPort contract + same prompt/parse, swappable transport.\n *\n * Engines register full descriptors and are dispatched by id (no `engineId ===`\n * branching at the call site). Add a CLI by adding a descriptor below.\n *\n * Two output shapes are covered:\n * - **JSON-envelope** (claude-code) — `--output-format json` wraps the answer;\n * `parseClaudeJsonOutput` unwraps `{ result }`.\n * - **plain-text** (gemini / codex / opencode) — the CLI prints the answer\n * straight to stdout; `plainTextOutput` only strips ANSI, and the tolerant\n * `parseItems` grabs the `[…]` JSON array out of the text.\n *\n * NOTE on verification: claude-code's flags are verified against `claude -p\n * --help`. The other three use each CLI's *first-party non-interactive* print\n * mode (`gemini` piped stdin · `codex exec -` · `opencode run`), distinct from\n * the ACP wrappers `@agentproto/adapter-*` use for streaming/tool sessions. They\n * read the prompt from stdin and print plain text — the right fit for one-shot\n * distill with no adapter dependency. Confirm the exact flags against each CLI's\n * `--help` on the host before relying on them; they are easy to tweak here.\n */\n\nimport { parseClaudeJsonOutput } from \"@agentproto/cli-exec\"\n\n/** What a CLI engine needs to drive one stdin→stdout completion. */\nexport interface CliEngine {\n /** Stable id, used by `corpus distill --engine <id>`. */\n readonly id: string\n /** Whether this engine bills a subscription (no API key needed). Surfaced in help. */\n readonly subscriptionBilled: boolean\n /** Executable to invoke — must be on PATH and logged in. */\n readonly command: string\n /** Build the argv for one completion. The prompt is fed over stdin, not argv. */\n buildArgs(opts: { readonly model?: string }): string[]\n /** Extract the model's text from captured stdout; null → fall back to raw stdout. */\n parseOutput(stdout: string): string | null\n}\n\n/**\n * Plain-text print engines (gemini / codex / opencode) emit the model's answer\n * directly on stdout — no JSON envelope to unwrap. We only strip ANSI so the\n * tolerant `parseItems` JSON-array grab isn't tripped by colour codes when a CLI\n * forgets it's not a TTY. Returns the cleaned text (never null) — the fallback is\n * the text itself.\n */\nconst ANSI = new RegExp(String.fromCharCode(27) + \"\\\\[[0-9;]*m\", \"g\")\nfunction plainTextOutput(stdout: string): string {\n return stdout.replace(ANSI, \"\")\n}\n\n/**\n * Codex `exec --json` emits a JSONL event stream; the model's answer is the\n * `agent_message` item, not a clean text-only stdout (its human mode prints a\n * preamble whose brackets break the tolerant `[…]` grab). Walk the lines and\n * return the LAST agent-message text. Tolerates the two known event shapes\n * (`item.completed`→`item.text`, and the older `agent_message`→`message`);\n * verify against `codex exec --json` on the host if a version drifts. Null when\n * no message line is found → fall back to raw stdout.\n */\nfunction parseCodexJsonl(stdout: string): string | null {\n let found: string | null = null\n for (const line of stdout.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed.startsWith(\"{\")) continue\n let evt: unknown\n try {\n evt = JSON.parse(trimmed)\n } catch {\n continue\n }\n if (!evt || typeof evt !== \"object\") continue\n const e = evt as Record<string, unknown>\n const item = e.item as Record<string, unknown> | undefined\n if (item?.type === \"agent_message\" && typeof item.text === \"string\") {\n found = item.text\n } else if (e.type === \"agent_message\" && typeof e.message === \"string\") {\n found = e.message\n }\n }\n return found\n}\n\n/**\n * Claude Code in headless print mode, billed against the logged-in subscription.\n *\n * Flags (verified against `claude -p --help`):\n * -p non-interactive print mode\n * --output-format json single-result JSON envelope ({ result, is_error, … })\n * --strict-mcp-config ignore all MCP servers (no --mcp-config ⇒ none load)\n * --model <m> optional alias (\"haiku\"/\"sonnet\") or full id\n * Deliberately NOT --bare: that flag forces ANTHROPIC_API_KEY auth and never\n * reads OAuth/keychain — which would bypass the subscription we're here to use.\n * Pair with cwd=os.tmpdir() (CliAgentDistiller default) so no project CLAUDE.md\n * is auto-discovered and the agent can't wander a repo.\n */\nconst CLAUDE_CODE: CliEngine = {\n id: \"claude-code\",\n subscriptionBilled: true,\n command: \"claude\",\n buildArgs: ({ model }) => [\n \"-p\",\n \"--output-format\",\n \"json\",\n \"--strict-mcp-config\",\n ...(model ? [\"--model\", model] : []),\n ],\n parseOutput: parseClaudeJsonOutput,\n}\n\n/**\n * Google Gemini CLI in non-interactive print mode. Piping the prompt on stdin to\n * a non-TTY `gemini` runs one completion and prints the answer to stdout. Auth is\n * the logged-in Google account (free tier) or GEMINI_API_KEY.\n * -m <model> optional model id (e.g. \"gemini-2.5-pro\" / \"gemini-2.5-flash\")\n */\nconst GEMINI: CliEngine = {\n id: \"gemini\",\n subscriptionBilled: true,\n command: \"gemini\",\n buildArgs: ({ model }) => [...(model ? [\"-m\", model] : [])],\n parseOutput: plainTextOutput,\n}\n\n/**\n * OpenAI Codex CLI in non-interactive automation mode (`codex exec`). The `-`\n * positional reads the prompt from stdin; the final assistant message prints to\n * stdout. Auth: ChatGPT login (subscription) or OPENAI_API_KEY / CODEX_API_KEY.\n * exec one-shot, non-interactive run\n * --skip-git-repo-check allow running outside a git repo (cwd is os.tmpdir())\n * --json JSONL event stream (clean — its human mode prints a\n * preamble whose brackets break the JSON-array grab)\n * -m <model> optional model id (e.g. \"gpt-5-codex\")\n * - read the prompt from stdin\n * NOTE: this is Codex's own print mode, NOT the @zed-industries/codex-acp wrapper\n * the AIP-45 adapter uses for streaming sessions.\n */\nconst CODEX: CliEngine = {\n id: \"codex\",\n subscriptionBilled: true,\n command: \"codex\",\n buildArgs: ({ model }) => [\n \"exec\",\n \"--skip-git-repo-check\",\n \"--json\",\n ...(model ? [\"-m\", model] : []),\n \"-\",\n ],\n parseOutput: parseCodexJsonl,\n}\n\n/**\n * sst/opencode CLI in non-interactive run mode (`opencode run`). Reads the piped\n * stdin as the message and prints the assistant text to stdout. Multi-provider —\n * auth via the provider key the chosen model needs (ANTHROPIC_API_KEY,\n * OPENAI_API_KEY, OPENROUTER_API_KEY, …), so not subscription-billed by default.\n * run one-shot, non-interactive run\n * -m <p/model> optional provider/model id (e.g. \"anthropic/claude-haiku-4-5\")\n * NOTE: this is opencode's own print mode, NOT the `opencode acp` server the\n * AIP-45 adapter uses for streaming sessions.\n */\nconst OPENCODE: CliEngine = {\n id: \"opencode\",\n subscriptionBilled: false,\n command: \"opencode\",\n buildArgs: ({ model }) => [\"run\", ...(model ? [\"-m\", model] : [])],\n parseOutput: plainTextOutput,\n}\n\n/** Registry of CLI engines, keyed by id. */\nexport const CLI_ENGINES: Readonly<Record<string, CliEngine>> = {\n [CLAUDE_CODE.id]: CLAUDE_CODE,\n [GEMINI.id]: GEMINI,\n [CODEX.id]: CODEX,\n [OPENCODE.id]: OPENCODE,\n}\n","/**\n * Minimal streamable-HTTP MCP client (host-agnostic). Used by config-driven\n * sinks/sources to call ANY MCP server's tools — the corpus never names a\n * specific host; the endpoint + tool come from a manifest.\n *\n * Handles both JSON and SSE (`text/event-stream`) responses, optional\n * `Mcp-Session-Id`, and the initialize handshake.\n */\n\nimport { z } from \"zod\"\n\n/** JSON-RPC envelope (result/error opaque). */\nconst RPC_RESPONSE = z\n .object({ result: z.unknown().optional(), error: z.unknown().optional() })\n .loose()\n\n/** A JSON-RPC message with an id (SSE-delivered responses). */\nconst RPC_MESSAGE = z\n .object({\n id: z.number().optional(),\n result: z.unknown().optional(),\n error: z.unknown().optional(),\n })\n .loose()\n\n/** An MCP `tools/call` result (content blocks left opaque). */\nconst CALL_RESULT = z\n .object({\n content: z.unknown().optional(),\n structuredContent: z.unknown().optional(),\n isError: z.boolean().optional(),\n })\n .loose()\n\nexport interface McpClientLike {\n callTool(name: string, args: Record<string, unknown>): Promise<{\n content?: unknown\n structuredContent?: unknown\n isError?: boolean\n }>\n}\n\nexport interface ConnectMcpHttpOptions {\n readonly endpoint: string\n readonly headers?: Record<string, string>\n readonly protocolVersion?: string\n /** \"streamable-http\" (POST, default) or \"sse\" (legacy GET stream + POST messages). */\n readonly transport?: \"streamable-http\" | \"sse\"\n}\n\nexport async function connectMcpHttp(\n opts: ConnectMcpHttpOptions\n): Promise<McpClientLike> {\n if (opts.transport === \"sse\") {\n const sse = new SseMcpClient(opts)\n await sse.connect()\n return sse\n }\n const client = new StreamableHttpMcpClient(opts)\n await client.initialize()\n return client\n}\n\nclass StreamableHttpMcpClient implements McpClientLike {\n private id = 0\n private sessionId: string | undefined\n private readonly endpoint: string\n private readonly headers: Record<string, string>\n private readonly protocolVersion: string\n\n constructor(opts: ConnectMcpHttpOptions) {\n this.endpoint = opts.endpoint\n this.headers = opts.headers ?? {}\n this.protocolVersion = opts.protocolVersion ?? \"2025-06-18\"\n }\n\n async initialize(): Promise<void> {\n const res = await this.rpc({\n jsonrpc: \"2.0\",\n id: ++this.id,\n method: \"initialize\",\n params: {\n protocolVersion: this.protocolVersion,\n capabilities: {},\n clientInfo: { name: \"corpus-cli\", version: \"0.1.0\" },\n },\n })\n await this.rpc({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} }, false)\n if (res?.error) throw new Error(`initialize failed: ${JSON.stringify(res.error)}`)\n }\n\n async callTool(name: string, args: Record<string, unknown>) {\n const res = await this.rpc({\n jsonrpc: \"2.0\",\n id: ++this.id,\n method: \"tools/call\",\n params: { name, arguments: args },\n })\n if (res?.error) throw new Error(`tools/call ${name}: ${JSON.stringify(res.error)}`)\n const parsed = CALL_RESULT.safeParse(res?.result ?? {})\n return parsed.success ? parsed.data : {}\n }\n\n private async rpc(\n body: Record<string, unknown>,\n expectResponse = true\n ): Promise<{ result?: unknown; error?: unknown } | null> {\n const res = await fetch(this.endpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json, text/event-stream\",\n ...(this.sessionId ? { \"mcp-session-id\": this.sessionId } : {}),\n ...this.headers,\n },\n body: JSON.stringify(body),\n })\n const sid = res.headers.get(\"mcp-session-id\")\n if (sid) this.sessionId = sid\n if (!expectResponse) return null\n if (!res.ok) throw new Error(`MCP HTTP ${res.status} ${res.statusText}`)\n return parseRpc(await res.text(), res.headers.get(\"content-type\"))\n }\n}\n\n/**\n * Legacy HTTP+SSE MCP transport: GET the stream → first `endpoint` event gives\n * the POST URL → POST JSON-RPC requests there; responses arrive back on the\n * stream (correlated by id). Used for servers like Guilde's `/guilde/mcp/sse`.\n */\nclass SseMcpClient implements McpClientLike {\n private id = 0\n private messagesUrl: string | undefined\n private readonly pending = new Map<number, (msg: { result?: unknown; error?: unknown }) => void>()\n private readyResolve!: () => void\n private readonly ready = new Promise<void>(r => (this.readyResolve = r))\n private readonly base: URL\n\n constructor(private readonly opts: ConnectMcpHttpOptions) {\n this.base = new URL(opts.endpoint)\n }\n\n async connect(): Promise<void> {\n const res = await fetch(this.opts.endpoint, {\n headers: { accept: \"text/event-stream\", ...(this.opts.headers ?? {}) },\n })\n if (!res.ok || !res.body) throw new Error(`SSE connect ${res.status} ${res.statusText}`)\n void this.readLoop(res.body.getReader())\n // Wait for the endpoint event (POST url), then initialize.\n await withTimeout(this.ready, 10_000, \"SSE endpoint event\")\n const init = await this.send(\"initialize\", {\n protocolVersion: this.opts.protocolVersion ?? \"2025-06-18\",\n capabilities: {},\n clientInfo: { name: \"corpus-cli\", version: \"0.1.0\" },\n })\n if (init?.error) throw new Error(`initialize failed: ${JSON.stringify(init.error)}`)\n await this.post({ jsonrpc: \"2.0\", method: \"notifications/initialized\", params: {} })\n }\n\n async callTool(name: string, args: Record<string, unknown>) {\n const res = await this.send(\"tools/call\", { name, arguments: args })\n if (res?.error) throw new Error(`tools/call ${name}: ${JSON.stringify(res.error)}`)\n const parsed = CALL_RESULT.safeParse(res?.result ?? {})\n return parsed.success ? parsed.data : {}\n }\n\n private async send(method: string, params: unknown) {\n const id = ++this.id\n const wait = new Promise<{ result?: unknown; error?: unknown }>(resolve => this.pending.set(id, resolve))\n await this.post({ jsonrpc: \"2.0\", id, method, params })\n return withTimeout(wait, 60_000, `${method} response`)\n }\n\n private async post(body: Record<string, unknown>): Promise<void> {\n if (!this.messagesUrl) throw new Error(\"SSE messages endpoint not ready\")\n const res = await fetch(this.messagesUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", ...(this.opts.headers ?? {}) },\n body: JSON.stringify(body),\n })\n if (!res.ok && res.status !== 202) throw new Error(`SSE POST ${res.status}`)\n }\n\n private async readLoop(reader: ReadableStreamDefaultReader<Uint8Array>): Promise<void> {\n const dec = new TextDecoder()\n let buf = \"\"\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buf += dec.decode(value, { stream: true })\n let nl: number\n while ((nl = buf.indexOf(\"\\n\\n\")) >= 0) {\n const raw = buf.slice(0, nl)\n buf = buf.slice(nl + 2)\n this.handleEvent(raw)\n }\n }\n }\n\n private handleEvent(raw: string): void {\n let event = \"message\"\n const data: string[] = []\n for (const line of raw.split(\"\\n\")) {\n if (line.startsWith(\"event:\")) event = line.slice(6).trim()\n else if (line.startsWith(\"data:\")) data.push(line.slice(5).trim())\n }\n const payload = data.join(\"\\n\")\n if (event === \"endpoint\") {\n this.messagesUrl = new URL(payload, this.base).toString()\n this.readyResolve()\n return\n }\n if (!payload) return\n try {\n const parsed = RPC_MESSAGE.safeParse(JSON.parse(payload))\n if (!parsed.success) return\n const msg = parsed.data\n if (typeof msg.id === \"number\" && this.pending.has(msg.id)) {\n this.pending.get(msg.id)!(msg)\n this.pending.delete(msg.id)\n }\n } catch {\n /* skip non-JSON */\n }\n }\n}\n\nfunction withTimeout<T>(p: Promise<T>, ms: number, what: string): Promise<T> {\n return Promise.race([\n p,\n new Promise<T>((_, rej) => setTimeout(() => rej(new Error(`timeout waiting for ${what}`)), ms)),\n ])\n}\n\nfunction parseRpc(\n text: string,\n contentType: string | null\n): { result?: unknown; error?: unknown } | null {\n if (!text.trim()) return null\n if (!(contentType ?? \"\").includes(\"text/event-stream\")) {\n const parsed = RPC_RESPONSE.safeParse(JSON.parse(text))\n return parsed.success ? parsed.data : null\n }\n let last: { result?: unknown; error?: unknown } | null = null\n for (const line of text.split(\"\\n\")) {\n const t = line.trim()\n if (!t.startsWith(\"data:\")) continue\n const p = t.slice(5).trim()\n if (!p || p === \"[DONE]\") continue\n try {\n last = JSON.parse(p)\n } catch {\n /* skip non-JSON frames */\n }\n }\n return last\n}\n","/**\n * McpSink — a config-driven SinkPort that pushes each refined entry by calling\n * a configured MCP tool. Host-agnostic: the endpoint, tool name, and the\n * entry→args mapping all come from a sink manifest, so the corpus links to ANY\n * host (a Guilde guild KB, a Notion db, a vector store) without naming it.\n *\n * The manifest's `args` is a template: string values containing `${slug}`,\n * `${title}`, `${body}`, `${sources}`, `${tags}`, `${access}`, `${uri}`,\n * `${kind}`, `${confidence}` are substituted per entry. A value that is exactly\n * one placeholder (e.g. `\"${sources}\"`) is replaced with the typed value (array\n * / number), not a string.\n */\n\nimport { z } from \"zod\"\nimport type { SinkPort, SinkItem, SinkPushResult } from \"@agentproto/corpus\"\nimport { connectMcpHttp, type McpClientLike } from \"./mcp-http-client.js\"\n\n/** Validates a sink manifest (the `--config` JSON) — single source for the type. */\nexport const SINK_CONFIG_SCHEMA = z.object({\n endpoint: z.string().min(1),\n tool: z.string().min(1),\n /** Arg template — substituted per entry. */\n args: z.record(z.string(), z.unknown()),\n headers: z.record(z.string(), z.string()).optional(),\n /** MCP transport: \"streamable-http\" (default) or \"sse\". */\n transport: z.enum([\"streamable-http\", \"sse\"]).optional(),\n /**\n * If set, calls go through `mcp_imported_call({ alias, toolName, args })`\n * (the agentproto daemon's imported-MCP proxy) instead of the tool directly.\n */\n importedAlias: z.string().optional(),\n})\n\nexport type McpSinkConfig = z.infer<typeof SINK_CONFIG_SCHEMA>\n\nexport class McpSink implements SinkPort {\n private client: McpClientLike | undefined\n constructor(\n private readonly config: McpSinkConfig,\n client?: McpClientLike // injectable for tests\n ) {\n this.client = client\n }\n\n private async ensure(): Promise<McpClientLike> {\n if (!this.client) {\n this.client = await connectMcpHttp({\n endpoint: this.config.endpoint,\n ...(this.config.headers ? { headers: this.config.headers } : {}),\n ...(this.config.transport ? { transport: this.config.transport } : {}),\n })\n }\n return this.client\n }\n\n async push(item: SinkItem): Promise<SinkPushResult> {\n let client: McpClientLike\n try {\n client = await this.ensure()\n } catch (e) {\n return { uri: item.uri, ok: false, error: `connect: ${msg(e)}` }\n }\n const args = template(this.config.args, item)\n const call = this.config.importedAlias\n ? { name: \"mcp_imported_call\", args: { alias: this.config.importedAlias, toolName: this.config.tool, args } }\n : { name: this.config.tool, args }\n try {\n const res = await client.callTool(call.name, call.args)\n if (res.isError) return { uri: item.uri, ok: false, error: \"tool returned isError\" }\n return { uri: item.uri, ok: true }\n } catch (e) {\n return { uri: item.uri, ok: false, error: msg(e) }\n }\n }\n}\n\n// ── templating ──────────────────────────────────────────────────────\n\nconst PLACEHOLDER_RE = /\\$\\{(\\w+)\\}/g\n\nfunction template(args: Record<string, unknown>, item: SinkItem): Record<string, unknown> {\n const fields: Record<string, unknown> = {\n slug: item.slug,\n title: item.title,\n body: item.body,\n sources: item.sources,\n tags: item.tags,\n access: item.access ?? \"\",\n uri: item.uri,\n kind: item.kind,\n confidence: item.confidence,\n }\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(args)) {\n out[key] = substitute(value, fields)\n }\n return out\n}\n\nfunction substitute(value: unknown, fields: Record<string, unknown>): unknown {\n if (typeof value === \"string\") {\n // Whole-value placeholder → typed substitution.\n const whole = value.match(/^\\$\\{(\\w+)\\}$/)\n if (whole && whole[1]! in fields) return fields[whole[1]!]\n // Otherwise string interpolation.\n return value.replace(PLACEHOLDER_RE, (_, k) =>\n k in fields ? stringify(fields[k]) : `\\${${k}}`\n )\n }\n if (Array.isArray(value)) return value.map(v => substitute(v, fields))\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value)) out[k] = substitute(v, fields)\n return out\n }\n return value\n}\n\nfunction stringify(v: unknown): string {\n if (Array.isArray(v)) return v.join(\", \")\n return v == null ? \"\" : String(v)\n}\n\nfunction msg(e: unknown): string {\n return e instanceof Error ? e.message : String(e)\n}\n"]}