sweet-search 0.0.1 → 2.3.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 (161) hide show
  1. package/LICENSE +190 -0
  2. package/NOTICE +23 -0
  3. package/core/cli.js +51 -0
  4. package/core/config.js +27 -0
  5. package/core/embedding/embedding-cache.js +467 -0
  6. package/core/embedding/embedding-local-model.js +845 -0
  7. package/core/embedding/embedding-remote.js +492 -0
  8. package/core/embedding/embedding-service.js +712 -0
  9. package/core/embedding/embedding-telemetry.js +219 -0
  10. package/core/embedding/index.js +40 -0
  11. package/core/graph/community-detector.js +294 -0
  12. package/core/graph/graph-expansion.js +839 -0
  13. package/core/graph/graph-extractor.js +2304 -0
  14. package/core/graph/graph-search.js +2148 -0
  15. package/core/graph/hcgs-generator.js +666 -0
  16. package/core/graph/index.js +16 -0
  17. package/core/graph/leiden-algorithm.js +547 -0
  18. package/core/graph/relationship-resolver.js +366 -0
  19. package/core/graph/repo-map.js +408 -0
  20. package/core/graph/summary-manager.js +549 -0
  21. package/core/indexing/artifact-builder.js +1054 -0
  22. package/core/indexing/ast-chunker.js +709 -0
  23. package/core/indexing/chunking/chunk-builder.js +170 -0
  24. package/core/indexing/chunking/markdown-chunker.js +503 -0
  25. package/core/indexing/chunking/plaintext-chunker.js +104 -0
  26. package/core/indexing/dedup/dedup-phase.js +159 -0
  27. package/core/indexing/dedup/exemplar-selector.js +65 -0
  28. package/core/indexing/document-chunker.js +56 -0
  29. package/core/indexing/incremental-parser.js +390 -0
  30. package/core/indexing/incremental-tracker.js +761 -0
  31. package/core/indexing/index-codebase-v21.js +472 -0
  32. package/core/indexing/index-maintainer.mjs +1674 -0
  33. package/core/indexing/index.js +90 -0
  34. package/core/indexing/indexer-ann.js +1077 -0
  35. package/core/indexing/indexer-build.js +742 -0
  36. package/core/indexing/indexer-phases.js +800 -0
  37. package/core/indexing/indexer-pool.js +764 -0
  38. package/core/indexing/indexer-sparse-gram.js +98 -0
  39. package/core/indexing/indexer-utils.js +536 -0
  40. package/core/indexing/indexer-worker.js +148 -0
  41. package/core/indexing/li-skip-policy.js +225 -0
  42. package/core/indexing/merkle-tracker.js +244 -0
  43. package/core/indexing/model-pool.js +166 -0
  44. package/core/infrastructure/code-graph-repository.js +120 -0
  45. package/core/infrastructure/codebase-repository.js +131 -0
  46. package/core/infrastructure/config/dedup.js +54 -0
  47. package/core/infrastructure/config/embedding.js +298 -0
  48. package/core/infrastructure/config/graph.js +80 -0
  49. package/core/infrastructure/config/index.js +82 -0
  50. package/core/infrastructure/config/indexing.js +8 -0
  51. package/core/infrastructure/config/platform.js +254 -0
  52. package/core/infrastructure/config/ranking.js +221 -0
  53. package/core/infrastructure/config/search.js +396 -0
  54. package/core/infrastructure/config/translation.js +89 -0
  55. package/core/infrastructure/config/vector-store.js +114 -0
  56. package/core/infrastructure/constants.js +86 -0
  57. package/core/infrastructure/coreml-cascade.js +909 -0
  58. package/core/infrastructure/coreml-cascade.json +46 -0
  59. package/core/infrastructure/coreml-provider.js +81 -0
  60. package/core/infrastructure/db-utils.js +69 -0
  61. package/core/infrastructure/dedup-hashing.js +83 -0
  62. package/core/infrastructure/hardware-capability.js +332 -0
  63. package/core/infrastructure/index.js +104 -0
  64. package/core/infrastructure/language-patterns/maps.js +121 -0
  65. package/core/infrastructure/language-patterns/registry-core.js +323 -0
  66. package/core/infrastructure/language-patterns/registry-data-query.js +155 -0
  67. package/core/infrastructure/language-patterns/registry-object-oriented.js +285 -0
  68. package/core/infrastructure/language-patterns/registry-tooling.js +240 -0
  69. package/core/infrastructure/language-patterns/registry-web-style.js +143 -0
  70. package/core/infrastructure/language-patterns/registry.js +19 -0
  71. package/core/infrastructure/language-patterns.js +141 -0
  72. package/core/infrastructure/llm-provider.js +733 -0
  73. package/core/infrastructure/manifest.json +46 -0
  74. package/core/infrastructure/maxsim.wasm +0 -0
  75. package/core/infrastructure/model-fetcher.js +423 -0
  76. package/core/infrastructure/model-registry.js +214 -0
  77. package/core/infrastructure/native-inference.js +587 -0
  78. package/core/infrastructure/native-resolver.js +187 -0
  79. package/core/infrastructure/native-sparse-gram.js +257 -0
  80. package/core/infrastructure/native-tokenizer.js +160 -0
  81. package/core/infrastructure/onnx-mutex.js +45 -0
  82. package/core/infrastructure/onnx-session-utils.js +261 -0
  83. package/core/infrastructure/ort-pipeline.js +111 -0
  84. package/core/infrastructure/project-detector.js +102 -0
  85. package/core/infrastructure/quantization.js +410 -0
  86. package/core/infrastructure/simd-distance.js +502 -0
  87. package/core/infrastructure/simd-distance.wasm +0 -0
  88. package/core/infrastructure/tree-sitter-provider.js +665 -0
  89. package/core/infrastructure/webgpu-maxsim.js +222 -0
  90. package/core/query/index.js +35 -0
  91. package/core/query/intent-detector.js +201 -0
  92. package/core/query/intent-router.js +156 -0
  93. package/core/query/query-router-catboost.js +222 -0
  94. package/core/query/query-router-ml.js +266 -0
  95. package/core/query/query-router.js +213 -0
  96. package/core/ranking/cascaded-scorer.js +379 -0
  97. package/core/ranking/flashrank.js +810 -0
  98. package/core/ranking/index.js +49 -0
  99. package/core/ranking/late-interaction-index.js +2383 -0
  100. package/core/ranking/late-interaction-model.js +812 -0
  101. package/core/ranking/local-reranker.js +374 -0
  102. package/core/ranking/mmr.js +379 -0
  103. package/core/ranking/quality-scorer.js +363 -0
  104. package/core/search/context-expander.js +1167 -0
  105. package/core/search/dedup/sibling-expander.js +327 -0
  106. package/core/search/index.js +16 -0
  107. package/core/search/search-boost.js +259 -0
  108. package/core/search/search-cli.js +544 -0
  109. package/core/search/search-format.js +282 -0
  110. package/core/search/search-fusion.js +327 -0
  111. package/core/search/search-hybrid.js +204 -0
  112. package/core/search/search-pattern-chunks.js +337 -0
  113. package/core/search/search-pattern-planner.js +439 -0
  114. package/core/search/search-pattern-prefilter.js +412 -0
  115. package/core/search/search-pattern-ripgrep.js +663 -0
  116. package/core/search/search-pattern.js +463 -0
  117. package/core/search/search-postprocess.js +452 -0
  118. package/core/search/search-semantic.js +706 -0
  119. package/core/search/search-server.js +554 -0
  120. package/core/search/session-daemon-prewarm.mjs +164 -0
  121. package/core/search/session-warmup.js +595 -0
  122. package/core/search/sweet-search.js +632 -0
  123. package/core/search/warmup-metrics.js +532 -0
  124. package/core/start-server.js +6 -0
  125. package/core/training/query-router/features/extractor.js +762 -0
  126. package/core/training/query-router/features/multilingual-patterns.js +431 -0
  127. package/core/training/query-router/features/text-segmenter.js +303 -0
  128. package/core/training/query-router/features/unicode-utils.js +383 -0
  129. package/core/training/query-router/output/v45_router_d4.js +11521 -0
  130. package/core/training/query-router/output/v46_router_d4.js +11498 -0
  131. package/core/vector-store/binary-heap.js +227 -0
  132. package/core/vector-store/binary-hnsw-index.js +1004 -0
  133. package/core/vector-store/float-vector-store.js +234 -0
  134. package/core/vector-store/hnsw-index.js +580 -0
  135. package/core/vector-store/index.js +39 -0
  136. package/core/vector-store/seismic-index.js +498 -0
  137. package/core/vocabulary/index.js +84 -0
  138. package/core/vocabulary/vocab-constants.js +20 -0
  139. package/core/vocabulary/vocab-miner-extractors.js +375 -0
  140. package/core/vocabulary/vocab-miner-nl.js +404 -0
  141. package/core/vocabulary/vocab-miner-utils.js +146 -0
  142. package/core/vocabulary/vocab-miner.js +574 -0
  143. package/core/vocabulary/vocab-prewarm-cli.js +110 -0
  144. package/core/vocabulary/vocab-ranker.js +492 -0
  145. package/core/vocabulary/vocab-warmer.js +523 -0
  146. package/core/vocabulary/vocab-warmup-orchestrator.js +425 -0
  147. package/core/vocabulary/vocabulary-utils.js +704 -0
  148. package/crates/wasm-router/pkg/package.json +13 -0
  149. package/crates/wasm-router/pkg/query_router_wasm.d.ts +36 -0
  150. package/crates/wasm-router/pkg/query_router_wasm.js +271 -0
  151. package/crates/wasm-router/pkg/query_router_wasm_bg.wasm +0 -0
  152. package/crates/wasm-router/pkg/query_router_wasm_bg.wasm.d.ts +19 -0
  153. package/mcp/config-gen.js +121 -0
  154. package/mcp/server.js +335 -0
  155. package/mcp/tool-handlers.js +476 -0
  156. package/package.json +131 -9
  157. package/scripts/benchmark-harness.js +794 -0
  158. package/scripts/init.js +1058 -0
  159. package/scripts/smoke-test.js +435 -0
  160. package/scripts/uninstall.js +478 -0
  161. package/scripts/verify-runtime.js +176 -0
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Multilingual Patterns for Query Router
3
+ *
4
+ * Provides non-English structural and semantic keyword detection for 15+ languages.
5
+ * Enables the query router to correctly classify queries in any supported language.
6
+ *
7
+ * P0 Fixes Applied:
8
+ * - Added try/catch error handling to all pattern matching functions
9
+ * - Fixed regex catastrophic backtracking by replacing .+ with bounded patterns
10
+ * - Added input length limits to prevent DoS
11
+ *
12
+ * Languages covered:
13
+ * - Latin: English, German, Spanish, French, Portuguese, Italian
14
+ * - Cyrillic: Serbian, Russian, Ukrainian
15
+ * - CJK: Chinese (Simplified/Traditional), Japanese
16
+ * - Hangul: Korean
17
+ * - Arabic: Arabic, Persian, Urdu
18
+ * - Other: Greek, Thai, Hebrew, Hindi (Devanagari), Vietnamese
19
+ */
20
+
21
+ // P0 Fix: Maximum query length to prevent DoS via regex
22
+ const MAX_QUERY_LENGTH = 500;
23
+
24
+ /**
25
+ * STRUCTURAL PATTERNS - Detect dependency/relationship queries
26
+ *
27
+ * Patterns for: callers, callees, implementations, impact, hierarchy
28
+ */
29
+ export const STRUCTURAL_PATTERNS = {
30
+ // WHO/WHAT CALLS X - Find callers of a symbol
31
+ // Note: \b doesn't work with non-ASCII, so we use (?:^|\s) for non-Latin scripts
32
+ callers: {
33
+ en: /\b(what|who|which)\s+(calls?|uses?|invokes?|references?)\s+/i,
34
+ de: /\b(was|wer|welche[rs]?)\s+(ruft|benutzt|verwendet|aufruft)\s+/i,
35
+ es: /\b(qué|quién|cuál)\s+(llama|usa|invoca|referencia)\s+/i,
36
+ fr: /\b(qu['']?est-ce qui|qui|quel)\s+(appelle|utilise|invoque)\s+/i,
37
+ pt: /\b(o que|quem|qual)\s+(chama|usa|invoca|referencia)\s+/i,
38
+ it: /\b(cosa|chi|quale)\s+(chiama|usa|invoca|riferisce)\s+/i,
39
+ sr: /(?:^|\s)(шта|ко|који)\s+(позива|користи|зове|референцира)/i,
40
+ ru: /(?:^|\s)(что|кто|какой)\s+(вызывает|использует|вызовет)/i,
41
+ uk: /(?:^|\s)(що|хто|який)\s+(викликає|використовує|звертається)/i,
42
+ zh: /(什么|谁|哪个)\s*(调用|使用|引用|访问)/,
43
+ ja: /を?(呼び出す|使う|利用する|参照する)/,
44
+ ko: /를?\s*(호출|사용|참조|이용)/,
45
+ ar: /(ما|من|أي)\s*(يستدعي|يستخدم|يشير)/,
46
+ el: /(?:^|\s)(τι|ποιος|ποια)\s+(καλεί|χρησιμοποιεί)/i,
47
+ th: /(อะไร|ใคร)\s*(เรียก|ใช้|อ้างอิง)/,
48
+ he: /(מה|מי|איזה)\s*(קורא|משתמש|מפנה)/,
49
+ hi: /(क्या|कौन)\s*(कॉल|उपयोग|संदर्भ)/,
50
+ // P1 Fix: Changed \b to (?:^|\s) - \b fails with Vietnamese diacritics
51
+ vi: /(?:^|\s)(cái gì|ai|cái nào)\s+(gọi|sử dụng|tham chiếu)\s+/i,
52
+ },
53
+
54
+ // WHAT DOES X CALL - Find callees of a symbol
55
+ // P0 Fix: Replaced .+ with bounded patterns to prevent catastrophic backtracking
56
+ callees: {
57
+ en: /\b(what\s+does|what\s+do|which\s+methods?|which\s+functions?)\s+\S+\s+(call|use|invoke|depend)/i,
58
+ de: /\b(was\s+ruft|welche\s+methoden?)\s+\S+\s+(auf|benutzt)/i,
59
+ es: /\b(qué\s+llama|qué\s+métodos?)\s+\S+\s+(usa|invoca)/i,
60
+ fr: /\b(qu['']?appelle|quelles?\s+méthodes?)\s+/i,
61
+ sr: /(?:^|\s)(шта\s+позива|које\s+методе)/i,
62
+ ru: /(?:^|\s)(что\s+вызывает|какие\s+методы)/i,
63
+ zh: /[\u4e00-\u9fff\w]+\s*(调用什么|使用什么|依赖什么)/,
64
+ ja: /[\u3040-\u30ff\u4e00-\u9fff\w]+\s*(が呼び出す|が使う|が依存)/,
65
+ ko: /[\uac00-\ud7af\w]+\s*(가\s*호출|가\s*사용|에\s*의존)/,
66
+ },
67
+
68
+ // IMPLEMENTATIONS OF X - Find implementing classes/interfaces
69
+ // P0 Fix: Replaced .* with bounded patterns to prevent catastrophic backtracking
70
+ implementations: {
71
+ en: /\b(implementations?\s+of|classes?\s+implementing|implements|subclasses?\s+of|extends)\s+/i,
72
+ de: /\b(implementierungen?\s+von|klassen?\s+die\s+implementieren|unterklassen?\s+von|erweitert)\s+/i,
73
+ es: /\b(implementaciones?\s+de|clases?\s+que\s+implementan|subclases?\s+de|extiende)\s+/i,
74
+ fr: /\b(implémentations?\s+de|classes?\s+implémentant|sous-classes?\s+de|étend)\s+/i,
75
+ sr: /(?:^|\s)(имплементације|класе\s+које\s+имплементирају|подкласе|наслеђује)/i,
76
+ ru: /(?:^|\s)(реализации|классы\s+реализующие|подклассы|наследует)/i,
77
+ zh: /(实现|实现类|子类|继承)/,
78
+ ja: /(の実装|を実装|サブクラス|継承)/,
79
+ ko: /(구현|구현\s*클래스|하위\s*클래스|상속)/,
80
+ },
81
+
82
+ // IMPACT OF CHANGING X - Impact analysis
83
+ // P0 Fix: Replaced .* with bounded patterns to prevent catastrophic backtracking
84
+ impact: {
85
+ en: /\b(impact|affected|breaking|ripple|consequence|side\s*effect)\s+(of\s+)?(changing|modifying|refactoring|removing|deleting)\s+/i,
86
+ de: /\b(auswirkung|betroffen|konsequenz)\s+(von\s+)?(änderung|modifizierung|entfernung)\s+/i,
87
+ es: /\b(impacto|afectado|consecuencia)\s+(de\s+)?(cambiar|modificar|eliminar)\s+/i,
88
+ fr: /\b(impact|affecté|conséquence)\s+(de\s+)?(changer|modifier|supprimer)\s+/i,
89
+ sr: /(?:^|\s)(утицај|последица|погођено)\s+(промене|модификације|брисања)/i,
90
+ ru: /(?:^|\s)(влияние|последствие|затронуто)\s+(изменения|модификации|удаления)/i,
91
+ zh: /(影响|变更\S*影响|修改\S*后果|删除\S*结果)/,
92
+ ja: /(への影響|変更\S*影響|削除\S*結果)/,
93
+ ko: /(영향|변경\S*영향|삭제\S*결과)/,
94
+ },
95
+
96
+ // HIERARCHY/INHERITANCE
97
+ // P0 Fix: Replaced .* with bounded patterns to prevent catastrophic backtracking
98
+ hierarchy: {
99
+ en: /\b(class\s+hierarchy|inheritance\s+tree|parent\s+class|base\s+class|super\s*class)\s*/i,
100
+ de: /\b(klassenhierarchie|vererbungsbaum|elternklasse|basisklasse|superklasse)\s*/i,
101
+ es: /\b(jerarquía\s+de\s+clases|árbol\s+de\s+herencia|clase\s+padre|clase\s+base|superclase)\s*/i,
102
+ sr: /(?:^|\s)(хијерархија|стабло\s+наслеђивања|родитељска\s+класа|базна\s+класа)/i,
103
+ ru: /(?:^|\s)(иерархия\s+классов|дерево\s+наследования|родительский\s+класс|базовый\s+класс)/i,
104
+ zh: /(类层次|继承树|父类|基类|超类)/,
105
+ ja: /(クラス階層|継承ツリー|親クラス|基底クラス|スーパークラス)/,
106
+ ko: /(클래스\s*계층|상속\s*트리|부모\s*클래스|기본\s*클래스)/,
107
+ },
108
+ };
109
+
110
+ /**
111
+ * SEMANTIC PATTERNS - Detect conceptual/explanatory queries
112
+ *
113
+ * Patterns for: questions, processes, architecture, explanations
114
+ */
115
+ export const SEMANTIC_PATTERNS = {
116
+ // QUESTION WORDS - How/Why/What is...
117
+ // Note: \b doesn't work with non-ASCII, so we use (?:^|\s) for non-Latin scripts
118
+ questionWords: {
119
+ en: /\b(how\s+does|how\s+do|how\s+to|how\s+is|why\s+does|why\s+do|why\s+is|what\s+is|what\s+are|explain|describe)\s+/i,
120
+ de: /\b(wie\s+funktioniert|wie\s+macht|warum\s+ist|was\s+ist|erkläre|beschreibe)\s+/i,
121
+ es: /\b(cómo\s+funciona|cómo\s+se|por\s+qué|qué\s+es|explica|describe)\s+/i,
122
+ fr: /\b(comment\s+fonctionne|comment\s+fait|pourquoi|qu['']?est-ce\s+que|expliquer|décrire)\s+/i,
123
+ pt: /\b(como\s+funciona|como\s+faz|por\s+que|o\s+que\s+é|explique|descreva)\s+/i,
124
+ it: /\b(come\s+funziona|come\s+fa|perché|cosa\s+è|spiega|descrivi)\s+/i,
125
+ sr: /(?:^|\s)(како\s+функционише|како\s+ради|зашто|шта\s+је|објасни|опиши)/i,
126
+ ru: /(?:^|\s)(как\s+работает|как\s+сделать|почему|что\s+такое|объясни|опиши)/i,
127
+ uk: /(?:^|\s)(як\s+працює|як\s+зробити|чому|що\s+таке|поясни|опиши)/i,
128
+ zh: /(如何|怎么|为什么|是什么|解释|描述)/,
129
+ ja: /(どのように|どうやって|なぜ|とは何|説明して|説明する)/,
130
+ ko: /(어떻게|왜|무엇|설명해|설명하다)/,
131
+ ar: /(كيف|لماذا|ما هو|اشرح|صف)/,
132
+ el: /(?:^|\s)(πώς|γιατί|τι\s+είναι|εξήγησε|περίγραψε)/i,
133
+ th: /(อย่างไร|ทำไม|คืออะไร|อธิบาย)/,
134
+ he: /(איך|למה|מה זה|הסבר|תאר)/,
135
+ hi: /(कैसे|क्यों|क्या है|समझाइए|वर्णन)/,
136
+ // P1 Fix: Changed \b to (?:^|\s) - \b fails with Vietnamese diacritics
137
+ vi: /(?:^|\s)(như thế nào|tại sao|là gì|giải thích|mô tả)\s*/i,
138
+ },
139
+
140
+ // PROCESS/FLOW - Authentication flow, request lifecycle
141
+ processWords: {
142
+ en: /\b(flow|process|lifecycle|workflow|pipeline|sequence|steps?|phases?)\s+/i,
143
+ de: /\b(ablauf|prozess|lebenszyklus|arbeitsablauf|pipeline|sequenz|schritte?|phasen?)\s+/i,
144
+ es: /\b(flujo|proceso|ciclo\s+de\s+vida|flujo\s+de\s+trabajo|secuencia|pasos?|fases?)\s+/i,
145
+ fr: /\b(flux|processus|cycle\s+de\s+vie|workflow|séquence|étapes?|phases?)\s+/i,
146
+ sr: /(?:^|\s)(ток|процес|животни\s+циклус|радни\s+ток|секвенца|кораци?|фазе?)/i,
147
+ ru: /(?:^|\s)(поток|процесс|жизненный\s+цикл|рабочий\s+процесс|последовательность|шаги?|фазы?)/i,
148
+ zh: /(流程|过程|生命周期|工作流|管道|序列|步骤|阶段)/,
149
+ ja: /(フロー|プロセス|ライフサイクル|ワークフロー|パイプライン|シーケンス|ステップ|フェーズ)/,
150
+ ko: /(흐름|프로세스|생명주기|워크플로우|파이프라인|시퀀스|단계)/,
151
+ },
152
+
153
+ // ARCHITECTURE/DESIGN - Patterns, architecture, design
154
+ architectureWords: {
155
+ en: /\b(architecture|design\s+pattern|pattern|structure|component|module|layer|tier)\s+/i,
156
+ de: /\b(architektur|entwurfsmuster|muster|struktur|komponente|modul|schicht)\s+/i,
157
+ es: /\b(arquitectura|patrón\s+de\s+diseño|patrón|estructura|componente|módulo|capa)\s+/i,
158
+ fr: /\b(architecture|patron\s+de\s+conception|motif|structure|composant|module|couche)\s+/i,
159
+ sr: /(?:^|\s)(архитектура|шаблон|образац|структура|компонента|модул|слој)/i,
160
+ ru: /(?:^|\s)(архитектура|шаблон\s+проектирования|паттерн|структура|компонент|модуль|слой)/i,
161
+ zh: /(架构|设计模式|模式|结构|组件|模块|层)/,
162
+ ja: /(アーキテクチャ|デザインパターン|パターン|構造|コンポーネント|モジュール|レイヤー)/,
163
+ ko: /(아키텍처|디자인\s*패턴|패턴|구조|컴포넌트|모듈|레이어)/,
164
+ },
165
+
166
+ // CONCEPT WORDS - Error handling, validation, etc.
167
+ // Note: Slavic languages use prefix matching (7+ chars) to handle grammatical cases
168
+ // e.g., "аутентификац" matches аутентификација/аутентификације/аутентификацији
169
+ conceptWords: {
170
+ en: /\b(error\s+handling|validation|authentication|authorization|caching|logging|security|performance|optimization|database|queries?|token|management|logic|session|configuration)\s*/i,
171
+ de: /\b(fehlerbehandlung|validierung|authentifizierung|autorisierung|caching|protokollierung|sicherheit|leistung|optimierung)\s*/i,
172
+ es: /\b(manejo\s+de\s+errores|validación|autenticación|autorización|caché|registro|seguridad|rendimiento|optimización)\s*/i,
173
+ fr: /\b(gestion\s+des\s+erreurs|validation|authentification|autorisation|mise\s+en\s+cache|journalisation|sécurité|performance|optimisation)\s*/i,
174
+ // Serbian: prefix matching for grammatical cases + added логик (logic), процес, механизам
175
+ sr: /(?:^|\s)(обрад\w*\s+грешак|валидациј\w*|аутентификациј\w*|ауторизациј\w*|кеширањ\w*|логовањ\w*|безбедност\w*|перформанс\w*|оптимизациј\w*|логик\w*|процес\w*|механизам\w*|пријав\w*|сесиј\w*)/i,
176
+ // Russian: prefix matching for grammatical cases + added логик (logic), процесс, механизм
177
+ ru: /(?:^|\s)(обработк\w*\s+ошибок|валидациj?\w*|аутентификациj?\w*|авторизациj?\w*|кэшировани\w*|логировани\w*|безопасност\w*|производительност\w*|оптимизациj?\w*|логик\w*|процесс?\w*|механизм\w*|авториз\w*|сесси\w*)/i,
178
+ // Ukrainian: prefix matching
179
+ uk: /(?:^|\s)(обробк\w*\s+помилок|валідаці\w*|автентифікаці\w*|авторизаці\w*|кешуванн\w*|логуванн\w*|безпек\w*|продуктивніст\w*|оптимізаці\w*|логік\w*|процес\w*|механізм\w*)/i,
180
+ zh: /(错误处理|验证|认证|授权|缓存|日志|安全|性能|优化|数据库|查询|令牌|管理|逻辑)/,
181
+ ja: /(エラー処理|バリデーション|認証|認可|キャッシュ|ロギング|セキュリティ|パフォーマンス|最適化|データベース|クエリ|トークン|管理|ロジック)/,
182
+ ko: /(오류\s*처리|검증|인증|권한|캐싱|로깅|보안|성능|최적화|데이터베이스|쿼리|토큰|관리|로직)/,
183
+ // Hindi: added common concept words
184
+ hi: /(त्रुटि\s*हैंडलिंग|सत्यापन|प्रमाणीकरण|प्राधिकरण|कैशिंग|लॉगिंग|सुरक्षा|प्रदर्शन|अनुकूलन|डेटाबेस|क्वेरी|टोकन|प्रबंधन|तर्क)/,
185
+ // Thai: added common concept words
186
+ th: /(การจัดการข้อผิดพลาด|การตรวจสอบ|การยืนยันตัวตน|การอนุญาต|แคช|การบันทึก|ความปลอดภัย|ประสิทธิภาพ|การเพิ่มประสิทธิภาพ|ฐานข้อมูล|คิวรี|โทเค็น|การจัดการ|ตรรกะ)/,
187
+ // Hebrew: added common concept words
188
+ he: /(טיפול\s*בשגיאות|אימות|הרשאה|מטמון|רישום|אבטחה|ביצועים|אופטימיזציה|מסד\s*נתונים|שאילתה|אסימון|ניהול|לוגיקה)/,
189
+ // Vietnamese: added common concept words
190
+ vi: /(?:^|\s)(xử\s*lý\s*lỗi|xác\s*thực|ủy\s*quyền|bộ\s*nhớ\s*đệm|ghi\s*nhật\s*ký|bảo\s*mật|hiệu\s*suất|tối\s*ưu\s*hóa|cơ\s*sở\s*dữ\s*liệu|truy\s*vấn|mã\s*thông\s*báo|quản\s*lý|logic)/i,
191
+ // Arabic: added common concept words
192
+ ar: /(معالجة\s*الأخطاء|التحقق|المصادقة|التفويض|التخزين\s*المؤقت|التسجيل|الأمان|الأداء|التحسين|قاعدة\s*البيانات|استعلام|رمز|إدارة|منطق)/,
193
+ // Greek: added common concept words
194
+ el: /(?:^|\s)(χειρισμός\s*σφαλμάτων|επικύρωση|πιστοποίηση|εξουσιοδότηση|προσωρινή\s*αποθήκευση|καταγραφή|ασφάλεια|απόδοση|βελτιστοποίηση|βάση\s*δεδομένων|ερώτημα|διακριτικό|διαχείριση|λογική)/i,
195
+ },
196
+ };
197
+
198
+ /**
199
+ * Check if query matches any structural pattern
200
+ *
201
+ * P0 Fix: Added try/catch error handling and length check to prevent DoS
202
+ *
203
+ * @param {string} query - Query to check
204
+ * @returns {{matched: boolean, type: string|null, language: string|null}}
205
+ */
206
+ export function matchesStructuralPattern(query) {
207
+ if (!query || typeof query !== 'string') {
208
+ return { matched: false, type: null, language: null };
209
+ }
210
+
211
+ // P0 Fix: Length check to prevent DoS via long inputs
212
+ if (query.length > MAX_QUERY_LENGTH) {
213
+ return { matched: false, type: null, language: null };
214
+ }
215
+
216
+ try {
217
+ for (const [type, patterns] of Object.entries(STRUCTURAL_PATTERNS)) {
218
+ for (const [lang, pattern] of Object.entries(patterns)) {
219
+ if (pattern.test(query)) {
220
+ return { matched: true, type, language: lang };
221
+ }
222
+ }
223
+ }
224
+ } catch (error) {
225
+ // P0 Fix: Catch regex errors (e.g., stack overflow from backtracking)
226
+ console.error(`[multilingual-patterns] matchesStructuralPattern error: ${error.message}`);
227
+ return { matched: false, type: null, language: null };
228
+ }
229
+
230
+ return { matched: false, type: null, language: null };
231
+ }
232
+
233
+ /**
234
+ * Check if query matches any semantic pattern
235
+ *
236
+ * P0 Fix: Added try/catch error handling and length check to prevent DoS
237
+ *
238
+ * @param {string} query - Query to check
239
+ * @returns {{matched: boolean, type: string|null, language: string|null}}
240
+ */
241
+ export function matchesSemanticPattern(query) {
242
+ if (!query || typeof query !== 'string') {
243
+ return { matched: false, type: null, language: null };
244
+ }
245
+
246
+ // P0 Fix: Length check to prevent DoS via long inputs
247
+ if (query.length > MAX_QUERY_LENGTH) {
248
+ return { matched: false, type: null, language: null };
249
+ }
250
+
251
+ try {
252
+ for (const [type, patterns] of Object.entries(SEMANTIC_PATTERNS)) {
253
+ for (const [lang, pattern] of Object.entries(patterns)) {
254
+ if (pattern.test(query)) {
255
+ return { matched: true, type, language: lang };
256
+ }
257
+ }
258
+ }
259
+ } catch (error) {
260
+ // P0 Fix: Catch regex errors (e.g., stack overflow from backtracking)
261
+ console.error(`[multilingual-patterns] matchesSemanticPattern error: ${error.message}`);
262
+ return { matched: false, type: null, language: null };
263
+ }
264
+
265
+ return { matched: false, type: null, language: null };
266
+ }
267
+
268
+ /**
269
+ * Check if query has structural keywords in non-English language
270
+ * (Feature 27 for query router)
271
+ *
272
+ * @param {string} query - Query to check
273
+ * @returns {boolean}
274
+ */
275
+ export function hasStructuralKeywordNonEn(query) {
276
+ const result = matchesStructuralPattern(query);
277
+ return result.matched && result.language !== 'en';
278
+ }
279
+
280
+ /**
281
+ * Check if query has semantic keywords in non-English language
282
+ * (Feature 28 for query router)
283
+ *
284
+ * @param {string} query - Query to check
285
+ * @returns {boolean}
286
+ */
287
+ export function hasSemanticKeywordNonEn(query) {
288
+ const result = matchesSemanticPattern(query);
289
+ return result.matched && result.language !== 'en';
290
+ }
291
+
292
+ /**
293
+ * Check if query has cross-script concept pattern (Feature 29 for query router)
294
+ * Detects: identifier in script A + concept words in script B
295
+ *
296
+ * This is a strong HYBRID signal - mixing identifier lookup with conceptual context
297
+ * in different scripts.
298
+ *
299
+ * Examples:
300
+ * "समयट्रैकर security checks" → Hindi identifier + English concept
301
+ * "database queries in समयट्रैकर" → English concept + Hindi identifier
302
+ * "МониторПроцеса логика" → Cyrillic identifier + Cyrillic concept (same script, no match)
303
+ *
304
+ * @param {string} query - Query to check
305
+ * @returns {boolean}
306
+ */
307
+ export function hasCrossScriptConcept(query) {
308
+ if (!query || typeof query !== 'string' || query.length > 500) {
309
+ return false;
310
+ }
311
+
312
+ // Detect scripts present in query
313
+ const hasLatin = /[a-zA-Z]{2,}/.test(query);
314
+ const hasCyrillic = /[\u0400-\u04FF]{2,}/.test(query);
315
+ const hasDevanagari = /[\u0900-\u097F]{2,}/.test(query); // Hindi
316
+ const hasThai = /[\u0E00-\u0E7F]{2,}/.test(query);
317
+ const hasHebrew = /[\u0590-\u05FF]{2,}/.test(query);
318
+ const hasArabic = /[\u0600-\u06FF]{2,}/.test(query);
319
+ const hasGreek = /[\u0370-\u03FF]{2,}/.test(query);
320
+ const hasCJK = /[\u4E00-\u9FFF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]{2,}/.test(query);
321
+ const hasVietnamese = /[àáảãạăắằẳẵặâấầẩẫậèéẻẽẹêếềểễệìíỉĩịòóỏõọôốồổỗộơớờởỡợùúủũụưứừửữựỳýỷỹỵđ]{2,}/i.test(query);
322
+
323
+ // Count how many scripts are present
324
+ const scripts = [hasLatin, hasCyrillic, hasDevanagari, hasThai, hasHebrew, hasArabic, hasGreek, hasCJK, hasVietnamese];
325
+ const scriptCount = scripts.filter(Boolean).length;
326
+
327
+ // Need at least 2 different scripts
328
+ if (scriptCount < 2) {
329
+ return false;
330
+ }
331
+
332
+ // Check for concept words in at least one of the scripts
333
+ // Latin concept words (English)
334
+ const hasLatinConcept = /\b(flow|process|mechanism|logic|algorithm|authentication|validation|security|management|database|queries?|token|checks?|handling|session|error|login|password|user|data|handles?)\b/i.test(query);
335
+
336
+ // Non-Latin concept detection via semantic patterns
337
+ const semanticMatch = matchesSemanticPattern(query);
338
+ const hasNonLatinConcept = semanticMatch.matched && semanticMatch.language !== 'en';
339
+
340
+ // Cross-script concept: Latin concept + non-Latin identifier OR non-Latin concept + Latin identifier
341
+ if (hasLatin && hasLatinConcept && (hasCyrillic || hasDevanagari || hasThai || hasHebrew || hasArabic || hasGreek || hasCJK || hasVietnamese)) {
342
+ return true; // English concept + non-Latin identifier
343
+ }
344
+
345
+ if (hasNonLatinConcept && hasLatin) {
346
+ return true; // Non-Latin concept + Latin identifier
347
+ }
348
+
349
+ // Cyrillic concept + non-Cyrillic non-Latin identifier
350
+ if (hasCyrillic && !hasLatin && (hasDevanagari || hasThai || hasHebrew || hasArabic || hasGreek || hasCJK)) {
351
+ const cyrillicSemanticMatch = matchesSemanticPattern(query);
352
+ if (cyrillicSemanticMatch.matched && (cyrillicSemanticMatch.language === 'sr' || cyrillicSemanticMatch.language === 'ru' || cyrillicSemanticMatch.language === 'uk')) {
353
+ return true;
354
+ }
355
+ }
356
+
357
+ return false;
358
+ }
359
+
360
+ /**
361
+ * Detect query language based on patterns
362
+ *
363
+ * @param {string} query - Query to analyze
364
+ * @returns {string} - Detected language code or 'unknown'
365
+ */
366
+ export function detectQueryLanguage(query) {
367
+ // Check structural patterns first
368
+ const structural = matchesStructuralPattern(query);
369
+ if (structural.matched) {
370
+ return structural.language;
371
+ }
372
+
373
+ // Check semantic patterns
374
+ const semantic = matchesSemanticPattern(query);
375
+ if (semantic.matched) {
376
+ return semantic.language;
377
+ }
378
+
379
+ // Default to English if no pattern matched
380
+ return 'unknown';
381
+ }
382
+
383
+ /**
384
+ * Get all supported languages for a pattern type
385
+ *
386
+ * @param {string} type - Pattern type ('structural' or 'semantic')
387
+ * @returns {string[]} - Array of language codes
388
+ */
389
+ export function getSupportedLanguages(type = 'all') {
390
+ const languages = new Set();
391
+
392
+ if (type === 'structural' || type === 'all') {
393
+ for (const patterns of Object.values(STRUCTURAL_PATTERNS)) {
394
+ for (const lang of Object.keys(patterns)) {
395
+ languages.add(lang);
396
+ }
397
+ }
398
+ }
399
+
400
+ if (type === 'semantic' || type === 'all') {
401
+ for (const patterns of Object.values(SEMANTIC_PATTERNS)) {
402
+ for (const lang of Object.keys(patterns)) {
403
+ languages.add(lang);
404
+ }
405
+ }
406
+ }
407
+
408
+ return [...languages].sort();
409
+ }
410
+
411
+ // Language code to name mapping
412
+ export const LANGUAGE_NAMES = {
413
+ en: 'English',
414
+ de: 'German',
415
+ es: 'Spanish',
416
+ fr: 'French',
417
+ pt: 'Portuguese',
418
+ it: 'Italian',
419
+ sr: 'Serbian',
420
+ ru: 'Russian',
421
+ uk: 'Ukrainian',
422
+ zh: 'Chinese',
423
+ ja: 'Japanese',
424
+ ko: 'Korean',
425
+ ar: 'Arabic',
426
+ el: 'Greek',
427
+ th: 'Thai',
428
+ he: 'Hebrew',
429
+ hi: 'Hindi',
430
+ vi: 'Vietnamese',
431
+ };