skill-creator 1.4.3 → 1.5.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.
Files changed (187) hide show
  1. package/dist/chunk-Da8dvM5T.mjs +1 -0
  2. package/dist/cli.d.mts +1016 -0
  3. package/dist/cli.d.mts.map +1 -0
  4. package/dist/cli.mjs +36 -0
  5. package/dist/cli.mjs.map +1 -0
  6. package/dist/contentManager-8rmWJMb6.mjs +22 -0
  7. package/dist/contentManager-8rmWJMb6.mjs.map +1 -0
  8. package/dist/contentManager-Xt8N5psY.mjs +1 -0
  9. package/dist/dist-DZL34HNo.mjs +8 -0
  10. package/dist/dist-DZL34HNo.mjs.map +1 -0
  11. package/dist/dist-X_kVEzbK.mjs +1 -0
  12. package/dist/esm-8qfZdcpd.mjs +33 -0
  13. package/dist/esm-8qfZdcpd.mjs.map +1 -0
  14. package/dist/esm-BF5pvSbc.mjs +1 -0
  15. package/dist/esm-BbhxxeGF.mjs +4 -0
  16. package/dist/esm-BbhxxeGF.mjs.map +1 -0
  17. package/dist/index.d.mts +1964 -0
  18. package/dist/index.d.mts.map +1 -0
  19. package/dist/index.mjs +21 -0
  20. package/dist/index.mjs.map +1 -0
  21. package/dist/listContext7-DKXzgWdn.mjs +2 -0
  22. package/dist/listContext7-DKXzgWdn.mjs.map +1 -0
  23. package/dist/package-B4FNst2t.mjs +2 -0
  24. package/dist/package-B4FNst2t.mjs.map +1 -0
  25. package/dist/path-CuoiIaIe.mjs +2 -0
  26. package/dist/path-CuoiIaIe.mjs.map +1 -0
  27. package/dist/removeContext7-DOXrTXeI.mjs +3 -0
  28. package/dist/removeContext7-DOXrTXeI.mjs.map +1 -0
  29. package/dist/removeSkill-C-ehFexk.mjs +5 -0
  30. package/dist/removeSkill-C-ehFexk.mjs.map +1 -0
  31. package/dist/removeSkill-DWwhvzej.mjs +1 -0
  32. package/dist/runScript-Cr9RRN9y.mjs +14 -0
  33. package/dist/runScript-Cr9RRN9y.mjs.map +1 -0
  34. package/dist/search_format-DIs-1lKk.mjs +5 -0
  35. package/dist/search_format-DIs-1lKk.mjs.map +1 -0
  36. package/dist/shared-CFoY2Xhg.mjs +2 -0
  37. package/dist/shared-CFoY2Xhg.mjs.map +1 -0
  38. package/dist/skillMdManager-DP8fGZb7.mjs +7 -0
  39. package/dist/skillMdManager-DP8fGZb7.mjs.map +1 -0
  40. package/dist/unifiedSearch-CGZXw0NB.mjs +1 -0
  41. package/dist/unifiedSearch-l-lrSc9C.mjs +4 -0
  42. package/dist/unifiedSearch-l-lrSc9C.mjs.map +1 -0
  43. package/package.json +30 -17
  44. package/dist/cli.d.ts +0 -8
  45. package/dist/cli.d.ts.map +0 -1
  46. package/dist/cli.js +0 -513
  47. package/dist/cli.js.map +0 -1
  48. package/dist/commands/addContent.d.ts +0 -5
  49. package/dist/commands/addContent.d.ts.map +0 -1
  50. package/dist/commands/addContent.js +0 -88
  51. package/dist/commands/addContent.js.map +0 -1
  52. package/dist/commands/buildIndex.d.ts +0 -5
  53. package/dist/commands/buildIndex.d.ts.map +0 -1
  54. package/dist/commands/buildIndex.js +0 -16
  55. package/dist/commands/buildIndex.js.map +0 -1
  56. package/dist/commands/createSkill.d.ts +0 -6
  57. package/dist/commands/createSkill.d.ts.map +0 -1
  58. package/dist/commands/createSkill.js +0 -32
  59. package/dist/commands/createSkill.js.map +0 -1
  60. package/dist/commands/downloadContext7.d.ts +0 -5
  61. package/dist/commands/downloadContext7.d.ts.map +0 -1
  62. package/dist/commands/downloadContext7.js +0 -71
  63. package/dist/commands/downloadContext7.js.map +0 -1
  64. package/dist/commands/init.d.ts +0 -5
  65. package/dist/commands/init.d.ts.map +0 -1
  66. package/dist/commands/init.js +0 -95
  67. package/dist/commands/init.js.map +0 -1
  68. package/dist/commands/listContent.d.ts +0 -5
  69. package/dist/commands/listContent.d.ts.map +0 -1
  70. package/dist/commands/listContent.js +0 -34
  71. package/dist/commands/listContent.js.map +0 -1
  72. package/dist/commands/listContext7.d.ts +0 -5
  73. package/dist/commands/listContext7.d.ts.map +0 -1
  74. package/dist/commands/listContext7.js +0 -26
  75. package/dist/commands/listContext7.js.map +0 -1
  76. package/dist/commands/listSkills.d.ts +0 -5
  77. package/dist/commands/listSkills.d.ts.map +0 -1
  78. package/dist/commands/listSkills.js +0 -34
  79. package/dist/commands/listSkills.js.map +0 -1
  80. package/dist/commands/removeContext7.d.ts +0 -5
  81. package/dist/commands/removeContext7.d.ts.map +0 -1
  82. package/dist/commands/removeContext7.js +0 -54
  83. package/dist/commands/removeContext7.js.map +0 -1
  84. package/dist/commands/removeSkill.d.ts +0 -5
  85. package/dist/commands/removeSkill.d.ts.map +0 -1
  86. package/dist/commands/removeSkill.js +0 -83
  87. package/dist/commands/removeSkill.js.map +0 -1
  88. package/dist/commands/searchContent.d.ts +0 -5
  89. package/dist/commands/searchContent.d.ts.map +0 -1
  90. package/dist/commands/searchContent.js +0 -99
  91. package/dist/commands/searchContent.js.map +0 -1
  92. package/dist/commands/shared.d.ts +0 -21
  93. package/dist/commands/shared.d.ts.map +0 -1
  94. package/dist/commands/shared.js +0 -80
  95. package/dist/commands/shared.js.map +0 -1
  96. package/dist/core/autoSearchAdapter.d.ts +0 -42
  97. package/dist/core/autoSearchAdapter.d.ts.map +0 -1
  98. package/dist/core/autoSearchAdapter.js +0 -116
  99. package/dist/core/autoSearchAdapter.js.map +0 -1
  100. package/dist/core/chromaSearch.d.ts +0 -24
  101. package/dist/core/chromaSearch.d.ts.map +0 -1
  102. package/dist/core/chromaSearch.js +0 -194
  103. package/dist/core/chromaSearch.js.map +0 -1
  104. package/dist/core/chromaSearchAdapter.d.ts +0 -86
  105. package/dist/core/chromaSearchAdapter.d.ts.map +0 -1
  106. package/dist/core/chromaSearchAdapter.js +0 -477
  107. package/dist/core/chromaSearchAdapter.js.map +0 -1
  108. package/dist/core/chromaServerManager.d.ts +0 -64
  109. package/dist/core/chromaServerManager.d.ts.map +0 -1
  110. package/dist/core/chromaServerManager.js +0 -186
  111. package/dist/core/chromaServerManager.js.map +0 -1
  112. package/dist/core/contentManager.d.ts +0 -65
  113. package/dist/core/contentManager.d.ts.map +0 -1
  114. package/dist/core/contentManager.js +0 -533
  115. package/dist/core/contentManager.js.map +0 -1
  116. package/dist/core/fuzzySearchAdapter.d.ts +0 -33
  117. package/dist/core/fuzzySearchAdapter.d.ts.map +0 -1
  118. package/dist/core/fuzzySearchAdapter.js +0 -185
  119. package/dist/core/fuzzySearchAdapter.js.map +0 -1
  120. package/dist/core/portUtils.d.ts +0 -51
  121. package/dist/core/portUtils.d.ts.map +0 -1
  122. package/dist/core/portUtils.js +0 -120
  123. package/dist/core/portUtils.js.map +0 -1
  124. package/dist/core/runScript.d.ts +0 -5
  125. package/dist/core/runScript.d.ts.map +0 -1
  126. package/dist/core/runScript.js +0 -40
  127. package/dist/core/runScript.js.map +0 -1
  128. package/dist/core/searchAdapter.d.ts +0 -48
  129. package/dist/core/searchAdapter.d.ts.map +0 -1
  130. package/dist/core/searchAdapter.js +0 -6
  131. package/dist/core/searchAdapter.js.map +0 -1
  132. package/dist/core/searchEngineFactory.d.ts +0 -30
  133. package/dist/core/searchEngineFactory.d.ts.map +0 -1
  134. package/dist/core/searchEngineFactory.js +0 -41
  135. package/dist/core/searchEngineFactory.js.map +0 -1
  136. package/dist/core/skillCreator.d.ts +0 -12
  137. package/dist/core/skillCreator.d.ts.map +0 -1
  138. package/dist/core/skillCreator.js +0 -79
  139. package/dist/core/skillCreator.js.map +0 -1
  140. package/dist/core/templateManager.d.ts +0 -28
  141. package/dist/core/templateManager.d.ts.map +0 -1
  142. package/dist/core/templateManager.js +0 -583
  143. package/dist/core/templateManager.js.map +0 -1
  144. package/dist/core/unifiedSearch.d.ts +0 -69
  145. package/dist/core/unifiedSearch.d.ts.map +0 -1
  146. package/dist/core/unifiedSearch.js +0 -105
  147. package/dist/core/unifiedSearch.js.map +0 -1
  148. package/dist/index.d.ts +0 -13
  149. package/dist/index.d.ts.map +0 -1
  150. package/dist/index.js +0 -11
  151. package/dist/index.js.map +0 -1
  152. package/dist/search_format/enhancedFormatter.d.ts +0 -109
  153. package/dist/search_format/enhancedFormatter.d.ts.map +0 -1
  154. package/dist/search_format/enhancedFormatter.js +0 -262
  155. package/dist/search_format/enhancedFormatter.js.map +0 -1
  156. package/dist/search_format/index.d.ts +0 -10
  157. package/dist/search_format/index.d.ts.map +0 -1
  158. package/dist/search_format/index.js +0 -22
  159. package/dist/search_format/index.js.map +0 -1
  160. package/dist/search_format/listFormatter.d.ts +0 -16
  161. package/dist/search_format/listFormatter.d.ts.map +0 -1
  162. package/dist/search_format/listFormatter.js +0 -51
  163. package/dist/search_format/listFormatter.js.map +0 -1
  164. package/dist/search_format/types.d.ts +0 -69
  165. package/dist/search_format/types.d.ts.map +0 -1
  166. package/dist/search_format/types.js +0 -5
  167. package/dist/search_format/types.js.map +0 -1
  168. package/dist/types/index.d.ts +0 -74
  169. package/dist/types/index.d.ts.map +0 -1
  170. package/dist/types/index.js +0 -2
  171. package/dist/types/index.js.map +0 -1
  172. package/dist/utils/claudeCodeDetection.d.ts +0 -27
  173. package/dist/utils/claudeCodeDetection.d.ts.map +0 -1
  174. package/dist/utils/claudeCodeDetection.js +0 -81
  175. package/dist/utils/claudeCodeDetection.js.map +0 -1
  176. package/dist/utils/config.d.ts +0 -23
  177. package/dist/utils/config.d.ts.map +0 -1
  178. package/dist/utils/config.js +0 -41
  179. package/dist/utils/config.js.map +0 -1
  180. package/dist/utils/package.d.ts +0 -88
  181. package/dist/utils/package.d.ts.map +0 -1
  182. package/dist/utils/package.js +0 -221
  183. package/dist/utils/package.js.map +0 -1
  184. package/dist/utils/skillMdManager.d.ts +0 -45
  185. package/dist/utils/skillMdManager.d.ts.map +0 -1
  186. package/dist/utils/skillMdManager.js +0 -173
  187. package/dist/utils/skillMdManager.js.map +0 -1
@@ -0,0 +1 @@
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/package.json CHANGED
@@ -1,12 +1,23 @@
1
1
  {
2
2
  "name": "skill-creator",
3
- "version": "1.4.3",
3
+ "version": "1.5.0",
4
4
  "description": "Create claude-code-skills with documentation management",
5
5
  "bin": {
6
- "skill-creator": "dist/cli.js",
7
- "sc": "dist/cli.js"
6
+ "skill-creator": "dist/cli.mjs",
7
+ "sc": "dist/cli.mjs"
8
8
  },
9
9
  "type": "module",
10
+ "main": "dist/index.mjs",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.mts",
14
+ "default": "./dist/index.mjs"
15
+ },
16
+ "./cli": {
17
+ "types": "./dist/cli.d.mts",
18
+ "default": "./dist/cli.mjs"
19
+ }
20
+ },
10
21
  "keywords": [
11
22
  "claude-code",
12
23
  "skills",
@@ -18,30 +29,32 @@
18
29
  "license": "MIT",
19
30
  "dependencies": {
20
31
  "@chroma-core/default-embed": "^0.1.8",
32
+ "chromadb": "^3.0.17"
33
+ },
34
+ "devDependencies": {
35
+ "@gaubee/nodekit": "^0.14.0",
21
36
  "@leeoniya/ufuzzy": "^1.0.19",
22
- "chromadb": "^3.0.17",
37
+ "@types/inquirer": "^9.0.9",
38
+ "@types/markdown-it": "^14.1.2",
39
+ "@types/node": "^24.9.1",
40
+ "@vitest/coverage-v8": "^3.2.4",
41
+ "@vitest/ui": "^3.2.4",
23
42
  "commander": "^14.0.1",
24
43
  "dedent": "^1.5.3",
25
44
  "fuse.js": "^7.1.0",
26
45
  "glob": "^11.0.0",
27
46
  "gradient-string": "^3.0.0",
28
47
  "inquirer": "^12.10.0",
48
+ "jsdom": "^27.0.1",
29
49
  "markdown-it": "^14.1.0",
30
50
  "ora": "^9.0.0",
31
- "ts-pattern": "^5.9.0",
32
- "zod": "^4.1.12"
33
- },
34
- "devDependencies": {
35
- "@types/inquirer": "^9.0.9",
36
- "@types/markdown-it": "^14.1.2",
37
- "@types/node": "^24.9.1",
38
- "@vitest/coverage-v8": "^3.2.4",
39
- "@vitest/ui": "^3.2.4",
40
- "jsdom": "^27.0.1",
41
51
  "prettier": "^3.4.2",
52
+ "ts-pattern": "^5.9.0",
53
+ "tsdown": "^0.16.3",
42
54
  "tsx": "^4.19.2",
43
55
  "typescript": "^5.7.2",
44
- "vitest": "^3.2.4"
56
+ "vitest": "^3.2.4",
57
+ "zod": "^4.1.12"
45
58
  },
46
59
  "repository": {
47
60
  "type": "git",
@@ -57,9 +70,9 @@
57
70
  },
58
71
  "scripts": {
59
72
  "pub": "pnpm publish --access publish --no-git-checks",
60
- "build": "tsc",
73
+ "build": "tsdown",
61
74
  "sc": "pnpm tsx src/cli.ts",
62
- "dev": "tsc --watch",
75
+ "dev": "tsdown --watch",
63
76
  "cli": "node dist/cli.js",
64
77
  "test": "vitest run",
65
78
  "test:watch": "vitest",
package/dist/cli.d.ts DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * CLI interface for skill creator
4
- */
5
- import { Command } from 'commander';
6
- declare const program: Command;
7
- export { program };
8
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAQnC,QAAA,MAAM,OAAO,SAAgB,CAAA;AA8iB7B,OAAO,EAAE,OAAO,EAAE,CAAA"}