@astrofoundry/grimoire 3.29.1 → 3.30.1
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.
- package/dist/{admin-E4L4RORC.js → admin-YF2OKHEQ.js} +806 -287
- package/dist/admin-YF2OKHEQ.js.map +7 -0
- package/dist/chunk-R46N6C3C.js +40 -0
- package/dist/{chunk-BRS6X3AE.js.map → chunk-R46N6C3C.js.map} +1 -1
- package/dist/cli.js +38 -22
- package/dist/cli.js.map +2 -2
- package/package.json +2 -1
- package/dist/admin-E4L4RORC.js.map +0 -7
- package/dist/chunk-BRS6X3AE.js +0 -12
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../node_modules/.pnpm/@joplin+turndown-plugin-gfm@1.0.67/node_modules/@joplin/turndown-plugin-gfm/lib/turndown-plugin-gfm.cjs.js", "../src/admin.ts", "../src/config.ts", "../src/scraper.ts", "../src/converter.ts", "../src/chunker.ts", "../src/tokens.ts", "../src/embedder.ts", "../src/store.ts", "../src/reranker.ts", "../src/search.ts", "../src/apikey.ts", "../src/llms-ingest.ts"],
|
|
4
|
+
"sourcesContent": ["'use strict';\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\nvar highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/;\n\nfunction highlightedCodeBlock (turndownService) {\n turndownService.addRule('highlightedCodeBlock', {\n filter: function (node) {\n var firstChild = node.firstChild;\n return (\n node.nodeName === 'DIV' &&\n highlightRegExp.test(node.className) &&\n firstChild &&\n firstChild.nodeName === 'PRE'\n )\n },\n replacement: function (content, node, options) {\n var className = node.className || '';\n var language = (className.match(highlightRegExp) || [null, ''])[1];\n\n return (\n '\\n\\n' + options.fence + language + '\\n' +\n node.firstChild.textContent +\n '\\n' + options.fence + '\\n\\n'\n )\n }\n });\n}\n\nfunction strikethrough (turndownService) {\n turndownService.addRule('strikethrough', {\n filter: ['del', 's', 'strike'],\n replacement: function (content) {\n return '~~' + content + '~~'\n }\n });\n}\n\nvar indexOf = Array.prototype.indexOf;\nvar every = Array.prototype.every;\nvar rules = {};\nvar alignMap = { left: ':---', right: '---:', center: ':---:' };\n\nlet isCodeBlock_ = null;\nlet options_ = null;\n\n// We need to cache the result of tableShouldBeSkipped() as it is expensive.\n// Caching it means we went from about 9000 ms for rendering down to 90 ms.\n// Fixes https://github.com/laurent22/joplin/issues/6736\nconst tableShouldBeSkippedCache_ = new WeakMap();\n\nfunction getAlignment(node) {\n return node ? (node.getAttribute('align') || node.style.textAlign || '').toLowerCase() : '';\n}\n\nfunction getBorder(alignment) {\n return alignment ? alignMap[alignment] : '---';\n}\n\nfunction getColumnAlignment(table, columnIndex) {\n var votes = {\n left: 0,\n right: 0,\n center: 0,\n '': 0,\n };\n\n var align = '';\n\n for (var i = 0; i < table.rows.length; ++i) {\n var row = table.rows[i];\n if (columnIndex < row.childNodes.length) {\n var cellAlignment = getAlignment(row.childNodes[columnIndex]);\n ++votes[cellAlignment];\n\n if (votes[cellAlignment] > votes[align]) {\n align = cellAlignment;\n }\n }\n }\n\n return align;\n}\n\nrules.tableCell = {\n filter: ['th', 'td'],\n replacement: function (content, node) {\n if (tableShouldBeSkipped(nodeParentTable(node))) return content;\n return cell(content, node)\n }\n};\n\nrules.tableRow = {\n filter: 'tr',\n replacement: function (content, node) {\n const parentTable = nodeParentTable(node);\n if (tableShouldBeSkipped(parentTable)) return content;\n\n var borderCells = '';\n\n if (isHeadingRow(node)) {\n const colCount = tableColCount(parentTable);\n for (var i = 0; i < colCount; i++) {\n const childNode = i < node.childNodes.length ? node.childNodes[i] : null;\n var border = getBorder(getColumnAlignment(parentTable, i));\n borderCells += cell(border, childNode, i);\n }\n }\n return '\\n' + content + (borderCells ? '\\n' + borderCells : '')\n }\n};\n\nrules.table = {\n filter: function (node, options) {\n return node.nodeName === 'TABLE';\n },\n\n replacement: function (content, node) {\n // Only convert tables that can result in valid Markdown\n // Other tables are kept as HTML using `keep` (see below).\n if (tableShouldBeHtml(node, options_)) {\n let html = node.outerHTML;\n let divParent = nodeParentDiv(node);\n // Make table in HTML format horizontally scrollable by give table a div parent, so the width of the table is limited to the screen width.\n\t // see https://github.com/laurent22/joplin/pull/10161\n // test cases:\n // packages/app-cli/tests/html_to_md/preserve_nested_tables.html\n // packages/app-cli/tests/html_to_md/table_with_blockquote.html\n // packages/app-cli/tests/html_to_md/table_with_code_1.html\n // packages/app-cli/tests/html_to_md/table_with_code_2.html\n // packages/app-cli/tests/html_to_md/table_with_code_3.html\n // packages/app-cli/tests/html_to_md/table_with_heading.html\n // packages/app-cli/tests/html_to_md/table_with_hr.html\n // packages/app-cli/tests/html_to_md/table_with_list.html\n if (divParent === null || !divParent.classList.contains('joplin-table-wrapper')){\n return `\\n\\n<div class=\"joplin-table-wrapper\">${html}</div>\\n\\n`;\n } else {\n return html\n }\n } else {\n if (tableShouldBeSkipped(node)) return content;\n\n // Ensure there are no blank lines\n content = content.replace(/\\n+/g, '\\n');\n\n // If table has no heading, add an empty one so as to get a valid Markdown table\n var secondLine = content.trim().split('\\n');\n if (secondLine.length >= 2) secondLine = secondLine[1];\n var secondLineIsDivider = /\\| :?---/.test(secondLine);\n\n var columnCount = tableColCount(node);\n var emptyHeader = '';\n if (columnCount && !secondLineIsDivider) {\n emptyHeader = '|' + ' |'.repeat(columnCount) + '\\n' + '|';\n for (var columnIndex = 0; columnIndex < columnCount; ++columnIndex) {\n emptyHeader += ' ' + getBorder(getColumnAlignment(node, columnIndex)) + ' |';\n }\n }\n\n const captionNode = node.querySelector ? node.querySelector('caption') : node.caption;\n const captionContent = captionNode ? captionNode.textContent || '' : '';\n const caption = captionContent ? `${captionContent}\\n\\n` : '';\n const tableContent = `${emptyHeader}${content}`.trimStart();\n return `\\n\\n${caption}${tableContent}\\n\\n`;\n }\n }\n};\n\nrules.tableCaption = {\n filter: ['caption'],\n replacement: () => '',\n};\n\nrules.tableColgroup = {\n filter: ['colgroup', 'col'],\n replacement: () => '',\n};\n\nrules.tableSection = {\n filter: ['thead', 'tbody', 'tfoot'],\n replacement: function (content) {\n return content\n }\n};\n\n// A tr is a heading row if:\n// - the parent is a THEAD\n// - or if its the first child of the TABLE or the first TBODY (possibly\n// following a blank THEAD)\n// - and every cell is a TH\nfunction isHeadingRow (tr) {\n var parentNode = tr.parentNode;\n return (\n parentNode.nodeName === 'THEAD' ||\n (\n parentNode.firstChild === tr &&\n (parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) &&\n every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' })\n )\n )\n}\n\nfunction isFirstTbody (element) {\n var previousSibling = element.previousSibling;\n return (\n element.nodeName === 'TBODY' && (\n !previousSibling ||\n (\n previousSibling.nodeName === 'THEAD' &&\n /^\\s*$/i.test(previousSibling.textContent)\n )\n )\n )\n}\n\nfunction cell (content, node = null, index = null) {\n if (index === null) index = indexOf.call(node.parentNode.childNodes, node);\n var prefix = ' ';\n if (index === 0) prefix = '| ';\n let filteredContent = content.trim().replace(/\\n\\r/g, '<br>').replace(/\\n/g, \"<br>\");\n filteredContent = filteredContent.replace(/\\|+/g, '\\\\|');\n while (filteredContent.length < 3) filteredContent += ' ';\n if (node) filteredContent = handleColSpan(filteredContent, node, ' ');\n return prefix + filteredContent + ' |'\n}\n\nfunction nodeContainsTable(node) {\n if (!node.childNodes) return false;\n\n for (let i = 0; i < node.childNodes.length; i++) {\n const child = node.childNodes[i];\n if (child.nodeName === 'TABLE') return true;\n if (nodeContainsTable(child)) return true;\n }\n return false;\n}\n\nconst nodeContains = (node, types) => {\n if (!node.childNodes) return false;\n\n for (let i = 0; i < node.childNodes.length; i++) {\n const child = node.childNodes[i];\n if (types === 'code' && isCodeBlock_ && isCodeBlock_(child)) return true;\n if (types.includes(child.nodeName)) return true;\n if (nodeContains(child, types)) return true;\n }\n\n return false;\n};\n\n// Style properties that count as user customization.\n// Excludes TinyMCE/Joplin defaults:\n// - border-collapse: set by default on all tables\n// - width: set on every cell by TinyMCE\n// - text-align: converted to Markdown alignment (:---, :---:, ---:)\n// - height: false positives from TinyMCE defaults\nconst customStyleProperties = [\n 'background-color', 'background',\n 'border-color', 'border',\n 'border-top', 'border-right', 'border-bottom', 'border-left',\n 'border-style', 'border-width',\n 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left',\n 'float', 'margin-left', 'margin-right',\n];\n\n// HTML attributes TinyMCE may set instead of CSS.\nconst customAttributeNames = [\n 'bgcolor',\n 'bordercolor',\n 'background',\n];\n\nconst nodeHasCustomStyle = (node) => {\n if (!node || !node.getAttribute) return false;\n const styleAttr = node.getAttribute('style');\n if (!styleAttr) return false;\n // Extract property names from the raw style string\n const properties = styleAttr.split(';')\n .map(s => s.split(':')[0].trim().toLowerCase())\n .filter(s => s.length > 0);\n for (let i = 0; i < properties.length; i++) {\n if (customStyleProperties.includes(properties[i])) return true;\n }\n return false;\n};\n\nconst hasNonDefaultSpacingAttribute = (node, name) => {\n if (!node || !node.getAttribute) return false;\n const value = node.getAttribute(name);\n if (value === null) return false;\n const normalisedValue = `${value}`.trim().toLowerCase();\n if (!normalisedValue) return false;\n if (normalisedValue === '0' || normalisedValue === '0px') return false;\n return true;\n};\n\nconst nodeHasCustomAttributes = (node) => {\n if (!node || !node.getAttribute) return false;\n\n for (let i = 0; i < customAttributeNames.length; i++) {\n const value = node.getAttribute(customAttributeNames[i]);\n if (value !== null && `${value}`.trim() !== '') return true;\n }\n\n if (node.nodeName === 'TABLE') {\n if (hasNonDefaultSpacingAttribute(node, 'cellpadding')) return true;\n if (hasNonDefaultSpacingAttribute(node, 'cellspacing')) return true;\n }\n\n return false;\n};\n\nconst nodeHasCustomFormatting = (node) => {\n return nodeHasCustomStyle(node) || nodeHasCustomAttributes(node);\n};\n\n// Returns true if the table or any of its rows/cells have custom formatting.\nconst tableHasCustomStyles = (tableNode) => {\n if (nodeHasCustomFormatting(tableNode)) return true;\n\n const rows = tableNode.rows;\n if (!rows) return false;\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n if (nodeHasCustomFormatting(row)) return true;\n for (let j = 0; j < row.childNodes.length; j++) {\n const cell = row.childNodes[j];\n if ((cell.nodeName === 'TD' || cell.nodeName === 'TH') && nodeHasCustomFormatting(cell)) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nconst tableShouldBeHtml = (tableNode, options) => {\n const possibleTags = [\n 'UL',\n 'OL',\n 'H1',\n 'H2',\n 'H3',\n 'H4',\n 'H5',\n 'H6',\n 'HR',\n 'BLOCKQUOTE',\n ];\n\n // In general we should leave as HTML tables that include other tables. The\n // exception is with the Web Clipper when we import a web page with a layout\n // that's made of HTML tables. In that case we have this logic of removing the\n // outer table and keeping only the inner ones. For the Rich Text editor\n // however we always want to keep nested tables.\n if (options.preserveNestedTables) possibleTags.push('TABLE');\n\n return nodeContains(tableNode, 'code') ||\n nodeContains(tableNode, possibleTags) ||\n (options.preserveTableStyles && tableHasCustomStyles(tableNode));\n};\n\n// Various conditions under which a table should be skipped - i.e. each cell\n// will be rendered one after the other as if they were paragraphs.\nfunction tableShouldBeSkipped(tableNode) {\n const cached = tableShouldBeSkippedCache_.get(tableNode);\n if (cached !== undefined) return cached;\n\n const result = tableShouldBeSkipped_(tableNode);\n\n tableShouldBeSkippedCache_.set(tableNode, result);\n return result;\n}\n\nfunction tableShouldBeSkipped_(tableNode) {\n if (!tableNode) return true;\n if (!tableNode.rows) return true;\n if (tableNode.rows.length === 1 && tableNode.rows[0].childNodes.length <= 1) return true; // Table with only one cell\n if (nodeContainsTable(tableNode)) return true;\n return false;\n}\n\nfunction nodeParentDiv(node) {\n let parent = node.parentNode;\n while (parent.nodeName !== 'DIV') {\n parent = parent.parentNode;\n if (!parent) return null;\n }\n return parent;\n}\n\nfunction nodeParentTable(node) {\n let parent = node.parentNode;\n while (parent.nodeName !== 'TABLE') {\n parent = parent.parentNode;\n if (!parent) return null;\n }\n return parent;\n}\n\nfunction handleColSpan(content, node, emptyChar) {\n const colspan = node.getAttribute('colspan') || 1;\n for (let i = 1; i < colspan; i++) {\n content += ' | ' + emptyChar.repeat(3);\n }\n return content\n}\n\nfunction tableColCount(node) {\n let maxColCount = 0;\n for (let i = 0; i < node.rows.length; i++) {\n const row = node.rows[i];\n const colCount = row.childNodes.length;\n if (colCount > maxColCount) maxColCount = colCount;\n }\n return maxColCount\n}\n\nfunction tables (turndownService) {\n isCodeBlock_ = turndownService.isCodeBlock;\n options_ = turndownService.options;\n\n turndownService.keep(function (node) {\n if (node.nodeName === 'TABLE' && tableShouldBeHtml(node, turndownService.options)) return true;\n return false;\n });\n for (var key in rules) turndownService.addRule(key, rules[key]);\n}\n\nfunction taskListItems (turndownService) {\n turndownService.addRule('taskListItems', {\n filter: function (node) {\n const parent = node.parentNode;\n const grandparent = parent.parentNode;\n const grandparentIsListItem = !!grandparent && grandparent.nodeName === 'LI';\n return (node.type === 'checkbox' || node.getAttribute('role') === 'checkbox') && (\n parent.nodeName === 'LI'\n // Handles the case where the label contains the checkbox. For example,\n // <label><input ...> ...label text...</label>\n || (parent.nodeName === 'LABEL' && grandparentIsListItem)\n // Handles the case where the input is contained within a <span>\n // <li><span><input ...></span></li>\n || (parent.nodeName === 'SPAN' && grandparentIsListItem)\n )\n },\n replacement: function (content, node) {\n const checked = node.nodeName === 'INPUT' ? node.checked : node.getAttribute('aria-checked') === 'true';\n return (checked ? '[x]' : '[ ]') + ' '\n }\n });\n}\n\nfunction gfm (turndownService) {\n turndownService.use([\n highlightedCodeBlock,\n strikethrough,\n tables,\n taskListItems\n ]);\n}\n\nexports.gfm = gfm;\nexports.highlightedCodeBlock = highlightedCodeBlock;\nexports.strikethrough = strikethrough;\nexports.tables = tables;\nexports.taskListItems = taskListItems;\n", "import { parseArgs } from \"node:util\";\nimport { readFile, writeFile, readdir, rm } 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, buildEmbedText } from \"./chunker.js\";\nimport { contentHash } from \"./tokens.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 getSourceChunkHashes,\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\n// Embed-and-store window. Each window is embedded then written before the\n// next starts, so heap stays flat regardless of source size, and an\n// interrupted refresh resumes for free: stored chunks hash-match next run.\nconst EMBED_WINDOW = 1000;\n\nasync function syncChunks(\n sourceName: string,\n allChunks: Chunk[],\n urlCount: number,\n version: string | undefined,\n): Promise<void> {\n console.log(\" Comparing with Firestore...\");\n const existing = await getSourceChunkHashes(sourceName);\n const currentIds = new Set(allChunks.map((c) => c.id));\n const toDelete = [...existing.keys()].filter((id) => !currentIds.has(id));\n const toEmbed = allChunks.filter(\n (chunk) => existing.get(chunk.id) !== contentHash(buildEmbedText(chunk)),\n );\n\n console.log(\n ` Sync: ${toEmbed.length} to embed, ${allChunks.length - toEmbed.length} unchanged, ${toDelete.length} to delete.`,\n );\n\n if (toDelete.length > 0) {\n await deleteChunksByIds(toDelete, (cur, total) => {\n console.log(` [${cur}/${total}] deleted`);\n });\n }\n\n for (let i = 0; i < toEmbed.length; i += EMBED_WINDOW) {\n const window = toEmbed.slice(i, i + EMBED_WINDOW);\n const embeddings = await embedTexts(window.map((c) => buildEmbedText(c)), {\n onProgress: (done) => {\n console.log(` [${i + done}/${toEmbed.length}] embedded`);\n },\n });\n await storeChunks(window, embeddings, (cur) => {\n console.log(` [${i + cur}/${toEmbed.length}] stored`);\n });\n }\n\n await updateSourceMeta(sourceName, allChunks.length, urlCount, version);\n console.log(` Done. ${allChunks.length} chunks live for \"${sourceName}\".`);\n}\n\ninterface RefreshPage {\n url: string;\n title: string;\n markdown: string;\n}\n\nasync function readCachedMarkdownPages(mdDir: string): Promise<RefreshPage[]> {\n const mdFiles = await readdir(mdDir).catch(() => [] as string[]);\n const pages: RefreshPage[] = [];\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 if (!urlMatch) {\n console.warn(` WARNING: ${f} has no url in frontmatter, skipping page.`);\n continue;\n }\n pages.push({\n markdown: content,\n url: urlMatch[1],\n title: titleMatch?.[1] ?? \"Untitled\",\n });\n }\n return pages;\n}\n\nasync function recoverUrlsFromHtml(rawDir: string): Promise<string[]> {\n const urlsJsonPath = join(rawDir, \"urls.json\");\n try {\n return JSON.parse(await readFile(urlsJsonPath, \"utf-8\")) as string[];\n } catch {\n const rawFiles = await readdir(rawDir);\n const urls: string[] = [];\n let skipped = 0;\n for (const f of rawFiles.filter((f) => f.endsWith(\".html\"))) {\n const fileSlug = f.replace(/\\.html$/, \"\");\n const html = await readFile(join(rawDir, f), \"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 console.warn(` WARNING: cannot recover URL for ${f}, skipping page.`);\n skipped++;\n }\n if (skipped > 0) {\n console.warn(` Skipped ${skipped} pages with unrecoverable URLs. Provide urls.json to include them.`);\n }\n return urls;\n }\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 concurrency: { type: \"string\" },\n limit: { type: \"string\" },\n \"from-html\": { type: \"boolean\", default: false },\n \"from-markdown\": { 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] [--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\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 pages: RefreshPage[];\n\n if (args.values[\"from-markdown\"]) {\n console.log(\" Reading cached markdown...\");\n pages = await readCachedMarkdownPages(mdDir);\n if (pages.length === 0) {\n console.error(\" No cached markdown found. Run with --from-html first.\");\n process.exit(1);\n }\n console.log(` Found ${pages.length} cached pages.`);\n } else 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 let urls: string[];\n if (args.values[\"from-html\"]) {\n console.log(\" Reading URLs from cached HTML...\");\n urls = await recoverUrlsFromHtml(rawDir);\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 if (args.values[\"skip-store\"]) {\n console.log(` Done. ${allChunks.length} chunks ready (dry run, no embed/store).`);\n continue;\n }\n\n await syncChunks(sourceName, allChunks, pages.length, source.version);\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 candidates: { 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>] [--candidates <n>] [--compact]\");\n process.exit(1);\n }\n\n const topN = args.values.top ? parseInt(args.values.top, 10) : undefined;\n const candidates = args.values.candidates ? parseInt(args.values.candidates, 10) : undefined;\n const results = await search(query, { source: args.values.source, topN, candidates });\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 if (source.wait_for_selector) {\n await page.waitForSelector(source.wait_for_selector, { timeout: 30000 });\n }\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 wait_for_selector?: 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 user_agent: source.user_agent as string | undefined,\n llms_full_url: source.llms_full_url as string | undefined,\n wait_for_selector: source.wait_for_selector 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 waitForSelector?: string,\n): Promise<string> {\n try {\n await page.goto(url, {\n waitUntil: headed ? \"networkidle\" : \"domcontentloaded\",\n timeout: headed ? NAV_TIMEOUT_MS_HEADED : NAV_TIMEOUT_MS,\n });\n } catch (err) {\n // Bot-protected sites with polling widgets (Zendesk live chat, intercom)\n // never reach networkidle. The DOM has loaded by then, so accept the\n // timeout and fall through; wait_for_selector below gates content validity.\n if (!(err instanceof Error) || !/Timeout|Navigation timeout/i.test(err.message)) {\n throw err;\n }\n }\n if (waitForSelector) {\n await page.waitForSelector(waitForSelector, { timeout: NAV_TIMEOUT_MS_HEADED });\n }\n return page.content();\n}\n\nconst DEFAULT_CONCURRENCY = 50;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function runPool<T>(\n items: T[],\n concurrency: number,\n rateLimitMs: number,\n fn: (item: T, index: number) => Promise<void>,\n): Promise<void> {\n let nextIndex = 0;\n\n async function worker(): Promise<void> {\n let isFirst = true;\n while (nextIndex < items.length) {\n const index = nextIndex++;\n if (!isFirst && rateLimitMs > 0) {\n await sleep(rateLimitMs);\n }\n isFirst = false;\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 rateLimitMs = source.rate_limit_ms ?? 0;\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 async function attemptScrape(url: string, maxAttempts: number): Promise<string | null> {\n let lastError: unknown;\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const page = await context.newPage();\n try {\n const html = await fetchPage(page, url, source.headed, source.wait_for_selector);\n const slug = slugifyUrl(url);\n await writeFile(join(rawDir, `${slug}.html`), html, \"utf-8\");\n return null;\n } catch (err) {\n lastError = err;\n } finally {\n await page.close();\n }\n }\n return lastError instanceof Error ? lastError.message : String(lastError);\n }\n\n try {\n await runPool(urls, concurrency, rateLimitMs, async (url) => {\n const errorMsg = await attemptScrape(url, 2);\n if (errorMsg === null) {\n succeeded.push(url);\n } else {\n failed.push({ url, error: errorMsg });\n }\n completed++;\n onProgress?.(completed, urls.length, url);\n });\n\n // Recovery pass: retry transient failures sequentially with throttling.\n // Zendesk and similar bot-protected sites randomly time out under parallel\n // load even at low concurrency; a serialized retry usually catches them.\n if (failed.length > 0) {\n const toRetry = failed.splice(0).map((f) => f.url);\n const recoveryRateLimit = Math.max(rateLimitMs, 1000);\n console.log(` Recovery pass: retrying ${toRetry.length} failed pages sequentially...`);\n await runPool(toRetry, 1, recoveryRateLimit, async (url) => {\n const errorMsg = await attemptScrape(url, 2);\n if (errorMsg === null) {\n succeeded.push(url);\n } else {\n failed.push({ url, error: errorMsg });\n }\n });\n console.log(` Recovered ${toRetry.length - failed.length}/${toRetry.length} pages.`);\n }\n\n if (failed.length > 0) {\n console.error(` Skipped ${failed.length}/${urls.length} pages after recovery:`);\n for (const { url, error } of failed.slice(0, 10)) {\n console.error(` ${url} - ${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 { tables } from \"@joplin/turndown-plugin-gfm\";\nimport { slugifyUrl } from \"./scraper.js\";\n\nconst turndown = new TurndownService({\n headingStyle: \"atx\",\n codeBlockStyle: \"fenced\",\n bulletListMarker: \"-\",\n});\nturndown.use(tables);\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\n// The GFM tables plugin keeps a table as raw HTML when its cells contain\n// code, lists, or other block markup. Reference tables (e.g. GCP flag docs)\n// are full of those, so flatten cell markup to plain text first - pipe rows\n// preserve the name/type/default association that flattened paragraphs lose.\nfunction flattenTableCellMarkup(contentEl: Element): void {\n for (const table of contentEl.querySelectorAll(\"table\")) {\n if (!table.isConnected) continue;\n for (const inner of table.querySelectorAll(\"table\")) {\n if (!inner.isConnected) continue;\n const rows = [...inner.rows]\n .map((row) =>\n [...row.cells]\n .map((c) => c.textContent?.replace(/\\s+/g, \" \").trim() ?? \"\")\n .filter(Boolean)\n .join(\" \"),\n )\n .filter(Boolean);\n inner.replaceWith(rows.join(\"; \"));\n }\n for (const code of table.querySelectorAll(\"code\")) {\n code.replaceWith(code.textContent ?? \"\");\n }\n for (const list of table.querySelectorAll(\"ul, ol\")) {\n if (!list.isConnected) continue;\n const items = [...list.querySelectorAll(\"li\")]\n .map((li) => li.textContent?.replace(/\\s+/g, \" \").trim() ?? \"\")\n .filter(Boolean);\n list.replaceWith(items.join(\"; \"));\n }\n for (const block of table.querySelectorAll(\"aside, blockquote, h1, h2, h3, h4, h5, h6\")) {\n if (!block.isConnected) continue;\n block.replaceWith(block.textContent?.replace(/\\s+/g, \" \").trim() ?? \"\");\n }\n }\n}\n\n// Table cells emit <br> for in-cell line breaks; replace with \"; \" so pipe\n// rows stay single-line and the embedded text carries no HTML tags.\nfunction cleanTableRowBreaks(md: string): string {\n return md\n .split(\"\\n\")\n .map((line) =>\n line.startsWith(\"|\") ? line.replace(/\\s*<br\\s*\\/?>\\s*/g, \"; \") : line,\n )\n .join(\"\\n\");\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) ?? doc.body;\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 flattenTableCellMarkup(contentEl);\n\n return cleanMarkdown(\n cleanTableRowBreaks(turndown.turndown(contentEl.innerHTML)),\n removeTextPatterns,\n );\n}\n\n// Strip only the trailing site-name segment (after the last pipe, dash with\n// surrounding spaces, or en/em dash) so mid-title hyphens and inner segments\n// like \"ExportContext | Cloud SQL Admin API\" survive.\nexport function extractTitle(html: string): string {\n const dom = new JSDOM(html);\n const raw = dom.window.document\n .querySelector(\"title\")\n ?.textContent?.replace(/\\s+/g, \" \")\n .trim();\n if (!raw) return \"Untitled\";\n const stripped = raw\n .replace(/\\s*\\|[^|]*$/, \"\")\n .replace(/\\s*[\\u2013\\u2014][^\\u2013\\u2014]*$/, \"\")\n .replace(/\\s+-\\s+(?!.*\\s-\\s)[^|]*$/, \"\")\n .trim();\n return stripped || raw;\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\n// The text whose embedding represents the chunk. Prepending the page title\n// and heading path pulls dense reference chunks (flag tables, REST schemas)\n// toward queries that name the page or section, not just the body text.\nexport function buildEmbedText(chunk: Chunk): string {\n const path = chunk.heading_path[0] === chunk.title\n ? chunk.heading_path.slice(1)\n : chunk.heading_path;\n const context = [chunk.title, ...path].filter(Boolean).join(\" > \");\n return context ? `${context}\\n\\n${chunk.content}` : chunk.content;\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 let inFence = false;\n let fenceMarker = \"\";\n\n for (const line of lines) {\n const fenceMatch = line.match(/^\\s*(```+|~~~+)/);\n if (fenceMatch) {\n const marker = fenceMatch[1][0];\n if (!inFence) {\n inFence = true;\n fenceMarker = marker;\n } else if (marker === fenceMarker) {\n inFence = false;\n }\n }\n\n const headingMatch = inFence ? null : 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\ntype BlockKind = \"paragraph\" | \"fence\" | \"table\";\n\ninterface Block {\n kind: BlockKind;\n lines: string[];\n}\n\nfunction isTableLine(line: string): boolean {\n return line.trimStart().startsWith(\"|\");\n}\n\nfunction isTableSeparator(line: string): boolean {\n return /^\\s*\\|?[\\s:|-]+\\|?\\s*$/.test(line) && line.includes(\"-\");\n}\n\n// Group section lines into atomic blocks so splitting never lands inside a\n// fenced code block (blank lines in fences are not paragraph boundaries) and\n// tables can be split row-wise instead of as one opaque paragraph.\nfunction parseBlocks(lines: string[]): Block[] {\n const blocks: Block[] = [];\n let current: string[] = [];\n let kind: BlockKind = \"paragraph\";\n let inFence = false;\n let fenceMarker = \"\";\n\n function flush(): void {\n while (current.length > 0 && current[current.length - 1].trim() === \"\") {\n current.pop();\n }\n if (current.length > 0) {\n blocks.push({ kind, lines: current });\n }\n current = [];\n kind = \"paragraph\";\n }\n\n for (const line of lines) {\n if (inFence) {\n current.push(line);\n const fenceMatch = line.match(/^\\s*(```+|~~~+)/);\n if (fenceMatch && fenceMatch[1][0] === fenceMarker) {\n inFence = false;\n flush();\n }\n continue;\n }\n\n const fenceMatch = line.match(/^\\s*(```+|~~~+)/);\n if (fenceMatch) {\n flush();\n kind = \"fence\";\n inFence = true;\n fenceMarker = fenceMatch[1][0];\n current.push(line);\n continue;\n }\n\n if (isTableLine(line)) {\n if (kind !== \"table\") {\n flush();\n kind = \"table\";\n }\n current.push(line);\n continue;\n }\n\n if (kind === \"table\") {\n flush();\n }\n\n if (line.trim() === \"\") {\n flush();\n } else {\n current.push(line);\n }\n }\n\n flush();\n return blocks;\n}\n\nfunction groupLines(lines: string[], budget: number): string[][] {\n const groups: string[][] = [];\n let current: string[] = [];\n let tokens = 0;\n\n for (const line of lines) {\n const lineTokens = estimateTokens(line) + 1;\n if (tokens + lineTokens > budget && current.length > 0) {\n groups.push(current);\n current = [];\n tokens = 0;\n }\n current.push(line);\n tokens += lineTokens;\n }\n\n if (current.length > 0) groups.push(current);\n return groups;\n}\n\n// Split an oversized block into pieces that each stay valid markdown:\n// tables repeat the header row per piece, fences are re-opened and re-closed.\nfunction splitBlock(block: Block, budget: number): string[] {\n if (block.kind === \"table\") {\n const hasHeader = block.lines.length >= 2 && isTableSeparator(block.lines[1]);\n const header = hasHeader ? block.lines.slice(0, 2) : [];\n const rows = hasHeader ? block.lines.slice(2) : block.lines;\n const headerTokens = estimateTokens(header.join(\"\\n\"));\n return groupLines(rows, Math.max(budget - headerTokens, 50)).map((group) =>\n [...header, ...group].join(\"\\n\"),\n );\n }\n\n if (block.kind === \"fence\") {\n const opening = block.lines[0];\n const closing = block.lines[block.lines.length - 1].match(/^\\s*(```+|~~~+)\\s*$/)\n ? block.lines[block.lines.length - 1]\n : opening.match(/^\\s*(```+|~~~+)/)![1];\n const body = block.lines.slice(1, block.lines[block.lines.length - 1] === closing ? -1 : undefined);\n const frameTokens = estimateTokens(opening) + estimateTokens(closing) + 2;\n return groupLines(body, Math.max(budget - frameTokens, 50)).map((group) =>\n [opening, ...group, closing].join(\"\\n\"),\n );\n }\n\n return groupLines(block.lines, budget).map((group) => group.join(\"\\n\"));\n}\n\n// Pack blocks into parts within the token budget. Every part of a split\n// section carries the heading line so continuation chunks keep their context.\nfunction splitSectionIntoParts(\n blocks: Block[],\n headingLine: string,\n maxTokens: number,\n): string[] {\n const budget = Math.max(maxTokens - estimateTokens(headingLine), 100);\n const parts: string[][] = [];\n let current: string[] = [];\n let tokens = 0;\n\n function flush(): void {\n if (current.length > 0) {\n parts.push(current);\n current = [];\n tokens = 0;\n }\n }\n\n for (const block of blocks) {\n const text = block.lines.join(\"\\n\");\n const blockTokens = estimateTokens(text) + 2;\n\n if (blockTokens > budget) {\n flush();\n for (const piece of splitBlock(block, budget)) {\n parts.push([piece]);\n }\n continue;\n }\n\n if (tokens + blockTokens > budget) {\n flush();\n }\n current.push(text);\n tokens += blockTokens;\n }\n\n flush();\n return parts.map((blockTexts) => headingLine + blockTexts.join(\"\\n\\n\"));\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 body = section.lines.join(\"\\n\").trim();\n const content = headingLine + body;\n\n if (!content.trim()) continue;\n\n const headingSlug = section.heading\n ? slugifyHeading(section.heading)\n : \"intro\";\n\n if (estimateTokens(content) <= 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: estimateTokens(content),\n });\n continue;\n }\n\n const blocks = parseBlocks(body.split(\"\\n\"));\n const parts = splitSectionIntoParts(blocks, headingLine, MAX_TOKENS);\n\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 return chunks;\n}\n", "import { createHash } from \"node:crypto\";\n\n// Identifier-shaped tokens: snake_case, kebab-case, dotted.paths (and mixes),\n// camelCase, PascalCase. Plain prose words are deliberately excluded - the\n// lexical index exists to find exact identifiers that dense embeddings dilute,\n// while ordinary vocabulary is the vector search's job.\nconst IDENTIFIER_PATTERN =\n /(?<![A-Za-z0-9._])(?:[A-Za-z][A-Za-z0-9]*(?:[_.-][A-Za-z0-9]+)+|[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)+|(?:[A-Z][a-z0-9]+){2,})(?![A-Za-z0-9])/g;\n\nconst MIN_TOKEN_LENGTH = 4;\nconst MAX_TOKEN_LENGTH = 80;\nconst MAX_TOKENS_PER_CHUNK = 100;\n\n// Drop URLs/link targets (their hostnames and paths are identifier-shaped\n// noise) and undo markdown escaping (`max\\_connections` must tokenize as\n// max_connections).\nfunction normalizeForTokens(text: string): string {\n return text\n .replace(/\\]\\([^)]*\\)/g, \"]\")\n .replace(/https?:\\/\\/\\S+/g, \" \")\n .replace(/\\\\([_*[\\]()#`~-])/g, \"$1\");\n}\n\nexport function extractIdentifierTokens(text: string, limit = MAX_TOKENS_PER_CHUNK): string[] {\n const seen = new Set<string>();\n for (const match of normalizeForTokens(text).matchAll(IDENTIFIER_PATTERN)) {\n const token = match[0].toLowerCase();\n if (token.length < MIN_TOKEN_LENGTH || token.length > MAX_TOKEN_LENGTH) continue;\n seen.add(token);\n if (seen.size >= limit) break;\n }\n return [...seen];\n}\n\nexport function extractQueryTokens(query: string): string[] {\n return extractIdentifierTokens(query, 5);\n}\n\nexport function contentHash(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\");\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;\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(\"500\") || message.includes(\"502\") || message.includes(\"503\") || message.includes(\"504\")) {\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 maxRetries?: 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 } = options;\n const maxRetries = options.maxRetries ?? MAX_RETRIES;\n\n const embeddings: number[][] = [];\n\n for (let i = 0; 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 < maxRetries; 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 < maxRetries - 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 if (i + BATCH_SIZE < texts.length) {\n await new Promise((resolve) => setTimeout(resolve, BATCH_DELAY_MS));\n }\n }\n\n return embeddings;\n}\n\n// Online query path - one shot, no retries. The Cloud Function request\n// timeout (60s) is shorter than the embedder's first rate-limit backoff\n// (60s), so any retry here would only ever cause a 504. Surface the error\n// to the caller, who can retry at their own cadence.\nexport async function embedText(text: string): Promise<number[]> {\n const [embedding] = await embedTexts([text], { maxRetries: 1 });\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\";\nimport { buildEmbedText } from \"./chunker.js\";\nimport { contentHash, extractIdentifierTokens } from \"./tokens.js\";\n\n// Vector-indexed writes are heavy; 500-doc batches against the vector index\n// can exceed the commit deadline on large sources (25k+ chunks). Smaller\n// batches commit faster and a short inter-batch pause smooths sustained\n// write throughput so the vector index backend keeps up.\nconst BATCH_SIZE = 200;\nconst INTER_BATCH_DELAY_MS = 150;\nconst MAX_RETRIES = 7;\nconst BASE_DELAY_MS = 5000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Transient Firestore/gRPC failures worth retrying. batch.commit() with fixed\n// document ids is idempotent, so re-committing the same batch is safe.\nconst TRANSIENT_PATTERNS = [\n \"RESOURCE_EXHAUSTED\",\n \"Quota exceeded\",\n \"DEADLINE_EXCEEDED\",\n \"UNAVAILABLE\",\n \"ABORTED\",\n \"INTERNAL\",\n \"503\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n];\n\nasync function retryOnTransient<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 (TRANSIENT_PATTERNS.some((p) => message.includes(p)) && attempt < MAX_RETRIES - 1) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n console.log(` Transient Firestore error (${message.split(\":\")[0].slice(0, 40)}), retrying in ${delay / 1000}s...`);\n await sleep(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 tokens: extractIdentifierTokens(chunk.content),\n content_hash: contentHash(buildEmbedText(chunk)),\n embedded_at: new Date().toISOString(),\n embedding: FieldValue.vector(embSlice[j]),\n });\n }\n\n await retryOnTransient(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, chunks.length), chunks.length);\n\n if (i + BATCH_SIZE < chunks.length) {\n await sleep(INTER_BATCH_DELAY_MS);\n }\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 retryOnTransient(() => batch.commit());\n batch = database.batch();\n }\n }\n\n if (count % BATCH_SIZE !== 0) {\n await retryOnTransient(() => 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 retryOnTransient(() => batch.commit());\n onProgress?.(Math.min(i + BATCH_SIZE, ids.length), ids.length);\n }\n}\n\n// id -> content_hash for every stored chunk of a source. Chunks stored before\n// hashing existed map to \"\", which never equals a real hash, so they are\n// re-embedded on the next refresh.\nexport async function getSourceChunkHashes(sourceName: string): Promise<Map<string, string>> {\n const col = chunksCol();\n const snapshot = await col.where(\"source\", \"==\", sourceName).select(\"content_hash\").get();\n return new Map(\n snapshot.docs.map((doc) => [doc.id, (doc.data().content_hash as string | undefined) ?? \"\"]),\n );\n}\n\nexport interface TokenHit {\n id: string;\n data: Record<string, unknown>;\n matchedTokens: number;\n}\n\nconst TOKEN_QUERY_LIMIT = 100;\n\n// Exact-identifier lookup: one array-contains query per token, merged by id.\n// Sources stored before the tokens field existed simply produce no hits.\nexport async function tokenSearch(\n tokens: string[],\n source?: string,\n): Promise<TokenHit[]> {\n if (tokens.length === 0) return [];\n const col = chunksCol();\n\n const hits = new Map<string, TokenHit>();\n\n const snapshots = await Promise.all(\n tokens.map((token) => {\n let query = col.where(\"tokens\", \"array-contains\", token);\n if (source) {\n query = query.where(\"source\", \"==\", source);\n }\n return query.limit(TOKEN_QUERY_LIMIT).get();\n }),\n );\n\n for (const snapshot of snapshots) {\n for (const doc of snapshot.docs) {\n const existing = hits.get(doc.id);\n if (existing) {\n existing.matchedTokens++;\n } else {\n hits.set(doc.id, { id: doc.id, data: doc.data(), matchedTokens: 1 });\n }\n }\n }\n\n return [...hits.values()].sort((a, b) => b.matchedTokens - a.matchedTokens);\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, tokenSearch } from \"./store.js\";\nimport { rerank } from \"./reranker.js\";\nimport { buildEmbedText } from \"./chunker.js\";\nimport { extractQueryTokens } from \"./tokens.js\";\nimport type { Chunk, SearchResult } from \"./types.js\";\n\nexport type { SearchResult };\n\nconst DEFAULT_CANDIDATES = 50;\nconst RRF_K = 60;\n\nfunction hasReranker(): boolean {\n return !!process.env.RERANKER_URL;\n}\n\ninterface VectorLike {\n toArray(): number[];\n}\n\nfunction isVectorLike(value: unknown): value is VectorLike {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as VectorLike).toArray === \"function\"\n );\n}\n\nfunction cosineSimilarity(a: number[], b: number[]): number {\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n return dot / (Math.sqrt(normA) * Math.sqrt(normB));\n}\n\ninterface Candidate {\n id: string;\n data: Record<string, unknown>;\n fusedScore: number;\n similarity: number | null;\n}\n\nfunction contextualText(data: Record<string, unknown>): string {\n return buildEmbedText({\n title: data.title as string,\n heading_path: data.heading_path as string[],\n content: data.content as string,\n } as Chunk);\n}\n\nfunction toSearchResult(candidate: Candidate, relevance: number): SearchResult {\n const data = candidate.data;\n return {\n id: candidate.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: relevance,\n };\n}\n\n// Hybrid retrieval: dense vector candidates fused with exact-identifier\n// token hits via reciprocal rank fusion. The lexical leg recovers identifiers\n// (max_connections, ExportContext) that sit outside the vector pool because\n// their chunk's embedding is dominated by sibling identifiers.\nexport async function search(\n query: string,\n options: { source?: string; candidates?: number; topN?: number } = {},\n): Promise<SearchResult[]> {\n const { source, candidates = DEFAULT_CANDIDATES, topN = 5 } = options;\n\n const queryEmbedding = await embedText(query);\n const [vectorResults, lexicalHits] = await Promise.all([\n vectorSearch(queryEmbedding, candidates, source),\n tokenSearch(extractQueryTokens(query), source),\n ]);\n\n const pool = new Map<string, Candidate>();\n\n vectorResults.forEach((result, rank) => {\n pool.set(result.id, {\n id: result.id,\n data: result.data,\n fusedScore: 1 / (RRF_K + rank + 1),\n similarity: 1 - result.distance,\n });\n });\n\n lexicalHits.forEach((hit, rank) => {\n const lexicalScore = 1 / (RRF_K + rank + 1);\n const existing = pool.get(hit.id);\n if (existing) {\n existing.fusedScore += lexicalScore;\n return;\n }\n const embedding = hit.data.embedding;\n delete hit.data.embedding;\n pool.set(hit.id, {\n id: hit.id,\n data: hit.data,\n fusedScore: lexicalScore,\n similarity: isVectorLike(embedding)\n ? cosineSimilarity(queryEmbedding, embedding.toArray())\n : null,\n });\n });\n\n const fused = [...pool.values()].sort((a, b) => b.fusedScore - a.fusedScore);\n if (fused.length === 0) return [];\n\n if (hasReranker()) {\n const rerankPool = fused.slice(0, candidates);\n const documents = rerankPool.map((c) => contextualText(c.data));\n const reranked = await rerank(query, documents, topN);\n return reranked.map((r) => toSearchResult(rerankPool[r.index], r.relevance_score));\n }\n\n return fused.slice(0, topN).map((candidate) => {\n const similarity = candidate.similarity ?? 0;\n return toSearchResult(candidate, Math.max(0, (1 + similarity) / 2));\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": ["cell", "tables", "readFile", "writeFile", "join", "resolve", "readFile", "writeFile", "mkdir", "join", "DEFAULT_CONCURRENCY", "join", "mkdir", "readFile", "writeFile", "fenceMatch", "resolve", "BATCH_SIZE", "MAX_RETRIES", "sleep", "resolve", "createHash", "getFirestore", "initializeApp", "applicationDefault", "getApps", "db", "getDb", "getApps", "initializeApp", "applicationDefault", "getFirestore", "createHash", "writeFile", "mkdir", "join", "join", "mkdir", "writeFile", "join", "resolve", "readFile", "writeFile", "f"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// src/format.ts
|
|
28
|
+
var isTTY = process.stdout.isTTY ?? false;
|
|
29
|
+
var bold = (s) => isTTY ? `\x1B[1m${s}\x1B[0m` : s;
|
|
30
|
+
var cyan = (s) => isTTY ? `\x1B[36m${s}\x1B[0m` : s;
|
|
31
|
+
var yellow = (s) => isTTY ? `\x1B[33m${s}\x1B[0m` : s;
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
__commonJS,
|
|
35
|
+
__toESM,
|
|
36
|
+
bold,
|
|
37
|
+
cyan,
|
|
38
|
+
yellow
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=chunk-R46N6C3C.js.map
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/format.ts"],
|
|
4
4
|
"sourcesContent": ["const isTTY = process.stdout.isTTY ?? false;\n\nexport const bold = (s: string): string => isTTY ? `\\x1b[1m${s}\\x1b[0m` : s;\nexport const cyan = (s: string): string => isTTY ? `\\x1b[36m${s}\\x1b[0m` : s;\nexport const yellow = (s: string): string => isTTY ? `\\x1b[33m${s}\\x1b[0m` : s;\nexport const red = (s: string): string => isTTY ? `\\x1b[31m${s}\\x1b[0m` : s;\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAM,QAAQ,QAAQ,OAAO,SAAS;AAE/B,IAAM,OAAO,CAAC,MAAsB,QAAQ,UAAU,CAAC,YAAY;AACnE,IAAM,OAAO,CAAC,MAAsB,QAAQ,WAAW,CAAC,YAAY;AACpE,IAAM,SAAS,CAAC,MAAsB,QAAQ,WAAW,CAAC,YAAY;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
bold,
|
|
4
4
|
cyan,
|
|
5
5
|
yellow
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-R46N6C3C.js";
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
import { parseArgs } from "node:util";
|
|
@@ -92,7 +92,12 @@ async function apiRequest(config, path, options) {
|
|
|
92
92
|
async function cmdConsumerSearch(config, query, options) {
|
|
93
93
|
const data = await apiRequest(config, "/search", {
|
|
94
94
|
method: "POST",
|
|
95
|
-
body: JSON.stringify({
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
query,
|
|
97
|
+
source: options.source,
|
|
98
|
+
topN: options.topN,
|
|
99
|
+
candidates: options.candidates
|
|
100
|
+
})
|
|
96
101
|
});
|
|
97
102
|
if (data.results.length === 0) {
|
|
98
103
|
console.log("No results found.");
|
|
@@ -186,11 +191,13 @@ function showHelp(isConsumer) {
|
|
|
186
191
|
grimoire \u2014 Documentation RAG
|
|
187
192
|
|
|
188
193
|
USAGE
|
|
189
|
-
grimoire search "<query>" [--source <name>] [--top <n>] [--compact]
|
|
194
|
+
grimoire search "<query>" [--source <name>] [--top <n>] [--candidates <n>] [--compact]
|
|
190
195
|
|
|
191
196
|
QUERY TIPS
|
|
192
197
|
- Use the library's own terminology ("Firestore batched writes"
|
|
193
198
|
not "how do I do multi-write in firestore")
|
|
199
|
+
- Exact identifiers (max_connections, ExportContext, snake_case,
|
|
200
|
+
dotted.paths, camelCase) are matched literally - include them verbatim
|
|
194
201
|
- Scope with --source when you know the area
|
|
195
202
|
- Rephrase if first search misses
|
|
196
203
|
- Prefer --compact for scanning; omit for full snippets
|
|
@@ -199,19 +206,25 @@ QUERY TIPS
|
|
|
199
206
|
EXAMPLES
|
|
200
207
|
grimoire search "Firestore batched writes" --source firebase-firestore --compact
|
|
201
208
|
grimoire search "react server components" --top 3
|
|
209
|
+
grimoire search "mysql max_connections default" --source gcp-cloud-sql
|
|
202
210
|
grimoire list --names
|
|
203
211
|
|
|
204
212
|
FLAGS
|
|
205
|
-
--source <name>
|
|
206
|
-
|
|
207
|
-
--top <n>
|
|
208
|
-
--
|
|
209
|
-
|
|
210
|
-
|
|
213
|
+
--source <name> Scope to one indexed source. Run \`grimoire list --names\`
|
|
214
|
+
for the full list (sources are added regularly).
|
|
215
|
+
--top <n> Max results. Default: 5.
|
|
216
|
+
--candidates <n> Retrieval pool size before final ranking. Default: 50,
|
|
217
|
+
max: 200. Raise for broad/ambiguous queries.
|
|
218
|
+
--compact One line per result: score | source | title | heading | url
|
|
219
|
+
Default (non-compact): multi-line block with title, URL,
|
|
220
|
+
heading path, and content snippet.
|
|
211
221
|
|
|
212
222
|
RELEVANCE SCORES
|
|
213
|
-
Range 0
|
|
223
|
+
Range 0-1 (higher = better). >0.85 strong match, 0.6-0.85 relevant,
|
|
214
224
|
<0.6 usually too weak to cite. "No results found." + exit 0 = clean miss.
|
|
225
|
+
Results are ranked by hybrid vector + exact-identifier match; the score
|
|
226
|
+
shown is vector similarity, so an exact identifier hit can rank first
|
|
227
|
+
with a modest score.
|
|
215
228
|
|
|
216
229
|
MANAGEMENT
|
|
217
230
|
grimoire list [--names] Show indexed sources
|
|
@@ -230,19 +243,20 @@ grimoire \u2014 Documentation RAG System (admin)
|
|
|
230
243
|
|
|
231
244
|
Commands:
|
|
232
245
|
add <name> --url <url> Add a new documentation source
|
|
233
|
-
refresh <source>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
refresh <source> --from-
|
|
237
|
-
refresh <source> --
|
|
238
|
-
refresh <source> --
|
|
239
|
-
refresh <source> --skip-store
|
|
246
|
+
refresh <source> Scrape, convert, then sync: only chunks
|
|
247
|
+
whose content changed are re-embedded and
|
|
248
|
+
written; removed chunks are deleted
|
|
249
|
+
refresh <source> --from-html Re-convert from cached HTML, then sync
|
|
250
|
+
refresh <source> --from-markdown Re-chunk from cached markdown, then sync
|
|
251
|
+
refresh <source> --full Purge chunks + caches, re-scrape from scratch
|
|
252
|
+
refresh <source> --skip-store Dry run: scrape/convert/chunk only,
|
|
253
|
+
no embedding, no Firestore writes
|
|
240
254
|
refresh --all Refresh all sources
|
|
241
255
|
delete <source> Delete source and all its chunks
|
|
242
256
|
scrape-urls <source> Fetch missing pages from urls.json
|
|
243
257
|
update Update grimoire to the latest version
|
|
244
|
-
search "<query>" [--source <n>] [--top <n>] [--compact]
|
|
245
|
-
|
|
258
|
+
search "<query>" [--source <n>] [--top <n>] [--candidates <n>] [--compact]
|
|
259
|
+
Hybrid search (vector + exact identifiers)
|
|
246
260
|
list [--names] List all sources
|
|
247
261
|
stats Show chunk/source statistics
|
|
248
262
|
export <source> Export source as JSON
|
|
@@ -287,17 +301,19 @@ async function main() {
|
|
|
287
301
|
options: {
|
|
288
302
|
source: { type: "string" },
|
|
289
303
|
top: { type: "string" },
|
|
304
|
+
candidates: { type: "string" },
|
|
290
305
|
compact: { type: "boolean", default: false }
|
|
291
306
|
},
|
|
292
307
|
allowPositionals: true
|
|
293
308
|
});
|
|
294
309
|
const query = args.positionals[0];
|
|
295
310
|
if (!query) {
|
|
296
|
-
console.error('Usage: grimoire search "<query>" [--source <name>] [--top <n>] [--compact]');
|
|
311
|
+
console.error('Usage: grimoire search "<query>" [--source <name>] [--top <n>] [--candidates <n>] [--compact]');
|
|
297
312
|
process.exit(1);
|
|
298
313
|
}
|
|
299
314
|
const topN = args.values.top ? parseInt(args.values.top, 10) : void 0;
|
|
300
|
-
|
|
315
|
+
const candidates = args.values.candidates ? parseInt(args.values.candidates, 10) : void 0;
|
|
316
|
+
await cmdConsumerSearch(config, query, { source: args.values.source, topN, candidates, compact: args.values.compact });
|
|
301
317
|
} else if (command === "list") {
|
|
302
318
|
const args = parseArgs({
|
|
303
319
|
args: process.argv.slice(3),
|
|
@@ -317,7 +333,7 @@ async function main() {
|
|
|
317
333
|
await cmdInit();
|
|
318
334
|
return;
|
|
319
335
|
}
|
|
320
|
-
const { ADMIN_COMMANDS } = await import("./admin-
|
|
336
|
+
const { ADMIN_COMMANDS } = await import("./admin-YF2OKHEQ.js");
|
|
321
337
|
const handler = ADMIN_COMMANDS[command];
|
|
322
338
|
if (!handler) {
|
|
323
339
|
console.error(`Unknown command: ${command}. Run "grimoire --help" for usage.`);
|