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.
- package/LICENSE +190 -0
- package/NOTICE +23 -0
- package/core/cli.js +51 -0
- package/core/config.js +27 -0
- package/core/embedding/embedding-cache.js +467 -0
- package/core/embedding/embedding-local-model.js +845 -0
- package/core/embedding/embedding-remote.js +492 -0
- package/core/embedding/embedding-service.js +712 -0
- package/core/embedding/embedding-telemetry.js +219 -0
- package/core/embedding/index.js +40 -0
- package/core/graph/community-detector.js +294 -0
- package/core/graph/graph-expansion.js +839 -0
- package/core/graph/graph-extractor.js +2304 -0
- package/core/graph/graph-search.js +2148 -0
- package/core/graph/hcgs-generator.js +666 -0
- package/core/graph/index.js +16 -0
- package/core/graph/leiden-algorithm.js +547 -0
- package/core/graph/relationship-resolver.js +366 -0
- package/core/graph/repo-map.js +408 -0
- package/core/graph/summary-manager.js +549 -0
- package/core/indexing/artifact-builder.js +1054 -0
- package/core/indexing/ast-chunker.js +709 -0
- package/core/indexing/chunking/chunk-builder.js +170 -0
- package/core/indexing/chunking/markdown-chunker.js +503 -0
- package/core/indexing/chunking/plaintext-chunker.js +104 -0
- package/core/indexing/dedup/dedup-phase.js +159 -0
- package/core/indexing/dedup/exemplar-selector.js +65 -0
- package/core/indexing/document-chunker.js +56 -0
- package/core/indexing/incremental-parser.js +390 -0
- package/core/indexing/incremental-tracker.js +761 -0
- package/core/indexing/index-codebase-v21.js +472 -0
- package/core/indexing/index-maintainer.mjs +1674 -0
- package/core/indexing/index.js +90 -0
- package/core/indexing/indexer-ann.js +1077 -0
- package/core/indexing/indexer-build.js +742 -0
- package/core/indexing/indexer-phases.js +800 -0
- package/core/indexing/indexer-pool.js +764 -0
- package/core/indexing/indexer-sparse-gram.js +98 -0
- package/core/indexing/indexer-utils.js +536 -0
- package/core/indexing/indexer-worker.js +148 -0
- package/core/indexing/li-skip-policy.js +225 -0
- package/core/indexing/merkle-tracker.js +244 -0
- package/core/indexing/model-pool.js +166 -0
- package/core/infrastructure/code-graph-repository.js +120 -0
- package/core/infrastructure/codebase-repository.js +131 -0
- package/core/infrastructure/config/dedup.js +54 -0
- package/core/infrastructure/config/embedding.js +298 -0
- package/core/infrastructure/config/graph.js +80 -0
- package/core/infrastructure/config/index.js +82 -0
- package/core/infrastructure/config/indexing.js +8 -0
- package/core/infrastructure/config/platform.js +254 -0
- package/core/infrastructure/config/ranking.js +221 -0
- package/core/infrastructure/config/search.js +396 -0
- package/core/infrastructure/config/translation.js +89 -0
- package/core/infrastructure/config/vector-store.js +114 -0
- package/core/infrastructure/constants.js +86 -0
- package/core/infrastructure/coreml-cascade.js +909 -0
- package/core/infrastructure/coreml-cascade.json +46 -0
- package/core/infrastructure/coreml-provider.js +81 -0
- package/core/infrastructure/db-utils.js +69 -0
- package/core/infrastructure/dedup-hashing.js +83 -0
- package/core/infrastructure/hardware-capability.js +332 -0
- package/core/infrastructure/index.js +104 -0
- package/core/infrastructure/language-patterns/maps.js +121 -0
- package/core/infrastructure/language-patterns/registry-core.js +323 -0
- package/core/infrastructure/language-patterns/registry-data-query.js +155 -0
- package/core/infrastructure/language-patterns/registry-object-oriented.js +285 -0
- package/core/infrastructure/language-patterns/registry-tooling.js +240 -0
- package/core/infrastructure/language-patterns/registry-web-style.js +143 -0
- package/core/infrastructure/language-patterns/registry.js +19 -0
- package/core/infrastructure/language-patterns.js +141 -0
- package/core/infrastructure/llm-provider.js +733 -0
- package/core/infrastructure/manifest.json +46 -0
- package/core/infrastructure/maxsim.wasm +0 -0
- package/core/infrastructure/model-fetcher.js +423 -0
- package/core/infrastructure/model-registry.js +214 -0
- package/core/infrastructure/native-inference.js +587 -0
- package/core/infrastructure/native-resolver.js +187 -0
- package/core/infrastructure/native-sparse-gram.js +257 -0
- package/core/infrastructure/native-tokenizer.js +160 -0
- package/core/infrastructure/onnx-mutex.js +45 -0
- package/core/infrastructure/onnx-session-utils.js +261 -0
- package/core/infrastructure/ort-pipeline.js +111 -0
- package/core/infrastructure/project-detector.js +102 -0
- package/core/infrastructure/quantization.js +410 -0
- package/core/infrastructure/simd-distance.js +502 -0
- package/core/infrastructure/simd-distance.wasm +0 -0
- package/core/infrastructure/tree-sitter-provider.js +665 -0
- package/core/infrastructure/webgpu-maxsim.js +222 -0
- package/core/query/index.js +35 -0
- package/core/query/intent-detector.js +201 -0
- package/core/query/intent-router.js +156 -0
- package/core/query/query-router-catboost.js +222 -0
- package/core/query/query-router-ml.js +266 -0
- package/core/query/query-router.js +213 -0
- package/core/ranking/cascaded-scorer.js +379 -0
- package/core/ranking/flashrank.js +810 -0
- package/core/ranking/index.js +49 -0
- package/core/ranking/late-interaction-index.js +2383 -0
- package/core/ranking/late-interaction-model.js +812 -0
- package/core/ranking/local-reranker.js +374 -0
- package/core/ranking/mmr.js +379 -0
- package/core/ranking/quality-scorer.js +363 -0
- package/core/search/context-expander.js +1167 -0
- package/core/search/dedup/sibling-expander.js +327 -0
- package/core/search/index.js +16 -0
- package/core/search/search-boost.js +259 -0
- package/core/search/search-cli.js +544 -0
- package/core/search/search-format.js +282 -0
- package/core/search/search-fusion.js +327 -0
- package/core/search/search-hybrid.js +204 -0
- package/core/search/search-pattern-chunks.js +337 -0
- package/core/search/search-pattern-planner.js +439 -0
- package/core/search/search-pattern-prefilter.js +412 -0
- package/core/search/search-pattern-ripgrep.js +663 -0
- package/core/search/search-pattern.js +463 -0
- package/core/search/search-postprocess.js +452 -0
- package/core/search/search-semantic.js +706 -0
- package/core/search/search-server.js +554 -0
- package/core/search/session-daemon-prewarm.mjs +164 -0
- package/core/search/session-warmup.js +595 -0
- package/core/search/sweet-search.js +632 -0
- package/core/search/warmup-metrics.js +532 -0
- package/core/start-server.js +6 -0
- package/core/training/query-router/features/extractor.js +762 -0
- package/core/training/query-router/features/multilingual-patterns.js +431 -0
- package/core/training/query-router/features/text-segmenter.js +303 -0
- package/core/training/query-router/features/unicode-utils.js +383 -0
- package/core/training/query-router/output/v45_router_d4.js +11521 -0
- package/core/training/query-router/output/v46_router_d4.js +11498 -0
- package/core/vector-store/binary-heap.js +227 -0
- package/core/vector-store/binary-hnsw-index.js +1004 -0
- package/core/vector-store/float-vector-store.js +234 -0
- package/core/vector-store/hnsw-index.js +580 -0
- package/core/vector-store/index.js +39 -0
- package/core/vector-store/seismic-index.js +498 -0
- package/core/vocabulary/index.js +84 -0
- package/core/vocabulary/vocab-constants.js +20 -0
- package/core/vocabulary/vocab-miner-extractors.js +375 -0
- package/core/vocabulary/vocab-miner-nl.js +404 -0
- package/core/vocabulary/vocab-miner-utils.js +146 -0
- package/core/vocabulary/vocab-miner.js +574 -0
- package/core/vocabulary/vocab-prewarm-cli.js +110 -0
- package/core/vocabulary/vocab-ranker.js +492 -0
- package/core/vocabulary/vocab-warmer.js +523 -0
- package/core/vocabulary/vocab-warmup-orchestrator.js +425 -0
- package/core/vocabulary/vocabulary-utils.js +704 -0
- package/crates/wasm-router/pkg/package.json +13 -0
- package/crates/wasm-router/pkg/query_router_wasm.d.ts +36 -0
- package/crates/wasm-router/pkg/query_router_wasm.js +271 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm +0 -0
- package/crates/wasm-router/pkg/query_router_wasm_bg.wasm.d.ts +19 -0
- package/mcp/config-gen.js +121 -0
- package/mcp/server.js +335 -0
- package/mcp/tool-handlers.js +476 -0
- package/package.json +131 -9
- package/scripts/benchmark-harness.js +794 -0
- package/scripts/init.js +1058 -0
- package/scripts/smoke-test.js +435 -0
- package/scripts/uninstall.js +478 -0
- 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
|
+
};
|