@skill-tools/router 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +61 -0
- package/dist/index.cjs +956 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +426 -0
- package/dist/index.d.ts +426 -0
- package/dist/index.js +950 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bm25/index.ts","../src/context/extractor.ts","../src/embeddings/local.ts","../src/stores/memory.ts","../src/router.ts"],"names":["tokenize","STOP_WORDS"],"mappings":"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AA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AA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","file":"index.js","sourcesContent":["/**\n * Okapi BM25 — Zero-dependency, optimized text search index.\n *\n * Builds an inverted index from document text and scores queries\n * using the BM25 ranking function. Designed for fast skill routing\n * with catalogs up to ~10,000 entries.\n *\n * Performance:\n * - Index build: O(n * avg_doc_len)\n * - Query: O(q * avg_posting_len) — only visits docs containing query terms\n * - Memory: O(vocabulary_size * avg_posting_len)\n *\n * @packageDocumentation\n */\n\n/** A document stored in the index */\ninterface BM25Document {\n\treadonly id: string;\n\treadonly length: number;\n\treadonly metadata: Record<string, unknown>;\n}\n\n/** A posting list entry: document index + term frequency */\ninterface Posting {\n\treadonly docIdx: number;\n\treadonly tf: number;\n}\n\n/** Serialized snapshot of BM25Index state */\nexport interface BM25Snapshot {\n\treadonly version: 2;\n\treadonly documents: ReadonlyArray<{\n\t\treadonly id: string;\n\t\treadonly length: number;\n\t\treadonly metadata: Record<string, unknown>;\n\t}>;\n\treadonly invertedIndex: ReadonlyArray<[string, Posting[]]>;\n\treadonly idf: ReadonlyArray<[string, number]>;\n\treadonly avgdl: number;\n\treadonly k1: number;\n\treadonly b: number;\n}\n\n/** Options for creating a BM25Index */\nexport interface BM25Options {\n\t/** Term frequency saturation parameter (default: 1.2) */\n\treadonly k1?: number;\n\t/** Document length normalization parameter (default: 0.75) */\n\treadonly b?: number;\n}\n\n/**\n * BM25Index — Fast, zero-dependency full-text search using Okapi BM25.\n *\n * @example\n * ```ts\n * const idx = new BM25Index();\n * idx.add([\n * { id: 'deploy', text: 'Deploy apps to Vercel production', metadata: {} },\n * { id: 'test', text: 'Run unit tests with coverage', metadata: {} },\n * ]);\n * const results = idx.search('deploy production', 5);\n * ```\n */\nexport class BM25Index {\n\tprivate readonly k1: number;\n\tprivate readonly b: number;\n\n\tprivate documents: BM25Document[] = [];\n\tprivate invertedIndex: Map<string, Posting[]> = new Map();\n\tprivate idfCache: Map<string, number> = new Map();\n\tprivate avgdl = 0;\n\tprivate totalDocLength = 0;\n\n\tconstructor(options?: BM25Options) {\n\t\tthis.k1 = options?.k1 ?? 1.2;\n\t\tthis.b = options?.b ?? 0.75;\n\t}\n\n\t/**\n\t * Add documents to the index.\n\t * Batch operation — IDF is recomputed once after all documents are added.\n\t */\n\tadd(\n\t\tentries: ReadonlyArray<{\n\t\t\treadonly id: string;\n\t\t\treadonly text: string;\n\t\t\treadonly metadata: Record<string, unknown>;\n\t\t}>,\n\t): void {\n\t\tif (entries.length === 0) return;\n\n\t\tfor (const entry of entries) {\n\t\t\tconst tokens = tokenize(entry.text);\n\t\t\tconst docIdx = this.documents.length;\n\n\t\t\tthis.documents.push({\n\t\t\t\tid: entry.id,\n\t\t\t\tlength: tokens.length,\n\t\t\t\tmetadata: entry.metadata,\n\t\t\t});\n\n\t\t\tthis.totalDocLength += tokens.length;\n\n\t\t\t// Build term frequencies for this document\n\t\t\tconst termFreq = new Map<string, number>();\n\t\t\tfor (const token of tokens) {\n\t\t\t\ttermFreq.set(token, (termFreq.get(token) ?? 0) + 1);\n\t\t\t}\n\n\t\t\t// Append to inverted index\n\t\t\tfor (const [term, tf] of termFreq) {\n\t\t\t\tlet postings = this.invertedIndex.get(term);\n\t\t\t\tif (!postings) {\n\t\t\t\t\tpostings = [];\n\t\t\t\t\tthis.invertedIndex.set(term, postings);\n\t\t\t\t}\n\t\t\t\tpostings.push({ docIdx, tf });\n\t\t\t}\n\t\t}\n\n\t\t// Recompute avgdl and IDF after batch add\n\t\tthis.avgdl = this.totalDocLength / this.documents.length;\n\t\tthis.recomputeIDF();\n\t}\n\n\t/**\n\t * Remove documents by ID.\n\t * Rebuilds internal index mappings after removal.\n\t */\n\tremove(ids: readonly string[]): void {\n\t\tconst idSet = new Set(ids);\n\t\tconst removedIndices = new Set<number>();\n\n\t\tfor (let i = 0; i < this.documents.length; i++) {\n\t\t\tif (idSet.has(this.documents[i]!.id)) {\n\t\t\t\tremovedIndices.add(i);\n\t\t\t\tthis.totalDocLength -= this.documents[i]!.length;\n\t\t\t}\n\t\t}\n\n\t\tif (removedIndices.size === 0) return;\n\n\t\t// Rebuild documents array and create old→new index mapping\n\t\tconst newDocuments: BM25Document[] = [];\n\t\tconst indexMap = new Map<number, number>();\n\t\tfor (let i = 0; i < this.documents.length; i++) {\n\t\t\tif (!removedIndices.has(i)) {\n\t\t\t\tindexMap.set(i, newDocuments.length);\n\t\t\t\tnewDocuments.push(this.documents[i]!);\n\t\t\t}\n\t\t}\n\t\tthis.documents = newDocuments;\n\n\t\t// Rebuild inverted index with remapped indices\n\t\tfor (const [term, postings] of this.invertedIndex) {\n\t\t\tconst filtered: Posting[] = [];\n\t\t\tfor (const p of postings) {\n\t\t\t\tif (!removedIndices.has(p.docIdx)) {\n\t\t\t\t\tfiltered.push({ docIdx: indexMap.get(p.docIdx)!, tf: p.tf });\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (filtered.length === 0) {\n\t\t\t\tthis.invertedIndex.delete(term);\n\t\t\t} else {\n\t\t\t\tthis.invertedIndex.set(term, filtered);\n\t\t\t}\n\t\t}\n\n\t\t// Recompute stats\n\t\tthis.avgdl = this.documents.length > 0 ? this.totalDocLength / this.documents.length : 0;\n\t\tthis.recomputeIDF();\n\t}\n\n\t/**\n\t * Search the index with a query string.\n\t *\n\t * Returns results sorted by BM25 score (highest first).\n\t * Scores are normalized to [0, 1] — the top result gets 1.0.\n\t *\n\t * Only documents containing at least one query term are scored,\n\t * making queries fast even on large indexes.\n\t */\n\tsearch(\n\t\tquery: string,\n\t\ttopK: number,\n\t\tthreshold = 0.0,\n\t): Array<{\n\t\treadonly id: string;\n\t\treadonly score: number;\n\t\treadonly metadata: Record<string, unknown>;\n\t}> {\n\t\tif (this.documents.length === 0) return [];\n\n\t\tconst queryTokens = tokenize(query);\n\t\tif (queryTokens.length === 0) return [];\n\n\t\t// Sparse score accumulator — only touched documents get entries\n\t\tconst scores = new Float64Array(this.documents.length);\n\t\tlet hasScores = false;\n\n\t\tfor (const token of queryTokens) {\n\t\t\tconst idf = this.idfCache.get(token);\n\t\t\tif (idf === undefined || idf <= 0) continue;\n\n\t\t\tconst postings = this.invertedIndex.get(token);\n\t\t\tif (!postings) continue;\n\n\t\t\tfor (const posting of postings) {\n\t\t\t\tconst docLen = this.documents[posting.docIdx]!.length;\n\t\t\t\tconst tf = posting.tf;\n\n\t\t\t\t// Okapi BM25 scoring\n\t\t\t\tconst numerator = tf * (this.k1 + 1);\n\t\t\t\tconst denominator = tf + this.k1 * (1 - this.b + this.b * (docLen / this.avgdl));\n\t\t\t\tscores[posting.docIdx] = scores[posting.docIdx]! + idf * (numerator / denominator);\n\t\t\t\thasScores = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!hasScores) return [];\n\n\t\t// Find max score for normalization\n\t\tlet maxScore = 0;\n\t\tfor (let i = 0; i < scores.length; i++) {\n\t\t\tif (scores[i]! > maxScore) maxScore = scores[i]!;\n\t\t}\n\n\t\tif (maxScore === 0) return [];\n\n\t\t// Collect results, normalize to [0, 1], filter by threshold\n\t\tconst results: Array<{ id: string; score: number; metadata: Record<string, unknown> }> = [];\n\n\t\tfor (let i = 0; i < scores.length; i++) {\n\t\t\tconst raw = scores[i]!;\n\t\t\tif (raw === 0) continue;\n\n\t\t\tconst normalized = raw / maxScore;\n\t\t\tif (normalized >= threshold) {\n\t\t\t\tresults.push({\n\t\t\t\t\tid: this.documents[i]!.id,\n\t\t\t\t\tscore: normalized,\n\t\t\t\t\tmetadata: this.documents[i]!.metadata,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Sort by score descending, take topK\n\t\tresults.sort((a, b) => b.score - a.score);\n\t\treturn results.slice(0, topK);\n\t}\n\n\t/** Number of indexed documents */\n\tsize(): number {\n\t\treturn this.documents.length;\n\t}\n\n\t/** Serialize to a JSON-compatible snapshot */\n\tserialize(): BM25Snapshot {\n\t\treturn {\n\t\t\tversion: 2,\n\t\t\tdocuments: this.documents.map((d) => ({\n\t\t\t\tid: d.id,\n\t\t\t\tlength: d.length,\n\t\t\t\tmetadata: d.metadata,\n\t\t\t})),\n\t\t\tinvertedIndex: Array.from(this.invertedIndex.entries()),\n\t\t\tidf: Array.from(this.idfCache.entries()),\n\t\t\tavgdl: this.avgdl,\n\t\t\tk1: this.k1,\n\t\t\tb: this.b,\n\t\t};\n\t}\n\n\t/** Restore from a serialized snapshot */\n\tdeserialize(data: unknown): void {\n\t\tconst obj = data as BM25Snapshot;\n\t\tif (!obj || typeof obj !== 'object') {\n\t\t\tthrow new Error('Invalid BM25 snapshot: expected an object');\n\t\t}\n\t\tif (obj.version !== 2) {\n\t\t\tthrow new Error(`Unsupported BM25 snapshot version: ${obj.version}`);\n\t\t}\n\n\t\tthis.documents = obj.documents.map((d) => ({\n\t\t\tid: d.id,\n\t\t\tlength: d.length,\n\t\t\tmetadata: d.metadata,\n\t\t}));\n\t\tthis.invertedIndex = new Map(obj.invertedIndex.map(([k, v]) => [k, [...v]]));\n\t\tthis.idfCache = new Map(obj.idf);\n\t\tthis.avgdl = obj.avgdl;\n\t\tthis.totalDocLength = this.documents.reduce((sum, d) => sum + d.length, 0);\n\t}\n\n\t/** Recompute IDF values for all terms in the inverted index */\n\tprivate recomputeIDF(): void {\n\t\tconst N = this.documents.length;\n\t\tthis.idfCache.clear();\n\n\t\tfor (const [term, postings] of this.invertedIndex) {\n\t\t\tconst df = postings.length;\n\t\t\t// BM25 IDF: log((N - df + 0.5) / (df + 0.5) + 1)\n\t\t\tthis.idfCache.set(term, Math.log((N - df + 0.5) / (df + 0.5) + 1));\n\t\t}\n\t}\n}\n\n/**\n * Tokenize text: lowercase, strip punctuation, split on whitespace,\n * filter stop words and single-character tokens.\n */\nfunction tokenize(text: string): string[] {\n\treturn text\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9\\s-]/g, ' ')\n\t\t.split(/\\s+/)\n\t\t.filter((t) => t.length > 1 && !STOP_WORDS.has(t));\n}\n\n/**\n * Common English stop words — filtered during tokenization.\n */\nconst STOP_WORDS = new Set([\n\t'a',\n\t'an',\n\t'the',\n\t'is',\n\t'are',\n\t'was',\n\t'were',\n\t'be',\n\t'been',\n\t'being',\n\t'have',\n\t'has',\n\t'had',\n\t'do',\n\t'does',\n\t'did',\n\t'will',\n\t'would',\n\t'could',\n\t'should',\n\t'may',\n\t'might',\n\t'shall',\n\t'can',\n\t'must',\n\t'to',\n\t'of',\n\t'in',\n\t'for',\n\t'on',\n\t'with',\n\t'at',\n\t'by',\n\t'from',\n\t'as',\n\t'into',\n\t'through',\n\t'during',\n\t'before',\n\t'after',\n\t'above',\n\t'below',\n\t'between',\n\t'out',\n\t'off',\n\t'over',\n\t'under',\n\t'again',\n\t'further',\n\t'then',\n\t'once',\n\t'here',\n\t'there',\n\t'when',\n\t'where',\n\t'why',\n\t'how',\n\t'all',\n\t'each',\n\t'every',\n\t'both',\n\t'few',\n\t'more',\n\t'most',\n\t'other',\n\t'some',\n\t'such',\n\t'no',\n\t'nor',\n\t'not',\n\t'only',\n\t'own',\n\t'same',\n\t'so',\n\t'than',\n\t'too',\n\t'very',\n\t'and',\n\t'but',\n\t'or',\n\t'if',\n\t'it',\n\t'its',\n\t'this',\n\t'that',\n\t'these',\n\t'those',\n\t'he',\n\t'she',\n\t'they',\n\t'we',\n\t'you',\n\t'i',\n\t'me',\n\t'my',\n\t'your',\n\t'his',\n\t'her',\n\t'their',\n\t'our',\n\t'what',\n\t'which',\n\t'who',\n\t'whom',\n]);\n","/**\n * Context extractor for contextual retrieval.\n *\n * Extracts supplementary terms from a skill's body and sections\n * to enrich the description before BM25 indexing. This is a\n * deterministic, zero-dependency alternative to LLM-generated\n * chunk context (see: Anthropic's contextual retrieval paper).\n *\n * @packageDocumentation\n */\n\n/** Minimal skill shape required for context extraction */\nexport interface ContextInput {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly body?: string;\n\treadonly sections?: ReadonlyArray<{\n\t\treadonly heading: string;\n\t\treadonly depth: number;\n\t\treadonly content: string;\n\t}>;\n}\n\n/** Maximum number of context tokens to prepend */\nconst MAX_CONTEXT_TOKENS = 80;\n\n/**\n * Extract supplementary context from a skill's body and structure.\n *\n * Returns a space-separated string of unique terms derived from:\n * 1. Skill name parts (split on `-` and `_`)\n * 2. Section headings\n * 3. Inline code references (backtick-wrapped)\n * 4. Key terms from body text\n *\n * Terms already present in the description are omitted.\n * Result is truncated to ~80 tokens.\n *\n * Returns empty string if no useful context can be extracted.\n */\nexport function extractContext(skill: ContextInput): string {\n\tconst terms: string[] = [];\n\n\t// 1. Split skill name on - and _\n\tconst nameParts = skill.name\n\t\t.split(/[-_]/)\n\t\t.map((p) => p.toLowerCase())\n\t\t.filter((p) => p.length > 1);\n\tterms.push(...nameParts);\n\n\t// 2. Section headings\n\tif (skill.sections) {\n\t\tfor (const section of skill.sections) {\n\t\t\tconst headingWords = section.heading\n\t\t\t\t.toLowerCase()\n\t\t\t\t.replace(/[^a-z0-9\\s-]/g, ' ')\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.filter((w) => w.length > 1);\n\t\t\tterms.push(...headingWords);\n\t\t}\n\t}\n\n\t// 3. Inline code references from body\n\tif (skill.body) {\n\t\tconst codeRefs = extractCodeRefs(skill.body);\n\t\tterms.push(...codeRefs);\n\t}\n\n\t// 4. Key terms from section content (longer words, likely meaningful)\n\tif (skill.sections) {\n\t\tfor (const section of skill.sections) {\n\t\t\tconst contentWords = section.content\n\t\t\t\t.toLowerCase()\n\t\t\t\t.replace(/[^a-z0-9\\s-]/g, ' ')\n\t\t\t\t.split(/\\s+/)\n\t\t\t\t.filter((w) => w.length > 3 && !COMMON_WORDS.has(w));\n\t\t\tterms.push(...contentWords);\n\t\t}\n\t}\n\n\t// Dedup against description\n\tconst descLower = skill.description.toLowerCase();\n\tconst descTokens = new Set(\n\t\tdescLower\n\t\t\t.replace(/[^a-z0-9\\s-]/g, ' ')\n\t\t\t.split(/\\s+/)\n\t\t\t.filter((t) => t.length > 0),\n\t);\n\n\tconst seen = new Set<string>();\n\tconst unique: string[] = [];\n\n\tfor (const term of terms) {\n\t\tconst lower = term.toLowerCase();\n\t\tif (lower.length < 2) continue;\n\t\tif (seen.has(lower)) continue;\n\t\tif (descTokens.has(lower)) continue;\n\t\tseen.add(lower);\n\t\tunique.push(lower);\n\t}\n\n\t// Truncate to MAX_CONTEXT_TOKENS\n\treturn truncateTokens(unique, MAX_CONTEXT_TOKENS).join(' ');\n}\n\n/**\n * Extract inline code references from markdown body.\n * Matches single-backtick code spans (not fenced blocks).\n */\nfunction extractCodeRefs(body: string): string[] {\n\tconst refs: string[] = [];\n\tconst pattern = /`([^`\\n]+)`/g;\n\n\tfor (const match of body.matchAll(pattern)) {\n\t\tconst code = match[1]!.trim();\n\t\t// Split compound code refs (e.g. \"vercel --prod\" → [\"vercel\", \"--prod\"])\n\t\tconst parts = code\n\t\t\t.split(/\\s+/)\n\t\t\t.map((p) => p.replace(/^-+/, '').toLowerCase())\n\t\t\t.filter((p) => p.length > 1);\n\t\trefs.push(...parts);\n\t}\n\n\treturn refs;\n}\n\n/**\n * Truncate a list of tokens to a maximum count.\n */\nfunction truncateTokens(tokens: string[], max: number): string[] {\n\tif (tokens.length <= max) return tokens;\n\treturn tokens.slice(0, max);\n}\n\n/**\n * Common English words to filter from section content.\n * More aggressive than BM25 stop words — we only want meaningful terms.\n */\nconst COMMON_WORDS = new Set([\n\t'also',\n\t'about',\n\t'after',\n\t'again',\n\t'been',\n\t'before',\n\t'being',\n\t'between',\n\t'both',\n\t'check',\n\t'could',\n\t'does',\n\t'done',\n\t'down',\n\t'each',\n\t'even',\n\t'every',\n\t'first',\n\t'following',\n\t'from',\n\t'have',\n\t'here',\n\t'into',\n\t'just',\n\t'know',\n\t'like',\n\t'make',\n\t'many',\n\t'might',\n\t'more',\n\t'most',\n\t'much',\n\t'must',\n\t'need',\n\t'only',\n\t'other',\n\t'over',\n\t'same',\n\t'should',\n\t'some',\n\t'such',\n\t'sure',\n\t'take',\n\t'than',\n\t'that',\n\t'them',\n\t'then',\n\t'there',\n\t'these',\n\t'they',\n\t'this',\n\t'those',\n\t'through',\n\t'under',\n\t'very',\n\t'want',\n\t'well',\n\t'were',\n\t'what',\n\t'when',\n\t'where',\n\t'which',\n\t'while',\n\t'will',\n\t'with',\n\t'would',\n\t'your',\n]);\n","import type { EmbeddingProvider } from './interface.js';\n\n/**\n * Local TF-IDF based embedding provider.\n *\n * Uses a deterministic hash-based approach to create sparse-then-dense\n * embeddings from text. No external API calls or model downloads needed.\n *\n * Quality is lower than neural embedding models, but sufficient for\n * keyword-heavy skill descriptions where exact word matching matters.\n * Ideal for catalogs under 500 skills.\n */\nexport class LocalEmbeddingProvider implements EmbeddingProvider {\n\treadonly name = 'local-tfidf';\n\treadonly dimensions: number;\n\n\tprivate vocabulary: Map<string, number> = new Map();\n\tprivate idfValues: Map<string, number> = new Map();\n\tprivate isBuilt = false;\n\n\tconstructor(dimensions = 256) {\n\t\tthis.dimensions = dimensions;\n\t}\n\n\t/**\n\t * Build the vocabulary and IDF values from a corpus.\n\t * Call this once after indexing all skill descriptions.\n\t */\n\tbuildVocabulary(texts: string[]): void {\n\t\tconst docCount = texts.length;\n\t\tconst termDocFreq = new Map<string, number>();\n\n\t\tfor (const text of texts) {\n\t\t\tconst tokens = new Set(tokenize(text));\n\t\t\tfor (const token of tokens) {\n\t\t\t\ttermDocFreq.set(token, (termDocFreq.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\n\t\t// Compute IDF values\n\t\tfor (const [term, df] of termDocFreq) {\n\t\t\tthis.idfValues.set(term, Math.log((docCount + 1) / (df + 1)) + 1);\n\t\t}\n\n\t\t// Build vocabulary (top terms by IDF)\n\t\tconst sorted = Array.from(this.idfValues.entries()).sort((a, b) => b[1] - a[1]);\n\t\tlet idx = 0;\n\t\tfor (const [term] of sorted) {\n\t\t\tthis.vocabulary.set(term, idx % this.dimensions);\n\t\t\tidx++;\n\t\t}\n\n\t\tthis.isBuilt = true;\n\t}\n\n\tasync embed(texts: string[]): Promise<number[][]> {\n\t\treturn texts.map((text) => this.embedSingle(text));\n\t}\n\n\tprivate embedSingle(text: string): number[] {\n\t\tconst vector = new Float64Array(this.dimensions);\n\t\tconst tokens = tokenize(text);\n\t\tconst termFreq = new Map<string, number>();\n\n\t\tfor (const token of tokens) {\n\t\t\ttermFreq.set(token, (termFreq.get(token) ?? 0) + 1);\n\t\t}\n\n\t\tfor (const [term, tf] of termFreq) {\n\t\t\tconst idf = this.idfValues.get(term) ?? 1;\n\t\t\tconst tfidf = (1 + Math.log(tf)) * idf;\n\n\t\t\tif (this.isBuilt) {\n\t\t\t\t// Use vocabulary mapping if built\n\t\t\t\tconst idx = this.vocabulary.get(term);\n\t\t\t\tif (idx !== undefined) {\n\t\t\t\t\tvector[idx] = (vector[idx] ?? 0) + tfidf;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Fall back to hash-based indexing\n\t\t\t\tconst idx = hashToIndex(term, this.dimensions);\n\t\t\t\tvector[idx] = (vector[idx] ?? 0) + tfidf;\n\t\t\t}\n\t\t}\n\n\t\t// L2 normalize\n\t\treturn l2Normalize(Array.from(vector));\n\t}\n}\n\n/**\n * Tokenize text into lowercase tokens, removing stop words and punctuation.\n */\nfunction tokenize(text: string): string[] {\n\treturn text\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9\\s-]/g, ' ')\n\t\t.split(/\\s+/)\n\t\t.filter((t) => t.length > 1 && !STOP_WORDS.has(t));\n}\n\n/**\n * Deterministic hash of a string to an index in range [0, size).\n * Uses FNV-1a hash.\n */\nfunction hashToIndex(str: string, size: number): number {\n\tlet hash = 0x811c9dc5; // FNV offset basis\n\tfor (let i = 0; i < str.length; i++) {\n\t\thash ^= str.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193); // FNV prime\n\t}\n\treturn Math.abs(hash) % size;\n}\n\n/**\n * L2 normalize a vector.\n */\nfunction l2Normalize(vector: number[]): number[] {\n\tlet sum = 0;\n\tfor (const v of vector) {\n\t\tsum += v * v;\n\t}\n\tconst magnitude = Math.sqrt(sum);\n\tif (magnitude === 0) return vector;\n\treturn vector.map((v) => v / magnitude);\n}\n\n/**\n * Common English stop words.\n */\nconst STOP_WORDS = new Set([\n\t'a',\n\t'an',\n\t'the',\n\t'is',\n\t'are',\n\t'was',\n\t'were',\n\t'be',\n\t'been',\n\t'being',\n\t'have',\n\t'has',\n\t'had',\n\t'do',\n\t'does',\n\t'did',\n\t'will',\n\t'would',\n\t'could',\n\t'should',\n\t'may',\n\t'might',\n\t'shall',\n\t'can',\n\t'must',\n\t'to',\n\t'of',\n\t'in',\n\t'for',\n\t'on',\n\t'with',\n\t'at',\n\t'by',\n\t'from',\n\t'as',\n\t'into',\n\t'through',\n\t'during',\n\t'before',\n\t'after',\n\t'above',\n\t'below',\n\t'between',\n\t'out',\n\t'off',\n\t'over',\n\t'under',\n\t'again',\n\t'further',\n\t'then',\n\t'once',\n\t'here',\n\t'there',\n\t'when',\n\t'where',\n\t'why',\n\t'how',\n\t'all',\n\t'each',\n\t'every',\n\t'both',\n\t'few',\n\t'more',\n\t'most',\n\t'other',\n\t'some',\n\t'such',\n\t'no',\n\t'nor',\n\t'not',\n\t'only',\n\t'own',\n\t'same',\n\t'so',\n\t'than',\n\t'too',\n\t'very',\n\t'and',\n\t'but',\n\t'or',\n\t'if',\n\t'it',\n\t'its',\n\t'this',\n\t'that',\n\t'these',\n\t'those',\n\t'he',\n\t'she',\n\t'they',\n\t'we',\n\t'you',\n\t'i',\n\t'me',\n\t'my',\n\t'your',\n\t'his',\n\t'her',\n\t'their',\n\t'our',\n\t'what',\n\t'which',\n\t'who',\n\t'whom',\n]);\n","import type { SearchResult, VectorEntry, VectorStore } from './interface.js';\n\n/**\n * In-memory vector store using brute-force cosine similarity search.\n *\n * Suitable for catalogs of up to ~1,000 skills. For larger catalogs,\n * use the SQLite backend.\n *\n * At 1,000 entries with 256-dimensional vectors, search takes <5ms.\n */\nexport class MemoryVectorStore implements VectorStore {\n\tprivate entries: VectorEntry[] = [];\n\n\tasync add(entries: VectorEntry[]): Promise<void> {\n\t\tthis.entries.push(...entries);\n\t}\n\n\tasync search(queryVector: number[], topK: number, threshold = 0.0): Promise<SearchResult[]> {\n\t\tconst scored = this.entries.map((entry) => ({\n\t\t\tid: entry.id,\n\t\t\tscore: cosineSimilarity(queryVector, entry.vector),\n\t\t\tmetadata: entry.metadata,\n\t\t}));\n\n\t\treturn scored\n\t\t\t.filter((r) => r.score >= threshold)\n\t\t\t.sort((a, b) => b.score - a.score)\n\t\t\t.slice(0, topK);\n\t}\n\n\tasync remove(ids: string[]): Promise<void> {\n\t\tconst idSet = new Set(ids);\n\t\tthis.entries = this.entries.filter((e) => !idSet.has(e.id));\n\t}\n\n\tsize(): number {\n\t\treturn this.entries.length;\n\t}\n\n\tserialize(): unknown {\n\t\treturn {\n\t\t\tversion: 1,\n\t\t\tentries: this.entries.map((e) => ({\n\t\t\t\tid: e.id,\n\t\t\t\tvector: e.vector,\n\t\t\t\tmetadata: e.metadata,\n\t\t\t})),\n\t\t};\n\t}\n\n\tdeserialize(data: unknown): void {\n\t\tif (!data || typeof data !== 'object') {\n\t\t\tthrow new Error('Invalid snapshot: expected an object');\n\t\t}\n\t\tconst obj = data as Record<string, unknown>;\n\t\tif (obj.version !== 1) {\n\t\t\tthrow new Error(`Unsupported vector store version: ${obj.version}`);\n\t\t}\n\t\tif (!Array.isArray(obj.entries)) {\n\t\t\tthrow new Error('Invalid snapshot: entries must be an array');\n\t\t}\n\t\tfor (const entry of obj.entries as unknown[]) {\n\t\t\tif (!entry || typeof entry !== 'object') {\n\t\t\t\tthrow new Error('Invalid snapshot: each entry must be an object');\n\t\t\t}\n\t\t\tconst e = entry as Record<string, unknown>;\n\t\t\tif (typeof e.id !== 'string') {\n\t\t\t\tthrow new Error('Invalid snapshot: entry id must be a string');\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!Array.isArray(e.vector) ||\n\t\t\t\t!(e.vector as unknown[]).every((v) => typeof v === 'number')\n\t\t\t) {\n\t\t\t\tthrow new Error('Invalid snapshot: entry vector must be an array of numbers');\n\t\t\t}\n\t\t}\n\t\tthis.entries = obj.entries as VectorEntry[];\n\t}\n}\n\n/**\n * Compute cosine similarity between two vectors.\n * Returns a value between -1 and 1. For normalized vectors, this is equivalent\n * to the dot product.\n */\nfunction cosineSimilarity(a: number[], b: number[]): number {\n\tif (a.length !== b.length) {\n\t\tthrow new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);\n\t}\n\n\tlet dotProduct = 0;\n\tlet normA = 0;\n\tlet normB = 0;\n\n\tfor (let i = 0; i < a.length; i++) {\n\t\tdotProduct += a[i]! * b[i]!;\n\t\tnormA += a[i]! * a[i]!;\n\t\tnormB += b[i]! * b[i]!;\n\t}\n\n\tconst denominator = Math.sqrt(normA) * Math.sqrt(normB);\n\tif (denominator === 0) return 0;\n\n\treturn dotProduct / denominator;\n}\n","import { parseSkill, resolveSkillFiles } from '@skill-tools/core';\nimport type { BM25Options } from './bm25/index.js';\nimport { BM25Index } from './bm25/index.js';\nimport { extractContext } from './context/extractor.js';\nimport type { EmbeddingConfig, EmbeddingProvider } from './embeddings/interface.js';\nimport { LocalEmbeddingProvider } from './embeddings/local.js';\nimport type { VectorStore } from './stores/interface.js';\nimport { MemoryVectorStore } from './stores/memory.js';\n\n/**\n * A skill entry prepared for indexing.\n */\nexport interface SkillEntry {\n\t/** Unique identifier (typically the skill name) */\n\treadonly name: string;\n\t/** The description text to embed */\n\treadonly description: string;\n\t/** Path to the SKILL.md file */\n\treadonly path?: string;\n\t/** Additional metadata to store alongside the embedding */\n\treadonly metadata?: Record<string, unknown>;\n\t/** Raw markdown body (used for contextual retrieval) */\n\treadonly body?: string;\n\t/** Parsed sections from the SKILL.md (used for contextual retrieval) */\n\treadonly sections?: ReadonlyArray<{\n\t\treadonly heading: string;\n\t\treadonly depth: number;\n\t\treadonly content: string;\n\t}>;\n}\n\n/**\n * Result of selecting a skill for a query.\n */\nexport interface SelectionResult {\n\t/** Skill name/ID */\n\treadonly skill: string;\n\t/** Similarity score (0-1) */\n\treadonly score: number;\n\t/** Metadata from the indexed skill */\n\treadonly metadata: Record<string, unknown>;\n}\n\n/**\n * Options for skill selection queries.\n */\nexport interface SelectOptions {\n\t/** Number of results to return (default: 5) */\n\treadonly topK?: number;\n\t/** Minimum similarity threshold (default: 0.0) */\n\treadonly threshold?: number;\n\t/** Skill names to boost in ranking */\n\treadonly boost?: string[];\n\t/** Skill name patterns to exclude */\n\treadonly exclude?: string[];\n}\n\n/**\n * Options for the SkillRouter constructor.\n */\nexport interface SkillRouterOptions {\n\t/** Embedding provider configuration. Defaults to BM25 ('local'). */\n\treadonly embedding?: EmbeddingConfig;\n\t/** BM25 tuning parameters (only used with the default BM25 engine) */\n\treadonly bm25?: BM25Options;\n\t/**\n\t * Enable contextual retrieval. When true (default), skills with\n\t * body or sections will have supplementary context extracted and\n\t * prepended to their description before indexing.\n\t * Only affects indexing — result descriptions stay unchanged.\n\t */\n\treadonly context?: boolean;\n}\n\n/**\n * SkillRouter — Skill selection middleware using BM25 full-text search.\n *\n * Indexes skill descriptions and enables fast, ranked search to find\n * the most relevant skills for a given query. Uses Okapi BM25 by default\n * with zero external dependencies.\n *\n * For neural/semantic embeddings, pass a custom embedding provider\n * via the `embedding` option.\n *\n * @example\n * ```ts\n * const router = new SkillRouter();\n * await router.indexSkills([\n * { name: 'deploy-vercel', description: 'Deploy apps to Vercel...' },\n * { name: 'run-tests', description: 'Execute test suites...' },\n * ]);\n *\n * const results = await router.select('deploy my app');\n * // => [{ skill: 'deploy-vercel', score: 0.89, ... }]\n * ```\n */\nexport class SkillRouter {\n\t/** BM25 index — used when no external embedding provider is configured */\n\tprivate readonly bm25: BM25Index | null;\n\n\t/** Embedding provider — used with custom/openai/ollama providers */\n\tprivate readonly embedding: EmbeddingProvider | null;\n\n\t/** Vector store — used alongside embedding provider */\n\tprivate readonly store: VectorStore | null;\n\n\t/** Whether the router uses the BM25 engine (true) or embedding+store (false) */\n\tprivate readonly usesBM25: boolean;\n\n\t/** Whether contextual retrieval is enabled */\n\tprivate readonly contextEnabled: boolean;\n\n\tprivate skillNames: Set<string> = new Set();\n\n\tconstructor(options?: SkillRouterOptions) {\n\t\tconst embeddingConfig = options?.embedding ?? 'local';\n\t\tthis.contextEnabled = options?.context !== false;\n\n\t\tif (embeddingConfig === 'local') {\n\t\t\t// Default: BM25 full-text search — fast, zero-dependency\n\t\t\tthis.bm25 = new BM25Index(options?.bm25);\n\t\t\tthis.embedding = null;\n\t\t\tthis.store = null;\n\t\t\tthis.usesBM25 = true;\n\t\t} else {\n\t\t\t// External embedding provider: use embedding + vector store\n\t\t\tthis.embedding = createEmbeddingProvider(embeddingConfig);\n\t\t\tthis.store = new MemoryVectorStore();\n\t\t\tthis.bm25 = null;\n\t\t\tthis.usesBM25 = false;\n\t\t}\n\t}\n\n\t/**\n\t * Index a list of skill entries.\n\t * With BM25 (default): indexes description text directly.\n\t * With embeddings: embeds descriptions and stores vectors.\n\t */\n\tasync indexSkills(skills: SkillEntry[]): Promise<void> {\n\t\tif (skills.length === 0) return;\n\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\t// BM25 path — direct text indexing, no vectors\n\t\t\tthis.bm25.add(\n\t\t\t\tskills.map((s) => ({\n\t\t\t\t\tid: s.name,\n\t\t\t\t\ttext: this.enrichText(s),\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tdescription: s.description,\n\t\t\t\t\t\tpath: s.path,\n\t\t\t\t\t\t...s.metadata,\n\t\t\t\t\t},\n\t\t\t\t})),\n\t\t\t);\n\t\t} else if (this.embedding && this.store) {\n\t\t\t// Embedding path — vectorize and store\n\t\t\tconst descriptions = skills.map((s) => this.enrichText(s));\n\n\t\t\tif (this.embedding instanceof LocalEmbeddingProvider) {\n\t\t\t\tthis.embedding.buildVocabulary(descriptions);\n\t\t\t}\n\n\t\t\tconst vectors = await this.embedding.embed(descriptions);\n\n\t\t\tconst entries = skills.map((skill, i) => ({\n\t\t\t\tid: skill.name,\n\t\t\t\tvector: vectors[i]!,\n\t\t\t\tmetadata: {\n\t\t\t\t\tdescription: skill.description,\n\t\t\t\t\tpath: skill.path,\n\t\t\t\t\t...skill.metadata,\n\t\t\t\t},\n\t\t\t}));\n\n\t\t\tawait this.store.add(entries);\n\t\t}\n\n\t\tfor (const skill of skills) {\n\t\t\tthis.skillNames.add(skill.name);\n\t\t}\n\t}\n\n\t/**\n\t * Index all SKILL.md files in a directory.\n\t * Parses each file and indexes its description.\n\t */\n\tasync indexDirectory(dirPath: string): Promise<number> {\n\t\tconst locations = await resolveSkillFiles(dirPath);\n\t\tconst skills: SkillEntry[] = [];\n\n\t\tfor (const location of locations) {\n\t\t\tconst result = await parseSkill(location.skillFile);\n\t\t\tif (result.ok && result.skill.metadata.description) {\n\t\t\t\tskills.push({\n\t\t\t\t\tname: result.skill.metadata.name ?? location.dirName,\n\t\t\t\t\tdescription: result.skill.metadata.description,\n\t\t\t\t\tpath: location.skillFile,\n\t\t\t\t\tbody: result.skill.body,\n\t\t\t\t\tsections: result.skill.sections,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait this.indexSkills(skills);\n\t\treturn skills.length;\n\t}\n\n\t/**\n\t * Select the most relevant skills for a query.\n\t */\n\tasync select(query: string, options?: SelectOptions): Promise<SelectionResult[]> {\n\t\tconst topK = options?.topK ?? 5;\n\t\tconst threshold = options?.threshold ?? 0.0;\n\t\tconst boost = new Set(options?.boost ?? []);\n\t\tconst exclude = options?.exclude ?? [];\n\n\t\tlet results: Array<{ id: string; score: number; metadata: Record<string, unknown> }>;\n\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\t// BM25 path — direct text scoring\n\t\t\tresults = this.bm25.search(query, topK * 2, threshold);\n\t\t} else if (this.embedding && this.store) {\n\t\t\t// Embedding path — vectorize query and search store\n\t\t\tconst [queryVector] = await this.embedding.embed([query]);\n\t\t\tif (!queryVector) {\n\t\t\t\tthrow new Error('Embedding provider returned empty result for query');\n\t\t\t}\n\t\t\tresults = await this.store.search(queryVector, topK * 2, threshold);\n\t\t} else {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Apply exclude filters\n\t\tif (exclude.length > 0) {\n\t\t\tresults = results.filter((r) => {\n\t\t\t\treturn !exclude.some((pattern) => {\n\t\t\t\t\tif (pattern.endsWith('*')) {\n\t\t\t\t\t\treturn r.id.startsWith(pattern.slice(0, -1));\n\t\t\t\t\t}\n\t\t\t\t\treturn r.id === pattern;\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// Apply boost\n\t\tif (boost.size > 0) {\n\t\t\tresults = results.map((r) => ({\n\t\t\t\t...r,\n\t\t\t\tscore: boost.has(r.id) ? r.score * 1.2 : r.score,\n\t\t\t}));\n\t\t\tresults.sort((a, b) => b.score - a.score);\n\t\t}\n\n\t\treturn results.slice(0, topK).map((r) => ({\n\t\t\tskill: r.id,\n\t\t\tscore: r.score,\n\t\t\tmetadata: r.metadata,\n\t\t}));\n\t}\n\n\t/**\n\t * Detect skills with overlapping descriptions.\n\t */\n\tasync detectConflicts(threshold = 0.85): Promise<ConflictGroup[]> {\n\t\tconst conflicts: ConflictGroup[] = [];\n\t\tconst names = Array.from(this.skillNames);\n\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\t// BM25 path — search each skill name against descriptions\n\t\t\tfor (const name of names) {\n\t\t\t\tconst results = this.bm25.search(name, names.length, threshold);\n\t\t\t\tconst similar = results\n\t\t\t\t\t.filter((r) => r.id !== name && r.score >= threshold)\n\t\t\t\t\t.map((r) => r.id);\n\n\t\t\t\tif (similar.length > 0) {\n\t\t\t\t\tconst existing = conflicts.find(\n\t\t\t\t\t\t(c) => c.skills.includes(name) || similar.some((s) => c.skills.includes(s)),\n\t\t\t\t\t);\n\t\t\t\t\tif (!existing) {\n\t\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\t\tskills: [name, ...similar],\n\t\t\t\t\t\t\tsimilarity: results.find((r) => r.id !== name)?.score ?? threshold,\n\t\t\t\t\t\t\tsuggestion:\n\t\t\t\t\t\t\t\t'These skills have highly similar descriptions. Consider differentiating their trigger contexts.',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.embedding && this.store) {\n\t\t\t// Embedding path — embed skill names and search store\n\t\t\tfor (const name of names) {\n\t\t\t\tconst results = await this.store.search(\n\t\t\t\t\t(await this.embedding.embed([name]))[0]!,\n\t\t\t\t\tnames.length,\n\t\t\t\t\tthreshold,\n\t\t\t\t);\n\n\t\t\t\tconst similar = results\n\t\t\t\t\t.filter((r) => r.id !== name && r.score >= threshold)\n\t\t\t\t\t.map((r) => r.id);\n\n\t\t\t\tif (similar.length > 0) {\n\t\t\t\t\tconst existing = conflicts.find(\n\t\t\t\t\t\t(c) => c.skills.includes(name) || similar.some((s) => c.skills.includes(s)),\n\t\t\t\t\t);\n\t\t\t\t\tif (!existing) {\n\t\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\t\tskills: [name, ...similar],\n\t\t\t\t\t\t\tsimilarity: results.find((r) => r.id !== name)?.score ?? threshold,\n\t\t\t\t\t\t\tsuggestion:\n\t\t\t\t\t\t\t\t'These skills have highly similar descriptions. Consider differentiating their trigger contexts.',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn conflicts;\n\t}\n\n\t/**\n\t * Build the text to index for a skill entry.\n\t * When contextual retrieval is enabled and the skill has body/sections,\n\t * prepends extracted context to the description.\n\t */\n\tprivate enrichText(skill: SkillEntry): string {\n\t\tif (this.contextEnabled && (skill.body || skill.sections)) {\n\t\t\tconst ctx = extractContext(skill);\n\t\t\tif (ctx) return `${ctx} ${skill.description}`;\n\t\t}\n\t\treturn skill.description;\n\t}\n\n\t/**\n\t * Get the number of indexed skills.\n\t */\n\tget count(): number {\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\treturn this.bm25.size();\n\t\t}\n\t\treturn this.store?.size() ?? 0;\n\t}\n\n\t/**\n\t * Save the index to a JSON-serializable object.\n\t */\n\tsave(): SkillRouterSnapshot {\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\treturn {\n\t\t\t\tversion: 1,\n\t\t\t\tembeddingProvider: 'bm25',\n\t\t\t\tdimensions: 0,\n\t\t\t\tstore: this.bm25.serialize(),\n\t\t\t\tskillNames: Array.from(this.skillNames),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tversion: 1,\n\t\t\tembeddingProvider: this.embedding!.name,\n\t\t\tdimensions: this.embedding!.dimensions,\n\t\t\tstore: this.store!.serialize(),\n\t\t\tskillNames: Array.from(this.skillNames),\n\t\t};\n\t}\n\n\t/**\n\t * Load a previously saved index.\n\t * Validates that the snapshot format matches the current engine.\n\t */\n\tload(snapshot: SkillRouterSnapshot): void {\n\t\tif (this.usesBM25 && this.bm25) {\n\t\t\tif (snapshot.embeddingProvider !== 'bm25') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Cannot load snapshot from provider \"${snapshot.embeddingProvider}\" into BM25 router. ` +\n\t\t\t\t\t\t'Create the router with a matching embedding config.',\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.bm25.deserialize(snapshot.store);\n\t\t} else if (this.embedding && this.store) {\n\t\t\tif (snapshot.dimensions !== this.embedding.dimensions) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Snapshot dimensions (${snapshot.dimensions}) don't match current provider dimensions (${this.embedding.dimensions})`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.store.deserialize(snapshot.store);\n\t\t}\n\n\t\tthis.skillNames = new Set(snapshot.skillNames);\n\t}\n\n\t/**\n\t * Create a SkillRouter from a saved snapshot.\n\t */\n\tstatic fromSnapshot(snapshot: SkillRouterSnapshot, options?: SkillRouterOptions): SkillRouter {\n\t\tconst router = new SkillRouter(options);\n\t\trouter.load(snapshot);\n\t\treturn router;\n\t}\n}\n\n/**\n * A group of conflicting (highly similar) skills.\n */\nexport interface ConflictGroup {\n\treadonly skills: string[];\n\treadonly similarity: number;\n\treadonly suggestion: string;\n}\n\n/**\n * Serialized snapshot of a SkillRouter state.\n */\nexport interface SkillRouterSnapshot {\n\treadonly version: number;\n\treadonly embeddingProvider: string;\n\treadonly dimensions: number;\n\treadonly store: unknown;\n\treadonly skillNames: string[];\n}\n\n/**\n * Create an embedding provider from config.\n */\nfunction createEmbeddingProvider(config: EmbeddingConfig): EmbeddingProvider {\n\tif (config === 'local') {\n\t\treturn new LocalEmbeddingProvider();\n\t}\n\n\tif (config.provider === 'custom') {\n\t\treturn {\n\t\t\tname: 'custom',\n\t\t\tdimensions: config.dimensions,\n\t\t\tembed: config.embed,\n\t\t};\n\t}\n\n\t// For openai/ollama, we'd need their SDKs as optional deps.\n\t// For now, throw a helpful error.\n\tthrow new Error(\n\t\t`Embedding provider \"${config.provider}\" requires additional setup. ` +\n\t\t\t'Install the appropriate SDK and configure an API key. ' +\n\t\t\t'See: https://github.com/skill-tools/skill-tools#embedding-providers',\n\t);\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skill-tools/router",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "BM25 skill selection middleware for Agent Skills — fast full-text routing for large skill catalogs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"agent-skills",
|
|
26
|
+
"skill-routing",
|
|
27
|
+
"bm25",
|
|
28
|
+
"full-text-search",
|
|
29
|
+
"skill-md",
|
|
30
|
+
"ai-agent"
|
|
31
|
+
],
|
|
32
|
+
"author": "Piyush Vyas <pyyush>",
|
|
33
|
+
"license": "Apache-2.0",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/skill-tools/skill-tools",
|
|
37
|
+
"directory": "packages/router"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/skill-tools/skill-tools/tree/main/packages/router",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/skill-tools/skill-tools/issues"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@skill-tools/core": "0.2.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@biomejs/biome": "^2.3.14",
|
|
51
|
+
"@types/node": "^25.2.2",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vitest": "^4.0.18"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"dev": "tsup --watch",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:watch": "vitest",
|
|
61
|
+
"typecheck": "tsc --noEmit",
|
|
62
|
+
"lint": "biome check src/",
|
|
63
|
+
"lint:fix": "biome check --write src/",
|
|
64
|
+
"format": "biome format --write src/",
|
|
65
|
+
"format:check": "biome format src/",
|
|
66
|
+
"clean": "rm -rf dist"
|
|
67
|
+
}
|
|
68
|
+
}
|