skill-creator 1.5.1 → 2.0.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/CHANGELOG.md +73 -0
- package/LICENSE +21 -0
- package/README.md +248 -275
- package/dist/cli.js +51129 -0
- package/dist/cli.js.map +7 -0
- package/dist/daemon.js +52163 -0
- package/dist/daemon.js.map +7 -0
- package/dist/package.json +5 -0
- package/dist/webui/_app/immutable/assets/0.0XN00VKF.css +2 -0
- package/dist/webui/_app/immutable/assets/ProviderView.DEH95hqa.css +1 -0
- package/dist/webui/_app/immutable/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-greek-wght-normal.CkhJZR-_.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-latin-wght-normal.Dx4kXJAl.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2 +0 -0
- package/dist/webui/_app/immutable/assets/shell.U4CQV8re.css +1 -0
- package/dist/webui/_app/immutable/chunks/0umLG1IN.js +1 -0
- package/dist/webui/_app/immutable/chunks/B2zyE4XX.js +1 -0
- package/dist/webui/_app/immutable/chunks/BD9g8Udg.js +1 -0
- package/dist/webui/_app/immutable/chunks/BEPs9Z9s.js +1 -0
- package/dist/webui/_app/immutable/chunks/BEsyQXpe.js +1 -0
- package/dist/webui/_app/immutable/chunks/BIfnT_mK.js +1 -0
- package/dist/webui/_app/immutable/chunks/BYNWtKcf.js +259 -0
- package/dist/webui/_app/immutable/chunks/B_YFzSAv.js +2 -0
- package/dist/webui/_app/immutable/chunks/BaH4uqzh.js +1 -0
- package/dist/webui/_app/immutable/chunks/Bjy-W4x2.js +81 -0
- package/dist/webui/_app/immutable/chunks/BkEnd9_Z.js +1 -0
- package/dist/webui/_app/immutable/chunks/BrDKAjtR.js +1 -0
- package/dist/webui/_app/immutable/chunks/Bs27XW8_.js +1 -0
- package/dist/webui/_app/immutable/chunks/BySEbwqx.js +1 -0
- package/dist/webui/_app/immutable/chunks/C3mlWJXx.js +1 -0
- package/dist/webui/_app/immutable/chunks/CEpOi93z.js +2 -0
- package/dist/webui/_app/immutable/chunks/CIFG41pU.js +1 -0
- package/dist/webui/_app/immutable/chunks/CNPsST_i.js +1 -0
- package/dist/webui/_app/immutable/chunks/CQD9uzpA.js +1 -0
- package/dist/webui/_app/immutable/chunks/CeR4do8T.js +1 -0
- package/dist/webui/_app/immutable/chunks/Ckw1quWt.js +1 -0
- package/dist/webui/_app/immutable/chunks/CmCJ0SKP.js +3 -0
- package/dist/webui/_app/immutable/chunks/D-V0xBeS.js +1 -0
- package/dist/webui/_app/immutable/chunks/D-ecV3TD.js +1 -0
- package/dist/webui/_app/immutable/chunks/D0xHg31U.js +1 -0
- package/dist/webui/_app/immutable/chunks/D25cXQtk.js +1 -0
- package/dist/webui/_app/immutable/chunks/D8Der6oM.js +1 -0
- package/dist/webui/_app/immutable/chunks/DEtYLPO4.js +8 -0
- package/dist/webui/_app/immutable/chunks/DJNLWtK-.js +1 -0
- package/dist/webui/_app/immutable/chunks/DLuJKUyD.js +1 -0
- package/dist/webui/_app/immutable/chunks/DWcQbrnv.js +52 -0
- package/dist/webui/_app/immutable/chunks/DZ_Kltd5.js +1 -0
- package/dist/webui/_app/immutable/chunks/DecrR9TK.js +1 -0
- package/dist/webui/_app/immutable/chunks/Dl8eQ129.js +5 -0
- package/dist/webui/_app/immutable/chunks/Dnkino9G.js +1 -0
- package/dist/webui/_app/immutable/chunks/HclGiUj8.js +1 -0
- package/dist/webui/_app/immutable/chunks/IYkYSIV6.js +1 -0
- package/dist/webui/_app/immutable/chunks/J36u8XLO.js +1 -0
- package/dist/webui/_app/immutable/chunks/UeEccMjN.js +1 -0
- package/dist/webui/_app/immutable/chunks/Y--VMh3y.js +1 -0
- package/dist/webui/_app/immutable/chunks/iicbWqXp.js +3 -0
- package/dist/webui/_app/immutable/chunks/s48N5eaK.js +67 -0
- package/dist/webui/_app/immutable/chunks/xihTtKlq.js +1 -0
- package/dist/webui/_app/immutable/entry/app.CbFi8HIH.js +2 -0
- package/dist/webui/_app/immutable/entry/start.C3bV1TCO.js +1 -0
- package/dist/webui/_app/immutable/nodes/0.C7-AKGsj.js +231 -0
- package/dist/webui/_app/immutable/nodes/1.raBmjc20.js +1 -0
- package/dist/webui/_app/immutable/nodes/2.ewWz-Ki-.js +1 -0
- package/dist/webui/_app/immutable/nodes/3.DCVfhckZ.js +1 -0
- package/dist/webui/_app/version.json +1 -0
- package/dist/webui/icons/app-icon/darwin-dark.icns +0 -0
- package/dist/webui/icons/app-icon/darwin-light.icns +0 -0
- package/dist/webui/icons/app-icon/win32-dark.ico +0 -0
- package/dist/webui/icons/app-icon/win32-light.ico +0 -0
- package/dist/webui/icons/app-icon.icns +0 -0
- package/dist/webui/icons/app-icon.ico +0 -0
- package/dist/webui/icons/app-icon.json +84 -0
- package/dist/webui/icons/app-icon.png +0 -0
- package/dist/webui/icons/flat-symbol.png +0 -0
- package/dist/webui/icons/linux/128x128/app-icon.png +0 -0
- package/dist/webui/icons/linux/16x16/app-icon.png +0 -0
- package/dist/webui/icons/linux/256x256/app-icon.png +0 -0
- package/dist/webui/icons/linux/32x32/app-icon.png +0 -0
- package/dist/webui/icons/linux/48x48/app-icon.png +0 -0
- package/dist/webui/icons/linux/512x512/app-icon.png +0 -0
- package/dist/webui/icons/linux/64x64/app-icon.png +0 -0
- package/dist/webui/icons/monochrome-mini.png +0 -0
- package/dist/webui/index.html +62 -0
- package/dist/webui/robots.txt +3 -0
- package/package.json +100 -70
- package/dist/chunk-Da8dvM5T.mjs +0 -1
- package/dist/cli.d.mts +0 -1016
- package/dist/cli.d.mts.map +0 -1
- package/dist/cli.mjs +0 -36
- package/dist/cli.mjs.map +0 -1
- package/dist/contentManager-8rmWJMb6.mjs +0 -22
- package/dist/contentManager-8rmWJMb6.mjs.map +0 -1
- package/dist/contentManager-Xt8N5psY.mjs +0 -1
- package/dist/dist-DZL34HNo.mjs +0 -8
- package/dist/dist-DZL34HNo.mjs.map +0 -1
- package/dist/dist-X_kVEzbK.mjs +0 -1
- package/dist/esm-8qfZdcpd.mjs +0 -33
- package/dist/esm-8qfZdcpd.mjs.map +0 -1
- package/dist/esm-BF5pvSbc.mjs +0 -1
- package/dist/esm-BbhxxeGF.mjs +0 -4
- package/dist/esm-BbhxxeGF.mjs.map +0 -1
- package/dist/index.d.mts +0 -1964
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -21
- package/dist/index.mjs.map +0 -1
- package/dist/listContext7-DKXzgWdn.mjs +0 -2
- package/dist/listContext7-DKXzgWdn.mjs.map +0 -1
- package/dist/package-Cxx_VSyD.mjs +0 -2
- package/dist/package-Cxx_VSyD.mjs.map +0 -1
- package/dist/path-CuoiIaIe.mjs +0 -2
- package/dist/path-CuoiIaIe.mjs.map +0 -1
- package/dist/removeContext7-DOXrTXeI.mjs +0 -3
- package/dist/removeContext7-DOXrTXeI.mjs.map +0 -1
- package/dist/removeSkill-C-ehFexk.mjs +0 -5
- package/dist/removeSkill-C-ehFexk.mjs.map +0 -1
- package/dist/removeSkill-DWwhvzej.mjs +0 -1
- package/dist/runScript-Cr9RRN9y.mjs +0 -14
- package/dist/runScript-Cr9RRN9y.mjs.map +0 -1
- package/dist/search_format-DIs-1lKk.mjs +0 -5
- package/dist/search_format-DIs-1lKk.mjs.map +0 -1
- package/dist/shared-CFoY2Xhg.mjs +0 -2
- package/dist/shared-CFoY2Xhg.mjs.map +0 -1
- package/dist/skillMdManager-DP8fGZb7.mjs +0 -7
- package/dist/skillMdManager-DP8fGZb7.mjs.map +0 -1
- package/dist/unifiedSearch-CGZXw0NB.mjs +0 -1
- package/dist/unifiedSearch-l-lrSc9C.mjs +0 -4
- package/dist/unifiedSearch-l-lrSc9C.mjs.map +0 -1
- package/templates/SKILL.md +0 -41
- package/templates/SKILL.zh-CN.md +0 -297
- package/templates/skill-creator.md +0 -97
- package/templates/skill-creator.zh-CN.md +0 -100
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"unifiedSearch-l-lrSc9C.mjs","names":["uFuzzy","reTpl","p","intraIns","intraSub","intraTrn","intraDel","intraSlice","info","lftCharIdx","m","idxAcc","i","len","terms","needle","uFuzzy","results: SearchResult[]","serverInfo: ChromaServerInfo","searchResults: SearchResult[]","similarity: number","fs","glob","createHash","added: string[]","modified: string[]","deleted: string[]","documents: string[]","ids: string[]","metadatas: any[]","join","formattingOptions: FormattingOptions"],"sources":["../node_modules/.pnpm/@leeoniya+ufuzzy@1.0.19/node_modules/@leeoniya/ufuzzy/dist/uFuzzy.cjs","../src/core/fuzzySearchAdapter.ts","../src/core/portUtils.ts","../src/core/chromaServerManager.ts","../src/core/chromaSearchAdapter.ts","../src/core/autoSearchAdapter.ts","../src/core/searchEngineFactory.ts","../src/core/unifiedSearch.ts"],"sourcesContent":["/**\n* Copyright (c) 2025, Leon Sorokin\n* All rights reserved. (MIT Licensed)\n*\n* uFuzzy.js (μFuzzy)\n* A tiny, efficient fuzzy matcher that doesn't suck\n* https://github.com/leeoniya/uFuzzy (v1.0.19)\n*/\n\n'use strict';\n\nconst cmp = (a, b) => a > b ? 1 : a < b ? -1 : 0;\n\nconst inf = Infinity;\n\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#escaping\nconst escapeRegExp = str => str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\n// meh, magic tmp placeholder, must be tolerant to toLocaleLowerCase(), interSplit, and intraSplit\nconst EXACT_HERE = 'eexxaacctt';\n\nconst PUNCT_RE = /\\p{P}/gu;\n\nconst LATIN_UPPER = 'A-Z';\nconst LATIN_LOWER = 'a-z';\n\nconst COLLATE_ARGS = ['en', { numeric: true, sensitivity: 'base' }];\n\nconst swapAlpha = (str, upper, lower) => str.replace(LATIN_UPPER, upper).replace(LATIN_LOWER, lower);\n\nconst OPTS = {\n\t// whether regexps use a /u unicode flag\n\tunicode: false,\n\n\talpha: null,\n\n\t// term segmentation & punct/whitespace merging\n\tinterSplit: \"[^A-Za-z\\\\d']+\",\n\tintraSplit: \"[a-z][A-Z]\",\n\n\t// inter bounds that will be used to increase lft2/rgt2 info counters\n\tinterBound: \"[^A-Za-z\\\\d]\",\n\t// intra bounds that will be used to increase lft1/rgt1 info counters\n\tintraBound: \"[A-Za-z]\\\\d|\\\\d[A-Za-z]|[a-z][A-Z]\",\n\n\t// inter-bounds mode\n\t// 2 = strict (will only match 'man' on whitepace and punct boundaries: Mega Man, Mega_Man, mega.man)\n\t// 1 = loose (plus allowance for alpha-num and case-change boundaries: MegaMan, 0007man)\n\t// 0 = any (will match 'man' as any substring: megamaniac)\n\tinterLft: 0,\n\tinterRgt: 0,\n\n\t// allowance between terms\n\tinterChars: '.',\n\tinterIns: inf,\n\n\t// allowance between chars in terms\n\tintraChars: \"[a-z\\\\d']\", // internally case-insensitive\n\tintraIns: null,\n\n\tintraContr: \"'[a-z]{1,2}\\\\b\",\n\n\t// multi-insert or single-error mode\n\tintraMode: 0,\n\n\t// single-error bounds for errors within terms, default requires exact first char\n\tintraSlice: [1, inf],\n\n\t// single-error tolerance toggles\n\tintraSub: null,\n\tintraTrn: null,\n\tintraDel: null,\n\n\t// can post-filter matches that are too far apart in distance or length\n\t// (since intraIns is between each char, it can accum to nonsense matches)\n\tintraFilt: (term, match, index) => true, // should this also accept WIP info?\n\n\ttoUpper: str => str.toLocaleUpperCase(),\n\ttoLower: str => str.toLocaleLowerCase(),\n\tcompare: null,\n\n\t// final sorting fn\n\tsort: (info, haystack, needle, compare = cmp) => {\n\t\tlet {\n\t\t\tidx,\n\t\t\tchars,\n\t\t\tterms,\n\t\t\tinterLft2,\n\t\t\tinterLft1,\n\t\t//\tinterRgt2,\n\t\t//\tinterRgt1,\n\t\t\tstart,\n\t\t\tintraIns,\n\t\t\tinterIns,\n\t\t\tcases,\n\t\t} = info;\n\n\t\treturn idx.map((v, i) => i).sort((ia, ib) => (\n\t\t\t// most contig chars matched\n\t\t\tchars[ib] - chars[ia] ||\n\t\t\t// least char intra-fuzz (most contiguous)\n\t\t\tintraIns[ia] - intraIns[ib] ||\n\t\t\t// most prefix bounds, boosted by full term matches\n\t\t\t(\n\t\t\t\t(terms[ib] + interLft2[ib] + 0.5 * interLft1[ib]) -\n\t\t\t\t(terms[ia] + interLft2[ia] + 0.5 * interLft1[ia])\n\t\t\t) ||\n\t\t\t// highest density of match (least span)\n\t\t//\tspan[ia] - span[ib] ||\n\t\t\t// highest density of match (least term inter-fuzz)\n\t\t\tinterIns[ia] - interIns[ib] ||\n\t\t\t// earliest start of match\n\t\t\tstart[ia] - start[ib] ||\n\t\t\t// case match\n\t\t\tcases[ib] - cases[ia] ||\n\t\t\t// alphabetic\n\t\t\tcompare(haystack[idx[ia]], haystack[idx[ib]])\n\t\t));\n\t},\n};\n\nconst lazyRepeat = (chars, limit) => (\n\tlimit == 0 ? '' :\n\tlimit == 1 ? chars + '??' :\n\tlimit == inf ? chars + '*?' :\n\t chars + `{0,${limit}}?`\n);\n\nconst mode2Tpl = '(?:\\\\b|_)';\n\nfunction uFuzzy(opts) {\n\topts = Object.assign({}, OPTS, opts);\n\n\tlet {\n\t\tunicode,\n\t\tinterLft,\n\t\tinterRgt,\n\t\tintraMode,\n\t\tintraSlice,\n\t\tintraIns,\n\t\tintraSub,\n\t\tintraTrn,\n\t\tintraDel,\n\t\tintraContr,\n\t\tintraSplit: _intraSplit,\n\t\tinterSplit: _interSplit,\n\t\tintraBound: _intraBound,\n\t\tinterBound: _interBound,\n\t\tintraChars,\n\t\ttoUpper,\n\t\ttoLower,\n\t\tcompare,\n\t} = opts;\n\n\tintraIns ??= intraMode;\n\tintraSub ??= intraMode;\n\tintraTrn ??= intraMode;\n\tintraDel ??= intraMode;\n\n\tcompare ??= typeof Intl == \"undefined\" ? cmp : new Intl.Collator(...COLLATE_ARGS).compare;\n\n\tlet alpha = opts.letters ?? opts.alpha;\n\n\tif (alpha != null) {\n\t\tlet upper = toUpper(alpha);\n\t\tlet lower = toLower(alpha);\n\n\t\t_interSplit = swapAlpha(_interSplit, upper, lower);\n\t\t_intraSplit = swapAlpha(_intraSplit, upper, lower);\n\t\t_interBound = swapAlpha(_interBound, upper, lower);\n\t\t_intraBound = swapAlpha(_intraBound, upper, lower);\n\t\tintraChars = swapAlpha(intraChars, upper, lower);\n\t\tintraContr = swapAlpha(intraContr, upper, lower);\n\t}\n\n\tlet uFlag = unicode ? 'u' : '';\n\n\tconst quotedAny = '\".+?\"';\n\tconst EXACTS_RE = new RegExp(quotedAny, 'gi' + uFlag);\n\tconst NEGS_RE = new RegExp(`(?:\\\\s+|^)-(?:${intraChars}+|${quotedAny})`, 'gi' + uFlag);\n\n\tlet { intraRules } = opts;\n\n\tif (intraRules == null) {\n\t\tintraRules = p => {\n\t\t\t// default is exact term matches only\n\t\t\tlet _intraSlice = OPTS.intraSlice, // requires first char\n\t\t\t\t_intraIns = 0,\n\t\t\t\t_intraSub = 0,\n\t\t\t\t_intraTrn = 0,\n\t\t\t\t_intraDel = 0;\n\n\t\t\t// only-digits strings should match exactly, else special rules for short strings\n\t\t\tif (/[^\\d]/.test(p)) {\n\t\t\t\tlet plen = p.length;\n\n\t\t\t\t// prevent junk matches by requiring stricter rules for short terms\n\t\t\t\tif (plen <= 4) {\n\t\t\t\t\tif (plen >= 3) {\n\t\t\t\t\t\t// one swap in non-first char when 3-4 chars\n\t\t\t\t\t\t_intraTrn = Math.min(intraTrn, 1);\n\n\t\t\t\t\t\t// or one insertion when 4 chars\n\t\t\t\t\t\tif (plen == 4)\n\t\t\t\t\t\t\t_intraIns = Math.min(intraIns, 1);\n\t\t\t\t\t}\n\t\t\t\t\t// else exact match when 1-2 chars\n\t\t\t\t}\n\t\t\t\t// use supplied opts\n\t\t\t\telse {\n\t\t\t\t\t_intraSlice = intraSlice;\n\t\t\t\t\t_intraIns = intraIns,\n\t\t\t\t\t_intraSub = intraSub,\n\t\t\t\t\t_intraTrn = intraTrn,\n\t\t\t\t\t_intraDel = intraDel;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tintraSlice: _intraSlice,\n\t\t\t\tintraIns: _intraIns,\n\t\t\t\tintraSub: _intraSub,\n\t\t\t\tintraTrn: _intraTrn,\n\t\t\t\tintraDel: _intraDel,\n\t\t\t};\n\t\t};\n\t}\n\n\tlet withIntraSplit = !!_intraSplit;\n\n\tlet intraSplit = new RegExp(_intraSplit, 'g' + uFlag);\n\tlet interSplit = new RegExp(_interSplit, 'g' + uFlag);\n\n\tlet trimRe = new RegExp('^' + _interSplit + '|' + _interSplit + '$', 'g' + uFlag);\n\tlet contrsRe = new RegExp(intraContr, 'gi' + uFlag);\n\n\tconst split = (needle, keepCase = false) => {\n\t\tlet exacts = [];\n\n\t\tneedle = needle.replace(EXACTS_RE, m => {\n\t\t\texacts.push(m);\n\t\t\treturn EXACT_HERE;\n\t\t});\n\n\t\tneedle = needle.replace(trimRe, '');\n\n\t\tif (!keepCase)\n\t\t\tneedle = toLower(needle);\n\n\t\tif (withIntraSplit)\n\t\t\tneedle = needle.replace(intraSplit, m => m[0] + ' ' + m[1]);\n\n\t\tlet j = 0;\n\t\treturn needle.split(interSplit).filter(t => t != '').map(v => v === EXACT_HERE ? exacts[j++] : v);\n\t};\n\n\tconst NUM_OR_ALPHA_RE = /[^\\d]+|\\d+/g;\n\n\tconst prepQuery = (needle, capt = 0, interOR = false) => {\n\t\t// split on punct, whitespace, num-alpha, and upper-lower boundaries\n\t\tlet parts = split(needle);\n\n\t\tif (parts.length == 0)\n\t\t\treturn [];\n\n\t\t// split out any detected contractions for each term that become required suffixes\n\t\tlet contrs = Array(parts.length).fill('');\n\t\tparts = parts.map((p, pi) => p.replace(contrsRe, m => {\n\t\t\tcontrs[pi] = m;\n\t\t\treturn '';\n\t\t}));\n\n\t\t// array of regexp tpls for each term\n\t\tlet reTpl;\n\n\t\t// allows single mutations within each term\n\t\tif (intraMode == 1) {\n\t\t\treTpl = parts.map((p, pi) => {\n\t\t\t\tif (p[0] === '\"')\n\t\t\t\t\treturn escapeRegExp(p.slice(1, -1));\n\n\t\t\t\tlet reTpl = '';\n\n\t\t\t\t// split into numeric and alpha parts, so numbers are only matched as following punct or alpha boundaries, without swaps or insertions\n\t\t\t\tfor (let m of p.matchAll(NUM_OR_ALPHA_RE)) {\n\t\t\t\t\tlet p = m[0];\n\n\t\t\t\t\tlet {\n\t\t\t\t\t\tintraSlice,\n\t\t\t\t\t\tintraIns,\n\t\t\t\t\t\tintraSub,\n\t\t\t\t\t\tintraTrn,\n\t\t\t\t\t\tintraDel,\n\t\t\t\t\t} = intraRules(p);\n\n\t\t\t\t\tif (intraIns + intraSub + intraTrn + intraDel == 0)\n\t\t\t\t\t\treTpl += p + contrs[pi];\n\t\t\t\t\telse {\n\t\t\t\t\t\tlet [lftIdx, rgtIdx] = intraSlice;\n\t\t\t\t\t\tlet lftChar = p.slice(0, lftIdx); // prefix\n\t\t\t\t\t\tlet rgtChar = p.slice(rgtIdx); // suffix\n\n\t\t\t\t\t\tlet chars = p.slice(lftIdx, rgtIdx);\n\n\t\t\t\t\t\t// neg lookahead to prefer matching 'Test' instead of 'tTest' in ManifestTest or fittest\n\t\t\t\t\t\t// but skip when search term contains leading repetition (aardvark, aaa)\n\t\t\t\t\t\tif (intraIns == 1 && lftChar.length == 1 && lftChar != chars[0])\n\t\t\t\t\t\t\tlftChar += '(?!' + lftChar + ')';\n\n\t\t\t\t\t\tlet numChars = chars.length;\n\n\t\t\t\t\t\tlet variants = [p];\n\n\t\t\t\t\t\t// variants with single char substitutions\n\t\t\t\t\t\tif (intraSub) {\n\t\t\t\t\t\t\tfor (let i = 0; i < numChars; i++)\n\t\t\t\t\t\t\t\tvariants.push(lftChar + chars.slice(0, i) + intraChars + chars.slice(i + 1) + rgtChar);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// variants with single transpositions\n\t\t\t\t\t\tif (intraTrn) {\n\t\t\t\t\t\t\tfor (let i = 0; i < numChars - 1; i++) {\n\t\t\t\t\t\t\t\tif (chars[i] != chars[i+1])\n\t\t\t\t\t\t\t\t\tvariants.push(lftChar + chars.slice(0, i) + chars[i+1] + chars[i] + chars.slice(i + 2) + rgtChar);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// variants with single char omissions\n\t\t\t\t\t\tif (intraDel) {\n\t\t\t\t\t\t\tfor (let i = 0; i < numChars; i++)\n\t\t\t\t\t\t\t\tvariants.push(lftChar + chars.slice(0, i + 1) + '?' + chars.slice(i + 1) + rgtChar);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// variants with single char insertions\n\t\t\t\t\t\tif (intraIns) {\n\t\t\t\t\t\t\tlet intraInsTpl = lazyRepeat(intraChars, 1);\n\n\t\t\t\t\t\t\tfor (let i = 0; i < numChars; i++)\n\t\t\t\t\t\t\t\tvariants.push(lftChar + chars.slice(0, i) + intraInsTpl + chars.slice(i) + rgtChar);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treTpl += '(?:' + variants.join('|') + ')' + contrs[pi];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t//\tconsole.log(reTpl);\n\n\t\t\t\treturn reTpl;\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tlet intraInsTpl = lazyRepeat(intraChars, intraIns);\n\n\t\t\t// capture at char level\n\t\t\tif (capt == 2 && intraIns > 0) {\n\t\t\t\t// sadly, we also have to capture the inter-term junk via parenth-wrapping .*?\n\t\t\t\t// to accum other capture groups' indices for \\b boosting during scoring\n\t\t\t\tintraInsTpl = ')(' + intraInsTpl + ')(';\n\t\t\t}\n\n\t\t\treTpl = parts.map((p, pi) => p[0] === '\"' ? escapeRegExp(p.slice(1, -1)) : p.split('').map((c, i, chars) => {\n\t\t\t\t// neg lookahead to prefer matching 'Test' instead of 'tTest' in ManifestTest or fittest\n\t\t\t\t// but skip when search term contains leading repetition (aardvark, aaa)\n\t\t\t\tif (intraIns == 1 && i == 0 && chars.length > 1 && c != chars[i+1])\n\t\t\t\t\tc += '(?!' + c + ')';\n\n\t\t\t\treturn c;\n\t\t\t}).join(intraInsTpl) + contrs[pi]);\n\t\t}\n\n\t//\tconsole.log(reTpl);\n\n\t\t// this only helps to reduce initial matches early when they can be detected\n\t\t// TODO: might want a mode 3 that excludes _\n\t\tlet preTpl = interLft == 2 ? mode2Tpl : '';\n\t\tlet sufTpl = interRgt == 2 ? mode2Tpl : '';\n\n\t\tlet interCharsTpl = sufTpl + lazyRepeat(opts.interChars, opts.interIns) + preTpl;\n\n\t\t// capture at word level\n\t\tif (capt > 0) {\n\t\t\tif (interOR) {\n\t\t\t\t// this is basically for doing .matchAll() occurence counting and highlighting without needing permuted ooo needles\n\t\t\t\treTpl = preTpl + '(' + reTpl.join(')' + sufTpl + '|' + preTpl + '(') + ')' + sufTpl;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// sadly, we also have to capture the inter-term junk via parenth-wrapping .*?\n\t\t\t\t// to accum other capture groups' indices for \\b boosting during scoring\n\t\t\t\treTpl = '(' + reTpl.join(')(' + interCharsTpl + ')(') + ')';\n\t\t\t\treTpl = '(.??' + preTpl + ')' + reTpl + '(' + sufTpl + '.*)'; // nit: trailing capture here assumes interIns = Inf\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\treTpl = reTpl.join(interCharsTpl);\n\t\t\treTpl = preTpl + reTpl + sufTpl;\n\t\t}\n\n\t//\tconsole.log(reTpl);\n\n\t\treturn [new RegExp(reTpl, 'i' + uFlag), parts, contrs];\n\t};\n\n\tconst filter = (haystack, needle, idxs) => {\n\n\t\tlet [query] = prepQuery(needle);\n\n\t\tif (query == null)\n\t\t\treturn null;\n\n\t\tlet out = [];\n\n\t\tif (idxs != null) {\n\t\t\tfor (let i = 0; i < idxs.length; i++) {\n\t\t\t\tlet idx = idxs[i];\n\t\t\t\tquery.test(haystack[idx]) && out.push(idx);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor (let i = 0; i < haystack.length; i++)\n\t\t\t\tquery.test(haystack[i]) && out.push(i);\n\t\t}\n\n\t\treturn out;\n\t};\n\n\tlet withIntraBound = !!_intraBound;\n\n\tlet interBound = new RegExp(_interBound, uFlag);\n\tlet intraBound = new RegExp(_intraBound, uFlag);\n\n\tconst info = (idxs, haystack, needle) => {\n\n\t\tlet [query, parts, contrs] = prepQuery(needle, 1);\n\t\tlet partsCased = split(needle, true);\n\t\tlet [queryR] = prepQuery(needle, 2);\n\t\tlet partsLen = parts.length;\n\n\t\tlet _terms = Array(partsLen);\n\t\tlet _termsCased = Array(partsLen);\n\n\t\tfor (let j = 0; j < partsLen; j++) {\n\t\t\tlet part = parts[j];\n\t\t\tlet partCased = partsCased[j];\n\n\t\t\tlet term = part[0] == '\"' ? part.slice(1, -1) : part + contrs[j];\n\t\t\tlet termCased = partCased[0] == '\"' ? partCased.slice(1, -1) : partCased + contrs[j];\n\n\t\t\t_terms[j] = term;\n\t\t\t_termsCased[j] = termCased;\n\t\t}\n\n\t\tlet len = idxs.length;\n\n\t\tlet field = Array(len).fill(0);\n\n\t\tlet info = {\n\t\t\t// idx in haystack\n\t\t\tidx: Array(len),\n\n\t\t\t// start of match\n\t\t\tstart: field.slice(),\n\t\t\t// length of match\n\t\t//\tspan: field.slice(),\n\n\t\t\t// contiguous chars matched\n\t\t\tchars: field.slice(),\n\n\t\t\t// case matched in term (via term.includes(match))\n\t\t\tcases: field.slice(),\n\n\t\t\t// contiguous (no fuzz) and bounded terms (intra=0, lft2/1, rgt2/1)\n\t\t\t// excludes terms that are contiguous but have < 2 bounds (substrings)\n\t\t\tterms: field.slice(),\n\n\t\t\t// cumulative length of unmatched chars (fuzz) within span\n\t\t\tinterIns: field.slice(), // between terms\n\t\t\tintraIns: field.slice(), // within terms\n\n\t\t\t// interLft/interRgt counters\n\t\t\tinterLft2: field.slice(),\n\t\t\tinterRgt2: field.slice(),\n\t\t\tinterLft1: field.slice(),\n\t\t\tinterRgt1: field.slice(),\n\n\t\t\tranges: Array(len),\n\t\t};\n\n\t\t// might discard idxs based on bounds checks\n\t\tlet mayDiscard = interLft == 1 || interRgt == 1;\n\n\t\tlet ii = 0;\n\n\t\tfor (let i = 0; i < idxs.length; i++) {\n\t\t\tlet mhstr = haystack[idxs[i]];\n\n\t\t\t// the matched parts are [full, junk, term, junk, term, junk]\n\t\t\tlet m = mhstr.match(query);\n\n\t\t\t// leading junk\n\t\t\tlet start = m.index + m[1].length;\n\n\t\t\tlet idxAcc = start;\n\t\t//\tlet span = m[0].length;\n\n\t\t\tlet disc = false;\n\t\t\tlet lft2 = 0;\n\t\t\tlet lft1 = 0;\n\t\t\tlet rgt2 = 0;\n\t\t\tlet rgt1 = 0;\n\t\t\tlet chars = 0;\n\t\t\tlet terms = 0;\n\t\t\tlet cases = 0;\n\t\t\tlet inter = 0;\n\t\t\tlet intra = 0;\n\n\t\t\tlet refine = [];\n\n\t\t\tfor (let j = 0, k = 2; j < partsLen; j++, k+=2) {\n\t\t\t\tlet group = toLower(m[k]);\n\t\t\t\tlet term = _terms[j];\n\t\t\t\tlet termCased = _termsCased[j];\n\t\t\t\tlet termLen = term.length;\n\t\t\t\tlet groupLen = group.length;\n\t\t\t\tlet fullMatch = group == term;\n\n\t\t\t\tif (m[k] == termCased)\n\t\t\t\t\tcases++;\n\n\t\t\t\t// this won't handle the case when an exact match exists across the boundary of the current group and the next junk\n\t\t\t\t// e.g. blob,ob when searching for 'bob' but finding the earlier `blob` (with extra insertion)\n\t\t\t\tif (!fullMatch && m[k+1].length >= termLen) {\n\t\t\t\t\t// probe for exact match in inter junk (TODO: maybe even in this matched part?)\n\t\t\t\t\tlet idxOf = toLower(m[k+1]).indexOf(term);\n\n\t\t\t\t\tif (idxOf > -1) {\n\t\t\t\t\t\trefine.push(idxAcc, groupLen, idxOf, termLen);\n\t\t\t\t\t\tidxAcc += refineMatch(m, k, idxOf, termLen);\n\t\t\t\t\t\tgroup = term;\n\t\t\t\t\t\tgroupLen = termLen;\n\t\t\t\t\t\tfullMatch = true;\n\n\t\t\t\t\t\tif (j == 0)\n\t\t\t\t\t\t\tstart = idxAcc;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (mayDiscard || fullMatch) {\n\t\t\t\t\t// does group's left and/or right land on \\b\n\t\t\t\t\tlet lftCharIdx = idxAcc - 1;\n\t\t\t\t\tlet rgtCharIdx = idxAcc + groupLen;\n\n\t\t\t\t\tlet isPre = false;\n\t\t\t\t\tlet isSuf = false;\n\n\t\t\t\t\t// prefix info\n\t\t\t\t\tif (lftCharIdx == -1 || interBound.test(mhstr[lftCharIdx])) {\n\t\t\t\t\t\tfullMatch && lft2++;\n\t\t\t\t\t\tisPre = true;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (interLft == 2) {\n\t\t\t\t\t\t\tdisc = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (withIntraBound && intraBound.test(mhstr[lftCharIdx] + mhstr[lftCharIdx + 1])) {\n\t\t\t\t\t\t\tfullMatch && lft1++;\n\t\t\t\t\t\t\tisPre = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (interLft == 1) {\n\t\t\t\t\t\t\t\t// regexps are eager, so try to improve the match by probing forward inter junk for exact match at a boundary\n\t\t\t\t\t\t\t\tlet junk = m[k+1];\n\t\t\t\t\t\t\t\tlet junkIdx = idxAcc + groupLen;\n\n\t\t\t\t\t\t\t\tif (junk.length >= termLen) {\n\t\t\t\t\t\t\t\t\tlet idxOf = 0;\n\t\t\t\t\t\t\t\t\tlet found = false;\n\t\t\t\t\t\t\t\t\tlet re = new RegExp(term, 'ig' + uFlag);\n\n\t\t\t\t\t\t\t\t\tlet m2;\n\t\t\t\t\t\t\t\t\twhile (m2 = re.exec(junk)) {\n\t\t\t\t\t\t\t\t\t\tidxOf = m2.index;\n\n\t\t\t\t\t\t\t\t\t\tlet charIdx = junkIdx + idxOf;\n\t\t\t\t\t\t\t\t\t\tlet lftCharIdx = charIdx - 1;\n\n\t\t\t\t\t\t\t\t\t\tif (lftCharIdx == -1 || interBound.test(mhstr[lftCharIdx])) {\n\t\t\t\t\t\t\t\t\t\t\tlft2++;\n\t\t\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (intraBound.test(mhstr[lftCharIdx] + mhstr[charIdx])) {\n\t\t\t\t\t\t\t\t\t\t\tlft1++;\n\t\t\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (found) {\n\t\t\t\t\t\t\t\t\t\tisPre = true;\n\n\t\t\t\t\t\t\t\t\t\t// identical to exact term refinement pass above\n\t\t\t\t\t\t\t\t\t\trefine.push(idxAcc, groupLen, idxOf, termLen);\n\t\t\t\t\t\t\t\t\t\tidxAcc += refineMatch(m, k, idxOf, termLen);\n\t\t\t\t\t\t\t\t\t\tgroup = term;\n\t\t\t\t\t\t\t\t\t\tgroupLen = termLen;\n\t\t\t\t\t\t\t\t\t\tfullMatch = true;\n\n\t\t\t\t\t\t\t\t\t\tif (j == 0)\n\t\t\t\t\t\t\t\t\t\t\tstart = idxAcc;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (!isPre) {\n\t\t\t\t\t\t\t\t\tdisc = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// suffix info\n\t\t\t\t\tif (rgtCharIdx == mhstr.length || interBound.test(mhstr[rgtCharIdx])) {\n\t\t\t\t\t\tfullMatch && rgt2++;\n\t\t\t\t\t\tisSuf = true;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (interRgt == 2) {\n\t\t\t\t\t\t\tdisc = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (withIntraBound && intraBound.test(mhstr[rgtCharIdx - 1] + mhstr[rgtCharIdx])) {\n\t\t\t\t\t\t\tfullMatch && rgt1++;\n\t\t\t\t\t\t\tisSuf = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif (interRgt == 1) {\n\t\t\t\t\t\t\t\tdisc = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (fullMatch) {\n\t\t\t\t\t\tchars += termLen;\n\n\t\t\t\t\t\tif (isPre && isSuf)\n\t\t\t\t\t\t\tterms++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (groupLen > termLen)\n\t\t\t\t\tintra += groupLen - termLen; // intraFuzz\n\n\t\t\t\tif (j > 0)\n\t\t\t\t\tinter += m[k-1].length; // interFuzz\n\n\t\t\t\t// TODO: group here is lowercased, which is okay for length cmp, but not more case-sensitive filts\n\t\t\t\tif (!opts.intraFilt(term, group, idxAcc)) {\n\t\t\t\t\tdisc = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (j < partsLen - 1)\n\t\t\t\t\tidxAcc += groupLen + m[k+1].length;\n\t\t\t}\n\n\t\t\tif (!disc) {\n\t\t\t\tinfo.idx[ii] = idxs[i];\n\t\t\t\tinfo.interLft2[ii] = lft2;\n\t\t\t\tinfo.interLft1[ii] = lft1;\n\t\t\t\tinfo.interRgt2[ii] = rgt2;\n\t\t\t\tinfo.interRgt1[ii] = rgt1;\n\t\t\t\tinfo.chars[ii] = chars;\n\t\t\t\tinfo.terms[ii] = terms;\n\t\t\t\tinfo.cases[ii] = cases;\n\t\t\t\tinfo.interIns[ii] = inter;\n\t\t\t\tinfo.intraIns[ii] = intra;\n\n\t\t\t\tinfo.start[ii] = start;\n\t\t\t//\tinfo.span[ii] = span;\n\n\t\t\t\t// ranges\n\t\t\t\tlet m = mhstr.match(queryR);\n\n\t\t\t\tlet idxAcc = m.index + m[1].length;\n\n\t\t\t\tlet refLen = refine.length;\n\t\t\t\tlet ri = refLen > 0 ? 0 : Infinity;\n\t\t\t\tlet lastRi = refLen - 4;\n\n\t\t\t\tfor (let i = 2; i < m.length;) {\n\t\t\t\t\tlet len = m[i].length;\n\n\t\t\t\t\tif (ri <= lastRi && refine[ri] == idxAcc) {\n\t\t\t\t\t\tlet groupLen = refine[ri+1];\n\t\t\t\t\t\tlet idxOf = refine[ri+2];\n\t\t\t\t\t\tlet termLen = refine[ri+3];\n\n\t\t\t\t\t\t// advance to end of original (full) group match that includes intra-junk\n\t\t\t\t\t\tlet j = i;\n\t\t\t\t\t\tlet v = '';\n\t\t\t\t\t\tfor (let _len = 0; _len < groupLen; j++) {\n\t\t\t\t\t\t\tv += m[j];\n\t\t\t\t\t\t\t_len += m[j].length;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tm.splice(i, j - i, v);\n\n\t\t\t\t\t\tidxAcc += refineMatch(m, i, idxOf, termLen);\n\n\t\t\t\t\t\tri += 4;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tidxAcc += len;\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tidxAcc = m.index + m[1].length;\n\n\t\t\t\tlet ranges = info.ranges[ii] = [];\n\t\t\t\tlet from = idxAcc;\n\t\t\t\tlet to = idxAcc;\n\n\t\t\t\tfor (let i = 2; i < m.length; i++) {\n\t\t\t\t\tlet len = m[i].length;\n\n\t\t\t\t\tidxAcc += len;\n\n\t\t\t\t\tif (i % 2 == 0)\n\t\t\t\t\t\tto = idxAcc;\n\t\t\t\t\telse if (len > 0) {\n\t\t\t\t\t\tranges.push(from, to);\n\t\t\t\t\t\tfrom = to = idxAcc;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (to > from)\n\t\t\t\t\tranges.push(from, to);\n\n\t\t\t\tii++;\n\t\t\t}\n\t\t}\n\n\t\t// trim arrays\n\t\tif (ii < idxs.length) {\n\t\t\tfor (let k in info)\n\t\t\t\tinfo[k] = info[k].slice(0, ii);\n\t\t}\n\n\t\treturn info;\n\t};\n\n\tconst refineMatch = (m, k, idxInNext, termLen) => {\n\t\t// shift the current group into the prior junk\n\t\tlet prepend = m[k] + m[k+1].slice(0, idxInNext);\n\t\tm[k-1] += prepend;\n\t\tm[k] = m[k+1].slice(idxInNext, idxInNext + termLen);\n\t\tm[k+1] = m[k+1].slice(idxInNext + termLen);\n\t\treturn prepend.length;\n\t};\n\n\tconst OOO_TERMS_LIMIT = 5;\n\n\t// returns [idxs, info, order]\n\tconst _search = (haystack, needle, outOfOrder, infoThresh = 1e3, preFiltered) => {\n\t\toutOfOrder = !outOfOrder ? 0 : outOfOrder === true ? OOO_TERMS_LIMIT : outOfOrder;\n\n\t\tlet needles = null;\n\t\tlet matches = null;\n\n\t\tlet negs = [];\n\n\t\tneedle = needle.replace(NEGS_RE, m => {\n\t\t\tlet neg = m.trim().slice(1);\n\n\t\t\tneg = neg[0] === '\"' ? escapeRegExp(neg.slice(1,-1)) : neg.replace(PUNCT_RE, '');\n\n\t\t\tif (neg != '')\n\t\t\t\tnegs.push(neg);\n\n\t\t\treturn '';\n\t\t});\n\n\t\tlet terms = split(needle);\n\n\t\tlet negsRe;\n\n\t\tif (negs.length > 0) {\n\t\t\tnegsRe = new RegExp(negs.join('|'), 'i' + uFlag);\n\n\t\t\tif (terms.length == 0) {\n\t\t\t\tlet idxs = [];\n\n\t\t\t\tfor (let i = 0; i < haystack.length; i++) {\n\t\t\t\t\tif (!negsRe.test(haystack[i]))\n\t\t\t\t\t\tidxs.push(i);\n\t\t\t\t}\n\n\t\t\t\treturn [idxs, null, null];\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// abort search (needle is empty after pre-processing, e.g. no alpha-numeric chars)\n\t\t\tif (terms.length == 0)\n\t\t\t\treturn [null, null, null];\n\t\t}\n\n\t//\tconsole.log(negs);\n\t//\tconsole.log(needle);\n\n\t\tif (outOfOrder > 0) {\n\t\t\t// since uFuzzy is an AND-based search, we can iteratively pre-reduce the haystack by searching\n\t\t\t// for each term in isolation before running permutations on what's left.\n\t\t\t// this is a major perf win. e.g. searching \"test man ger pp a\" goes from 570ms -> 14ms\n\t\t\tlet terms = split(needle);\n\n\t\t\tif (terms.length > 1) {\n\t\t\t\t// longest -> shortest\n\t\t\t\tlet terms2 = terms.slice().sort((a, b) => b.length - a.length);\n\n\t\t\t\tfor (let ti = 0; ti < terms2.length; ti++) {\n\t\t\t\t\t// no haystack item contained all terms\n\t\t\t\t\tif (preFiltered?.length == 0)\n\t\t\t\t\t\treturn [[], null, null];\n\n\t\t\t\t\tpreFiltered = filter(haystack, terms2[ti], preFiltered);\n\t\t\t\t}\n\n\t\t\t\t// avoid combinatorial explosion by limiting outOfOrder to 5 terms (120 max searches)\n\t\t\t\t// fall back to just filter() otherwise\n\t\t\t\tif (terms.length > outOfOrder)\n\t\t\t\t\treturn [preFiltered, null, null];\n\n\t\t\t\tneedles = permute(terms).map(perm => perm.join(' '));\n\n\t\t\t\t// filtered matches for each needle excluding same matches for prior needles\n\t\t\t\tmatches = [];\n\n\t\t\t\t// keeps track of already-matched idxs to skip in follow-up permutations\n\t\t\t\tlet matchedIdxs = new Set();\n\n\t\t\t\tfor (let ni = 0; ni < needles.length; ni++) {\n\t\t\t\t\tif (matchedIdxs.size < preFiltered.length) {\n\t\t\t\t\t\t// filter further for this needle, exclude already-matched\n\t\t\t\t\t\tlet preFiltered2 = preFiltered.filter(idx => !matchedIdxs.has(idx));\n\n\t\t\t\t\t\tlet matched = filter(haystack, needles[ni], preFiltered2);\n\n\t\t\t\t\t\tfor (let j = 0; j < matched.length; j++)\n\t\t\t\t\t\t\tmatchedIdxs.add(matched[j]);\n\n\t\t\t\t\t\tmatches.push(matched);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tmatches.push([]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// interOR\n\t//\tconsole.log(prepQuery(needle, 1, null, true));\n\n\t\t// non-ooo or ooo w/single term\n\t\tif (needles == null) {\n\t\t\tneedles = [needle];\n\t\t\tmatches = [preFiltered?.length > 0 ? preFiltered : filter(haystack, needle)];\n\t\t}\n\n\t\tlet retInfo = null;\n\t\tlet retOrder = null;\n\n\t\tif (negs.length > 0)\n\t\t\tmatches = matches.map(idxs => idxs.filter(idx => !negsRe.test(haystack[idx])));\n\n\t\tlet matchCount = matches.reduce((acc, idxs) => acc + idxs.length, 0);\n\n\t\t// rank, sort, concat\n\t\tif (matchCount <= infoThresh) {\n\t\t\tretInfo = {};\n\t\t\tretOrder = [];\n\n\t\t\tfor (let ni = 0; ni < matches.length; ni++) {\n\t\t\t\tlet idxs = matches[ni];\n\n\t\t\t\tif (idxs == null || idxs.length == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tlet needle = needles[ni];\n\t\t\t\tlet _info = info(idxs, haystack, needle);\n\t\t\t\tlet order = opts.sort(_info, haystack, needle, compare);\n\n\t\t\t\t// offset idxs for concat'ing infos\n\t\t\t\tif (ni > 0) {\n\t\t\t\t\tfor (let i = 0; i < order.length; i++)\n\t\t\t\t\t\torder[i] += retOrder.length;\n\t\t\t\t}\n\n\t\t\t\tfor (let k in _info)\n\t\t\t\t\tretInfo[k] = (retInfo[k] ?? []).concat(_info[k]);\n\n\t\t\t\tretOrder = retOrder.concat(order);\n\t\t\t}\n\t\t}\n\n\t\treturn [\n\t\t\t[].concat(...matches),\n\t\t\tretInfo,\n\t\t\tretOrder,\n\t\t];\n\t};\n\n\treturn {\n\t\tsearch: (...args) => {\n\t\t\tlet out = _search(...args);\n\t\t\treturn out;\n\t\t},\n\t\tsplit,\n\t\tfilter,\n\t\tinfo,\n\t\tsort: opts.sort,\n\t};\n}\n\nconst latinize = (() => {\n\tlet accents = {\n\t\tA: 'ÁÀÃÂÄĄĂÅ',\n\t\ta: 'áàãâäąăå',\n\t\tE: 'ÉÈÊËĖĚ',\n\t\te: 'éèêëęě',\n\t\tI: 'ÍÌÎÏĮİ',\n\t\ti: 'íìîïįı',\n\t\tO: 'ÓÒÔÕÖ',\n\t\to: 'óòôõö',\n\t\tU: 'ÚÙÛÜŪŲŮŰ',\n\t\tu: 'úùûüūųůű',\n\t\tC: 'ÇČĆ',\n\t\tc: 'çčć',\n\t\tD: 'Ď',\n\t\td: 'ď',\n\t\tG: 'Ğ',\n\t\tg: 'ğ',\n\t\tL: 'Ł',\n\t\tl: 'ł',\n\t\tN: 'ÑŃŇ',\n\t\tn: 'ñńň',\n\t\tS: 'ŠŚȘŞ',\n\t\ts: 'šśșş',\n\t\tT: 'ŢȚŤ',\n\t\tt: 'ţțť',\n\t\tY: 'Ý',\n\t\ty: 'ý',\n\t\tZ: 'ŻŹŽ',\n\t\tz: 'żźž'\n\t};\n\n\t// str.normalize(\"NFD\").replace(/\\p{Diacritic}/gu, \"\")\n\n\tlet accentsMap = {};\n\tlet accentsTpl = '';\n\n\tfor (let r in accents) {\n\t\taccents[r].split('').forEach(a => {\n\t\t\taccentsTpl += a;\n\t\t\taccentsMap[a] = r;\n\t\t});\n\t}\n\n\tlet accentsRe = new RegExp(`[${accentsTpl}]`, 'g');\n\tlet replacer = m => accentsMap[m];\n\n\treturn strings => {\n\t\tif (typeof strings == 'string')\n\t\t\treturn strings.replace(accentsRe, replacer);\n\n\t\tlet out = Array(strings.length);\n\t\tfor (let i = 0; i < strings.length; i++)\n\t\t\tout[i] = strings[i].replace(accentsRe, replacer);\n\t\treturn out;\n\t};\n})();\n\n// https://stackoverflow.com/questions/9960908/permutations-in-javascript/37580979#37580979\nfunction permute(arr) {\n\tarr = arr.slice();\n\n\tlet length = arr.length,\n\t\tresult = [arr.slice()],\n\t\tc = new Array(length).fill(0),\n\t\ti = 1, k, p;\n\n\twhile (i < length) {\n\t\tif (c[i] < i) {\n\t\t\tk = i % 2 && c[i];\n\t\t\tp = arr[i];\n\t\t\tarr[i] = arr[k];\n\t\t\tarr[k] = p;\n\t\t\t++c[i];\n\t\t\ti = 1;\n\t\t\tresult.push(arr.slice());\n\t\t} else {\n\t\t\tc[i] = 0;\n\t\t\t++i;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nconst _mark = (part, matched) => matched ? `<mark>${part}</mark>` : part;\nconst _append = (acc, part) => acc + part;\n\nfunction highlight(str, ranges, mark = _mark, accum = '', append = _append) {\n\taccum = append(accum, mark(str.substring(0, ranges[0]), false)) ?? accum;\n\n\tfor (let i = 0; i < ranges.length; i+=2) {\n\t\tlet fr = ranges[i];\n\t\tlet to = ranges[i+1];\n\n\t\taccum = append(accum, mark(str.substring(fr, to), true)) ?? accum;\n\n\t\tif (i < ranges.length - 3)\n\t\t\taccum = append(accum, mark(str.substring(ranges[i+1], ranges[i+2]), false)) ?? accum;\n\t}\n\n\taccum = append(accum, mark(str.substring(ranges[ranges.length - 1]), false)) ?? accum;\n\n\treturn accum;\n}\n\nuFuzzy.latinize = latinize;\nuFuzzy.permute = arr => {\n\tlet idxs = permute([...Array(arr.length).keys()]).sort((a,b) => {\n\t\tfor (let i = 0; i < a.length; i++) {\n\t\t\tif (a[i] != b[i])\n\t\t\t\treturn a[i] - b[i];\n\t\t}\n\t\treturn 0;\n\t});\n\n\treturn idxs.map(pi => pi.map(i => arr[i]));\n};\nuFuzzy.highlight = highlight;\n\nmodule.exports = uFuzzy;\n","/**\n * Fuzzy Search Engine Adapter\n * Implements the SearchEngine interface using uFuzzy library\n * Clean, focused implementation - formatting handled by separate formatters\n */\n\nimport uFuzzy from '@leeoniya/ufuzzy'\nimport type { SearchEngine, SearchResult, SearchOptions } from './searchAdapter'\nimport { glob } from 'glob'\nimport { readFileSync } from 'node:fs'\nimport { join, basename } from 'node:path'\n\n/**\n * uFuzzy-based Search Engine Adapter\n * Clean implementation focused only on search functionality\n */\nexport class FuzzySearchAdapter implements SearchEngine {\n private documents: Array<{\n id: string\n title: string\n content: string\n source: 'user' | 'context7'\n file_path: string\n metadata: any\n }> = []\n\n private fuzzy: uFuzzy\n private lastSearchInfo: Map<string, any> = new Map()\n\n constructor() {\n // Initialize uFuzzy with sensible defaults\n this.fuzzy = new uFuzzy({\n unicode: true,\n })\n }\n\n async buildIndex(referencesDir: string): Promise<void> {\n console.log('🔨 Building fuzzy search index with uFuzzy...')\n\n const files = await glob('**/*.md', { cwd: referencesDir })\n\n if (files.length === 0) {\n console.log('No documentation files found to index')\n return\n }\n\n this.documents = []\n\n for (const filePath of files) {\n try {\n const fullPath = join(referencesDir, filePath)\n const content = readFileSync(fullPath, 'utf-8')\n\n // Extract title from first line or filename\n const lines = content.split('\\n')\n const title =\n lines[0]?.replace(/^#+\\s*/, '').trim() || basename(filePath, '.md').replace(/[-_]/g, ' ')\n\n const source = filePath.includes('context7/') ? 'context7' : 'user'\n\n this.documents.push({\n id: filePath,\n title,\n content,\n source,\n file_path: fullPath,\n metadata: {\n file_name: basename(filePath),\n file_path: filePath,\n },\n })\n } catch (error) {\n console.warn(`Warning: Failed to index file ${filePath}:`, error)\n }\n }\n\n console.log(`✅ Fuzzy search index built with ${this.documents.length} documents`)\n }\n\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { topK = 5, where } = options\n\n if (this.documents.length === 0) {\n console.warn('Search index not built. Call buildIndex() first.')\n return []\n }\n\n // Filter documents by source if specified\n let searchableDocs = this.documents\n if (where?.source) {\n searchableDocs = this.documents.filter((doc) => doc.source === where.source)\n }\n\n if (searchableDocs.length === 0) {\n return []\n }\n\n const results: SearchResult[] = []\n const seenIds = new Set<string>()\n\n // Prepare search arrays\n const titles = searchableDocs.map((doc) => doc.title)\n const contents = searchableDocs.map((doc) => doc.content)\n const fileNames = searchableDocs.map((doc) => doc.metadata.file_name)\n\n // Search in titles (highest priority - score 1.0)\n const titleMatches = this.fuzzySearch(titles, query)\n titleMatches.forEach((idx) => {\n const doc = searchableDocs[idx]\n if (doc && !seenIds.has(doc.id)) {\n seenIds.add(doc.id)\n results.push({\n id: doc.id,\n title: doc.title,\n content: doc.content,\n source: doc.source,\n file_path: doc.file_path,\n score: 1.0,\n metadata: {\n ...doc.metadata,\n matchType: 'title',\n },\n })\n }\n })\n\n // Search in content (medium priority - score 0.7)\n const contentMatches = this.fuzzySearch(contents, query)\n contentMatches.forEach((idx) => {\n const doc = searchableDocs[idx]\n if (doc && !seenIds.has(doc.id)) {\n seenIds.add(doc.id)\n results.push({\n id: doc.id,\n title: doc.title,\n content: doc.content,\n source: doc.source,\n file_path: doc.file_path,\n score: 0.7,\n metadata: {\n ...doc.metadata,\n matchType: 'content',\n },\n })\n }\n })\n\n // Search in file names (lowest priority - score 0.5)\n const fileNameMatches = this.fuzzySearch(fileNames, query)\n fileNameMatches.forEach((idx) => {\n const doc = searchableDocs[idx]\n if (doc && !seenIds.has(doc.id)) {\n seenIds.add(doc.id)\n results.push({\n id: doc.id,\n title: doc.title,\n content: doc.content,\n source: doc.source,\n file_path: doc.file_path,\n score: 0.5,\n metadata: {\n ...doc.metadata,\n matchType: 'filename',\n },\n })\n }\n })\n\n // Sort by score and limit to topK\n return results.sort((a, b) => b.score - a.score).slice(0, topK)\n }\n\n /**\n * Basic fuzzy search using uFuzzy\n */\n private fuzzySearch(haystack: string[], needle: string): number[] {\n const result = this.fuzzySearchWithInfo(haystack, needle)\n return result.indices\n }\n\n /**\n * Enhanced fuzzy search that returns both indices and detailed info\n */\n private fuzzySearchWithInfo(\n haystack: string[],\n needle: string\n ): {\n indices: number[]\n info: any\n } {\n if (!needle || needle.length < 1) return { indices: [], info: null }\n if (!haystack || haystack.length === 0) return { indices: [], info: null }\n\n const idxs = this.fuzzy.filter(haystack, needle)\n\n if (!idxs || idxs.length === 0) {\n return { indices: [], info: null }\n }\n\n const info = this.fuzzy.info(idxs, haystack, needle)\n const order = this.fuzzy.sort(info, haystack, needle)\n\n // Store info for later use\n const searchKey = `${needle}-${JSON.stringify(haystack.slice(0, 3))}`\n this.lastSearchInfo.set(searchKey, info)\n\n const indices = order.map((sortedIdx: number) => {\n return info.idx[sortedIdx]\n })\n\n return { indices, info }\n }\n\n isBuilt(): boolean {\n return this.documents.length > 0\n }\n\n async getStats(): Promise<{ totalDocuments: number }> {\n return { totalDocuments: this.documents.length }\n }\n\n async searchByPriority(query: string, topK: number = 5): Promise<SearchResult[]> {\n // For fuzzy search, this is the same as regular search\n return this.search(query, { topK })\n }\n\n clearIndex(): void {\n this.documents = []\n this.lastSearchInfo.clear()\n }\n}\n","/**\n * 端口管理工具\n * 用于动态分配和管理 ChromaDB 服务器端口\n */\n\nimport { AddressInfo, createServer } from 'node:net'\nimport { promisify } from 'node:util'\nimport { createRequire } from 'node:module'\n\n/**\n * 查找可用的端口\n * @param startPort 起始端口号\n * @param maxPort 最大端口号\n * @returns 可用的端口号\n */\nexport async function findAvailablePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const tryPort = () => {\n const server = createServer()\n\n server.listen(0, () => {\n const actualPort = (server.address() as AddressInfo)?.port\n server.close(() => {\n resolve(actualPort)\n })\n })\n }\n\n tryPort()\n })\n}\n\n/**\n * 检查端口是否可用\n * @param port 端口号\n * @returns 端口是否可用\n */\nexport async function isPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer()\n\n server.listen(port, () => {\n const actualPort = (server.address() as any)?.port\n server.close(() => {\n resolve(actualPort === port)\n })\n })\n\n server.on('error', () => {\n resolve(false)\n })\n })\n}\n\n/**\n * 等待端口上的服务启动\n * @param port 端口号\n * @param timeout 超时时间(毫秒)\n * @returns 服务是否成功启动\n */\nexport async function waitForService(port: number, timeout: number = 10000): Promise<boolean> {\n return new Promise((resolve) => {\n const startTime = Date.now()\n\n const checkService = () => {\n if (Date.now() - startTime > timeout) {\n resolve(false)\n return\n }\n\n const require = createRequire(import.meta.url)\n const socket = new (require('net').Socket)()\n\n socket.setTimeout(1000)\n\n socket.connect(port, 'localhost', () => {\n socket.destroy()\n resolve(true)\n })\n\n socket.on('error', () => {\n setTimeout(checkService, 500)\n })\n\n socket.on('timeout', () => {\n socket.destroy()\n setTimeout(checkService, 500)\n })\n }\n\n checkService()\n })\n}\n\n/**\n * 端口管理器类\n */\nexport class PortManager {\n private usedPorts: Set<number> = new Set()\n private basePort: number\n\n constructor(basePort: number = 8000) {\n this.basePort = basePort\n }\n\n /**\n * 分配一个可用端口\n * @returns 分配的端口号\n */\n async allocatePort(): Promise<number> {\n let port = this.basePort\n\n // 找到下一个可用端口\n while (this.usedPorts.has(port) || !(await isPortAvailable(port))) {\n port++\n }\n\n this.usedPorts.add(port)\n return port\n }\n\n /**\n * 释放端口\n * @param port 要释放的端口号\n */\n releasePort(port: number): void {\n this.usedPorts.delete(port)\n }\n\n /**\n * 获取当前已使用的端口数量\n */\n getUsedPortCount(): number {\n return this.usedPorts.size\n }\n\n /**\n * 清理所有端口\n */\n cleanup(): void {\n this.usedPorts.clear()\n }\n}\n","/**\n * ChromaDB Server Manager\n * Manages on-demand ChromaDB server startup and shutdown with process isolation\n */\n\nimport { spawn, ChildProcess } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport path, { join, dirname } from 'node:path'\nimport { createRequire } from 'node:module'\nimport { findAvailablePort, waitForService } from './portUtils.js'\n\nexport interface ChromaServerConfig {\n /** 技能目录路径 */\n skillDir: string\n /** 临时目录名称 */\n tempDirName?: string\n /** 端口号(可选,如果不指定会自动分配) */\n port?: number\n /** 服务器启动超时时间(毫秒) */\n startupTimeout?: number\n}\n\nexport interface ChromaServerInfo {\n /** 端口号 */\n port: number\n /** 数据目录路径 */\n dataPath: string\n /** 进程实例 */\n process: ChildProcess\n /** 配置信息 */\n config: ChromaServerConfig\n}\n\nexport class ChromaServerManager {\n private static instance: ChromaServerManager | null = null\n private servers: Map<string, ChromaServerInfo> = new Map()\n private chromaCliPath: string | null = null\n\n private constructor() {}\n\n /**\n * 获取单例实例\n */\n static getInstance(): ChromaServerManager {\n if (!ChromaServerManager.instance) {\n ChromaServerManager.instance = new ChromaServerManager()\n }\n return ChromaServerManager.instance\n }\n\n /**\n * 初始化 ChromaDB CLI 路径\n */\n private async initChromaCliPath(): Promise<string> {\n if (this.chromaCliPath) return this.chromaCliPath\n\n try {\n // 首先尝试从当前项目目录查找\n let projectDir = process.cwd()\n\n // 如果我们在 skill 目录中,需要向上查找找到包含 node_modules 的项目根目录\n while (!existsSync(join(projectDir, 'node_modules', 'chromadb')) && projectDir !== '/') {\n projectDir = dirname(projectDir)\n }\n\n const nodeModulesPath = join(projectDir, 'node_modules')\n const chromaDir = join(nodeModulesPath, 'chromadb')\n const cliPath = join(chromaDir, 'dist', 'cli.mjs')\n\n if (existsSync(cliPath)) {\n console.log(`✅ Found ChromaDB CLI: ${cliPath}`)\n return (this.chromaCliPath = cliPath)\n } else {\n throw new Error(`ChromaDB CLI not found at ${cliPath}`)\n }\n } catch (error) {\n throw new Error(\n `Failed to locate ChromaDB CLI: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n }\n\n /**\n * 生成服务器唯一标识(基于skill目录)\n */\n private generateServerId(config: ChromaServerConfig): string {\n // 简化ID生成,直接使用skill目录的hash\n const hash = createHash('md5')\n hash.update(config.skillDir)\n return hash.digest('hex').substring(0, 12)\n }\n\n /**\n * 启动 ChromaDB 服务器(在独立进程中)\n */\n async startServer(config: ChromaServerConfig): Promise<ChromaServerInfo> {\n const chromaCliPath = await this.initChromaCliPath()\n\n const serverId = this.generateServerId(config)\n\n // 检查服务器是否已经运行\n if (this.servers.has(serverId)) {\n const existingServer = this.servers.get(serverId)!\n if (existingServer.process && !existingServer.process.killed) {\n console.log(`📡 ChromaDB 服务器已在运行 (端口: ${existingServer.port})`)\n return existingServer\n } else {\n // 清理死进程\n this.servers.delete(serverId)\n }\n }\n\n console.log('🚀 启动 ChromaDB 服务器...')\n\n // 分配端口\n const port = config.port || (await findAvailablePort())\n\n // 创建持久化目录:assets/chromadb\n const chromaDir = join(config.skillDir, 'chromadb')\n if (!existsSync(chromaDir)) {\n mkdirSync(chromaDir, { recursive: true })\n }\n\n console.log(`🔧 启动命令: chroma run --path ./chromadb --port ${port} --host localhost`)\n console.log(`📁 数据目录: ${chromaDir}`)\n console.log(`🌐 服务端口: ${port}`)\n console.log(`🔄 工作目录: ${config.skillDir}`)\n\n // 启动进程 - 从项目根目录启动以确保能找到依赖\n const subprocess = spawn(process.argv[0], [chromaCliPath, 'run', '--port', port.toString()], {\n stdio: 'ignore',\n detached: true,\n cwd: chromaDir,\n })\n subprocess.unref()\n\n subprocess.on('error', (error: Error) => {\n console.log('❌ ChromaDB 进程错误:', error.message)\n })\n\n subprocess.on('exit', (code: number | null, signal: string | null) => {\n console.log(`🔚 ChromaDB 进程退出 (code: ${code}, signal: ${signal})`)\n this.servers.delete(serverId)\n })\n\n // 等待服务器启动\n const startupTimeout = config.startupTimeout || 15000\n console.log(`⏳ 等待 ChromaDB 服务器启动 (超时: ${startupTimeout}ms)...`)\n\n const isStarted = await waitForService(port, startupTimeout)\n\n if (!isStarted) {\n subprocess.kill('SIGTERM')\n throw new Error(`ChromaDB 服务器启动超时 (端口: ${port})`)\n }\n\n console.log(`✅ ChromaDB 服务器启动成功 (端口: ${port})`)\n\n // 保存服务器信息\n const serverInfo: ChromaServerInfo = {\n port,\n dataPath: chromaDir,\n process: subprocess,\n config,\n }\n\n this.servers.set(serverId, serverInfo)\n return serverInfo\n }\n\n /**\n * 停止 ChromaDB 服务器\n */\n async stopServer(config: ChromaServerConfig): Promise<void> {\n const serverId = this.generateServerId(config)\n const serverInfo = this.servers.get(serverId)\n\n if (!serverInfo) {\n console.log('⚠️ ChromaDB 服务器未运行')\n return\n }\n\n console.log(`🛑 停止 ChromaDB 服务器 (端口: ${serverInfo.port})...`)\n\n try {\n // 尝试优雅关闭\n serverInfo.process.kill('SIGTERM')\n\n // 等待进程结束\n const timeout = setTimeout(() => {\n if (!serverInfo.process.killed) {\n console.log('⚡ 强制终止 ChromaDB 进程...')\n serverInfo.process.kill('SIGKILL')\n }\n }, 5000)\n\n serverInfo.process.on('exit', () => {\n clearTimeout(timeout)\n })\n\n this.servers.delete(serverId)\n console.log('✅ ChromaDB 服务器已停止')\n } catch (error) {\n console.error('❌ 停止 ChromaDB 服务器时出错:', error)\n }\n }\n\n /**\n * 停止所有服务器\n */\n async stopAllServers(): Promise<void> {\n const stopPromises = Array.from(this.servers.values()).map(async (serverInfo) => {\n try {\n serverInfo.process.kill('SIGTERM')\n } catch (error) {\n console.error(`停止服务器时出错 (端口: ${serverInfo.port}):`, error)\n }\n })\n\n await Promise.all(stopPromises)\n this.servers.clear()\n console.log('✅ 所有 ChromaDB 服务器已停止')\n }\n\n /**\n * 获取服务器信息\n */\n getServerInfo(config: ChromaServerConfig): ChromaServerInfo | null {\n const serverId = this.generateServerId(config)\n return this.servers.get(serverId) || null\n }\n\n /**\n * 检查服务器是否运行\n */\n isServerRunning(config: ChromaServerConfig): boolean {\n const serverInfo = this.getServerInfo(config)\n return serverInfo !== null && serverInfo.process && !serverInfo.process.killed\n }\n}\n","/**\n * ChromaDB Search Adapter\n * Implements on-demand ChromaDB search with automatic fallback to fuzzy search\n */\n\nimport { ChromaClient } from 'chromadb'\nimport { DefaultEmbeddingFunction } from '@chroma-core/default-embed'\nimport type { SearchEngine, SearchResult, SearchOptions } from './searchAdapter.js'\nimport { FuzzySearchAdapter } from './fuzzySearchAdapter.js'\nimport { ChromaServerManager } from './chromaServerManager.js'\n\nexport interface ChromaSearchOptions {\n /** 技能目录路径 */\n skillDir: string\n /** ChromaDB 集合名称 */\n collectionName: string\n /** 启动超时时间(毫秒) */\n startupTimeout?: number\n /** 是否启用自动回退 */\n enableFallback?: boolean\n}\n\nexport interface ChromaPreparedResult {\n /** ChromaDB 客户端 */\n client: ChromaClient\n /** 服务器信息 */\n serverInfo: {\n port: number\n dataPath: string\n }\n /** 是否需要自动关闭服务器 */\n shouldAutoShutdown: boolean\n}\n\n/**\n * ChromaDB Search Adapter\n * 支持按需启动、自动回退和优雅关闭\n */\nexport class ChromaSearchAdapter implements SearchEngine {\n private fuzzyAdapter: FuzzySearchAdapter\n private serverManager: ChromaServerManager\n private options: ChromaSearchOptions\n private isIndexBuilt = false\n private embeddingFunction: DefaultEmbeddingFunction\n\n constructor(options: ChromaSearchOptions) {\n this.options = options\n this.fuzzyAdapter = new FuzzySearchAdapter()\n this.serverManager = ChromaServerManager.getInstance()\n this.embeddingFunction = new DefaultEmbeddingFunction()\n }\n\n /**\n * 统一准备ChromaDB环境\n * 封装服务器启动、客户端创建和配置的通用逻辑\n */\n private async prepareChromadb(\n operation: 'search' | 'build-index' | 'clear-index' = 'search',\n autoShutdown: boolean = true\n ): Promise<ChromaPreparedResult> {\n // 检查服务器是否已运行\n const isServerRunning = this.serverManager.isServerRunning({\n skillDir: this.options.skillDir,\n })\n\n let serverInfo\n let shouldAutoShutdown = autoShutdown\n\n if (isServerRunning) {\n // 服务器已运行,获取现有信息\n serverInfo = this.serverManager.getServerInfo({\n skillDir: this.options.skillDir,\n })!\n console.log(`🔄 使用现有的 ChromaDB 服务器 (端口: ${serverInfo.port})`)\n shouldAutoShutdown = false // 现有服务器不自动关闭\n } else {\n // 启动新服务器\n serverInfo = await this.serverManager.startServer({\n skillDir: this.options.skillDir,\n startupTimeout: this.options.startupTimeout,\n })\n }\n\n // 创建ChromaDB客户端\n console.log(`🔗 连接到 ChromaDB: http://localhost:${serverInfo.port}`)\n const client = new ChromaClient({\n host: 'localhost',\n port: serverInfo.port,\n })\n\n // 测试连接\n try {\n await client.heartbeat()\n console.log(`✅ ChromaDB 连接成功`)\n } catch (error) {\n throw new Error(\n `ChromaDB 连接失败: ${error instanceof Error ? error.message : String(error)}`\n )\n }\n\n return {\n client,\n serverInfo: {\n port: serverInfo.port,\n dataPath: serverInfo.dataPath,\n },\n shouldAutoShutdown,\n }\n }\n\n /**\n * 安全关闭ChromaDB服务器\n */\n private async safeShutdownServer(\n serverInfo: { port: number; dataPath: string },\n shouldShutdown: boolean\n ): Promise<void> {\n if (!shouldShutdown) {\n console.log(`🔄 保持 ChromaDB 服务器运行 (端口: ${serverInfo.port})`)\n return\n }\n\n try {\n await this.serverManager.stopServer({\n skillDir: this.options.skillDir,\n })\n console.log(`✅ ChromaDB 服务器已关闭 (端口: ${serverInfo.port})`)\n } catch (error) {\n console.warn(`⚠️ 关闭 ChromaDB 服务器时出现警告:`, error)\n }\n }\n\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { topK = 5, where } = options\n\n try {\n console.log('🔍 启动 ChromaDB 搜索...')\n\n // 准备ChromaDB环境\n const { client, serverInfo, shouldAutoShutdown } = await this.prepareChromadb('search')\n\n try {\n // 获取或创建集合\n let collection\n try {\n collection = await client.getCollection({\n name: this.options.collectionName,\n embeddingFunction: this.embeddingFunction,\n })\n console.log(`📚 获取现有集合: ${this.options.collectionName}`)\n } catch (error) {\n if (!this.isIndexBuilt) {\n console.log(`⚠️ 集合不存在且索引未构建,跳过 ChromaDB 搜索`)\n throw new Error('ChromaDB 索引未构建')\n }\n throw error\n }\n\n // 检查是否有数据\n try {\n const count = await collection.count()\n if (count === 0) {\n console.log(`📭 集合为空,跳过 ChromaDB 搜索`)\n throw new Error('ChromaDB 集合为空')\n }\n } catch (error) {\n console.log(`⚠️ 无法获取集合计数,可能集合为空`)\n throw new Error('ChromaDB 集合不可访问')\n }\n\n // 执行搜索\n console.log(`🔎 查询 ChromaDB: \"${query}\"`)\n const results = await collection.query({\n queryTexts: [query],\n nResults: topK,\n })\n\n // 转换结果\n const searchResults: SearchResult[] = []\n if (results.ids[0] && results.ids[0].length > 0) {\n for (let i = 0; i < results.ids[0].length; i++) {\n const id = results.ids[0][i]\n const document = results.documents[0]?.[i]\n const metadata = results.metadatas[0]?.[i]\n const distance = results.distances?.[0]?.[i] || 1\n\n if (id && document) {\n // 将distance转换为similarity\n // ChromaDB使用不同的距离度量,这里使用更通用的转换方法\n let similarity: number\n\n if (distance <= 0) {\n // 完美匹配\n similarity = 1.0\n } else if (distance <= 1) {\n // 对于小距离使用线性转换\n similarity = 1 - distance\n } else {\n // 对于大距离使用归一化到0-0.3范围\n // 这确保即使距离很大,也不会完全为0\n similarity = Math.max(0.1, 0.3 / distance)\n }\n\n searchResults.push({\n id,\n title: (typeof metadata?.title === 'string'\n ? metadata.title\n : `Document ${id}`) as string,\n content: document,\n source: (metadata?.source === 'user' || metadata?.source === 'context7'\n ? metadata.source\n : 'user') as 'user' | 'context7',\n file_path: (typeof metadata?.file_path === 'string'\n ? metadata.file_path\n : `unknown/${id}`) as string,\n score: similarity,\n metadata: {\n ...metadata,\n similarity: distance,\n distance: distance,\n serverPort: serverInfo.port,\n indexedAt: new Date().toISOString(),\n },\n })\n }\n }\n }\n\n console.log(`✅ ChromaDB 搜索完成,找到 ${searchResults.length} 个结果`)\n return searchResults\n } finally {\n // 安全关闭服务器\n await this.safeShutdownServer(serverInfo, shouldAutoShutdown)\n }\n } catch (error) {\n console.log(`❌ ChromaDB 搜索失败: ${error instanceof Error ? error.message : String(error)}`)\n\n // 自动回退到模糊搜索\n if (this.options.enableFallback) {\n console.log('🔄 自动回退到模糊搜索...')\n return this.fuzzyAdapter.search(query, { topK, where })\n }\n\n throw error\n }\n }\n\n /**\n * 计算当前文件的hash映射 {filename: hash}\n */\n private async calculateFileHashes(referencesDir: string): Promise<Map<string, string>> {\n const fs = await import('node:fs')\n const { createHash } = await import('node:crypto')\n const { glob } = await import('glob')\n\n const files = await glob('**/*.md', { cwd: referencesDir })\n const fileHashes = new Map<string, string>()\n\n for (const file of files.sort()) {\n try {\n const fullPath = `${referencesDir}/${file}`\n const content = fs.readFileSync(fullPath, 'utf-8')\n const hash = createHash('sha256').update(content).digest('hex')\n fileHashes.set(file, hash)\n } catch (error) {\n console.warn(`⚠️ 计算文件hash失败 ${file}:`, error)\n }\n }\n\n return fileHashes\n }\n\n /**\n * 加载之前的文件hash缓存\n */\n private async loadFileHashCache(cacheFile: string): Promise<Map<string, string>> {\n const fs = await import('node:fs')\n const path = await import('node:path')\n\n // 确保缓存目录存在\n const cacheDir = path.dirname(cacheFile)\n if (!fs.existsSync(cacheDir)) {\n fs.mkdirSync(cacheDir, { recursive: true })\n }\n\n const fileHashes = new Map<string, string>()\n\n try {\n if (fs.existsSync(cacheFile)) {\n const content = fs.readFileSync(cacheFile, 'utf-8')\n const data = JSON.parse(content)\n Object.entries(data).forEach(([file, hash]) => {\n fileHashes.set(file, hash as string)\n })\n }\n } catch (error) {\n console.warn('⚠️ 读取文件hash缓存失败:', error)\n }\n\n return fileHashes\n }\n\n /**\n * 保存文件hash缓存\n */\n private async saveFileHashCache(\n cacheFile: string,\n fileHashes: Map<string, string>\n ): Promise<void> {\n const fs = await import('node:fs')\n\n try {\n const data = Object.fromEntries(fileHashes)\n fs.writeFileSync(cacheFile, JSON.stringify(data, null, 2))\n console.log('💾 已更新文件hash缓存')\n } catch (error) {\n console.warn('⚠️ 保存文件hash缓存失败:', error)\n }\n }\n\n /**\n * 分析文件变化\n */\n private analyzeFileChanges(\n currentHashes: Map<string, string>,\n previousHashes: Map<string, string>\n ): {\n added: string[]\n modified: string[]\n deleted: string[]\n } {\n const added: string[] = []\n const modified: string[] = []\n const deleted: string[] = []\n\n // 检查新增和修改的文件\n for (const [file, currentHash] of currentHashes) {\n const previousHash = previousHashes.get(file)\n if (!previousHash) {\n added.push(file)\n } else if (previousHash !== currentHash) {\n modified.push(file)\n }\n }\n\n // 检查删除的文件\n for (const file of previousHashes.keys()) {\n if (!currentHashes.has(file)) {\n deleted.push(file)\n }\n }\n\n return { added, modified, deleted }\n }\n\n /**\n * 获取或创建集合\n */\n private async getOrCreateCollection(client: any): Promise<any> {\n try {\n const collection = await client.getCollection({\n name: this.options.collectionName,\n embeddingFunction: this.embeddingFunction,\n })\n console.log(`📝 使用现有集合: ${this.options.collectionName}`)\n return collection\n } catch (error) {\n console.log(`📝 创建新集合: ${this.options.collectionName}`)\n return await client.createCollection({\n name: this.options.collectionName,\n embeddingFunction: this.embeddingFunction,\n })\n }\n }\n\n /**\n * 处理文件变化\n */\n private async processFileChanges(\n collection: any,\n referencesDir: string,\n changes: { added: string[]; modified: string[]; deleted: string[] }\n ): Promise<void> {\n const fs = await import('node:fs')\n const { join, relative } = await import('node:path')\n\n // 处理删除的文件\n if (changes.deleted.length > 0) {\n try {\n await collection.delete({\n ids: changes.deleted,\n })\n console.log(`🗑️ 已删除 ${changes.deleted.length} 个文档`)\n } catch (error) {\n console.warn('⚠️ 删除文档失败:', error)\n }\n }\n\n // 处理新增和修改的文件\n const filesToProcess = [...changes.added, ...changes.modified]\n if (filesToProcess.length > 0) {\n console.log(`📝 处理文件变更: 新增 ${changes.added.length}, 修改 ${changes.modified.length}`)\n\n // 分批处理\n const batchSize = 50\n for (let i = 0; i < filesToProcess.length; i += batchSize) {\n const batch = filesToProcess.slice(i, i + batchSize)\n const documents: string[] = []\n const ids: string[] = []\n const metadatas: any[] = []\n\n for (const file of batch) {\n try {\n const fullPath = join(referencesDir, file)\n const content = fs.readFileSync(fullPath, 'utf-8')\n\n // 提取标题\n const lines = content.split('\\n')\n const title = lines[0]?.replace(/^#+\\s*/, '').trim() || file.replace(/\\.md$/, '')\n\n documents.push(content)\n ids.push(file)\n metadatas.push({\n title,\n file_path: file,\n source: file.includes('context7/') ? 'context7' : 'user',\n file_name: file.split('/').pop() || file,\n updated_at: new Date().toISOString(),\n })\n } catch (error) {\n console.warn(`⚠️ 处理文件失败 ${file}:`, error)\n }\n }\n\n if (documents.length > 0) {\n // 先删除已存在的文档(用于修改的情况)\n const existingIds = ids.filter((id) => changes.modified.includes(id))\n if (existingIds.length > 0) {\n try {\n await collection.delete({\n ids: existingIds,\n })\n } catch (error) {\n // 忽略删除不存在的文档的错误\n }\n }\n\n // 添加新的文档\n await collection.add({\n ids,\n documents,\n metadatas,\n })\n console.log(\n `📚 已处理 ${Math.min(i + batchSize, filesToProcess.length)}/${filesToProcess.length} 个文档`\n )\n }\n }\n }\n }\n\n async buildIndex(referencesDir: string): Promise<void> {\n console.log('🔧 构建 ChromaDB 索引...')\n\n // 准备ChromaDB环境\n const { client, serverInfo, shouldAutoShutdown } = await this.prepareChromadb(\n 'build-index',\n false\n )\n\n try {\n // 计算当前文件的hash映射\n const currentFileHashes = await this.calculateFileHashes(referencesDir)\n\n // 读取之前的文件hash缓存\n const cacheFile = `${referencesDir}/../.cache/chroma-file-hashes.json`\n const previousFileHashes = await this.loadFileHashCache(cacheFile)\n\n // 分析文件变化\n const changes = this.analyzeFileChanges(currentFileHashes, previousFileHashes)\n\n console.log(\n `📊 文件变化分析: 新增 ${changes.added.length}, 修改 ${changes.modified.length}, 删除 ${changes.deleted.length}`\n )\n\n if (\n changes.added.length === 0 &&\n changes.modified.length === 0 &&\n changes.deleted.length === 0\n ) {\n console.log('✅ 文件未变化,跳过索引重建')\n this.isIndexBuilt = true\n return\n }\n\n // 获取或创建集合\n const collection = await this.getOrCreateCollection(client)\n\n // 处理文件变化\n await this.processFileChanges(collection, referencesDir, changes)\n\n // 保存新的文件hash缓存\n await this.saveFileHashCache(cacheFile, currentFileHashes)\n\n // 验证索引\n const count = await collection.count()\n console.log(`✅ ChromaDB 索引更新完成,当前包含 ${count} 个文档`)\n this.isIndexBuilt = true\n } finally {\n // 安全关闭服务器\n await this.safeShutdownServer(serverInfo, shouldAutoShutdown)\n }\n }\n\n async clearIndex(): Promise<void> {\n console.log('🗑️ 清除 ChromaDB 索引...')\n\n // 准备ChromaDB环境\n const { client, serverInfo, shouldAutoShutdown } = await this.prepareChromadb(\n 'clear-index',\n false\n )\n\n try {\n try {\n await client.deleteCollection({\n name: this.options.collectionName,\n })\n console.log('✅ ChromaDB 索引已清除')\n } catch (error) {\n console.log('⚠️ ChromaDB 集合不存在或已清除')\n }\n\n this.isIndexBuilt = false\n } finally {\n // 安全关闭服务器\n await this.safeShutdownServer(serverInfo, shouldAutoShutdown)\n }\n }\n\n isBuilt(): boolean {\n return this.isIndexBuilt\n }\n\n async getStats(): Promise<{ totalDocuments: number }> {\n try {\n // 准备ChromaDB环境\n const { client, shouldAutoShutdown } = await this.prepareChromadb('search')\n\n try {\n const collection = await client.getCollection({\n name: this.options.collectionName,\n embeddingFunction: this.embeddingFunction,\n })\n const count = await collection.count()\n return { totalDocuments: count }\n } finally {\n // 安全关闭服务器\n if (shouldAutoShutdown) {\n await this.serverManager.stopServer({\n skillDir: this.options.skillDir,\n })\n }\n }\n } catch (error) {\n console.log(`⚠️ 无法获取 ChromaDB 统计信息:`, error)\n return { totalDocuments: 0 }\n }\n }\n\n /**\n * 获取运行中的服务器状态\n */\n getServerStatus(): {\n isRunning: boolean\n } {\n const isRunning = this.serverManager.isServerRunning({\n skillDir: this.options.skillDir,\n })\n\n return { isRunning }\n }\n}\n","/**\n * Auto Search Adapter\n * Intelligently selects and switches between search engines based on query characteristics\n * and search quality evaluation\n */\n\nimport type { SearchEngine, SearchResult, SearchOptions } from './searchAdapter.js'\nimport { FuzzySearchAdapter } from './fuzzySearchAdapter.js'\nimport { ChromaSearchAdapter } from './chromaSearchAdapter.js'\n\nexport interface AutoSearchOptions {\n /** Skill directory for ChromaDB */\n skillDir: string\n /** ChromaDB collection name */\n collectionName: string\n /** Enable ChromaDB fallback on failure */\n enableChromaFallback?: boolean\n /** ChromaDB startup timeout in milliseconds */\n chromaStartupTimeout?: number\n /** Quality threshold for switching engines */\n qualityThreshold?: number\n}\n\n/**\n * Auto Search Adapter\n * Implements intelligent search engine selection and automatic switching\n */\nexport class AutoSearchAdapter implements SearchEngine {\n private fuzzyAdapter: FuzzySearchAdapter\n private chromaAdapter: ChromaSearchAdapter | null = null\n private options: AutoSearchOptions\n\n constructor(options: AutoSearchOptions) {\n this.options = options\n this.fuzzyAdapter = new FuzzySearchAdapter()\n\n // ChromaDB adapter created on-demand for better performance\n }\n\n private async getChromaAdapter(): Promise<ChromaSearchAdapter> {\n if (!this.chromaAdapter) {\n this.chromaAdapter = new ChromaSearchAdapter({\n skillDir: this.options.skillDir,\n collectionName: this.options.collectionName,\n startupTimeout: this.options.chromaStartupTimeout || 15000,\n enableFallback: this.options.enableChromaFallback || true,\n })\n }\n return this.chromaAdapter\n }\n\n async buildIndex(referencesDir: string): Promise<void> {\n // Always build fuzzy index (fast and reliable)\n await this.fuzzyAdapter.buildIndex(referencesDir)\n\n // Build ChromaDB index only if needed (on-demand)\n // This prevents unnecessary ChromaDB startup for simple searches\n }\n\n async search(query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n const { topK = 5, where } = options\n const qualityThreshold = this.options.qualityThreshold || 0.3\n\n console.log('🤖 Auto Mode: Starting with Fuzzy search...')\n\n // Always start with fuzzy search (fast, reliable, no external dependencies)\n const fuzzyResults = await this.fuzzyAdapter.search(query, { topK, where })\n\n // Evaluate search quality\n const quality = this.evaluateSearchQuality(fuzzyResults, query)\n console.log(`📊 Fuzzy search quality: ${quality.score.toFixed(2)} (${quality.reason})`)\n\n // If fuzzy search quality is good, return results\n if (quality.score >= qualityThreshold) {\n console.log('✅ Fuzzy search quality satisfactory, returning results')\n return fuzzyResults\n }\n\n // Try ChromaDB for better semantic understanding\n console.log('🔄 Fuzzy search quality below threshold, trying ChromaDB...')\n\n try {\n const chromaAdapter = await this.getChromaAdapter()\n const chromaResults = await chromaAdapter.search(query, { topK, where })\n console.log(`✅ ChromaDB search completed, found ${chromaResults.length} results`)\n return chromaResults\n } catch (error) {\n console.log(\n `❌ ChromaDB search failed, returning fuzzy results:`,\n error instanceof Error ? error.message : String(error)\n )\n return fuzzyResults\n }\n }\n\n /**\n * Evaluate search result quality\n */\n private evaluateSearchQuality(\n results: SearchResult[],\n query: string\n ): { score: number; reason: string } {\n if (results.length === 0) {\n return { score: 0, reason: 'No results found' }\n }\n\n // Quick win: check for exact matches\n const topResult = results[0]\n const queryLower = query.toLowerCase()\n\n if (topResult.title.toLowerCase().includes(queryLower)) {\n return { score: 1.0, reason: 'Exact title match found' }\n }\n\n // Check score distribution\n const scores = results.map((r) => r.score)\n const maxScore = Math.max(...scores)\n const avgScore = scores.reduce((sum, score) => sum + score, 0) / scores.length\n\n // High score threshold\n if (maxScore >= 0.8) {\n return { score: maxScore, reason: 'High quality matches found' }\n }\n\n // Multiple decent results\n if (results.length >= 3 && avgScore >= 0.5) {\n return { score: avgScore, reason: 'Multiple decent quality results' }\n }\n\n // Low quality indicators\n if (maxScore < 0.3) {\n return { score: maxScore, reason: 'Low quality matches only' }\n }\n\n if (results.length < 2) {\n return { score: maxScore * 0.8, reason: 'Too few results' }\n }\n\n // Default: return average score\n return { score: avgScore, reason: 'Average quality results' }\n }\n\n isBuilt(): boolean {\n return this.fuzzyAdapter.isBuilt()\n }\n\n async getStats(): Promise<{ totalDocuments: number }> {\n return this.fuzzyAdapter.getStats()\n }\n\n async searchByPriority(query: string, topK: number = 5): Promise<SearchResult[]> {\n return this.search(query, { topK })\n }\n\n clearIndex(): void {\n this.fuzzyAdapter.clearIndex()\n if (this.chromaAdapter) {\n this.chromaAdapter.clearIndex()\n }\n }\n}\n","/**\n * Search Engine Factory\n * Provides a simple way to create appropriate search engines based on options\n */\n\nimport type { SearchEngine } from './searchAdapter.js'\nimport { AutoSearchAdapter } from './autoSearchAdapter.js'\nimport { FuzzySearchAdapter } from './fuzzySearchAdapter.js'\nimport { ChromaSearchAdapter } from './chromaSearchAdapter.js'\nimport type { SkillConfig } from '../types/index.js'\n\nexport interface SearchEngineOptions {\n /** Search mode: auto, fuzzy, or chroma */\n mode?: 'auto' | 'fuzzy' | 'chroma'\n /** Skill directory for file operations */\n skillDir?: string\n /** References directory containing documentation */\n referencesDir?: string\n /** Skill configuration */\n config?: SkillConfig\n /** Additional options for adapters */\n adapterOptions?: {\n /** Enable ChromaDB fallback on failure */\n enableChromaFallback?: boolean\n /** ChromaDB startup timeout */\n chromaStartupTimeout?: number\n /** Auto search quality threshold */\n qualityThreshold?: number\n }\n}\n\n/**\n * Build and return appropriate search engine based on options\n */\nexport async function buildSearchEngine(options: SearchEngineOptions = {}): Promise<SearchEngine> {\n const { mode = 'auto', skillDir = '', referencesDir = '', config, adapterOptions = {} } = options\n\n switch (mode) {\n case 'auto':\n if (!config) {\n throw new Error('Config is required for auto mode')\n }\n\n return new AutoSearchAdapter({\n skillDir,\n collectionName: `skills`,\n enableChromaFallback: adapterOptions.enableChromaFallback ?? true,\n chromaStartupTimeout: adapterOptions.chromaStartupTimeout ?? 15000,\n qualityThreshold: adapterOptions.qualityThreshold ?? 0.3,\n })\n\n case 'fuzzy':\n return new FuzzySearchAdapter()\n\n case 'chroma':\n if (!config) {\n throw new Error('Config is required for chroma mode')\n }\n\n return new ChromaSearchAdapter({\n skillDir,\n collectionName: `skills`,\n startupTimeout: adapterOptions.chromaStartupTimeout ?? 15000,\n enableFallback: adapterOptions.enableChromaFallback ?? true,\n })\n\n default:\n throw new Error(`Invalid search mode: ${mode}. Use 'auto', 'fuzzy', or 'chroma'.`)\n }\n}\n","/**\n * Unified Search Engine\n * Acts as a coordinator between search adapters and formatters\n * Provides a clean interface for the complete search pipeline\n */\n\nimport { join } from 'node:path'\nimport type { SearchResult, SearchOptions } from './searchAdapter.js'\nimport type { SearchFormatter, FormattingOptions, FormattedResult } from '../search_format/types.js'\nimport { createFormatter } from '../search_format/index.js'\nimport type { SearchEngineOptions } from './searchEngineFactory.js'\nimport { buildSearchEngine } from './searchEngineFactory.js'\n\n/**\n * Unified search options including formatting preferences\n */\nexport interface UnifiedSearchOptions extends SearchEngineOptions {\n /** Output format: list, enhanced, or custom */\n format?: 'list' | 'enhanced' | string\n /** Skill path for relative path calculation */\n skillPath?: string\n /** Formatting options */\n formatting?: {\n maxPreviewLength?: number\n showFullContentThreshold?: number\n minScoreForPreview?: number\n showLineNumbers?: boolean\n }\n}\n\n/**\n * Unified Search Engine\n * Coordinates search adapters with formatters for complete search experience\n */\nexport class UnifiedSearchEngine {\n private searchEngine: Awaited<ReturnType<typeof buildSearchEngine>> | null = null\n private formatter: SearchFormatter | null = null\n private options: UnifiedSearchOptions\n\n constructor(options: UnifiedSearchOptions) {\n this.options = options\n // Note: actual engine creation happens asynchronously\n }\n\n /**\n * Initialize the search engine\n */\n async initialize(): Promise<void> {\n const {\n skillDir = '',\n referencesDir = '',\n config,\n mode = 'auto',\n adapterOptions = {},\n } = this.options\n\n this.searchEngine = await buildSearchEngine({\n mode,\n skillDir,\n referencesDir,\n config,\n adapterOptions,\n })\n\n // Initialize formatter if format is specified\n if (this.options.format) {\n this.formatter = createFormatter(this.options.format as 'list' | 'enhanced')\n }\n }\n\n /**\n * Build search index\n */\n async buildIndex(referencesDir: string): Promise<void> {\n await this.ensureInitialized()\n if (this.searchEngine) {\n await this.searchEngine.buildIndex(referencesDir)\n }\n }\n\n /**\n * Search and optionally format results\n */\n async search(\n query: string,\n topK: number = 5,\n where?: Record<string, any>\n ): Promise<SearchResult[]> {\n await this.ensureInitialized()\n if (!this.searchEngine) {\n return []\n }\n return this.searchEngine.search(query, { topK, where })\n }\n\n /**\n * Search and return formatted results\n */\n async searchAndFormat(\n query: string,\n topK: number = 5,\n where?: Record<string, any>\n ): Promise<FormattedResult[]> {\n const results = await this.search(query, topK, where)\n\n if (!this.formatter) {\n throw new Error('No formatter configured. Use format option in constructor.')\n }\n\n const formattingOptions: FormattingOptions = {\n skillPath: this.options.skillPath || process.cwd(),\n maxPreviewLength: this.options.formatting?.maxPreviewLength || 200,\n showFullContentThreshold: this.options.formatting?.showFullContentThreshold || 0.15,\n minScoreForPreview: this.options.formatting?.minScoreForPreview || 0.1,\n showLineNumbers: this.options.formatting?.showLineNumbers ?? true,\n }\n\n return this.formatter.format(results, formattingOptions)\n }\n\n /**\n * Check if search index is built\n */\n async isBuilt(): Promise<boolean> {\n await this.ensureInitialized()\n return this.searchEngine?.isBuilt() || false\n }\n\n /**\n * Get search statistics\n */\n async getStats(): Promise<{ totalDocuments: number }> {\n await this.ensureInitialized()\n return this.searchEngine?.getStats() || { totalDocuments: 0 }\n }\n\n /**\n * Clear search index\n */\n async clearIndex(): Promise<void> {\n await this.ensureInitialized()\n if (this.searchEngine && 'clearIndex' in this.searchEngine) {\n this.searchEngine.clearIndex()\n }\n }\n\n /**\n * Ensure engine is initialized\n */\n private async ensureInitialized(): Promise<void> {\n if (!this.searchEngine) {\n await this.initialize()\n }\n }\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
package/templates/SKILL.md
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: |
|
|
3
|
-
{{ NAME }}
|
|
4
|
-
description: |
|
|
5
|
-
{{ DESCRIPTION }}
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# {{NAME}}
|
|
9
|
-
|
|
10
|
-
{{DESCRIPTION}}
|
|
11
|
-
|
|
12
|
-
## CLI Commands
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
# Add user content
|
|
16
|
-
skill-creator add-skill --pwd "{{SKILL_PATH}}" [--title "Title" --content "Content"]|[--file=*.md]
|
|
17
|
-
|
|
18
|
-
# Search documentation
|
|
19
|
-
skill-creator search-skill --pwd "{{SKILL_PATH}}" "query" [--mode=auto|chroma|fuzzy]
|
|
20
|
-
|
|
21
|
-
# Download Context7 docs
|
|
22
|
-
skill-creator download-context7 --pwd "{{SKILL_PATH}}" <context7_library_id>
|
|
23
|
-
|
|
24
|
-
# Update Context7 docs
|
|
25
|
-
skill-creator download-context7 --pwd "{{SKILL_PATH}}" --force [<context7_library_id>]
|
|
26
|
-
|
|
27
|
-
# List all Context7 projects
|
|
28
|
-
skill-creator list-context7 --pwd "{{SKILL_PATH}}"
|
|
29
|
-
|
|
30
|
-
# Remove Context7 project
|
|
31
|
-
skill-creator remove-context7 --pwd "{{SKILL_PATH}}" <context7_library_id>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## User Skills
|
|
35
|
-
|
|
36
|
-
<user-skills baseDir="assets/references/user">
|
|
37
|
-
</user-skills>
|
|
38
|
-
|
|
39
|
-
## Context7 Documentation
|
|
40
|
-
|
|
41
|
-
<!-- Context7 projects will be listed here automatically -->
|
package/templates/SKILL.zh-CN.md
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: |
|
|
3
|
-
{{ NAME }}
|
|
4
|
-
description: |
|
|
5
|
-
{{ DESCRIPTION }}
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
你是{{NAME}}专业领域助手,专门提供关于{{NAME}}库/框架的全面技术支持和文档查询服务。
|
|
9
|
-
|
|
10
|
-
## 关于{{NAME}}
|
|
11
|
-
|
|
12
|
-
{{DESCRIPTION}}
|
|
13
|
-
|
|
14
|
-
### 核心特性
|
|
15
|
-
|
|
16
|
-
- **智能搜索**: 基于ChromaDB的语义搜索,快速定位相关信息
|
|
17
|
-
- **动态内容管理**: 支持添加自定义知识点,智能去重和更新
|
|
18
|
-
- **Context7集成**: 自动获取和切片最新官方文档
|
|
19
|
-
- **优先级管理**: 用户生成内容优先于官方文档
|
|
20
|
-
|
|
21
|
-
### 设计理念
|
|
22
|
-
|
|
23
|
-
基于官方文档和社区最佳实践,确保信息的准确性和时效性
|
|
24
|
-
|
|
25
|
-
注重实用性,提供可直接应用的代码示例和配置方案
|
|
26
|
-
|
|
27
|
-
循序渐进,从基础概念到高级模式的完整学习路径
|
|
28
|
-
|
|
29
|
-
持续更新,跟随版本迭代不断优化和完善知识库
|
|
30
|
-
|
|
31
|
-
### 解决的问题
|
|
32
|
-
|
|
33
|
-
- **学习曲线复杂**: 通过结构化的知识点和实例,降低学习门槛
|
|
34
|
-
- **文档分散**: 整合官方文档、社区经验和实践案例,提供一站式参考
|
|
35
|
-
- **最佳实践缺失**: 总结常见设计模式和最佳实践,避免常见陷阱
|
|
36
|
-
- **版本更新困扰**: 及时跟踪版本变化,提供迁移指南和新增特性说明
|
|
37
|
-
|
|
38
|
-
## 使用指南
|
|
39
|
-
|
|
40
|
-
### 搜索文档知识点
|
|
41
|
-
|
|
42
|
-
查询{{NAME}}的相关信息、API使用、最佳实践等:
|
|
43
|
-
|
|
44
|
-
#### 基础搜索
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" "搜索关键词"
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
#### 搜索模式选择
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
# 自动模式(默认)- 智能选择搜索策略
|
|
54
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=auto "搜索关键词"
|
|
55
|
-
|
|
56
|
-
# ChromaDB模式 - 语义化搜索,理解上下文含义
|
|
57
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=chroma "搜索关键词"
|
|
58
|
-
|
|
59
|
-
# Fuzzy模式 - 关键字搜索,字符串模糊匹配
|
|
60
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=fuzzy "搜索关键词"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
#### 搜索模式详解
|
|
64
|
-
|
|
65
|
-
**🤖 Auto 模式(自动模式,默认)**
|
|
66
|
-
|
|
67
|
-
- **工作原理**: 首先使用 Fuzzy 搜索进行快速匹配,如果没有找到满意结果,自动切换到 ChromaDB 进行语义搜索
|
|
68
|
-
- **适用场景**:
|
|
69
|
-
- 不确定使用哪种搜索方式时
|
|
70
|
-
- 希望获得最佳搜索平衡时
|
|
71
|
-
- 日常快速查询需求
|
|
72
|
-
- **优势**: 智能切换,兼顾速度和准确性,用户体验最佳
|
|
73
|
-
|
|
74
|
-
**🧠 ChromaDB 模式(语义搜索)**
|
|
75
|
-
|
|
76
|
-
- **工作原理**: 基于向量数据库和语义模型,理解查询意图和上下文含义,进行概念匹配
|
|
77
|
-
- **适用场景**:
|
|
78
|
-
- 概念性查询("如何处理状态管理")
|
|
79
|
-
- 功能性搜索("数据验证的方法")
|
|
80
|
-
- 需要理解语义的复杂查询
|
|
81
|
-
- 查找相关的技术概念和最佳实践
|
|
82
|
-
- **优势**: 理解查询意图,能找到语义相关但关键词不完全匹配的内容,适合概念性搜索
|
|
83
|
-
- **特点**:
|
|
84
|
-
- 支持自然语言查询
|
|
85
|
-
- 能理解同义词和相关概念
|
|
86
|
-
- 基于语义相似度排序结果
|
|
87
|
-
- 需要构建搜索索引
|
|
88
|
-
|
|
89
|
-
**🔍 Fuzzy 模式(模糊搜索)**
|
|
90
|
-
|
|
91
|
-
- **工作原理**: 基于字符串模糊匹配算法,快速查找包含指定关键词的内容
|
|
92
|
-
- **适用场景**:
|
|
93
|
-
- 精确关键词搜索("useQuery"、"useState")
|
|
94
|
-
- API名称和方法查找
|
|
95
|
-
- 配置项和参数搜索
|
|
96
|
-
- 快速定位特定术语
|
|
97
|
-
- **优势**: 响应速度快,关键词匹配精确,适合查找具体的API、配置项、方法名等
|
|
98
|
-
- **特点**:
|
|
99
|
-
- 支持部分匹配和模糊匹配
|
|
100
|
-
- 搜索速度快,无需索引
|
|
101
|
-
- 基于关键词相似度排序
|
|
102
|
-
- 适合技术术语和代码片段搜索
|
|
103
|
-
|
|
104
|
-
#### 实用搜索示例
|
|
105
|
-
|
|
106
|
-
**API 和方法查询**(推荐 Fuzzy 模式):
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
# 查找特定API
|
|
110
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=fuzzy "useQuery"
|
|
111
|
-
|
|
112
|
-
# 查找配置选项
|
|
113
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=fuzzy "baseURL配置"
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**概念和最佳实践查询**(推荐 ChromaDB 模式):
|
|
117
|
-
|
|
118
|
-
```bash
|
|
119
|
-
# 概念性问题
|
|
120
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=chroma "如何优化React组件性能"
|
|
121
|
-
|
|
122
|
-
# 最佳实践
|
|
123
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=chroma "状态管理最佳实践"
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
**日常查询**(使用 Auto 模式):
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
# 让系统自动选择最佳搜索方式
|
|
130
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --mode=auto "错误处理"
|
|
131
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" "路由配置" # --mode=auto 是默认值
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
#### 列表模式显示
|
|
135
|
-
|
|
136
|
-
如果只需要查看简要信息,可以使用列表模式:
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
skill-creator search-skill --pwd="{{SKILL_PATH}}" --list "搜索关键词"
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
**示例查询:**
|
|
143
|
-
|
|
144
|
-
- "如何创建router"
|
|
145
|
-
- "状态管理最佳实践"
|
|
146
|
-
- "错误处理机制"
|
|
147
|
-
- "性能优化技巧"
|
|
148
|
-
- "TypeScript集成"
|
|
149
|
-
|
|
150
|
-
### 添加自定义知识点
|
|
151
|
-
|
|
152
|
-
当发现文档中缺少重要信息时,可以添加自己的知识点:
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
skill-creator add-skill --pwd="{{SKILL_PATH}}" --title "知识点标题" --content "详细内容"
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**添加内容类型:**
|
|
159
|
-
|
|
160
|
-
- 🚀 **最佳实践**: 项目中的实际经验和技巧
|
|
161
|
-
- ⚠️ **注意事项**: 容易出错的地方和解决方案
|
|
162
|
-
- 🔧 **配置技巧**: 特殊场景的配置方法
|
|
163
|
-
- 📚 **学习资源**: 相关教程和链接
|
|
164
|
-
- 🐛 **问题解决**: 常见问题和解决步骤
|
|
165
|
-
|
|
166
|
-
### 更新官方文档
|
|
167
|
-
|
|
168
|
-
获取最新的官方文档并重新切片:
|
|
169
|
-
|
|
170
|
-
**强制更新(覆盖现有文档):**
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
skill-creator download-context7 --pwd="{{SKILL_PATH}}" --force
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### 查看所有内容
|
|
177
|
-
|
|
178
|
-
列出技能中所有可用的知识点:
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
skill-creator list-skills --pwd="{{SKILL_PATH}}"
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## 文档结构说明
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
{{SKILL_PATH}}/
|
|
188
|
-
├── assets/
|
|
189
|
-
│ └── references/
|
|
190
|
-
│ ├── context7/ # 官方文档切片
|
|
191
|
-
│ └── user/ # 用户自定义知识点
|
|
192
|
-
├── config.json # 技能配置
|
|
193
|
-
├── SKILL.md # 本文件
|
|
194
|
-
└── package.json # 依赖管理
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## 内容优先级
|
|
198
|
-
|
|
199
|
-
1. **用户内容优先**: `user/` 文件夹中的自定义知识点具有最高优先级
|
|
200
|
-
2. **官方文档**: `context7/` 文件夹中的官方文档作为基础参考
|
|
201
|
-
3. **智能去重**: 添加内容时自动检测相似度,避免重复信息
|
|
202
|
-
4. **版本管理**: 支持文档版本控制和增量更新
|
|
203
|
-
|
|
204
|
-
## 搜索技巧
|
|
205
|
-
|
|
206
|
-
### 🔍 **精确搜索**
|
|
207
|
-
|
|
208
|
-
使用具体的技术术语:
|
|
209
|
-
|
|
210
|
-
- "useQuery hook用法"
|
|
211
|
-
- "路由守卫实现"
|
|
212
|
-
- "异步状态管理"
|
|
213
|
-
|
|
214
|
-
### 🎯 **场景化搜索**
|
|
215
|
-
|
|
216
|
-
基于使用场景:
|
|
217
|
-
|
|
218
|
-
- "在React项目中集成"
|
|
219
|
-
- "服务端渲染配置"
|
|
220
|
-
- "移动端优化"
|
|
221
|
-
|
|
222
|
-
### 📋 **对比搜索**
|
|
223
|
-
|
|
224
|
-
比较不同方案:
|
|
225
|
-
|
|
226
|
-
- "useState vs useReducer"
|
|
227
|
-
- "客户端路由 vs 服务端路由"
|
|
228
|
-
|
|
229
|
-
### 🔧 **问题导向搜索**
|
|
230
|
-
|
|
231
|
-
描述具体问题:
|
|
232
|
-
|
|
233
|
-
- "解决内存泄漏问题"
|
|
234
|
-
- "优化首次加载时间"
|
|
235
|
-
- "处理并发请求"
|
|
236
|
-
|
|
237
|
-
## 贡献指南
|
|
238
|
-
|
|
239
|
-
### 📝 **内容贡献**
|
|
240
|
-
|
|
241
|
-
- 添加实际项目经验和最佳实践
|
|
242
|
-
- 分享遇到的问题和解决方案
|
|
243
|
-
- 补充官方文档中缺失的信息
|
|
244
|
-
- 提供代码示例和配置案例
|
|
245
|
-
|
|
246
|
-
### 🎯 **质量标准**
|
|
247
|
-
|
|
248
|
-
- 内容准确,经过实际验证
|
|
249
|
-
- 包含具体的代码示例
|
|
250
|
-
- 说明适用场景和限制条件
|
|
251
|
-
- 遵循现有的格式规范
|
|
252
|
-
|
|
253
|
-
### 🔄 **持续更新**
|
|
254
|
-
|
|
255
|
-
- 定期更新官方文档
|
|
256
|
-
- 根据版本迭代添加新特性说明
|
|
257
|
-
- 修正过时的信息和错误用法
|
|
258
|
-
|
|
259
|
-
## 工作流程
|
|
260
|
-
|
|
261
|
-
### 首次使用
|
|
262
|
-
|
|
263
|
-
1. **基础搜索**: 使用 `search-skill` 查询基础概念
|
|
264
|
-
2. **实践验证**: 根据搜索结果进行实际编码
|
|
265
|
-
3. **补充内容**: 将实践经验通过 `add-skill` 添加为知识点
|
|
266
|
-
4. **分享交流**: 与团队成员分享有价值的发现
|
|
267
|
-
|
|
268
|
-
### 日常使用
|
|
269
|
-
|
|
270
|
-
1. **问题查询**: 遇到问题时先搜索现有知识点
|
|
271
|
-
2. **内容扩展**: 发现新知识时及时补充
|
|
272
|
-
3. **文档更新**: 定期更新官方文档以保持同步
|
|
273
|
-
4. **质量维护**: 检查和优化现有知识点质量
|
|
274
|
-
|
|
275
|
-
## 技术支持
|
|
276
|
-
|
|
277
|
-
如果遇到技术问题,可以通过以下方式:
|
|
278
|
-
|
|
279
|
-
1. 搜索现有知识点
|
|
280
|
-
2. 查看官方文档部分
|
|
281
|
-
3. 添加问题描述到用户知识点
|
|
282
|
-
4. 寻求社区帮助
|
|
283
|
-
|
|
284
|
-
---
|
|
285
|
-
|
|
286
|
-
## 用户技能
|
|
287
|
-
|
|
288
|
-
<user-skills baseDir="assets/references/user">
|
|
289
|
-
</user-skills>
|
|
290
|
-
|
|
291
|
-
## Context7 文档
|
|
292
|
-
|
|
293
|
-
<!-- Context7 项目将自动在此列出 -->
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
_本技能基于skill-creator工具创建,持续更新以提供最佳的技术支持体验。_
|