@astrofoundry/grimoire 3.15.0 → 3.17.0

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.
@@ -154,8 +154,13 @@ async function discoverUrls(page, source) {
154
154
  }
155
155
  return discovered;
156
156
  }
157
+ var NAV_TIMEOUT_MS_HEADED = 6e4;
158
+ var NAV_TIMEOUT_MS = 3e4;
157
159
  async function fetchPage(page, url, headed) {
158
- await page.goto(url, { waitUntil: headed ? "networkidle" : "domcontentloaded" });
160
+ await page.goto(url, {
161
+ waitUntil: headed ? "networkidle" : "domcontentloaded",
162
+ timeout: headed ? NAV_TIMEOUT_MS_HEADED : NAV_TIMEOUT_MS
163
+ });
159
164
  return page.content();
160
165
  }
161
166
  var DEFAULT_CONCURRENCY = 50;
@@ -180,21 +185,40 @@ async function scrapeSource(source, sourceName, dataDir, onProgress) {
180
185
  const urls = await discoverUrls(discoveryPage, source);
181
186
  await discoveryPage.close();
182
187
  let completed = 0;
188
+ const succeeded = [];
189
+ const failed = [];
183
190
  try {
184
191
  await runPool(urls, concurrency, async (url) => {
185
- const page = await context.newPage();
186
- try {
187
- const html = await fetchPage(page, url, source.headed);
188
- const slug = slugifyUrl(url);
189
- await writeFile(join(rawDir, `${slug}.html`), html, "utf-8");
190
- completed++;
191
- onProgress?.(completed, urls.length, url);
192
- } finally {
193
- await page.close();
192
+ let lastError;
193
+ for (let attempt = 0; attempt < 2; attempt++) {
194
+ const page = await context.newPage();
195
+ try {
196
+ const html = await fetchPage(page, url, source.headed);
197
+ const slug = slugifyUrl(url);
198
+ await writeFile(join(rawDir, `${slug}.html`), html, "utf-8");
199
+ succeeded.push(url);
200
+ completed++;
201
+ onProgress?.(completed, urls.length, url);
202
+ return;
203
+ } catch (err) {
204
+ lastError = err;
205
+ } finally {
206
+ await page.close();
207
+ }
194
208
  }
209
+ failed.push({ url, error: lastError instanceof Error ? lastError.message : String(lastError) });
210
+ completed++;
211
+ onProgress?.(completed, urls.length, url);
195
212
  });
196
- await writeFile(join(rawDir, "urls.json"), JSON.stringify(urls), "utf-8");
197
- return urls;
213
+ if (failed.length > 0) {
214
+ console.error(` Skipped ${failed.length}/${urls.length} pages after retry:`);
215
+ for (const { url, error } of failed.slice(0, 10)) {
216
+ console.error(` ${url} \u2014 ${error.split("\n")[0]}`);
217
+ }
218
+ if (failed.length > 10) console.error(` ...and ${failed.length - 10} more.`);
219
+ }
220
+ await writeFile(join(rawDir, "urls.json"), JSON.stringify(succeeded), "utf-8");
221
+ return succeeded;
198
222
  } finally {
199
223
  await browser.close();
200
224
  }
@@ -1513,4 +1537,4 @@ var ADMIN_COMMANDS = {
1513
1537
  export {
1514
1538
  ADMIN_COMMANDS
1515
1539
  };
1516
- //# sourceMappingURL=admin-HA6FNUV4.js.map
1540
+ //# sourceMappingURL=admin-DFYURN2T.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/admin.ts", "../src/config.ts", "../src/scraper.ts", "../src/converter.ts", "../src/chunker.ts", "../src/embedder.ts", "../src/store.ts", "../src/reranker.ts", "../src/search.ts", "../src/apikey.ts", "../src/llms-ingest.ts"],
4
+ "sourcesContent": ["import { parseArgs } from \"node:util\";\nimport { readFile, writeFile, readdir, rm, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { stringify } from \"yaml\";\nimport { bold, cyan, yellow } from \"./format.js\";\nimport { loadConfig, type SourceConfig } from \"./config.js\";\nimport { scrapeSource, createBrowser, slugifyUrl } from \"./scraper.js\";\nimport { convertSource } from \"./converter.js\";\nimport { chunkMarkdown } from \"./chunker.js\";\nimport type { Chunk } from \"./types.js\";\nimport { embedTexts } from \"./embedder.js\";\nimport {\n storeChunks,\n purgeSource,\n updateSourceMeta,\n getAllSourcesMeta,\n getSourceMeta,\n deleteSourceMeta,\n deleteChunksByIds,\n getSourceChunkIds,\n} from \"./store.js\";\nimport { search } from \"./search.js\";\nimport { cmdApiKey } from \"./apikey.js\";\nimport { ingestLlmsFull } from \"./llms-ingest.js\";\n\nconst PROJECT_ROOT = resolve(import.meta.dirname, \"..\");\nconst CONFIG_PATH = join(PROJECT_ROOT, \"config\", \"sources.yaml\");\nconst DATA_DIR = join(PROJECT_ROOT, \"data\");\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\nasync function cmdAdd(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n url: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const name = args.positionals[0];\n const url = args.values.url;\n\n if (!name || !url) {\n console.error(\"Usage: grimoire add <name> --url <start_url>\");\n process.exit(1);\n }\n\n console.log(\"Scanning page...\\n\");\n\n const browser = await createBrowser();\n const context = await browser.newContext();\n const page = await context.newPage();\n\n try {\n await page.goto(url, { waitUntil: \"domcontentloaded\" });\n\n const navCandidates = await page.evaluate(() => {\n const selectors = [\"nav\", \"[role='navigation']\"];\n const results: { selector: string; label: string; linkCount: number }[] = [];\n const seen = new Set<Element>();\n\n for (const sel of selectors) {\n for (const el of document.querySelectorAll(sel)) {\n if (seen.has(el)) continue;\n seen.add(el);\n const links = el.querySelectorAll(\"a[href]\");\n const label =\n el.getAttribute(\"aria-label\") ||\n el.getAttribute(\"class\") ||\n el.tagName.toLowerCase();\n results.push({\n selector: sel,\n label,\n linkCount: links.length,\n });\n }\n }\n\n return results.sort((a, b) => b.linkCount - a.linkCount);\n });\n\n if (navCandidates.length === 0) {\n console.error(\"No navigation elements found on this page.\");\n process.exit(1);\n }\n\n console.log(\"Navigation candidates:\");\n for (let i = 0; i < navCandidates.length; i++) {\n const c = navCandidates[i];\n console.log(` [${i + 1}] ${c.selector} (${c.label}) \u2014 ${c.linkCount} links`);\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n const navChoice = await prompt(rl, \"\\nSelect navigation: \");\n const navIndex = parseInt(navChoice, 10) - 1;\n if (isNaN(navIndex) || navIndex < 0 || navIndex >= navCandidates.length) {\n console.error(\"Invalid selection.\");\n rl.close();\n process.exit(1);\n }\n\n const selectedNav = navCandidates[navIndex];\n\n const parsedUrl = new URL(url);\n const defaultPattern = parsedUrl.pathname.replace(/\\/$/, \"\");\n\n const allLinks = await page.$$eval(\n `${selectedNav.selector} a[href]`,\n (links, pattern) => {\n return [...new Set(\n (links as HTMLAnchorElement[])\n .map((a) => a.href)\n .filter((h) => h.startsWith(\"http\") && !h.includes(\"?hl=\") && !h.endsWith(\"#\") && h.includes(pattern)),\n )];\n },\n defaultPattern,\n );\n\n console.log(`\\nFound ${allLinks.length} links matching ${defaultPattern}`);\n\n const patternInput = await prompt(rl, `Include pattern [default: ${defaultPattern}]: `);\n const includePattern = patternInput.trim() || defaultPattern;\n\n const excludeInput = await prompt(rl, \"Exclude patterns (comma-separated, optional): \");\n const excludePatterns = excludeInput.trim()\n ? excludeInput.split(\",\").map((p) => p.trim())\n : undefined;\n\n rl.close();\n\n const contentSelector = await page.evaluate(() => {\n if (document.querySelector(\"article\")) return \"article\";\n if (document.querySelector(\"main\")) return \"main\";\n return \"body\";\n });\n\n const removeSelectors = await page.evaluate(() => {\n const candidates = [\n { selector: \"nav\", label: \"nav\" },\n { selector: \"footer\", label: \"footer\" },\n { selector: \"[role='complementary']\", label: \"[role='complementary']\" },\n { selector: \"[role='banner']\", label: \"[role='banner']\" },\n { selector: \".breadcrumbs, .breadcrumb\", label: \".breadcrumbs\" },\n { selector: \".pagination-nav, .pagination\", label: \".pagination-nav\" },\n ];\n return candidates\n .filter((c) => document.querySelector(c.selector) !== null)\n .map((c) => c.label);\n });\n\n if (removeSelectors.length > 0) {\n console.log(`\\nDetected removable elements: ${removeSelectors.join(\", \")}`);\n }\n\n const parsedUrlForSitemap = new URL(url);\n let sitemapUrl: string | undefined;\n try {\n const sitemapCheck = await page.goto(`${parsedUrlForSitemap.origin}/sitemap.xml`, { waitUntil: \"domcontentloaded\", timeout: 10000 });\n if (sitemapCheck && sitemapCheck.status() === 200) {\n const body = await page.textContent(\"body\");\n if (body && (body.includes(\"<urlset\") || body.includes(\"<sitemapindex\"))) {\n sitemapUrl = `${parsedUrlForSitemap.origin}/sitemap.xml`;\n console.log(`\\nSitemap found: ${sitemapUrl}`);\n }\n }\n } catch {\n // No sitemap available\n }\n\n const source: SourceConfig = {\n name: name.replace(/-/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase()),\n start_url: url,\n ...(sitemapUrl ? { sitemap_url: sitemapUrl } : {}),\n nav_selector: selectedNav.selector,\n content_selector: contentSelector,\n include_patterns: [includePattern],\n ...(excludePatterns ? { exclude_patterns: excludePatterns } : {}),\n ...(removeSelectors.length > 0 ? { remove_selectors: removeSelectors } : {}),\n };\n\n let existingContent = \"\";\n try {\n existingContent = await readFile(CONFIG_PATH, \"utf-8\");\n } catch {\n existingContent = \"sources:\\n\";\n }\n\n const newEntry = stringify({ [name]: source }, { indent: 2 });\n const indented = newEntry\n .split(\"\\n\")\n .map((line) => (line.trim() ? ` ${line}` : \"\"))\n .join(\"\\n\");\n\n await writeFile(CONFIG_PATH, existingContent.trimEnd() + \"\\n\" + indented, \"utf-8\");\n\n console.log(`\\nSource \"${name}\" added to config/sources.yaml`);\n console.log(`Run \"grimoire refresh ${name}\" to start scraping.`);\n } finally {\n await browser.close();\n }\n}\n\nasync function loadEmbeddingsCache(cachePath: string): Promise<number[][] | null> {\n try {\n const data = await readFile(cachePath, \"utf-8\");\n return JSON.parse(data) as number[][];\n } catch {\n return null;\n }\n}\n\nasync function embedWithCheckpoint(\n texts: string[],\n rawDir: string,\n embeddingsCachePath: string,\n): Promise<number[][]> {\n await mkdir(rawDir, { recursive: true });\n\n const partialCache = await loadEmbeddingsCache(embeddingsCachePath);\n const resumeFrom = partialCache && partialCache.length > 0 && partialCache.length < texts.length ? partialCache : undefined;\n\n return embedTexts(texts, {\n onProgress: (done, total) => {\n console.log(` [${done}/${total}] embedded`);\n },\n onCheckpoint: async (current) => {\n await writeFile(embeddingsCachePath, JSON.stringify(current), \"utf-8\");\n },\n resumeFrom,\n });\n}\n\nasync function storeWithStrategy(\n sourceName: string,\n allChunks: Chunk[],\n embeddings: number[][],\n urlCount: number,\n version: string | undefined,\n diff: boolean,\n): Promise<void> {\n if (diff) {\n console.log(\" Computing diff...\");\n const existingIds = await getSourceChunkIds(sourceName);\n const newIds = new Set(allChunks.map((c) => c.id));\n const toDelete = [...existingIds].filter((id) => !newIds.has(id));\n\n console.log(` Diff: ${toDelete.length} to delete, ${allChunks.length} to upsert (${existingIds.size} existing)`);\n\n if (toDelete.length > 0) {\n console.log(\" Deleting removed chunks...\");\n await deleteChunksByIds(toDelete, (cur, total) => {\n console.log(` [${cur}/${total}] deleted`);\n });\n }\n\n console.log(\" Upserting chunks...\");\n await storeChunks(allChunks, embeddings, (cur, total) => {\n console.log(` [${cur}/${total}] stored`);\n });\n } else {\n console.log(\" Purging old chunks...\");\n await purgeSource(sourceName);\n\n console.log(\" Storing in Firestore...\");\n await storeChunks(allChunks, embeddings, (cur, total) => {\n console.log(` [${cur}/${total}] stored`);\n });\n }\n\n await updateSourceMeta(sourceName, allChunks.length, urlCount, version);\n console.log(` Done. ${allChunks.length} chunks stored for \"${sourceName}\".`);\n}\n\nasync function cmdRefresh(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n full: { type: \"boolean\", default: false },\n all: { type: \"boolean\", default: false },\n diff: { type: \"boolean\", default: false },\n concurrency: { type: \"string\" },\n limit: { type: \"string\" },\n \"from-html\": { type: \"boolean\", default: false },\n \"from-markdown\": { type: \"boolean\", default: false },\n \"from-embeddings\": { type: \"boolean\", default: false },\n \"skip-store\": { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const config = await loadConfig(CONFIG_PATH);\n const sourcesToRefresh = args.values.all\n ? Object.keys(config.sources)\n : [args.positionals[0]];\n\n if (!args.values.all && !sourcesToRefresh[0]) {\n console.error(\"Usage: grimoire refresh <source> [--full] [--from-html] [--from-markdown] [--from-embeddings] [--skip-store] [--limit <n>] [--concurrency <n>]\");\n process.exit(1);\n }\n\n const concurrencyOverride = args.values.concurrency ? parseInt(args.values.concurrency, 10) : undefined;\n const urlLimit = args.values.limit ? parseInt(args.values.limit, 10) : undefined;\n\n for (const sourceName of sourcesToRefresh) {\n const source = config.sources[sourceName];\n if (!source) {\n console.error(`Source \"${sourceName}\" not found in config.`);\n process.exit(1);\n }\n\n if (concurrencyOverride) {\n source.concurrency = concurrencyOverride;\n }\n\n const rawDir = join(DATA_DIR, \"raw\", sourceName);\n const mdDir = join(DATA_DIR, \"markdown\", sourceName);\n const embeddingsCachePath = join(rawDir, \"embeddings.json\");\n\n console.log(`\\nRefreshing \"${sourceName}\"...`);\n\n if (args.values.full) {\n console.log(\" Purging existing chunks...\");\n const deleted = await purgeSource(sourceName);\n console.log(` Deleted ${deleted} chunks.`);\n await rm(rawDir, { recursive: true, force: true });\n await rm(mdDir, { recursive: true, force: true });\n }\n\n let urls: string[];\n\n if (args.values[\"from-embeddings\"]) {\n console.log(\" Loading cached embeddings...\");\n const cached = await loadEmbeddingsCache(embeddingsCachePath);\n if (!cached) {\n console.error(\" No cached embeddings found. Run without --from-embeddings first.\");\n process.exit(1);\n }\n\n const mdFiles = await readdir(mdDir);\n const allPages = [];\n for (const f of mdFiles.filter((f) => f.endsWith(\".md\"))) {\n const content = await readFile(join(mdDir, f), \"utf-8\");\n const urlMatch = content.match(/^url: \"(.+)\"$/m);\n const titleMatch = content.match(/^title: \"(.+)\"$/m);\n allPages.push({\n markdown: content,\n url: urlMatch?.[1] ?? \"\",\n title: titleMatch?.[1] ?? \"Untitled\",\n });\n }\n\n console.log(\" Chunking...\");\n const allChunks = allPages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n if (cached.length !== allChunks.length) {\n console.error(` Embeddings cache (${cached.length}) doesn't match chunk count (${allChunks.length}). Re-embed with --from-html.`);\n process.exit(1);\n }\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, cached, allPages.length, source.version, args.values.diff!);\n continue;\n }\n\n if (args.values[\"from-markdown\"]) {\n console.log(\" Reading cached markdown...\");\n const mdFiles = await readdir(mdDir).catch(() => [] as string[]);\n const markdownFiles = mdFiles.filter((f) => f.endsWith(\".md\"));\n if (markdownFiles.length === 0) {\n console.error(\" No cached markdown found. Run with --from-html first.\");\n process.exit(1);\n }\n\n const pages = [];\n for (const f of markdownFiles) {\n const content = await readFile(join(mdDir, f), \"utf-8\");\n const urlMatch = content.match(/^url: \"(.+)\"$/m);\n const titleMatch = content.match(/^title: \"(.+)\"$/m);\n pages.push({\n markdown: content,\n url: urlMatch?.[1] ?? \"\",\n title: titleMatch?.[1] ?? \"Untitled\",\n });\n }\n console.log(` Found ${pages.length} cached pages.`);\n\n console.log(\" Chunking...\");\n const allChunks = pages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n console.log(\" Embedding chunks...\");\n const texts = allChunks.map((c) => c.content);\n const embeddings = await embedWithCheckpoint(texts, rawDir, embeddingsCachePath);\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, embeddings, pages.length, source.version, args.values.diff!);\n continue;\n }\n\n let pages: { source: string; url: string; title: string; markdown: string }[];\n\n if (source.llms_full_url && !args.values[\"from-html\"]) {\n console.log(` Fetching llms-full.txt from ${source.llms_full_url}...`);\n pages = await ingestLlmsFull(\n source.llms_full_url,\n sourceName,\n source.start_url,\n DATA_DIR,\n (cur, total) => {\n console.log(` [${cur}/${total}] pages processed`);\n },\n );\n console.log(` Extracted ${pages.length} pages.`);\n } else {\n if (args.values[\"from-html\"]) {\n console.log(\" Reading URLs from cached HTML...\");\n const urlsJsonPath = join(rawDir, \"urls.json\");\n try {\n urls = JSON.parse(await readFile(urlsJsonPath, \"utf-8\"));\n } catch {\n const rawFiles = await readdir(rawDir);\n const htmlFiles = rawFiles.filter((f) => f.endsWith(\".html\"));\n urls = [];\n for (const f of htmlFiles) {\n const fileSlug = f.replace(/\\.html$/, \"\");\n const htmlPath = join(rawDir, f);\n const html = await readFile(htmlPath, \"utf-8\");\n const match = html.match(/<link[^>]+rel=\"canonical\"[^>]+href=\"([^\"]+)\"/);\n if (match && slugifyUrl(match[1]) === fileSlug) { urls.push(match[1]); continue; }\n const ogMatch = html.match(/<meta[^>]+property=\"og:url\"[^>]+content=\"([^\"]+)\"/);\n if (ogMatch && slugifyUrl(ogMatch[1]) === fileSlug) { urls.push(ogMatch[1]); continue; }\n urls.push(`https://recovered/${fileSlug}`);\n }\n }\n console.log(` Found ${urls.length} cached pages.`);\n } else {\n console.log(\" Scraping URLs...\");\n urls = await scrapeSource(source, sourceName, DATA_DIR, (cur, total, url) => {\n console.log(` [${cur}/${total}] ${url}`);\n });\n console.log(` Found ${urls.length} pages.`);\n }\n\n if (urlLimit && urls.length > urlLimit) {\n urls = urls.slice(0, urlLimit);\n console.log(` Limited to ${urlLimit} pages.`);\n }\n\n console.log(\" Converting to markdown...\");\n pages = await convertSource(\n sourceName,\n urls,\n source.content_selector!,\n source.remove_selectors,\n source.remove_text_patterns,\n DATA_DIR,\n source.concurrency,\n (cur, total) => {\n if (cur % 10 === 0 || cur === total) console.log(` [${cur}/${total}] converted`);\n },\n );\n }\n\n console.log(\" Chunking...\");\n const allChunks = pages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n console.log(\" Embedding chunks...\");\n const texts = allChunks.map((c) => c.content);\n const embeddings = await embedWithCheckpoint(texts, rawDir, embeddingsCachePath);\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, embeddings, pages.length, source.version, args.values.diff!);\n }\n}\n\nasync function cmdSearch(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n source: { type: \"string\" },\n top: { type: \"string\" },\n compact: { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const query = args.positionals.join(\" \");\n if (!query) {\n console.error(\"Usage: grimoire search \\\"<query>\\\" [--source <name>] [--top <n>] [--compact]\");\n process.exit(1);\n }\n\n const topN = args.values.top ? parseInt(args.values.top, 10) : undefined;\n const results = await search(query, { source: args.values.source, topN });\n\n if (results.length === 0) {\n console.log(\"No results found.\");\n return;\n }\n\n if (args.values.compact) {\n for (const r of results) {\n console.log(`${r.relevance_score.toFixed(4)} | ${r.source} | ${r.title} | ${r.heading_path.join(\" > \")} | ${r.url}`);\n }\n return;\n }\n\n for (let i = 0; i < results.length; i++) {\n const r = results[i];\n console.log(`\\n${bold(`[${i + 1}] ${r.title}`)} (${r.relevance_score.toFixed(4)})`);\n console.log(` ${cyan(r.url)}`);\n console.log(` ${yellow(r.heading_path.join(\" > \"))}`);\n console.log(` ${r.content.replace(/\\n/g, \" \")}`);\n }\n}\n\nasync function cmdList(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n names: { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const metas = await getAllSourcesMeta();\n\n if (metas.length === 0) {\n console.log(\"No sources have been refreshed yet.\");\n return;\n }\n\n if (args.values.names) {\n for (const meta of metas) {\n console.log(meta.source);\n }\n return;\n }\n\n console.log(\"\\nSources:\\n\");\n for (const meta of metas) {\n const ver = meta.version ? ` v${meta.version}` : \"\";\n console.log(` ${bold(meta.source)}${ver}`);\n console.log(` ${meta.chunk_count} chunks, ${meta.url_count} URLs, last refreshed ${meta.last_refreshed}`);\n }\n}\n\nasync function cmdStats(): Promise<void> {\n const metas = await getAllSourcesMeta();\n\n if (metas.length === 0) {\n console.log(\"No sources have been refreshed yet.\");\n return;\n }\n\n let totalChunks = 0;\n let totalUrls = 0;\n\n console.log(\"\\nSource Statistics:\\n\");\n for (const meta of metas) {\n const ver = meta.version ? ` v${meta.version}` : \"\";\n console.log(` ${bold(meta.source)}${ver}`);\n console.log(` Chunks: ${meta.chunk_count}`);\n console.log(` URLs: ${meta.url_count}`);\n console.log(` Last refreshed: ${meta.last_refreshed}`);\n totalChunks += meta.chunk_count;\n totalUrls += meta.url_count;\n }\n\n console.log(`\\n Total: ${totalChunks} chunks across ${totalUrls} URLs from ${metas.length} sources`);\n}\n\nasync function cmdExport(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n format: { type: \"string\", default: \"json\" },\n },\n allowPositionals: true,\n });\n\n const sourceName = args.positionals[0];\n if (!sourceName) {\n console.error(\"Usage: grimoire export <source> [--format json]\");\n process.exit(1);\n }\n\n const mdDir = join(DATA_DIR, \"markdown\", sourceName);\n let files: string[];\n try {\n files = await readdir(mdDir);\n } catch {\n console.error(`No markdown data found for source \"${sourceName}\".`);\n process.exit(1);\n }\n\n const pages = [];\n for (const file of files.filter((f) => f.endsWith(\".md\"))) {\n const content = await readFile(join(mdDir, file), \"utf-8\");\n pages.push({ file, content });\n }\n\n console.log(JSON.stringify(pages, null, 2));\n}\n\nasync function cmdDelete(): Promise<void> {\n const sourceName = process.argv[3];\n if (!sourceName) {\n console.error(\"Usage: grimoire delete <source>\");\n process.exit(1);\n }\n\n const meta = await getSourceMeta(sourceName);\n if (!meta) {\n console.error(`Source \"${sourceName}\" not found in Firestore.`);\n process.exit(1);\n }\n\n console.log(`Deleting \"${sourceName}\" (${meta.chunk_count} chunks)...`);\n const deleted = await purgeSource(sourceName);\n await deleteSourceMeta(sourceName);\n console.log(`Deleted ${deleted} chunks and source metadata for \"${sourceName}\".`);\n}\n\nasync function cmdScrapeUrls(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n concurrency: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const sourceName = args.positionals[0];\n if (!sourceName) {\n console.error(\"Usage: grimoire scrape-urls <source> [--concurrency <n>]\");\n process.exit(1);\n }\n\n const config = await loadConfig(CONFIG_PATH);\n const source = config.sources[sourceName];\n if (!source) {\n console.error(`Source \"${sourceName}\" not found in config.`);\n process.exit(1);\n }\n\n const rawDir = join(DATA_DIR, \"raw\", sourceName);\n const urlsPath = join(rawDir, \"urls.json\");\n\n let urls: string[];\n try {\n urls = JSON.parse(await readFile(urlsPath, \"utf-8\"));\n } catch {\n console.error(`No urls.json found for \"${sourceName}\". Run 'grimoire refresh ${sourceName} --skip-store' first.`);\n process.exit(1);\n }\n\n const missing = urls.filter((url) => !existsSync(join(rawDir, `${slugifyUrl(url)}.html`)));\n console.log(`\\nTotal: ${urls.length}, Cached: ${urls.length - missing.length}, Missing: ${missing.length}`);\n\n if (missing.length === 0) {\n console.log(\"Nothing to scrape.\");\n return;\n }\n\n const concurrency = args.values.concurrency ? parseInt(args.values.concurrency, 10) : source.concurrency ?? 20;\n const browser = await createBrowser();\n const context = await browser.newContext(source.user_agent ? { userAgent: source.user_agent } : {});\n let done = 0;\n\n for (let i = 0; i < missing.length; i += concurrency) {\n const batch = missing.slice(i, i + concurrency);\n await Promise.all(batch.map(async (url) => {\n const page = await context.newPage();\n try {\n await page.goto(url, { waitUntil: source.headed ? \"networkidle\" : \"domcontentloaded\", timeout: 30000 });\n const html = await page.content();\n await writeFile(join(rawDir, `${slugifyUrl(url)}.html`), html, \"utf-8\");\n done++;\n if (done % 10 === 0 || done === missing.length) console.log(` [${done}/${missing.length}]`);\n } catch (e) {\n console.error(` FAILED: ${url} - ${e instanceof Error ? e.message : String(e)}`);\n } finally {\n await page.close();\n }\n }));\n }\n\n console.log(`Done. Fetched ${done} pages.`);\n await browser.close();\n}\n\nexport const ADMIN_COMMANDS: Record<string, () => Promise<void>> = {\n add: cmdAdd,\n refresh: cmdRefresh,\n delete: cmdDelete,\n \"scrape-urls\": cmdScrapeUrls,\n search: cmdSearch,\n list: cmdList,\n stats: cmdStats,\n export: cmdExport,\n apikey: cmdApiKey,\n};\n", "import { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\n\nexport interface SourceConfig {\n name: string;\n version?: string;\n start_url: string;\n nav_selector?: string;\n content_selector?: string;\n remove_selectors?: string[];\n remove_text_patterns?: string[];\n include_patterns?: string[];\n exclude_patterns?: string[];\n rate_limit_ms?: number;\n concurrency?: number;\n headed?: boolean;\n sitemap_url?: string;\n user_agent?: string;\n llms_full_url?: string;\n}\n\nexport interface GrimoireConfig {\n sources: Record<string, SourceConfig>;\n}\n\nconst REQUIRED_SOURCE_FIELDS = [\n \"name\",\n \"start_url\",\n] as const;\n\nconst SCRAPE_REQUIRED_FIELDS = [\n \"nav_selector\",\n \"content_selector\",\n] as const;\n\nexport function validateConfig(data: unknown): GrimoireConfig {\n if (typeof data !== \"object\" || data === null || !(\"sources\" in data)) {\n throw new Error(\"Config must have a 'sources' key\");\n }\n\n const { sources } = data as { sources: unknown };\n\n if (typeof sources !== \"object\" || sources === null) {\n throw new Error(\"'sources' must be an object\");\n }\n\n const entries = Object.entries(sources as Record<string, unknown>);\n\n if (entries.length === 0) {\n throw new Error(\"'sources' must contain at least one source\");\n }\n\n const validated: Record<string, SourceConfig> = {};\n\n for (const [key, value] of entries) {\n if (typeof value !== \"object\" || value === null) {\n throw new Error(`Source '${key}' must be an object`);\n }\n\n const source = value as Record<string, unknown>;\n\n for (const field of REQUIRED_SOURCE_FIELDS) {\n if (typeof source[field] !== \"string\" || source[field] === \"\") {\n throw new Error(`Source '${key}' is missing required field '${field}'`);\n }\n }\n\n if (!source.llms_full_url) {\n for (const field of SCRAPE_REQUIRED_FIELDS) {\n if (typeof source[field] !== \"string\" || source[field] === \"\") {\n throw new Error(`Source '${key}' is missing required field '${field}'`);\n }\n }\n }\n\n try {\n new URL(source.start_url as string);\n } catch {\n throw new Error(`Source '${key}' has invalid start_url: ${source.start_url}`);\n }\n\n if (source.remove_selectors !== undefined && !Array.isArray(source.remove_selectors)) {\n throw new Error(`Source '${key}': remove_selectors must be an array`);\n }\n\n if (source.remove_text_patterns !== undefined && !Array.isArray(source.remove_text_patterns)) {\n throw new Error(`Source '${key}': remove_text_patterns must be an array`);\n }\n\n if (source.include_patterns !== undefined && !Array.isArray(source.include_patterns)) {\n throw new Error(`Source '${key}': include_patterns must be an array`);\n }\n\n if (source.exclude_patterns !== undefined && !Array.isArray(source.exclude_patterns)) {\n throw new Error(`Source '${key}': exclude_patterns must be an array`);\n }\n\n if (source.rate_limit_ms !== undefined && typeof source.rate_limit_ms !== \"number\") {\n throw new Error(`Source '${key}': rate_limit_ms must be a number`);\n }\n\n if (source.concurrency !== undefined && typeof source.concurrency !== \"number\") {\n throw new Error(`Source '${key}': concurrency must be a number`);\n }\n\n validated[key] = {\n name: source.name as string,\n version: source.version as string | undefined,\n start_url: source.start_url as string,\n nav_selector: source.nav_selector as string | undefined,\n content_selector: source.content_selector as string | undefined,\n remove_selectors: source.remove_selectors as string[] | undefined,\n remove_text_patterns: source.remove_text_patterns as string[] | undefined,\n include_patterns: source.include_patterns as string[] | undefined,\n exclude_patterns: source.exclude_patterns as string[] | undefined,\n rate_limit_ms: source.rate_limit_ms as number | undefined,\n concurrency: source.concurrency as number | undefined,\n headed: source.headed as boolean | undefined,\n sitemap_url: source.sitemap_url as string | undefined,\n llms_full_url: source.llms_full_url as string | undefined,\n };\n }\n\n return { sources: validated };\n}\n\nexport async function loadConfig(path: string): Promise<GrimoireConfig> {\n const content = await readFile(path, \"utf-8\");\n const data = parse(content, { merge: true });\n return validateConfig(data);\n}\n", "import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { chromium, type Browser, type Page } from \"playwright\";\nimport type { SourceConfig } from \"./config.js\";\n\nexport function slugifyUrl(url: string): string {\n const parsed = new URL(url);\n return parsed.pathname\n .replace(/^\\//, \"\")\n .replace(/\\/$/, \"\")\n .replace(/\\//g, \"-\")\n .replace(/[^a-zA-Z0-9-]/g, \"\");\n}\n\nexport function filterUrls(\n urls: string[],\n includePatterns?: string[],\n excludePatterns?: string[],\n): string[] {\n let filtered = urls.filter(\n (url) => url.startsWith(\"http\") && !url.includes(\"?hl=\") && !url.endsWith(\"#\"),\n );\n\n if (includePatterns && includePatterns.length > 0) {\n filtered = filtered.filter((url) =>\n includePatterns.some((pattern) => url.includes(pattern)),\n );\n }\n\n if (excludePatterns && excludePatterns.length > 0) {\n filtered = filtered.filter(\n (url) => !excludePatterns.some((pattern) => url.includes(pattern)),\n );\n }\n\n return [...new Set(filtered)].sort();\n}\n\nasync function fetchSitemapUrls(sitemapUrl: string): Promise<string[]> {\n const response = await fetch(sitemapUrl);\n const xml = await response.text();\n const locs = [...xml.matchAll(/<loc>([^<]+)<\\/loc>/g)].map((m) => m[1]);\n\n if (xml.includes(\"<sitemapindex\")) {\n const nested = await Promise.all(locs.map((loc) => fetchSitemapUrls(loc)));\n return nested.flat();\n }\n\n return locs;\n}\n\nasync function discoverFromSitemap(sitemapUrl: string, source: SourceConfig): Promise<string[]> {\n const urls = await fetchSitemapUrls(sitemapUrl);\n return filterUrls(urls, source.include_patterns, source.exclude_patterns);\n}\n\nexport async function discoverUrls(\n page: Page,\n source: SourceConfig,\n): Promise<string[]> {\n if (source.sitemap_url) {\n return discoverFromSitemap(source.sitemap_url, source);\n }\n\n await page.goto(source.start_url, { waitUntil: source.headed ? \"networkidle\" : \"domcontentloaded\" });\n\n const rawUrls = await page.$$eval(\n `${source.nav_selector} a[href]`,\n (links) => links.map((a) => (a as HTMLAnchorElement).href),\n );\n\n const discovered = filterUrls(rawUrls, source.include_patterns, source.exclude_patterns);\n if (!discovered.includes(source.start_url)) {\n discovered.unshift(source.start_url);\n }\n return discovered;\n}\n\nconst NAV_TIMEOUT_MS_HEADED = 60000;\nconst NAV_TIMEOUT_MS = 30000;\n\nexport async function fetchPage(\n page: Page,\n url: string,\n headed?: boolean,\n): Promise<string> {\n await page.goto(url, {\n waitUntil: headed ? \"networkidle\" : \"domcontentloaded\",\n timeout: headed ? NAV_TIMEOUT_MS_HEADED : NAV_TIMEOUT_MS,\n });\n return page.content();\n}\n\nconst DEFAULT_CONCURRENCY = 50;\n\nasync function runPool<T>(\n items: T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<void>,\n): Promise<void> {\n let nextIndex = 0;\n\n async function worker(): Promise<void> {\n while (nextIndex < items.length) {\n const index = nextIndex++;\n await fn(items[index], index);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n}\n\nexport async function scrapeSource(\n source: SourceConfig,\n sourceName: string,\n dataDir: string,\n onProgress?: (current: number, total: number, url: string) => void,\n): Promise<string[]> {\n const rawDir = join(dataDir, \"raw\", sourceName);\n await mkdir(rawDir, { recursive: true });\n\n const concurrency = source.concurrency ?? DEFAULT_CONCURRENCY;\n const browser = await chromium.launch({ channel: \"chrome\", headless: !source.headed });\n const context = await browser.newContext(source.user_agent ? { userAgent: source.user_agent } : {});\n\n const discoveryPage = await context.newPage();\n const urls = await discoverUrls(discoveryPage, source);\n await discoveryPage.close();\n\n let completed = 0;\n const succeeded: string[] = [];\n const failed: { url: string; error: string }[] = [];\n\n try {\n await runPool(urls, concurrency, async (url) => {\n let lastError: unknown;\n for (let attempt = 0; attempt < 2; attempt++) {\n const page = await context.newPage();\n try {\n const html = await fetchPage(page, url, source.headed);\n const slug = slugifyUrl(url);\n await writeFile(join(rawDir, `${slug}.html`), html, \"utf-8\");\n succeeded.push(url);\n completed++;\n onProgress?.(completed, urls.length, url);\n return;\n } catch (err) {\n lastError = err;\n } finally {\n await page.close();\n }\n }\n failed.push({ url, error: lastError instanceof Error ? lastError.message : String(lastError) });\n completed++;\n onProgress?.(completed, urls.length, url);\n });\n\n if (failed.length > 0) {\n console.error(` Skipped ${failed.length}/${urls.length} pages after retry:`);\n for (const { url, error } of failed.slice(0, 10)) {\n console.error(` ${url} \u2014 ${error.split(\"\\n\")[0]}`);\n }\n if (failed.length > 10) console.error(` ...and ${failed.length - 10} more.`);\n }\n\n await writeFile(join(rawDir, \"urls.json\"), JSON.stringify(succeeded), \"utf-8\");\n return succeeded;\n } finally {\n await browser.close();\n }\n}\n\nexport async function createBrowser(): Promise<Browser> {\n return chromium.launch({ channel: \"chrome\" });\n}\n", "import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { JSDOM } from \"jsdom\";\nimport TurndownService from \"turndown\";\nimport { slugifyUrl } from \"./scraper.js\";\n\nconst turndown = new TurndownService({\n headingStyle: \"atx\",\n codeBlockStyle: \"fenced\",\n bulletListMarker: \"-\",\n});\n\nexport interface ConvertedPage {\n source: string;\n url: string;\n title: string;\n markdown: string;\n}\n\nconst GENERIC_REMOVE = [\n \"style\",\n \"script\",\n \"noscript\",\n \"iframe\",\n \"svg\",\n];\n\nfunction cleanMarkdown(md: string, textPatterns?: string[]): string {\n let cleaned = md\n .replace(/^(#+)\\s*$/gm, \"\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n\n if (textPatterns) {\n for (const pattern of textPatterns) {\n cleaned = cleaned.replace(new RegExp(pattern, \"gm\"), \"\");\n }\n cleaned = cleaned.replace(/\\n{3,}/g, \"\\n\\n\");\n }\n\n return cleaned.trim();\n}\n\nexport function extractContent(\n html: string,\n contentSelector: string,\n removeSelectors?: string[],\n removeTextPatterns?: string[],\n): string {\n const dom = new JSDOM(html);\n const doc = dom.window.document;\n\n const contentEl = doc.querySelector(contentSelector);\n if (!contentEl) {\n return cleanMarkdown(turndown.turndown(doc.body.innerHTML), removeTextPatterns);\n }\n\n const allSelectors = [...GENERIC_REMOVE, ...(removeSelectors ?? [])];\n for (const selector of allSelectors) {\n for (const el of contentEl.querySelectorAll(selector)) {\n el.remove();\n }\n }\n\n return cleanMarkdown(turndown.turndown(contentEl.innerHTML), removeTextPatterns);\n}\n\nexport function extractTitle(html: string): string {\n const dom = new JSDOM(html);\n const titleEl = dom.window.document.querySelector(\"title\");\n if (!titleEl) return \"Untitled\";\n return titleEl.textContent?.replace(/\\s*[|\u2013\u2014-]\\s*.+$/, \"\").trim() ?? \"Untitled\";\n}\n\nexport function buildFrontmatter(source: string, url: string, title: string): string {\n return [\n \"---\",\n `source: ${source}`,\n `url: \"${url}\"`,\n `title: \"${title.replace(/\"/g, '\\\\\"')}\"`,\n `fetched_at: \"${new Date().toISOString()}\"`,\n \"---\",\n ].join(\"\\n\");\n}\n\nexport function convertPage(\n html: string,\n source: string,\n url: string,\n contentSelector: string,\n removeSelectors?: string[],\n removeTextPatterns?: string[],\n): ConvertedPage {\n const title = extractTitle(html);\n const content = extractContent(html, contentSelector, removeSelectors, removeTextPatterns);\n const frontmatter = buildFrontmatter(source, url, title);\n const markdown = `${frontmatter}\\n\\n${content}`;\n\n return { source, url, title, markdown };\n}\n\nconst DEFAULT_CONCURRENCY = 10;\n\nexport async function convertSource(\n sourceName: string,\n urls: string[],\n contentSelector: string,\n removeSelectors: string[] | undefined,\n removeTextPatterns: string[] | undefined,\n dataDir: string,\n concurrency = DEFAULT_CONCURRENCY,\n onProgress?: (current: number, total: number, url: string) => void,\n): Promise<ConvertedPage[]> {\n const rawDir = join(dataDir, \"raw\", sourceName);\n const mdDir = join(dataDir, \"markdown\", sourceName);\n await mkdir(mdDir, { recursive: true });\n\n const pages: ConvertedPage[] = new Array(urls.length);\n let completed = 0;\n let nextIndex = 0;\n\n async function worker(): Promise<void> {\n while (nextIndex < urls.length) {\n const i = nextIndex++;\n const url = urls[i];\n const slug = slugifyUrl(url);\n const htmlPath = join(rawDir, `${slug}.html`);\n const html = await readFile(htmlPath, \"utf-8\");\n\n const page = convertPage(html, sourceName, url, contentSelector, removeSelectors, removeTextPatterns);\n await writeFile(join(mdDir, `${slug}.md`), page.markdown, \"utf-8\");\n pages[i] = page;\n completed++;\n onProgress?.(completed, urls.length, url);\n }\n }\n\n const workers = Array.from(\n { length: Math.min(concurrency, urls.length) },\n () => worker(),\n );\n await Promise.all(workers);\n\n return pages;\n}\n", "import { slugifyUrl } from \"./scraper.js\";\nimport type { Chunk } from \"./types.js\";\n\nexport type { Chunk };\n\nconst MAX_TOKENS = 500;\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport function slugifyHeading(heading: string): string {\n return heading\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nexport function buildChunkId(\n source: string,\n url: string,\n headingSlug: string,\n index?: number,\n): string {\n const urlSlug = slugifyUrl(url);\n const prefix = `${source}::${urlSlug}::`;\n const maxSlugBytes = 1500 - Buffer.byteLength(prefix) - 10;\n const truncatedSlug =\n Buffer.byteLength(headingSlug) > maxSlugBytes\n ? Buffer.from(headingSlug).subarray(0, maxSlugBytes).toString()\n : headingSlug;\n const base = `${prefix}${truncatedSlug}`;\n return index !== undefined ? `${base}-${index}` : base;\n}\n\ninterface HeadingSection {\n level: number;\n heading: string;\n headingPath: string[];\n lines: string[];\n}\n\nfunction parseHeadingSections(markdown: string): HeadingSection[] {\n const lines = markdown.split(\"\\n\");\n const sections: HeadingSection[] = [];\n const headingStack: string[] = [];\n const levelStack: number[] = [];\n\n let currentSection: HeadingSection = {\n level: 0,\n heading: \"\",\n headingPath: [],\n lines: [],\n };\n\n for (const line of lines) {\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n\n if (headingMatch) {\n if (currentSection.lines.length > 0 || currentSection.heading !== \"\") {\n sections.push(currentSection);\n }\n\n const level = headingMatch[1].length;\n const heading = headingMatch[2].trim();\n\n while (levelStack.length > 0 && levelStack[levelStack.length - 1] >= level) {\n levelStack.pop();\n headingStack.pop();\n }\n\n headingStack.push(heading);\n levelStack.push(level);\n\n currentSection = {\n level,\n heading,\n headingPath: [...headingStack],\n lines: [],\n };\n } else {\n currentSection.lines.push(line);\n }\n }\n\n if (currentSection.lines.length > 0 || currentSection.heading !== \"\") {\n sections.push(currentSection);\n }\n\n return sections;\n}\n\nfunction splitAtParagraphBoundaries(text: string, maxTokens: number): string[] {\n const paragraphs = text.split(/\\n\\n+/);\n const parts: string[] = [];\n let current: string[] = [];\n let currentTokens = 0;\n\n for (const para of paragraphs) {\n const paraTokens = estimateTokens(para);\n\n if (currentTokens + paraTokens > maxTokens && current.length > 0) {\n parts.push(current.join(\"\\n\\n\"));\n current = [para];\n currentTokens = paraTokens;\n } else {\n current.push(para);\n currentTokens += paraTokens;\n }\n }\n\n if (current.length > 0) {\n parts.push(current.join(\"\\n\\n\"));\n }\n\n return parts;\n}\n\nfunction stripFrontmatter(markdown: string): string {\n if (markdown.startsWith(\"---\")) {\n const endIndex = markdown.indexOf(\"---\", 3);\n if (endIndex !== -1) {\n return markdown.slice(endIndex + 3).trim();\n }\n }\n return markdown;\n}\n\nexport function chunkMarkdown(\n markdown: string,\n source: string,\n url: string,\n title: string,\n): Chunk[] {\n const stripped = stripFrontmatter(markdown);\n const sections = parseHeadingSections(stripped);\n const chunks: Chunk[] = [];\n const usedIds = new Set<string>();\n\n function uniqueId(baseSlug: string): string {\n let id = buildChunkId(source, url, baseSlug);\n if (!usedIds.has(id)) {\n usedIds.add(id);\n return id;\n }\n let counter = 1;\n while (usedIds.has(buildChunkId(source, url, baseSlug, counter))) {\n counter++;\n }\n id = buildChunkId(source, url, baseSlug, counter);\n usedIds.add(id);\n return id;\n }\n\n for (const section of sections) {\n const headingLine = section.heading\n ? `${\"#\".repeat(section.level)} ${section.heading}\\n\\n`\n : \"\";\n const content = headingLine + section.lines.join(\"\\n\").trim();\n\n if (!content.trim()) continue;\n\n const headingSlug = section.heading\n ? slugifyHeading(section.heading)\n : \"intro\";\n\n const tokens = estimateTokens(content);\n\n if (tokens <= MAX_TOKENS) {\n chunks.push({\n id: uniqueId(headingSlug),\n source,\n url,\n title,\n heading_path: section.headingPath,\n content,\n token_count: tokens,\n });\n } else {\n const parts = splitAtParagraphBoundaries(content, MAX_TOKENS);\n for (let i = 0; i < parts.length; i++) {\n const partContent = parts[i].trim();\n if (!partContent) continue;\n\n const partSlug = parts.length > 1 ? `${headingSlug}-${i}` : headingSlug;\n chunks.push({\n id: uniqueId(partSlug),\n source,\n url,\n title,\n heading_path: section.headingPath,\n content: partContent,\n token_count: estimateTokens(partContent),\n });\n }\n }\n }\n\n return chunks;\n}\n", "import { GoogleGenerativeAI } from \"@google/generative-ai\";\n\nconst BATCH_SIZE = 50;\nconst MODEL = \"gemini-embedding-001\";\nconst OUTPUT_DIMENSIONALITY = 768;\nconst MAX_RETRIES = 5;\nconst RATE_LIMIT_BASE_DELAY_MS = 60000;\nconst NETWORK_BASE_DELAY_MS = 10000;\nconst BATCH_DELAY_MS = 2500;\nconst DEFAULT_CHECKPOINT_EVERY_BATCHES = 20;\n\nconst NETWORK_ERROR_PATTERNS = [\n \"fetch failed\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n \"ECONNREFUSED\",\n \"EAI_AGAIN\",\n \"ENOTFOUND\",\n \"socket hang up\",\n \"UND_ERR_\",\n];\n\nlet genAI: GoogleGenerativeAI | undefined;\n\nfunction getClient(): GoogleGenerativeAI {\n if (!genAI) {\n const apiKey = process.env.GEMINI_API_KEY;\n if (!apiKey) {\n throw new Error(\"GEMINI_API_KEY environment variable is not set\");\n }\n genAI = new GoogleGenerativeAI(apiKey);\n }\n return genAI;\n}\n\nfunction classifyError(message: string): \"rate_limit\" | \"network\" | \"other\" {\n if (message.includes(\"429\") || message.includes(\"503\")) {\n return \"rate_limit\";\n }\n if (NETWORK_ERROR_PATTERNS.some((p) => message.includes(p))) {\n return \"network\";\n }\n return \"other\";\n}\n\nexport interface EmbedOptions {\n onProgress?: (done: number, total: number) => void;\n onCheckpoint?: (embeddings: number[][]) => Promise<void>;\n checkpointEveryBatches?: number;\n resumeFrom?: number[][];\n}\n\nexport async function embedTexts(\n texts: string[],\n options: EmbedOptions = {},\n): Promise<number[][]> {\n const client = getClient();\n const model = client.getGenerativeModel({ model: MODEL });\n\n const { onProgress, onCheckpoint, resumeFrom } = options;\n const checkpointEveryBatches = options.checkpointEveryBatches ?? DEFAULT_CHECKPOINT_EVERY_BATCHES;\n\n const embeddings: number[][] = resumeFrom ? [...resumeFrom] : [];\n const startIndex = Math.floor(embeddings.length / BATCH_SIZE) * BATCH_SIZE;\n\n if (embeddings.length > startIndex) {\n embeddings.length = startIndex;\n }\n\n if (startIndex > 0) {\n console.log(` Resuming from chunk ${startIndex} of ${texts.length} (${embeddings.length} cached).`);\n }\n\n if (startIndex >= texts.length) {\n return embeddings.slice(0, texts.length);\n }\n\n let batchesSinceCheckpoint = 0;\n\n for (let i = startIndex; i < texts.length; i += BATCH_SIZE) {\n const batch = texts.slice(i, i + BATCH_SIZE);\n const batchNumber = i / BATCH_SIZE + 1;\n\n let result;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n result = await model.batchEmbedContents({\n requests: batch.map((text) => ({\n content: { role: \"user\", parts: [{ text }] },\n outputDimensionality: OUTPUT_DIMENSIONALITY,\n })),\n });\n break;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const kind = classifyError(message);\n\n if (kind !== \"other\" && attempt < MAX_RETRIES - 1) {\n const baseDelay = kind === \"rate_limit\" ? RATE_LIMIT_BASE_DELAY_MS : NETWORK_BASE_DELAY_MS;\n const delay = baseDelay * Math.pow(2, attempt);\n const label = kind === \"rate_limit\" ? \"Rate limited\" : \"Network error\";\n console.log(` ${label} (batch ${batchNumber}), retrying in ${delay / 1000}s...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n console.error(` Embedding failed at batch ${batchNumber} (chunks ${i + 1}-${i + batch.length}): ${message}`);\n throw err;\n }\n }\n\n for (const embedding of result!.embeddings) {\n embeddings.push(embedding.values);\n }\n\n onProgress?.(Math.min(i + BATCH_SIZE, texts.length), texts.length);\n\n batchesSinceCheckpoint++;\n if (onCheckpoint && batchesSinceCheckpoint >= checkpointEveryBatches && i + BATCH_SIZE < texts.length) {\n await onCheckpoint(embeddings);\n batchesSinceCheckpoint = 0;\n }\n\n if (i + BATCH_SIZE < texts.length) {\n await new Promise((resolve) => setTimeout(resolve, BATCH_DELAY_MS));\n }\n }\n\n if (onCheckpoint) {\n await onCheckpoint(embeddings);\n }\n\n return embeddings;\n}\n\nexport async function embedText(text: string): Promise<number[]> {\n const [embedding] = await embedTexts([text]);\n return embedding;\n}\n", "import { initializeApp, applicationDefault, getApps } from \"firebase-admin/app\";\nimport {\n getFirestore,\n FieldValue,\n type Firestore,\n} from \"firebase-admin/firestore\";\nimport type { Chunk, SourceMeta } from \"./types.js\";\n\nconst BATCH_SIZE = 500;\nconst MAX_RETRIES = 5;\nconst BASE_DELAY_MS = 5000;\n\nasync function retryOnQuota<T>(fn: () => Promise<T>): Promise<T> {\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n return await fn();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if ((message.includes(\"RESOURCE_EXHAUSTED\") || message.includes(\"Quota exceeded\")) && attempt < MAX_RETRIES - 1) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n console.log(` Quota exceeded, retrying in ${delay / 1000}s...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n throw err;\n }\n }\n throw new Error(\"Max retries exceeded\");\n}\n\nlet db: Firestore | undefined;\n\nfunction getDb(): Firestore {\n if (!db) {\n if (getApps().length === 0) {\n initializeApp({ credential: applicationDefault() });\n }\n db = getFirestore();\n }\n return db;\n}\n\nfunction chunksCol() {\n return getDb().collection(\"grimoire_chunks\");\n}\n\nfunction sourcesCol() {\n return getDb().collection(\"grimoire_sources\");\n}\n\nexport async function storeChunks(\n chunks: Chunk[],\n embeddings: number[][],\n onProgress?: (current: number, total: number) => void,\n): Promise<void> {\n const database = getDb();\n const col = chunksCol();\n\n for (let i = 0; i < chunks.length; i += BATCH_SIZE) {\n const batch = database.batch();\n const slice = chunks.slice(i, i + BATCH_SIZE);\n const embSlice = embeddings.slice(i, i + BATCH_SIZE);\n\n for (let j = 0; j < slice.length; j++) {\n const chunk = slice[j];\n batch.set(col.doc(chunk.id), {\n source: chunk.source,\n url: chunk.url,\n title: chunk.title,\n heading_path: chunk.heading_path,\n content: chunk.content,\n token_count: chunk.token_count,\n embedded_at: new Date().toISOString(),\n embedding: FieldValue.vector(embSlice[j]),\n });\n }\n\n await retryOnQuota(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, chunks.length), chunks.length);\n }\n}\n\nexport async function purgeSource(sourceName: string): Promise<number> {\n const database = getDb();\n const col = chunksCol();\n\n const snapshot = await col.where(\"source\", \"==\", sourceName).get();\n if (snapshot.empty) return 0;\n\n let batch = database.batch();\n let count = 0;\n\n for (const doc of snapshot.docs) {\n batch.delete(doc.ref);\n count++;\n if (count % BATCH_SIZE === 0) {\n await retryOnQuota(() => batch.commit());\n batch = database.batch();\n }\n }\n\n if (count % BATCH_SIZE !== 0) {\n await retryOnQuota(() => batch.commit());\n }\n\n return count;\n}\n\nexport async function updateSourceMeta(\n sourceName: string,\n chunkCount: number,\n urlCount: number,\n version?: string,\n): Promise<void> {\n await sourcesCol().doc(sourceName).set({\n source: sourceName,\n ...(version ? { version } : {}),\n last_refreshed: new Date().toISOString(),\n chunk_count: chunkCount,\n url_count: urlCount,\n });\n}\n\nexport async function getSourceMeta(sourceName: string): Promise<SourceMeta | null> {\n const doc = await sourcesCol().doc(sourceName).get();\n if (!doc.exists) return null;\n return doc.data() as SourceMeta;\n}\n\nexport async function getAllSourcesMeta(): Promise<SourceMeta[]> {\n const snapshot = await sourcesCol().get();\n return snapshot.docs.map((doc) => doc.data() as SourceMeta);\n}\n\nexport async function deleteSourceMeta(sourceName: string): Promise<void> {\n await sourcesCol().doc(sourceName).delete();\n}\n\nexport async function deleteChunksByIds(\n ids: string[],\n onProgress?: (current: number, total: number) => void,\n): Promise<void> {\n if (ids.length === 0) return;\n const database = getDb();\n const col = chunksCol();\n\n for (let i = 0; i < ids.length; i += BATCH_SIZE) {\n const batch = database.batch();\n const slice = ids.slice(i, i + BATCH_SIZE);\n for (const id of slice) {\n batch.delete(col.doc(id));\n }\n await retryOnQuota(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, ids.length), ids.length);\n }\n}\n\nexport async function getSourceChunkIds(sourceName: string): Promise<Set<string>> {\n const col = chunksCol();\n const snapshot = await col.where(\"source\", \"==\", sourceName).select().get();\n return new Set(snapshot.docs.map((doc) => doc.id));\n}\n\nexport async function vectorSearch(\n queryEmbedding: number[],\n limit: number,\n source?: string,\n): Promise<{ id: string; data: Record<string, unknown>; distance: number }[]> {\n const col = chunksCol();\n\n let query = col as FirebaseFirestore.Query;\n if (source) {\n query = query.where(\"source\", \"==\", source);\n }\n\n const snapshot = await query\n .findNearest({\n vectorField: \"embedding\",\n queryVector: FieldValue.vector(queryEmbedding),\n limit,\n distanceMeasure: \"COSINE\",\n distanceResultField: \"_distance\",\n })\n .get();\n\n return snapshot.docs.map((doc) => {\n const data = doc.data();\n const distance = (data._distance as number) ?? 0;\n delete data._distance;\n return { id: doc.id, data, distance };\n });\n}\n", "export interface RerankResult {\n index: number;\n relevance_score: number;\n}\n\ninterface LlamaCppRerankResponse {\n results: { index: number; relevance_score: number }[];\n}\n\nfunction getRerankerUrl(): string {\n const url = process.env.RERANKER_URL;\n if (!url) {\n throw new Error(\"RERANKER_URL environment variable is not set\");\n }\n return url;\n}\n\nexport async function rerank(\n query: string,\n documents: string[],\n topN = 5,\n): Promise<RerankResult[]> {\n const baseUrl = getRerankerUrl();\n const response = await fetch(`${baseUrl}/v1/rerank`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ query, documents, top_n: topN }),\n });\n\n if (!response.ok) {\n throw new Error(`Reranker request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as LlamaCppRerankResponse;\n return data.results;\n}\n", "import { embedText } from \"./embedder.js\";\nimport { vectorSearch } from \"./store.js\";\nimport { rerank } from \"./reranker.js\";\nimport type { SearchResult } from \"./types.js\";\n\nexport type { SearchResult };\n\nfunction hasReranker(): boolean {\n return !!process.env.RERANKER_URL;\n}\n\nexport async function search(\n query: string,\n options: { source?: string; candidates?: number; topN?: number } = {},\n): Promise<SearchResult[]> {\n const { source, candidates = 20, topN = 5 } = options;\n\n const queryEmbedding = await embedText(query);\n const rawResults = await vectorSearch(queryEmbedding, candidates, source);\n\n if (rawResults.length === 0) return [];\n\n if (hasReranker()) {\n const documents = rawResults.map((r) => r.data.content as string);\n const reranked = await rerank(query, documents, topN);\n\n return reranked.map((r) => {\n const original = rawResults[r.index];\n const data = original.data;\n return {\n id: original.id,\n source: data.source as string,\n url: data.url as string,\n title: data.title as string,\n heading_path: data.heading_path as string[],\n content: data.content as string,\n relevance_score: r.relevance_score,\n };\n });\n }\n\n return rawResults.slice(0, topN).map((r) => {\n const data = r.data;\n return {\n id: r.id,\n source: data.source as string,\n url: data.url as string,\n title: data.title as string,\n heading_path: data.heading_path as string[],\n content: data.content as string,\n relevance_score: Math.max(0, 1 - r.distance / 2),\n };\n });\n}\n", "import { randomBytes, createHash } from \"node:crypto\";\nimport {\n getFirestore,\n type Firestore,\n} from \"firebase-admin/firestore\";\nimport { initializeApp, applicationDefault, getApps } from \"firebase-admin/app\";\nimport { bold } from \"./format.js\";\n\nlet db: Firestore | undefined;\n\nfunction getDb(): Firestore {\n if (!db) {\n if (getApps().length === 0) {\n initializeApp({ credential: applicationDefault() });\n }\n db = getFirestore();\n }\n return db;\n}\n\nfunction hashKey(key: string): string {\n return createHash(\"sha256\").update(key).digest(\"hex\");\n}\n\nfunction apiKeysCol() {\n return getDb().collection(\"grimoire_api_keys\");\n}\n\nexport async function createApiKey(name: string): Promise<string> {\n const raw = `grim_${randomBytes(32).toString(\"base64url\")}`;\n const hash = hashKey(raw);\n\n await apiKeysCol().doc(hash).set({\n name,\n created_at: new Date().toISOString(),\n last_used_at: null,\n });\n\n return raw;\n}\n\nexport async function listApiKeys(): Promise<void> {\n const snapshot = await apiKeysCol().get();\n\n if (snapshot.empty) {\n console.log(\"No API keys found.\");\n return;\n }\n\n console.log(\"\\nAPI Keys:\\n\");\n for (const doc of snapshot.docs) {\n const data = doc.data();\n const lastUsed = data.last_used_at ?? \"never\";\n console.log(` ${bold(data.name)}`);\n console.log(` Created: ${data.created_at}`);\n console.log(` Last used: ${lastUsed}`);\n }\n}\n\nexport async function deleteApiKey(name: string): Promise<void> {\n const snapshot = await apiKeysCol().where(\"name\", \"==\", name).get();\n\n if (snapshot.empty) {\n throw new Error(`No API key found with name \"${name}\".`);\n }\n\n for (const doc of snapshot.docs) {\n await doc.ref.delete();\n }\n\n console.log(`API key \"${name}\" deleted.`);\n}\n\nexport async function cmdApiKey(): Promise<void> {\n const subcommand = process.argv[3];\n const arg = process.argv[4];\n\n if (subcommand === \"create\") {\n if (!arg) {\n console.error(\"Usage: grimoire apikey create <name>\");\n process.exit(1);\n }\n const key = await createApiKey(arg);\n console.log(`\\nAPI key created for \"${arg}\":\\n`);\n console.log(` ${key}\\n`);\n console.log(\"Save this key \u2014 it will not be shown again.\");\n } else if (subcommand === \"list\") {\n await listApiKeys();\n } else if (subcommand === \"delete\") {\n if (!arg) {\n console.error(\"Usage: grimoire apikey delete <name>\");\n process.exit(1);\n }\n await deleteApiKey(arg);\n } else {\n console.error(\"Usage: grimoire apikey <create|list|delete> [name]\");\n process.exit(1);\n }\n}\n", "import { writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { slugifyUrl } from \"./scraper.js\";\nimport { buildFrontmatter, type ConvertedPage } from \"./converter.js\";\n\ninterface LlmsPage {\n title: string;\n url: string;\n markdown: string;\n}\n\nconst BOILERPLATE_PATTERNS = [\n /^\\[Skip to content\\]\\([^)]*\\)\\s*$/gm,\n /^Was this helpful\\?\\s*$/gm,\n /^YesNo\\s*$/gm,\n /^\\[ Edit page \\]\\([^)]+\\) \\[ Report issue \\]\\([^)]+\\)\\s*$/gm,\n /^Copy page\\s*$/gm,\n /^```json\\n\\{\"@context\":\"https:\\/\\/schema\\.org\",\"@type\":\"BreadcrumbList\"[^`]*```\\s*$/gm,\n];\n\nfunction splitPages(content: string): LlmsPage[] {\n const pages: LlmsPage[] = [];\n const frontmatterPattern = /^---\\ntitle: (.+)\\n/gm;\n const boundaries: { index: number; title: string }[] = [];\n\n let match;\n while ((match = frontmatterPattern.exec(content)) !== null) {\n boundaries.push({ index: match.index, title: match[1] });\n }\n\n for (let i = 0; i < boundaries.length; i++) {\n const start = boundaries[i].index;\n const end = i + 1 < boundaries.length ? boundaries[i + 1].index : content.length;\n const raw = content.slice(start, end).trimEnd();\n\n const url = extractUrl(raw);\n if (!url) continue;\n\n const bodyStart = raw.indexOf(\"---\", 3);\n if (bodyStart === -1) continue;\n const body = raw.slice(raw.indexOf(\"\\n\", bodyStart) + 1);\n\n let cleaned = body;\n for (const pattern of BOILERPLATE_PATTERNS) {\n cleaned = cleaned.replace(pattern, \"\");\n }\n cleaned = cleaned.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n if (!cleaned) continue;\n\n pages.push({\n title: boundaries[i].title,\n url,\n markdown: cleaned,\n });\n }\n\n return pages;\n}\n\nfunction extractUrl(pageContent: string): string | null {\n const match = pageContent.match(\n /```json\\n\\{\"@context\":\"https:\\/\\/schema\\.org\",\"@type\":\"BreadcrumbList\",\"itemListElement\":\\[(.+?)\\]\\}\\n```/,\n );\n if (!match) return null;\n\n const items = JSON.parse(`[${match[1]}]`) as { item?: { \"@id\": string } }[];\n const last = items[items.length - 1];\n if (!last?.item?.[\"@id\"]) return null;\n\n return `https://developers.cloudflare.com${last.item[\"@id\"]}`;\n}\n\nexport async function ingestLlmsFull(\n llmsFullUrl: string,\n sourceName: string,\n baseUrl: string,\n dataDir: string,\n onProgress?: (current: number, total: number) => void,\n): Promise<ConvertedPage[]> {\n const response = await fetch(llmsFullUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${llmsFullUrl}: ${response.status} ${response.statusText}`);\n }\n const content = await response.text();\n\n const pages = splitPages(content);\n\n const mdDir = join(dataDir, \"markdown\", sourceName);\n await mkdir(mdDir, { recursive: true });\n\n const results: ConvertedPage[] = [];\n for (let i = 0; i < pages.length; i++) {\n const page = pages[i];\n const frontmatter = buildFrontmatter(sourceName, page.url, page.title);\n const fullMarkdown = `${frontmatter}\\n\\n${page.markdown}`;\n const slug = slugifyUrl(page.url);\n await writeFile(join(mdDir, `${slug}.md`), fullMarkdown, \"utf-8\");\n\n results.push({\n source: sourceName,\n url: page.url,\n title: page.title,\n markdown: fullMarkdown,\n });\n\n if (onProgress && ((i + 1) % 100 === 0 || i + 1 === pages.length)) {\n onProgress(i + 1, pages.length);\n }\n }\n\n return results;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["readFile", "writeFile", "mkdir", "join", "readFile", "writeFile", "mkdir", "join", "DEFAULT_CONCURRENCY", "join", "mkdir", "readFile", "writeFile", "resolve", "BATCH_SIZE", "MAX_RETRIES", "resolve", "getFirestore", "initializeApp", "applicationDefault", "getApps", "db", "getDb", "getApps", "initializeApp", "applicationDefault", "getFirestore", "writeFile", "mkdir", "join", "join", "mkdir", "writeFile", "join", "resolve", "readFile", "writeFile", "mkdir", "f", "allChunks", "pages", "texts", "embeddings"]
7
+ }
package/dist/cli.js CHANGED
@@ -317,7 +317,7 @@ async function main() {
317
317
  await cmdInit();
318
318
  return;
319
319
  }
320
- const { ADMIN_COMMANDS } = await import("./admin-HA6FNUV4.js");
320
+ const { ADMIN_COMMANDS } = await import("./admin-DFYURN2T.js");
321
321
  const handler = ADMIN_COMMANDS[command];
322
322
  if (!handler) {
323
323
  console.error(`Unknown command: ${command}. Run "grimoire --help" for usage.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrofoundry/grimoire",
3
- "version": "3.15.0",
3
+ "version": "3.17.0",
4
4
  "description": "Documentation RAG System",
5
5
  "keywords": [],
6
6
  "author": "",
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/admin.ts", "../src/config.ts", "../src/scraper.ts", "../src/converter.ts", "../src/chunker.ts", "../src/embedder.ts", "../src/store.ts", "../src/reranker.ts", "../src/search.ts", "../src/apikey.ts", "../src/llms-ingest.ts"],
4
- "sourcesContent": ["import { parseArgs } from \"node:util\";\nimport { readFile, writeFile, readdir, rm, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { stringify } from \"yaml\";\nimport { bold, cyan, yellow } from \"./format.js\";\nimport { loadConfig, type SourceConfig } from \"./config.js\";\nimport { scrapeSource, createBrowser, slugifyUrl } from \"./scraper.js\";\nimport { convertSource } from \"./converter.js\";\nimport { chunkMarkdown } from \"./chunker.js\";\nimport type { Chunk } from \"./types.js\";\nimport { embedTexts } from \"./embedder.js\";\nimport {\n storeChunks,\n purgeSource,\n updateSourceMeta,\n getAllSourcesMeta,\n getSourceMeta,\n deleteSourceMeta,\n deleteChunksByIds,\n getSourceChunkIds,\n} from \"./store.js\";\nimport { search } from \"./search.js\";\nimport { cmdApiKey } from \"./apikey.js\";\nimport { ingestLlmsFull } from \"./llms-ingest.js\";\n\nconst PROJECT_ROOT = resolve(import.meta.dirname, \"..\");\nconst CONFIG_PATH = join(PROJECT_ROOT, \"config\", \"sources.yaml\");\nconst DATA_DIR = join(PROJECT_ROOT, \"data\");\n\nfunction prompt(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\nasync function cmdAdd(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n url: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const name = args.positionals[0];\n const url = args.values.url;\n\n if (!name || !url) {\n console.error(\"Usage: grimoire add <name> --url <start_url>\");\n process.exit(1);\n }\n\n console.log(\"Scanning page...\\n\");\n\n const browser = await createBrowser();\n const context = await browser.newContext();\n const page = await context.newPage();\n\n try {\n await page.goto(url, { waitUntil: \"domcontentloaded\" });\n\n const navCandidates = await page.evaluate(() => {\n const selectors = [\"nav\", \"[role='navigation']\"];\n const results: { selector: string; label: string; linkCount: number }[] = [];\n const seen = new Set<Element>();\n\n for (const sel of selectors) {\n for (const el of document.querySelectorAll(sel)) {\n if (seen.has(el)) continue;\n seen.add(el);\n const links = el.querySelectorAll(\"a[href]\");\n const label =\n el.getAttribute(\"aria-label\") ||\n el.getAttribute(\"class\") ||\n el.tagName.toLowerCase();\n results.push({\n selector: sel,\n label,\n linkCount: links.length,\n });\n }\n }\n\n return results.sort((a, b) => b.linkCount - a.linkCount);\n });\n\n if (navCandidates.length === 0) {\n console.error(\"No navigation elements found on this page.\");\n process.exit(1);\n }\n\n console.log(\"Navigation candidates:\");\n for (let i = 0; i < navCandidates.length; i++) {\n const c = navCandidates[i];\n console.log(` [${i + 1}] ${c.selector} (${c.label}) \u2014 ${c.linkCount} links`);\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n const navChoice = await prompt(rl, \"\\nSelect navigation: \");\n const navIndex = parseInt(navChoice, 10) - 1;\n if (isNaN(navIndex) || navIndex < 0 || navIndex >= navCandidates.length) {\n console.error(\"Invalid selection.\");\n rl.close();\n process.exit(1);\n }\n\n const selectedNav = navCandidates[navIndex];\n\n const parsedUrl = new URL(url);\n const defaultPattern = parsedUrl.pathname.replace(/\\/$/, \"\");\n\n const allLinks = await page.$$eval(\n `${selectedNav.selector} a[href]`,\n (links, pattern) => {\n return [...new Set(\n (links as HTMLAnchorElement[])\n .map((a) => a.href)\n .filter((h) => h.startsWith(\"http\") && !h.includes(\"?hl=\") && !h.endsWith(\"#\") && h.includes(pattern)),\n )];\n },\n defaultPattern,\n );\n\n console.log(`\\nFound ${allLinks.length} links matching ${defaultPattern}`);\n\n const patternInput = await prompt(rl, `Include pattern [default: ${defaultPattern}]: `);\n const includePattern = patternInput.trim() || defaultPattern;\n\n const excludeInput = await prompt(rl, \"Exclude patterns (comma-separated, optional): \");\n const excludePatterns = excludeInput.trim()\n ? excludeInput.split(\",\").map((p) => p.trim())\n : undefined;\n\n rl.close();\n\n const contentSelector = await page.evaluate(() => {\n if (document.querySelector(\"article\")) return \"article\";\n if (document.querySelector(\"main\")) return \"main\";\n return \"body\";\n });\n\n const removeSelectors = await page.evaluate(() => {\n const candidates = [\n { selector: \"nav\", label: \"nav\" },\n { selector: \"footer\", label: \"footer\" },\n { selector: \"[role='complementary']\", label: \"[role='complementary']\" },\n { selector: \"[role='banner']\", label: \"[role='banner']\" },\n { selector: \".breadcrumbs, .breadcrumb\", label: \".breadcrumbs\" },\n { selector: \".pagination-nav, .pagination\", label: \".pagination-nav\" },\n ];\n return candidates\n .filter((c) => document.querySelector(c.selector) !== null)\n .map((c) => c.label);\n });\n\n if (removeSelectors.length > 0) {\n console.log(`\\nDetected removable elements: ${removeSelectors.join(\", \")}`);\n }\n\n const parsedUrlForSitemap = new URL(url);\n let sitemapUrl: string | undefined;\n try {\n const sitemapCheck = await page.goto(`${parsedUrlForSitemap.origin}/sitemap.xml`, { waitUntil: \"domcontentloaded\", timeout: 10000 });\n if (sitemapCheck && sitemapCheck.status() === 200) {\n const body = await page.textContent(\"body\");\n if (body && (body.includes(\"<urlset\") || body.includes(\"<sitemapindex\"))) {\n sitemapUrl = `${parsedUrlForSitemap.origin}/sitemap.xml`;\n console.log(`\\nSitemap found: ${sitemapUrl}`);\n }\n }\n } catch {\n // No sitemap available\n }\n\n const source: SourceConfig = {\n name: name.replace(/-/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase()),\n start_url: url,\n ...(sitemapUrl ? { sitemap_url: sitemapUrl } : {}),\n nav_selector: selectedNav.selector,\n content_selector: contentSelector,\n include_patterns: [includePattern],\n ...(excludePatterns ? { exclude_patterns: excludePatterns } : {}),\n ...(removeSelectors.length > 0 ? { remove_selectors: removeSelectors } : {}),\n };\n\n let existingContent = \"\";\n try {\n existingContent = await readFile(CONFIG_PATH, \"utf-8\");\n } catch {\n existingContent = \"sources:\\n\";\n }\n\n const newEntry = stringify({ [name]: source }, { indent: 2 });\n const indented = newEntry\n .split(\"\\n\")\n .map((line) => (line.trim() ? ` ${line}` : \"\"))\n .join(\"\\n\");\n\n await writeFile(CONFIG_PATH, existingContent.trimEnd() + \"\\n\" + indented, \"utf-8\");\n\n console.log(`\\nSource \"${name}\" added to config/sources.yaml`);\n console.log(`Run \"grimoire refresh ${name}\" to start scraping.`);\n } finally {\n await browser.close();\n }\n}\n\nasync function loadEmbeddingsCache(cachePath: string): Promise<number[][] | null> {\n try {\n const data = await readFile(cachePath, \"utf-8\");\n return JSON.parse(data) as number[][];\n } catch {\n return null;\n }\n}\n\nasync function embedWithCheckpoint(\n texts: string[],\n rawDir: string,\n embeddingsCachePath: string,\n): Promise<number[][]> {\n await mkdir(rawDir, { recursive: true });\n\n const partialCache = await loadEmbeddingsCache(embeddingsCachePath);\n const resumeFrom = partialCache && partialCache.length > 0 && partialCache.length < texts.length ? partialCache : undefined;\n\n return embedTexts(texts, {\n onProgress: (done, total) => {\n console.log(` [${done}/${total}] embedded`);\n },\n onCheckpoint: async (current) => {\n await writeFile(embeddingsCachePath, JSON.stringify(current), \"utf-8\");\n },\n resumeFrom,\n });\n}\n\nasync function storeWithStrategy(\n sourceName: string,\n allChunks: Chunk[],\n embeddings: number[][],\n urlCount: number,\n version: string | undefined,\n diff: boolean,\n): Promise<void> {\n if (diff) {\n console.log(\" Computing diff...\");\n const existingIds = await getSourceChunkIds(sourceName);\n const newIds = new Set(allChunks.map((c) => c.id));\n const toDelete = [...existingIds].filter((id) => !newIds.has(id));\n\n console.log(` Diff: ${toDelete.length} to delete, ${allChunks.length} to upsert (${existingIds.size} existing)`);\n\n if (toDelete.length > 0) {\n console.log(\" Deleting removed chunks...\");\n await deleteChunksByIds(toDelete, (cur, total) => {\n console.log(` [${cur}/${total}] deleted`);\n });\n }\n\n console.log(\" Upserting chunks...\");\n await storeChunks(allChunks, embeddings, (cur, total) => {\n console.log(` [${cur}/${total}] stored`);\n });\n } else {\n console.log(\" Purging old chunks...\");\n await purgeSource(sourceName);\n\n console.log(\" Storing in Firestore...\");\n await storeChunks(allChunks, embeddings, (cur, total) => {\n console.log(` [${cur}/${total}] stored`);\n });\n }\n\n await updateSourceMeta(sourceName, allChunks.length, urlCount, version);\n console.log(` Done. ${allChunks.length} chunks stored for \"${sourceName}\".`);\n}\n\nasync function cmdRefresh(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n full: { type: \"boolean\", default: false },\n all: { type: \"boolean\", default: false },\n diff: { type: \"boolean\", default: false },\n concurrency: { type: \"string\" },\n limit: { type: \"string\" },\n \"from-html\": { type: \"boolean\", default: false },\n \"from-markdown\": { type: \"boolean\", default: false },\n \"from-embeddings\": { type: \"boolean\", default: false },\n \"skip-store\": { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const config = await loadConfig(CONFIG_PATH);\n const sourcesToRefresh = args.values.all\n ? Object.keys(config.sources)\n : [args.positionals[0]];\n\n if (!args.values.all && !sourcesToRefresh[0]) {\n console.error(\"Usage: grimoire refresh <source> [--full] [--from-html] [--from-markdown] [--from-embeddings] [--skip-store] [--limit <n>] [--concurrency <n>]\");\n process.exit(1);\n }\n\n const concurrencyOverride = args.values.concurrency ? parseInt(args.values.concurrency, 10) : undefined;\n const urlLimit = args.values.limit ? parseInt(args.values.limit, 10) : undefined;\n\n for (const sourceName of sourcesToRefresh) {\n const source = config.sources[sourceName];\n if (!source) {\n console.error(`Source \"${sourceName}\" not found in config.`);\n process.exit(1);\n }\n\n if (concurrencyOverride) {\n source.concurrency = concurrencyOverride;\n }\n\n const rawDir = join(DATA_DIR, \"raw\", sourceName);\n const mdDir = join(DATA_DIR, \"markdown\", sourceName);\n const embeddingsCachePath = join(rawDir, \"embeddings.json\");\n\n console.log(`\\nRefreshing \"${sourceName}\"...`);\n\n if (args.values.full) {\n console.log(\" Purging existing chunks...\");\n const deleted = await purgeSource(sourceName);\n console.log(` Deleted ${deleted} chunks.`);\n await rm(rawDir, { recursive: true, force: true });\n await rm(mdDir, { recursive: true, force: true });\n }\n\n let urls: string[];\n\n if (args.values[\"from-embeddings\"]) {\n console.log(\" Loading cached embeddings...\");\n const cached = await loadEmbeddingsCache(embeddingsCachePath);\n if (!cached) {\n console.error(\" No cached embeddings found. Run without --from-embeddings first.\");\n process.exit(1);\n }\n\n const mdFiles = await readdir(mdDir);\n const allPages = [];\n for (const f of mdFiles.filter((f) => f.endsWith(\".md\"))) {\n const content = await readFile(join(mdDir, f), \"utf-8\");\n const urlMatch = content.match(/^url: \"(.+)\"$/m);\n const titleMatch = content.match(/^title: \"(.+)\"$/m);\n allPages.push({\n markdown: content,\n url: urlMatch?.[1] ?? \"\",\n title: titleMatch?.[1] ?? \"Untitled\",\n });\n }\n\n console.log(\" Chunking...\");\n const allChunks = allPages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n if (cached.length !== allChunks.length) {\n console.error(` Embeddings cache (${cached.length}) doesn't match chunk count (${allChunks.length}). Re-embed with --from-html.`);\n process.exit(1);\n }\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, cached, allPages.length, source.version, args.values.diff!);\n continue;\n }\n\n if (args.values[\"from-markdown\"]) {\n console.log(\" Reading cached markdown...\");\n const mdFiles = await readdir(mdDir).catch(() => [] as string[]);\n const markdownFiles = mdFiles.filter((f) => f.endsWith(\".md\"));\n if (markdownFiles.length === 0) {\n console.error(\" No cached markdown found. Run with --from-html first.\");\n process.exit(1);\n }\n\n const pages = [];\n for (const f of markdownFiles) {\n const content = await readFile(join(mdDir, f), \"utf-8\");\n const urlMatch = content.match(/^url: \"(.+)\"$/m);\n const titleMatch = content.match(/^title: \"(.+)\"$/m);\n pages.push({\n markdown: content,\n url: urlMatch?.[1] ?? \"\",\n title: titleMatch?.[1] ?? \"Untitled\",\n });\n }\n console.log(` Found ${pages.length} cached pages.`);\n\n console.log(\" Chunking...\");\n const allChunks = pages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n console.log(\" Embedding chunks...\");\n const texts = allChunks.map((c) => c.content);\n const embeddings = await embedWithCheckpoint(texts, rawDir, embeddingsCachePath);\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, embeddings, pages.length, source.version, args.values.diff!);\n continue;\n }\n\n let pages: { source: string; url: string; title: string; markdown: string }[];\n\n if (source.llms_full_url && !args.values[\"from-html\"]) {\n console.log(` Fetching llms-full.txt from ${source.llms_full_url}...`);\n pages = await ingestLlmsFull(\n source.llms_full_url,\n sourceName,\n source.start_url,\n DATA_DIR,\n (cur, total) => {\n console.log(` [${cur}/${total}] pages processed`);\n },\n );\n console.log(` Extracted ${pages.length} pages.`);\n } else {\n if (args.values[\"from-html\"]) {\n console.log(\" Reading URLs from cached HTML...\");\n const urlsJsonPath = join(rawDir, \"urls.json\");\n try {\n urls = JSON.parse(await readFile(urlsJsonPath, \"utf-8\"));\n } catch {\n const rawFiles = await readdir(rawDir);\n const htmlFiles = rawFiles.filter((f) => f.endsWith(\".html\"));\n urls = [];\n for (const f of htmlFiles) {\n const fileSlug = f.replace(/\\.html$/, \"\");\n const htmlPath = join(rawDir, f);\n const html = await readFile(htmlPath, \"utf-8\");\n const match = html.match(/<link[^>]+rel=\"canonical\"[^>]+href=\"([^\"]+)\"/);\n if (match && slugifyUrl(match[1]) === fileSlug) { urls.push(match[1]); continue; }\n const ogMatch = html.match(/<meta[^>]+property=\"og:url\"[^>]+content=\"([^\"]+)\"/);\n if (ogMatch && slugifyUrl(ogMatch[1]) === fileSlug) { urls.push(ogMatch[1]); continue; }\n urls.push(`https://recovered/${fileSlug}`);\n }\n }\n console.log(` Found ${urls.length} cached pages.`);\n } else {\n console.log(\" Scraping URLs...\");\n urls = await scrapeSource(source, sourceName, DATA_DIR, (cur, total, url) => {\n console.log(` [${cur}/${total}] ${url}`);\n });\n console.log(` Found ${urls.length} pages.`);\n }\n\n if (urlLimit && urls.length > urlLimit) {\n urls = urls.slice(0, urlLimit);\n console.log(` Limited to ${urlLimit} pages.`);\n }\n\n console.log(\" Converting to markdown...\");\n pages = await convertSource(\n sourceName,\n urls,\n source.content_selector!,\n source.remove_selectors,\n source.remove_text_patterns,\n DATA_DIR,\n source.concurrency,\n (cur, total) => {\n if (cur % 10 === 0 || cur === total) console.log(` [${cur}/${total}] converted`);\n },\n );\n }\n\n console.log(\" Chunking...\");\n const allChunks = pages.flatMap((p) => chunkMarkdown(p.markdown, sourceName, p.url, p.title));\n console.log(` Created ${allChunks.length} chunks.`);\n\n console.log(\" Embedding chunks...\");\n const texts = allChunks.map((c) => c.content);\n const embeddings = await embedWithCheckpoint(texts, rawDir, embeddingsCachePath);\n\n if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (skipped Firestore).`);\n continue;\n }\n\n await storeWithStrategy(sourceName, allChunks, embeddings, pages.length, source.version, args.values.diff!);\n }\n}\n\nasync function cmdSearch(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n source: { type: \"string\" },\n top: { type: \"string\" },\n compact: { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const query = args.positionals.join(\" \");\n if (!query) {\n console.error(\"Usage: grimoire search \\\"<query>\\\" [--source <name>] [--top <n>] [--compact]\");\n process.exit(1);\n }\n\n const topN = args.values.top ? parseInt(args.values.top, 10) : undefined;\n const results = await search(query, { source: args.values.source, topN });\n\n if (results.length === 0) {\n console.log(\"No results found.\");\n return;\n }\n\n if (args.values.compact) {\n for (const r of results) {\n console.log(`${r.relevance_score.toFixed(4)} | ${r.source} | ${r.title} | ${r.heading_path.join(\" > \")} | ${r.url}`);\n }\n return;\n }\n\n for (let i = 0; i < results.length; i++) {\n const r = results[i];\n console.log(`\\n${bold(`[${i + 1}] ${r.title}`)} (${r.relevance_score.toFixed(4)})`);\n console.log(` ${cyan(r.url)}`);\n console.log(` ${yellow(r.heading_path.join(\" > \"))}`);\n console.log(` ${r.content.replace(/\\n/g, \" \")}`);\n }\n}\n\nasync function cmdList(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n names: { type: \"boolean\", default: false },\n },\n allowPositionals: true,\n });\n\n const metas = await getAllSourcesMeta();\n\n if (metas.length === 0) {\n console.log(\"No sources have been refreshed yet.\");\n return;\n }\n\n if (args.values.names) {\n for (const meta of metas) {\n console.log(meta.source);\n }\n return;\n }\n\n console.log(\"\\nSources:\\n\");\n for (const meta of metas) {\n const ver = meta.version ? ` v${meta.version}` : \"\";\n console.log(` ${bold(meta.source)}${ver}`);\n console.log(` ${meta.chunk_count} chunks, ${meta.url_count} URLs, last refreshed ${meta.last_refreshed}`);\n }\n}\n\nasync function cmdStats(): Promise<void> {\n const metas = await getAllSourcesMeta();\n\n if (metas.length === 0) {\n console.log(\"No sources have been refreshed yet.\");\n return;\n }\n\n let totalChunks = 0;\n let totalUrls = 0;\n\n console.log(\"\\nSource Statistics:\\n\");\n for (const meta of metas) {\n const ver = meta.version ? ` v${meta.version}` : \"\";\n console.log(` ${bold(meta.source)}${ver}`);\n console.log(` Chunks: ${meta.chunk_count}`);\n console.log(` URLs: ${meta.url_count}`);\n console.log(` Last refreshed: ${meta.last_refreshed}`);\n totalChunks += meta.chunk_count;\n totalUrls += meta.url_count;\n }\n\n console.log(`\\n Total: ${totalChunks} chunks across ${totalUrls} URLs from ${metas.length} sources`);\n}\n\nasync function cmdExport(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n format: { type: \"string\", default: \"json\" },\n },\n allowPositionals: true,\n });\n\n const sourceName = args.positionals[0];\n if (!sourceName) {\n console.error(\"Usage: grimoire export <source> [--format json]\");\n process.exit(1);\n }\n\n const mdDir = join(DATA_DIR, \"markdown\", sourceName);\n let files: string[];\n try {\n files = await readdir(mdDir);\n } catch {\n console.error(`No markdown data found for source \"${sourceName}\".`);\n process.exit(1);\n }\n\n const pages = [];\n for (const file of files.filter((f) => f.endsWith(\".md\"))) {\n const content = await readFile(join(mdDir, file), \"utf-8\");\n pages.push({ file, content });\n }\n\n console.log(JSON.stringify(pages, null, 2));\n}\n\nasync function cmdDelete(): Promise<void> {\n const sourceName = process.argv[3];\n if (!sourceName) {\n console.error(\"Usage: grimoire delete <source>\");\n process.exit(1);\n }\n\n const meta = await getSourceMeta(sourceName);\n if (!meta) {\n console.error(`Source \"${sourceName}\" not found in Firestore.`);\n process.exit(1);\n }\n\n console.log(`Deleting \"${sourceName}\" (${meta.chunk_count} chunks)...`);\n const deleted = await purgeSource(sourceName);\n await deleteSourceMeta(sourceName);\n console.log(`Deleted ${deleted} chunks and source metadata for \"${sourceName}\".`);\n}\n\nasync function cmdScrapeUrls(): Promise<void> {\n const args = parseArgs({\n args: process.argv.slice(3),\n options: {\n concurrency: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const sourceName = args.positionals[0];\n if (!sourceName) {\n console.error(\"Usage: grimoire scrape-urls <source> [--concurrency <n>]\");\n process.exit(1);\n }\n\n const config = await loadConfig(CONFIG_PATH);\n const source = config.sources[sourceName];\n if (!source) {\n console.error(`Source \"${sourceName}\" not found in config.`);\n process.exit(1);\n }\n\n const rawDir = join(DATA_DIR, \"raw\", sourceName);\n const urlsPath = join(rawDir, \"urls.json\");\n\n let urls: string[];\n try {\n urls = JSON.parse(await readFile(urlsPath, \"utf-8\"));\n } catch {\n console.error(`No urls.json found for \"${sourceName}\". Run 'grimoire refresh ${sourceName} --skip-store' first.`);\n process.exit(1);\n }\n\n const missing = urls.filter((url) => !existsSync(join(rawDir, `${slugifyUrl(url)}.html`)));\n console.log(`\\nTotal: ${urls.length}, Cached: ${urls.length - missing.length}, Missing: ${missing.length}`);\n\n if (missing.length === 0) {\n console.log(\"Nothing to scrape.\");\n return;\n }\n\n const concurrency = args.values.concurrency ? parseInt(args.values.concurrency, 10) : source.concurrency ?? 20;\n const browser = await createBrowser();\n const context = await browser.newContext(source.user_agent ? { userAgent: source.user_agent } : {});\n let done = 0;\n\n for (let i = 0; i < missing.length; i += concurrency) {\n const batch = missing.slice(i, i + concurrency);\n await Promise.all(batch.map(async (url) => {\n const page = await context.newPage();\n try {\n await page.goto(url, { waitUntil: source.headed ? \"networkidle\" : \"domcontentloaded\", timeout: 30000 });\n const html = await page.content();\n await writeFile(join(rawDir, `${slugifyUrl(url)}.html`), html, \"utf-8\");\n done++;\n if (done % 10 === 0 || done === missing.length) console.log(` [${done}/${missing.length}]`);\n } catch (e) {\n console.error(` FAILED: ${url} - ${e instanceof Error ? e.message : String(e)}`);\n } finally {\n await page.close();\n }\n }));\n }\n\n console.log(`Done. Fetched ${done} pages.`);\n await browser.close();\n}\n\nexport const ADMIN_COMMANDS: Record<string, () => Promise<void>> = {\n add: cmdAdd,\n refresh: cmdRefresh,\n delete: cmdDelete,\n \"scrape-urls\": cmdScrapeUrls,\n search: cmdSearch,\n list: cmdList,\n stats: cmdStats,\n export: cmdExport,\n apikey: cmdApiKey,\n};\n", "import { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\n\nexport interface SourceConfig {\n name: string;\n version?: string;\n start_url: string;\n nav_selector?: string;\n content_selector?: string;\n remove_selectors?: string[];\n remove_text_patterns?: string[];\n include_patterns?: string[];\n exclude_patterns?: string[];\n rate_limit_ms?: number;\n concurrency?: number;\n headed?: boolean;\n sitemap_url?: string;\n user_agent?: string;\n llms_full_url?: string;\n}\n\nexport interface GrimoireConfig {\n sources: Record<string, SourceConfig>;\n}\n\nconst REQUIRED_SOURCE_FIELDS = [\n \"name\",\n \"start_url\",\n] as const;\n\nconst SCRAPE_REQUIRED_FIELDS = [\n \"nav_selector\",\n \"content_selector\",\n] as const;\n\nexport function validateConfig(data: unknown): GrimoireConfig {\n if (typeof data !== \"object\" || data === null || !(\"sources\" in data)) {\n throw new Error(\"Config must have a 'sources' key\");\n }\n\n const { sources } = data as { sources: unknown };\n\n if (typeof sources !== \"object\" || sources === null) {\n throw new Error(\"'sources' must be an object\");\n }\n\n const entries = Object.entries(sources as Record<string, unknown>);\n\n if (entries.length === 0) {\n throw new Error(\"'sources' must contain at least one source\");\n }\n\n const validated: Record<string, SourceConfig> = {};\n\n for (const [key, value] of entries) {\n if (typeof value !== \"object\" || value === null) {\n throw new Error(`Source '${key}' must be an object`);\n }\n\n const source = value as Record<string, unknown>;\n\n for (const field of REQUIRED_SOURCE_FIELDS) {\n if (typeof source[field] !== \"string\" || source[field] === \"\") {\n throw new Error(`Source '${key}' is missing required field '${field}'`);\n }\n }\n\n if (!source.llms_full_url) {\n for (const field of SCRAPE_REQUIRED_FIELDS) {\n if (typeof source[field] !== \"string\" || source[field] === \"\") {\n throw new Error(`Source '${key}' is missing required field '${field}'`);\n }\n }\n }\n\n try {\n new URL(source.start_url as string);\n } catch {\n throw new Error(`Source '${key}' has invalid start_url: ${source.start_url}`);\n }\n\n if (source.remove_selectors !== undefined && !Array.isArray(source.remove_selectors)) {\n throw new Error(`Source '${key}': remove_selectors must be an array`);\n }\n\n if (source.remove_text_patterns !== undefined && !Array.isArray(source.remove_text_patterns)) {\n throw new Error(`Source '${key}': remove_text_patterns must be an array`);\n }\n\n if (source.include_patterns !== undefined && !Array.isArray(source.include_patterns)) {\n throw new Error(`Source '${key}': include_patterns must be an array`);\n }\n\n if (source.exclude_patterns !== undefined && !Array.isArray(source.exclude_patterns)) {\n throw new Error(`Source '${key}': exclude_patterns must be an array`);\n }\n\n if (source.rate_limit_ms !== undefined && typeof source.rate_limit_ms !== \"number\") {\n throw new Error(`Source '${key}': rate_limit_ms must be a number`);\n }\n\n if (source.concurrency !== undefined && typeof source.concurrency !== \"number\") {\n throw new Error(`Source '${key}': concurrency must be a number`);\n }\n\n validated[key] = {\n name: source.name as string,\n version: source.version as string | undefined,\n start_url: source.start_url as string,\n nav_selector: source.nav_selector as string | undefined,\n content_selector: source.content_selector as string | undefined,\n remove_selectors: source.remove_selectors as string[] | undefined,\n remove_text_patterns: source.remove_text_patterns as string[] | undefined,\n include_patterns: source.include_patterns as string[] | undefined,\n exclude_patterns: source.exclude_patterns as string[] | undefined,\n rate_limit_ms: source.rate_limit_ms as number | undefined,\n concurrency: source.concurrency as number | undefined,\n headed: source.headed as boolean | undefined,\n sitemap_url: source.sitemap_url as string | undefined,\n llms_full_url: source.llms_full_url as string | undefined,\n };\n }\n\n return { sources: validated };\n}\n\nexport async function loadConfig(path: string): Promise<GrimoireConfig> {\n const content = await readFile(path, \"utf-8\");\n const data = parse(content, { merge: true });\n return validateConfig(data);\n}\n", "import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { chromium, type Browser, type Page } from \"playwright\";\nimport type { SourceConfig } from \"./config.js\";\n\nexport function slugifyUrl(url: string): string {\n const parsed = new URL(url);\n return parsed.pathname\n .replace(/^\\//, \"\")\n .replace(/\\/$/, \"\")\n .replace(/\\//g, \"-\")\n .replace(/[^a-zA-Z0-9-]/g, \"\");\n}\n\nexport function filterUrls(\n urls: string[],\n includePatterns?: string[],\n excludePatterns?: string[],\n): string[] {\n let filtered = urls.filter(\n (url) => url.startsWith(\"http\") && !url.includes(\"?hl=\") && !url.endsWith(\"#\"),\n );\n\n if (includePatterns && includePatterns.length > 0) {\n filtered = filtered.filter((url) =>\n includePatterns.some((pattern) => url.includes(pattern)),\n );\n }\n\n if (excludePatterns && excludePatterns.length > 0) {\n filtered = filtered.filter(\n (url) => !excludePatterns.some((pattern) => url.includes(pattern)),\n );\n }\n\n return [...new Set(filtered)].sort();\n}\n\nasync function fetchSitemapUrls(sitemapUrl: string): Promise<string[]> {\n const response = await fetch(sitemapUrl);\n const xml = await response.text();\n const locs = [...xml.matchAll(/<loc>([^<]+)<\\/loc>/g)].map((m) => m[1]);\n\n if (xml.includes(\"<sitemapindex\")) {\n const nested = await Promise.all(locs.map((loc) => fetchSitemapUrls(loc)));\n return nested.flat();\n }\n\n return locs;\n}\n\nasync function discoverFromSitemap(sitemapUrl: string, source: SourceConfig): Promise<string[]> {\n const urls = await fetchSitemapUrls(sitemapUrl);\n return filterUrls(urls, source.include_patterns, source.exclude_patterns);\n}\n\nexport async function discoverUrls(\n page: Page,\n source: SourceConfig,\n): Promise<string[]> {\n if (source.sitemap_url) {\n return discoverFromSitemap(source.sitemap_url, source);\n }\n\n await page.goto(source.start_url, { waitUntil: source.headed ? \"networkidle\" : \"domcontentloaded\" });\n\n const rawUrls = await page.$$eval(\n `${source.nav_selector} a[href]`,\n (links) => links.map((a) => (a as HTMLAnchorElement).href),\n );\n\n const discovered = filterUrls(rawUrls, source.include_patterns, source.exclude_patterns);\n if (!discovered.includes(source.start_url)) {\n discovered.unshift(source.start_url);\n }\n return discovered;\n}\n\nexport async function fetchPage(\n page: Page,\n url: string,\n headed?: boolean,\n): Promise<string> {\n await page.goto(url, { waitUntil: headed ? \"networkidle\" : \"domcontentloaded\" });\n return page.content();\n}\n\nconst DEFAULT_CONCURRENCY = 50;\n\nasync function runPool<T>(\n items: T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<void>,\n): Promise<void> {\n let nextIndex = 0;\n\n async function worker(): Promise<void> {\n while (nextIndex < items.length) {\n const index = nextIndex++;\n await fn(items[index], index);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());\n await Promise.all(workers);\n}\n\nexport async function scrapeSource(\n source: SourceConfig,\n sourceName: string,\n dataDir: string,\n onProgress?: (current: number, total: number, url: string) => void,\n): Promise<string[]> {\n const rawDir = join(dataDir, \"raw\", sourceName);\n await mkdir(rawDir, { recursive: true });\n\n const concurrency = source.concurrency ?? DEFAULT_CONCURRENCY;\n const browser = await chromium.launch({ channel: \"chrome\", headless: !source.headed });\n const context = await browser.newContext(source.user_agent ? { userAgent: source.user_agent } : {});\n\n const discoveryPage = await context.newPage();\n const urls = await discoverUrls(discoveryPage, source);\n await discoveryPage.close();\n\n let completed = 0;\n\n try {\n await runPool(urls, concurrency, async (url) => {\n const page = await context.newPage();\n try {\n const html = await fetchPage(page, url, source.headed);\n const slug = slugifyUrl(url);\n await writeFile(join(rawDir, `${slug}.html`), html, \"utf-8\");\n completed++;\n onProgress?.(completed, urls.length, url);\n } finally {\n await page.close();\n }\n });\n\n await writeFile(join(rawDir, \"urls.json\"), JSON.stringify(urls), \"utf-8\");\n return urls;\n } finally {\n await browser.close();\n }\n}\n\nexport async function createBrowser(): Promise<Browser> {\n return chromium.launch({ channel: \"chrome\" });\n}\n", "import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { JSDOM } from \"jsdom\";\nimport TurndownService from \"turndown\";\nimport { slugifyUrl } from \"./scraper.js\";\n\nconst turndown = new TurndownService({\n headingStyle: \"atx\",\n codeBlockStyle: \"fenced\",\n bulletListMarker: \"-\",\n});\n\nexport interface ConvertedPage {\n source: string;\n url: string;\n title: string;\n markdown: string;\n}\n\nconst GENERIC_REMOVE = [\n \"style\",\n \"script\",\n \"noscript\",\n \"iframe\",\n \"svg\",\n];\n\nfunction cleanMarkdown(md: string, textPatterns?: string[]): string {\n let cleaned = md\n .replace(/^(#+)\\s*$/gm, \"\")\n .replace(/\\n{3,}/g, \"\\n\\n\");\n\n if (textPatterns) {\n for (const pattern of textPatterns) {\n cleaned = cleaned.replace(new RegExp(pattern, \"gm\"), \"\");\n }\n cleaned = cleaned.replace(/\\n{3,}/g, \"\\n\\n\");\n }\n\n return cleaned.trim();\n}\n\nexport function extractContent(\n html: string,\n contentSelector: string,\n removeSelectors?: string[],\n removeTextPatterns?: string[],\n): string {\n const dom = new JSDOM(html);\n const doc = dom.window.document;\n\n const contentEl = doc.querySelector(contentSelector);\n if (!contentEl) {\n return cleanMarkdown(turndown.turndown(doc.body.innerHTML), removeTextPatterns);\n }\n\n const allSelectors = [...GENERIC_REMOVE, ...(removeSelectors ?? [])];\n for (const selector of allSelectors) {\n for (const el of contentEl.querySelectorAll(selector)) {\n el.remove();\n }\n }\n\n return cleanMarkdown(turndown.turndown(contentEl.innerHTML), removeTextPatterns);\n}\n\nexport function extractTitle(html: string): string {\n const dom = new JSDOM(html);\n const titleEl = dom.window.document.querySelector(\"title\");\n if (!titleEl) return \"Untitled\";\n return titleEl.textContent?.replace(/\\s*[|\u2013\u2014-]\\s*.+$/, \"\").trim() ?? \"Untitled\";\n}\n\nexport function buildFrontmatter(source: string, url: string, title: string): string {\n return [\n \"---\",\n `source: ${source}`,\n `url: \"${url}\"`,\n `title: \"${title.replace(/\"/g, '\\\\\"')}\"`,\n `fetched_at: \"${new Date().toISOString()}\"`,\n \"---\",\n ].join(\"\\n\");\n}\n\nexport function convertPage(\n html: string,\n source: string,\n url: string,\n contentSelector: string,\n removeSelectors?: string[],\n removeTextPatterns?: string[],\n): ConvertedPage {\n const title = extractTitle(html);\n const content = extractContent(html, contentSelector, removeSelectors, removeTextPatterns);\n const frontmatter = buildFrontmatter(source, url, title);\n const markdown = `${frontmatter}\\n\\n${content}`;\n\n return { source, url, title, markdown };\n}\n\nconst DEFAULT_CONCURRENCY = 10;\n\nexport async function convertSource(\n sourceName: string,\n urls: string[],\n contentSelector: string,\n removeSelectors: string[] | undefined,\n removeTextPatterns: string[] | undefined,\n dataDir: string,\n concurrency = DEFAULT_CONCURRENCY,\n onProgress?: (current: number, total: number, url: string) => void,\n): Promise<ConvertedPage[]> {\n const rawDir = join(dataDir, \"raw\", sourceName);\n const mdDir = join(dataDir, \"markdown\", sourceName);\n await mkdir(mdDir, { recursive: true });\n\n const pages: ConvertedPage[] = new Array(urls.length);\n let completed = 0;\n let nextIndex = 0;\n\n async function worker(): Promise<void> {\n while (nextIndex < urls.length) {\n const i = nextIndex++;\n const url = urls[i];\n const slug = slugifyUrl(url);\n const htmlPath = join(rawDir, `${slug}.html`);\n const html = await readFile(htmlPath, \"utf-8\");\n\n const page = convertPage(html, sourceName, url, contentSelector, removeSelectors, removeTextPatterns);\n await writeFile(join(mdDir, `${slug}.md`), page.markdown, \"utf-8\");\n pages[i] = page;\n completed++;\n onProgress?.(completed, urls.length, url);\n }\n }\n\n const workers = Array.from(\n { length: Math.min(concurrency, urls.length) },\n () => worker(),\n );\n await Promise.all(workers);\n\n return pages;\n}\n", "import { slugifyUrl } from \"./scraper.js\";\nimport type { Chunk } from \"./types.js\";\n\nexport type { Chunk };\n\nconst MAX_TOKENS = 500;\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nexport function slugifyHeading(heading: string): string {\n return heading\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .replace(/\\s+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nexport function buildChunkId(\n source: string,\n url: string,\n headingSlug: string,\n index?: number,\n): string {\n const urlSlug = slugifyUrl(url);\n const prefix = `${source}::${urlSlug}::`;\n const maxSlugBytes = 1500 - Buffer.byteLength(prefix) - 10;\n const truncatedSlug =\n Buffer.byteLength(headingSlug) > maxSlugBytes\n ? Buffer.from(headingSlug).subarray(0, maxSlugBytes).toString()\n : headingSlug;\n const base = `${prefix}${truncatedSlug}`;\n return index !== undefined ? `${base}-${index}` : base;\n}\n\ninterface HeadingSection {\n level: number;\n heading: string;\n headingPath: string[];\n lines: string[];\n}\n\nfunction parseHeadingSections(markdown: string): HeadingSection[] {\n const lines = markdown.split(\"\\n\");\n const sections: HeadingSection[] = [];\n const headingStack: string[] = [];\n const levelStack: number[] = [];\n\n let currentSection: HeadingSection = {\n level: 0,\n heading: \"\",\n headingPath: [],\n lines: [],\n };\n\n for (const line of lines) {\n const headingMatch = line.match(/^(#{1,6})\\s+(.+)$/);\n\n if (headingMatch) {\n if (currentSection.lines.length > 0 || currentSection.heading !== \"\") {\n sections.push(currentSection);\n }\n\n const level = headingMatch[1].length;\n const heading = headingMatch[2].trim();\n\n while (levelStack.length > 0 && levelStack[levelStack.length - 1] >= level) {\n levelStack.pop();\n headingStack.pop();\n }\n\n headingStack.push(heading);\n levelStack.push(level);\n\n currentSection = {\n level,\n heading,\n headingPath: [...headingStack],\n lines: [],\n };\n } else {\n currentSection.lines.push(line);\n }\n }\n\n if (currentSection.lines.length > 0 || currentSection.heading !== \"\") {\n sections.push(currentSection);\n }\n\n return sections;\n}\n\nfunction splitAtParagraphBoundaries(text: string, maxTokens: number): string[] {\n const paragraphs = text.split(/\\n\\n+/);\n const parts: string[] = [];\n let current: string[] = [];\n let currentTokens = 0;\n\n for (const para of paragraphs) {\n const paraTokens = estimateTokens(para);\n\n if (currentTokens + paraTokens > maxTokens && current.length > 0) {\n parts.push(current.join(\"\\n\\n\"));\n current = [para];\n currentTokens = paraTokens;\n } else {\n current.push(para);\n currentTokens += paraTokens;\n }\n }\n\n if (current.length > 0) {\n parts.push(current.join(\"\\n\\n\"));\n }\n\n return parts;\n}\n\nfunction stripFrontmatter(markdown: string): string {\n if (markdown.startsWith(\"---\")) {\n const endIndex = markdown.indexOf(\"---\", 3);\n if (endIndex !== -1) {\n return markdown.slice(endIndex + 3).trim();\n }\n }\n return markdown;\n}\n\nexport function chunkMarkdown(\n markdown: string,\n source: string,\n url: string,\n title: string,\n): Chunk[] {\n const stripped = stripFrontmatter(markdown);\n const sections = parseHeadingSections(stripped);\n const chunks: Chunk[] = [];\n const usedIds = new Set<string>();\n\n function uniqueId(baseSlug: string): string {\n let id = buildChunkId(source, url, baseSlug);\n if (!usedIds.has(id)) {\n usedIds.add(id);\n return id;\n }\n let counter = 1;\n while (usedIds.has(buildChunkId(source, url, baseSlug, counter))) {\n counter++;\n }\n id = buildChunkId(source, url, baseSlug, counter);\n usedIds.add(id);\n return id;\n }\n\n for (const section of sections) {\n const headingLine = section.heading\n ? `${\"#\".repeat(section.level)} ${section.heading}\\n\\n`\n : \"\";\n const content = headingLine + section.lines.join(\"\\n\").trim();\n\n if (!content.trim()) continue;\n\n const headingSlug = section.heading\n ? slugifyHeading(section.heading)\n : \"intro\";\n\n const tokens = estimateTokens(content);\n\n if (tokens <= MAX_TOKENS) {\n chunks.push({\n id: uniqueId(headingSlug),\n source,\n url,\n title,\n heading_path: section.headingPath,\n content,\n token_count: tokens,\n });\n } else {\n const parts = splitAtParagraphBoundaries(content, MAX_TOKENS);\n for (let i = 0; i < parts.length; i++) {\n const partContent = parts[i].trim();\n if (!partContent) continue;\n\n const partSlug = parts.length > 1 ? `${headingSlug}-${i}` : headingSlug;\n chunks.push({\n id: uniqueId(partSlug),\n source,\n url,\n title,\n heading_path: section.headingPath,\n content: partContent,\n token_count: estimateTokens(partContent),\n });\n }\n }\n }\n\n return chunks;\n}\n", "import { GoogleGenerativeAI } from \"@google/generative-ai\";\n\nconst BATCH_SIZE = 50;\nconst MODEL = \"gemini-embedding-001\";\nconst OUTPUT_DIMENSIONALITY = 768;\nconst MAX_RETRIES = 5;\nconst RATE_LIMIT_BASE_DELAY_MS = 60000;\nconst NETWORK_BASE_DELAY_MS = 10000;\nconst BATCH_DELAY_MS = 2500;\nconst DEFAULT_CHECKPOINT_EVERY_BATCHES = 20;\n\nconst NETWORK_ERROR_PATTERNS = [\n \"fetch failed\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n \"ECONNREFUSED\",\n \"EAI_AGAIN\",\n \"ENOTFOUND\",\n \"socket hang up\",\n \"UND_ERR_\",\n];\n\nlet genAI: GoogleGenerativeAI | undefined;\n\nfunction getClient(): GoogleGenerativeAI {\n if (!genAI) {\n const apiKey = process.env.GEMINI_API_KEY;\n if (!apiKey) {\n throw new Error(\"GEMINI_API_KEY environment variable is not set\");\n }\n genAI = new GoogleGenerativeAI(apiKey);\n }\n return genAI;\n}\n\nfunction classifyError(message: string): \"rate_limit\" | \"network\" | \"other\" {\n if (message.includes(\"429\") || message.includes(\"503\")) {\n return \"rate_limit\";\n }\n if (NETWORK_ERROR_PATTERNS.some((p) => message.includes(p))) {\n return \"network\";\n }\n return \"other\";\n}\n\nexport interface EmbedOptions {\n onProgress?: (done: number, total: number) => void;\n onCheckpoint?: (embeddings: number[][]) => Promise<void>;\n checkpointEveryBatches?: number;\n resumeFrom?: number[][];\n}\n\nexport async function embedTexts(\n texts: string[],\n options: EmbedOptions = {},\n): Promise<number[][]> {\n const client = getClient();\n const model = client.getGenerativeModel({ model: MODEL });\n\n const { onProgress, onCheckpoint, resumeFrom } = options;\n const checkpointEveryBatches = options.checkpointEveryBatches ?? DEFAULT_CHECKPOINT_EVERY_BATCHES;\n\n const embeddings: number[][] = resumeFrom ? [...resumeFrom] : [];\n const startIndex = Math.floor(embeddings.length / BATCH_SIZE) * BATCH_SIZE;\n\n if (embeddings.length > startIndex) {\n embeddings.length = startIndex;\n }\n\n if (startIndex > 0) {\n console.log(` Resuming from chunk ${startIndex} of ${texts.length} (${embeddings.length} cached).`);\n }\n\n if (startIndex >= texts.length) {\n return embeddings.slice(0, texts.length);\n }\n\n let batchesSinceCheckpoint = 0;\n\n for (let i = startIndex; i < texts.length; i += BATCH_SIZE) {\n const batch = texts.slice(i, i + BATCH_SIZE);\n const batchNumber = i / BATCH_SIZE + 1;\n\n let result;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n result = await model.batchEmbedContents({\n requests: batch.map((text) => ({\n content: { role: \"user\", parts: [{ text }] },\n outputDimensionality: OUTPUT_DIMENSIONALITY,\n })),\n });\n break;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const kind = classifyError(message);\n\n if (kind !== \"other\" && attempt < MAX_RETRIES - 1) {\n const baseDelay = kind === \"rate_limit\" ? RATE_LIMIT_BASE_DELAY_MS : NETWORK_BASE_DELAY_MS;\n const delay = baseDelay * Math.pow(2, attempt);\n const label = kind === \"rate_limit\" ? \"Rate limited\" : \"Network error\";\n console.log(` ${label} (batch ${batchNumber}), retrying in ${delay / 1000}s...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n console.error(` Embedding failed at batch ${batchNumber} (chunks ${i + 1}-${i + batch.length}): ${message}`);\n throw err;\n }\n }\n\n for (const embedding of result!.embeddings) {\n embeddings.push(embedding.values);\n }\n\n onProgress?.(Math.min(i + BATCH_SIZE, texts.length), texts.length);\n\n batchesSinceCheckpoint++;\n if (onCheckpoint && batchesSinceCheckpoint >= checkpointEveryBatches && i + BATCH_SIZE < texts.length) {\n await onCheckpoint(embeddings);\n batchesSinceCheckpoint = 0;\n }\n\n if (i + BATCH_SIZE < texts.length) {\n await new Promise((resolve) => setTimeout(resolve, BATCH_DELAY_MS));\n }\n }\n\n if (onCheckpoint) {\n await onCheckpoint(embeddings);\n }\n\n return embeddings;\n}\n\nexport async function embedText(text: string): Promise<number[]> {\n const [embedding] = await embedTexts([text]);\n return embedding;\n}\n", "import { initializeApp, applicationDefault, getApps } from \"firebase-admin/app\";\nimport {\n getFirestore,\n FieldValue,\n type Firestore,\n} from \"firebase-admin/firestore\";\nimport type { Chunk, SourceMeta } from \"./types.js\";\n\nconst BATCH_SIZE = 500;\nconst MAX_RETRIES = 5;\nconst BASE_DELAY_MS = 5000;\n\nasync function retryOnQuota<T>(fn: () => Promise<T>): Promise<T> {\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n try {\n return await fn();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n if ((message.includes(\"RESOURCE_EXHAUSTED\") || message.includes(\"Quota exceeded\")) && attempt < MAX_RETRIES - 1) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n console.log(` Quota exceeded, retrying in ${delay / 1000}s...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n throw err;\n }\n }\n throw new Error(\"Max retries exceeded\");\n}\n\nlet db: Firestore | undefined;\n\nfunction getDb(): Firestore {\n if (!db) {\n if (getApps().length === 0) {\n initializeApp({ credential: applicationDefault() });\n }\n db = getFirestore();\n }\n return db;\n}\n\nfunction chunksCol() {\n return getDb().collection(\"grimoire_chunks\");\n}\n\nfunction sourcesCol() {\n return getDb().collection(\"grimoire_sources\");\n}\n\nexport async function storeChunks(\n chunks: Chunk[],\n embeddings: number[][],\n onProgress?: (current: number, total: number) => void,\n): Promise<void> {\n const database = getDb();\n const col = chunksCol();\n\n for (let i = 0; i < chunks.length; i += BATCH_SIZE) {\n const batch = database.batch();\n const slice = chunks.slice(i, i + BATCH_SIZE);\n const embSlice = embeddings.slice(i, i + BATCH_SIZE);\n\n for (let j = 0; j < slice.length; j++) {\n const chunk = slice[j];\n batch.set(col.doc(chunk.id), {\n source: chunk.source,\n url: chunk.url,\n title: chunk.title,\n heading_path: chunk.heading_path,\n content: chunk.content,\n token_count: chunk.token_count,\n embedded_at: new Date().toISOString(),\n embedding: FieldValue.vector(embSlice[j]),\n });\n }\n\n await retryOnQuota(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, chunks.length), chunks.length);\n }\n}\n\nexport async function purgeSource(sourceName: string): Promise<number> {\n const database = getDb();\n const col = chunksCol();\n\n const snapshot = await col.where(\"source\", \"==\", sourceName).get();\n if (snapshot.empty) return 0;\n\n let batch = database.batch();\n let count = 0;\n\n for (const doc of snapshot.docs) {\n batch.delete(doc.ref);\n count++;\n if (count % BATCH_SIZE === 0) {\n await retryOnQuota(() => batch.commit());\n batch = database.batch();\n }\n }\n\n if (count % BATCH_SIZE !== 0) {\n await retryOnQuota(() => batch.commit());\n }\n\n return count;\n}\n\nexport async function updateSourceMeta(\n sourceName: string,\n chunkCount: number,\n urlCount: number,\n version?: string,\n): Promise<void> {\n await sourcesCol().doc(sourceName).set({\n source: sourceName,\n ...(version ? { version } : {}),\n last_refreshed: new Date().toISOString(),\n chunk_count: chunkCount,\n url_count: urlCount,\n });\n}\n\nexport async function getSourceMeta(sourceName: string): Promise<SourceMeta | null> {\n const doc = await sourcesCol().doc(sourceName).get();\n if (!doc.exists) return null;\n return doc.data() as SourceMeta;\n}\n\nexport async function getAllSourcesMeta(): Promise<SourceMeta[]> {\n const snapshot = await sourcesCol().get();\n return snapshot.docs.map((doc) => doc.data() as SourceMeta);\n}\n\nexport async function deleteSourceMeta(sourceName: string): Promise<void> {\n await sourcesCol().doc(sourceName).delete();\n}\n\nexport async function deleteChunksByIds(\n ids: string[],\n onProgress?: (current: number, total: number) => void,\n): Promise<void> {\n if (ids.length === 0) return;\n const database = getDb();\n const col = chunksCol();\n\n for (let i = 0; i < ids.length; i += BATCH_SIZE) {\n const batch = database.batch();\n const slice = ids.slice(i, i + BATCH_SIZE);\n for (const id of slice) {\n batch.delete(col.doc(id));\n }\n await retryOnQuota(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, ids.length), ids.length);\n }\n}\n\nexport async function getSourceChunkIds(sourceName: string): Promise<Set<string>> {\n const col = chunksCol();\n const snapshot = await col.where(\"source\", \"==\", sourceName).select().get();\n return new Set(snapshot.docs.map((doc) => doc.id));\n}\n\nexport async function vectorSearch(\n queryEmbedding: number[],\n limit: number,\n source?: string,\n): Promise<{ id: string; data: Record<string, unknown>; distance: number }[]> {\n const col = chunksCol();\n\n let query = col as FirebaseFirestore.Query;\n if (source) {\n query = query.where(\"source\", \"==\", source);\n }\n\n const snapshot = await query\n .findNearest({\n vectorField: \"embedding\",\n queryVector: FieldValue.vector(queryEmbedding),\n limit,\n distanceMeasure: \"COSINE\",\n distanceResultField: \"_distance\",\n })\n .get();\n\n return snapshot.docs.map((doc) => {\n const data = doc.data();\n const distance = (data._distance as number) ?? 0;\n delete data._distance;\n return { id: doc.id, data, distance };\n });\n}\n", "export interface RerankResult {\n index: number;\n relevance_score: number;\n}\n\ninterface LlamaCppRerankResponse {\n results: { index: number; relevance_score: number }[];\n}\n\nfunction getRerankerUrl(): string {\n const url = process.env.RERANKER_URL;\n if (!url) {\n throw new Error(\"RERANKER_URL environment variable is not set\");\n }\n return url;\n}\n\nexport async function rerank(\n query: string,\n documents: string[],\n topN = 5,\n): Promise<RerankResult[]> {\n const baseUrl = getRerankerUrl();\n const response = await fetch(`${baseUrl}/v1/rerank`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ query, documents, top_n: topN }),\n });\n\n if (!response.ok) {\n throw new Error(`Reranker request failed: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as LlamaCppRerankResponse;\n return data.results;\n}\n", "import { embedText } from \"./embedder.js\";\nimport { vectorSearch } from \"./store.js\";\nimport { rerank } from \"./reranker.js\";\nimport type { SearchResult } from \"./types.js\";\n\nexport type { SearchResult };\n\nfunction hasReranker(): boolean {\n return !!process.env.RERANKER_URL;\n}\n\nexport async function search(\n query: string,\n options: { source?: string; candidates?: number; topN?: number } = {},\n): Promise<SearchResult[]> {\n const { source, candidates = 20, topN = 5 } = options;\n\n const queryEmbedding = await embedText(query);\n const rawResults = await vectorSearch(queryEmbedding, candidates, source);\n\n if (rawResults.length === 0) return [];\n\n if (hasReranker()) {\n const documents = rawResults.map((r) => r.data.content as string);\n const reranked = await rerank(query, documents, topN);\n\n return reranked.map((r) => {\n const original = rawResults[r.index];\n const data = original.data;\n return {\n id: original.id,\n source: data.source as string,\n url: data.url as string,\n title: data.title as string,\n heading_path: data.heading_path as string[],\n content: data.content as string,\n relevance_score: r.relevance_score,\n };\n });\n }\n\n return rawResults.slice(0, topN).map((r) => {\n const data = r.data;\n return {\n id: r.id,\n source: data.source as string,\n url: data.url as string,\n title: data.title as string,\n heading_path: data.heading_path as string[],\n content: data.content as string,\n relevance_score: Math.max(0, 1 - r.distance / 2),\n };\n });\n}\n", "import { randomBytes, createHash } from \"node:crypto\";\nimport {\n getFirestore,\n type Firestore,\n} from \"firebase-admin/firestore\";\nimport { initializeApp, applicationDefault, getApps } from \"firebase-admin/app\";\nimport { bold } from \"./format.js\";\n\nlet db: Firestore | undefined;\n\nfunction getDb(): Firestore {\n if (!db) {\n if (getApps().length === 0) {\n initializeApp({ credential: applicationDefault() });\n }\n db = getFirestore();\n }\n return db;\n}\n\nfunction hashKey(key: string): string {\n return createHash(\"sha256\").update(key).digest(\"hex\");\n}\n\nfunction apiKeysCol() {\n return getDb().collection(\"grimoire_api_keys\");\n}\n\nexport async function createApiKey(name: string): Promise<string> {\n const raw = `grim_${randomBytes(32).toString(\"base64url\")}`;\n const hash = hashKey(raw);\n\n await apiKeysCol().doc(hash).set({\n name,\n created_at: new Date().toISOString(),\n last_used_at: null,\n });\n\n return raw;\n}\n\nexport async function listApiKeys(): Promise<void> {\n const snapshot = await apiKeysCol().get();\n\n if (snapshot.empty) {\n console.log(\"No API keys found.\");\n return;\n }\n\n console.log(\"\\nAPI Keys:\\n\");\n for (const doc of snapshot.docs) {\n const data = doc.data();\n const lastUsed = data.last_used_at ?? \"never\";\n console.log(` ${bold(data.name)}`);\n console.log(` Created: ${data.created_at}`);\n console.log(` Last used: ${lastUsed}`);\n }\n}\n\nexport async function deleteApiKey(name: string): Promise<void> {\n const snapshot = await apiKeysCol().where(\"name\", \"==\", name).get();\n\n if (snapshot.empty) {\n throw new Error(`No API key found with name \"${name}\".`);\n }\n\n for (const doc of snapshot.docs) {\n await doc.ref.delete();\n }\n\n console.log(`API key \"${name}\" deleted.`);\n}\n\nexport async function cmdApiKey(): Promise<void> {\n const subcommand = process.argv[3];\n const arg = process.argv[4];\n\n if (subcommand === \"create\") {\n if (!arg) {\n console.error(\"Usage: grimoire apikey create <name>\");\n process.exit(1);\n }\n const key = await createApiKey(arg);\n console.log(`\\nAPI key created for \"${arg}\":\\n`);\n console.log(` ${key}\\n`);\n console.log(\"Save this key \u2014 it will not be shown again.\");\n } else if (subcommand === \"list\") {\n await listApiKeys();\n } else if (subcommand === \"delete\") {\n if (!arg) {\n console.error(\"Usage: grimoire apikey delete <name>\");\n process.exit(1);\n }\n await deleteApiKey(arg);\n } else {\n console.error(\"Usage: grimoire apikey <create|list|delete> [name]\");\n process.exit(1);\n }\n}\n", "import { writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { slugifyUrl } from \"./scraper.js\";\nimport { buildFrontmatter, type ConvertedPage } from \"./converter.js\";\n\ninterface LlmsPage {\n title: string;\n url: string;\n markdown: string;\n}\n\nconst BOILERPLATE_PATTERNS = [\n /^\\[Skip to content\\]\\([^)]*\\)\\s*$/gm,\n /^Was this helpful\\?\\s*$/gm,\n /^YesNo\\s*$/gm,\n /^\\[ Edit page \\]\\([^)]+\\) \\[ Report issue \\]\\([^)]+\\)\\s*$/gm,\n /^Copy page\\s*$/gm,\n /^```json\\n\\{\"@context\":\"https:\\/\\/schema\\.org\",\"@type\":\"BreadcrumbList\"[^`]*```\\s*$/gm,\n];\n\nfunction splitPages(content: string): LlmsPage[] {\n const pages: LlmsPage[] = [];\n const frontmatterPattern = /^---\\ntitle: (.+)\\n/gm;\n const boundaries: { index: number; title: string }[] = [];\n\n let match;\n while ((match = frontmatterPattern.exec(content)) !== null) {\n boundaries.push({ index: match.index, title: match[1] });\n }\n\n for (let i = 0; i < boundaries.length; i++) {\n const start = boundaries[i].index;\n const end = i + 1 < boundaries.length ? boundaries[i + 1].index : content.length;\n const raw = content.slice(start, end).trimEnd();\n\n const url = extractUrl(raw);\n if (!url) continue;\n\n const bodyStart = raw.indexOf(\"---\", 3);\n if (bodyStart === -1) continue;\n const body = raw.slice(raw.indexOf(\"\\n\", bodyStart) + 1);\n\n let cleaned = body;\n for (const pattern of BOILERPLATE_PATTERNS) {\n cleaned = cleaned.replace(pattern, \"\");\n }\n cleaned = cleaned.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n\n if (!cleaned) continue;\n\n pages.push({\n title: boundaries[i].title,\n url,\n markdown: cleaned,\n });\n }\n\n return pages;\n}\n\nfunction extractUrl(pageContent: string): string | null {\n const match = pageContent.match(\n /```json\\n\\{\"@context\":\"https:\\/\\/schema\\.org\",\"@type\":\"BreadcrumbList\",\"itemListElement\":\\[(.+?)\\]\\}\\n```/,\n );\n if (!match) return null;\n\n const items = JSON.parse(`[${match[1]}]`) as { item?: { \"@id\": string } }[];\n const last = items[items.length - 1];\n if (!last?.item?.[\"@id\"]) return null;\n\n return `https://developers.cloudflare.com${last.item[\"@id\"]}`;\n}\n\nexport async function ingestLlmsFull(\n llmsFullUrl: string,\n sourceName: string,\n baseUrl: string,\n dataDir: string,\n onProgress?: (current: number, total: number) => void,\n): Promise<ConvertedPage[]> {\n const response = await fetch(llmsFullUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${llmsFullUrl}: ${response.status} ${response.statusText}`);\n }\n const content = await response.text();\n\n const pages = splitPages(content);\n\n const mdDir = join(dataDir, \"markdown\", sourceName);\n await mkdir(mdDir, { recursive: true });\n\n const results: ConvertedPage[] = [];\n for (let i = 0; i < pages.length; i++) {\n const page = pages[i];\n const frontmatter = buildFrontmatter(sourceName, page.url, page.title);\n const fullMarkdown = `${frontmatter}\\n\\n${page.markdown}`;\n const slug = slugifyUrl(page.url);\n await writeFile(join(mdDir, `${slug}.md`), fullMarkdown, \"utf-8\");\n\n results.push({\n source: sourceName,\n url: page.url,\n title: page.title,\n markdown: fullMarkdown,\n });\n\n if (onProgress && ((i + 1) % 100 === 0 || i + 1 === pages.length)) {\n onProgress(i + 1, pages.length);\n }\n }\n\n return results;\n}\n"],
5
- "mappings": "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",
6
- "names": ["readFile", "writeFile", "mkdir", "join", "readFile", "writeFile", "mkdir", "join", "DEFAULT_CONCURRENCY", "join", "mkdir", "readFile", "writeFile", "resolve", "BATCH_SIZE", "MAX_RETRIES", "resolve", "getFirestore", "initializeApp", "applicationDefault", "getApps", "db", "getDb", "getApps", "initializeApp", "applicationDefault", "getFirestore", "writeFile", "mkdir", "join", "join", "mkdir", "writeFile", "join", "resolve", "readFile", "writeFile", "mkdir", "f", "allChunks", "pages", "texts", "embeddings"]
7
- }