@cachly-dev/mcp-server 0.5.50 → 0.5.70
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/dist/index.js +523 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +451 -40
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ import { Redis } from 'ioredis';
|
|
|
47
47
|
const API_URL = process.env.CACHLY_API_URL ?? 'https://api.cachly.dev';
|
|
48
48
|
const JWT = process.env.CACHLY_JWT ?? '';
|
|
49
49
|
const EMBED_MODEL = process.env.CACHLY_EMBED_MODEL ?? '';
|
|
50
|
-
const CURRENT_VERSION = '0.5.
|
|
50
|
+
const CURRENT_VERSION = '0.5.70';
|
|
51
51
|
/**
|
|
52
52
|
* ┌──────────────────────────────────────────────────────────────────────┐
|
|
53
53
|
* │ EMBEDDING PROVIDER — pluggable, client-side first │
|
|
@@ -420,6 +420,40 @@ const STOPWORDS = new Set([
|
|
|
420
420
|
'मैं', 'तुम', 'उन', 'इन', 'ने', 'बहुत', 'सब', 'कुछ', 'फिर',
|
|
421
421
|
'अब', 'तो', 'ही', 'तरह', 'जैसे', 'करना', 'होना', 'रहा', 'रही',
|
|
422
422
|
'रहे', 'गया', 'गई', 'गए', 'किया', 'किए', 'कर', 'हुआ', 'हुई',
|
|
423
|
+
// ── Russian — common prepositions, pronouns, auxiliary verbs ───────────────
|
|
424
|
+
'в', 'на', 'не', 'с', 'и', 'а', 'но', 'по', 'за', 'из', 'от', 'до',
|
|
425
|
+
'к', 'у', 'о', 'об', 'во', 'при', 'под', 'над', 'без', 'для',
|
|
426
|
+
'что', 'как', 'это', 'все', 'так', 'уже', 'или', 'же', 'ли',
|
|
427
|
+
'если', 'то', 'да', 'нет', 'был', 'была', 'были', 'быть', 'есть',
|
|
428
|
+
'его', 'её', 'их', 'этот', 'эта', 'эти', 'который', 'которая',
|
|
429
|
+
'которые', 'который', 'мой', 'моя', 'мои', 'ваш', 'ваша', 'ваши',
|
|
430
|
+
'он', 'она', 'они', 'мы', 'вы', 'я', 'ты', 'тот', 'та', 'те',
|
|
431
|
+
'очень', 'тоже', 'также', 'когда', 'где', 'как', 'почему', 'зачем',
|
|
432
|
+
'сейчас', 'здесь', 'там', 'потому', 'поэтому', 'чтобы', 'тут',
|
|
433
|
+
// ── Turkish — common particles, postpositions, copulas ─────────────────────
|
|
434
|
+
'bir', 'bu', 'şu', 'o', 've', 'ile', 'de', 'da', 'için', 'gibi',
|
|
435
|
+
'ama', 'fakat', 'ancak', 'ya', 'ne', 'ki', 'mi', 'mı', 'mu', 'mü',
|
|
436
|
+
'var', 'yok', 'olan', 'oldu', 'olur', 'olarak', 'ise', 'daha',
|
|
437
|
+
'çok', 'en', 'her', 'hiç', 'bazı', 'tüm', 'bütün', 'hem', 'veya',
|
|
438
|
+
'bu', 'şu', 'ben', 'sen', 'biz', 'siz', 'onlar', 'benim', 'senin',
|
|
439
|
+
'nasıl', 'neden', 'niçin', 'nerede', 'ne', 'hangi', 'kaç',
|
|
440
|
+
// ── Polish — common prepositions, pronouns, particles ─────────────────────
|
|
441
|
+
'w', 'na', 'z', 'do', 'się', 'że', 'to', 'jest', 'i', 'a', 'nie',
|
|
442
|
+
'tak', 'jak', 'czy', 'po', 'o', 'ale', 'go', 'mu', 'jej', 'ich',
|
|
443
|
+
'tego', 'tej', 'te', 'ten', 'ta', 'są', 'był', 'była', 'było', 'byli',
|
|
444
|
+
'będzie', 'będą', 'ma', 'mam', 'masz', 'mają', 'ze', 'co', 'już',
|
|
445
|
+
'przez', 'przy', 'za', 'bez', 'nad', 'pod', 'przed', 'po', 'między',
|
|
446
|
+
'kiedy', 'gdzie', 'dlaczego', 'który', 'która', 'które', 'tylko', 'też',
|
|
447
|
+
// ── Czech — common words ──────────────────────────────────────────────────
|
|
448
|
+
'v', 'na', 'z', 'do', 'se', 'že', 'to', 'je', 'a', 'ne', 'pro',
|
|
449
|
+
'ale', 'jak', 'by', 'byl', 'být', 'jsem', 'jsou', 'má', 'mám',
|
|
450
|
+
'ten', 'ta', 'ty', 'tato', 'jeho', 'její', 'jejich', 'také', 'jen',
|
|
451
|
+
'kde', 'kdy', 'proč', 'který', 'která', 'které', 'co', 'při', 'bez',
|
|
452
|
+
// ── Bengali — common particles, pronouns, verbs ───────────────────────────
|
|
453
|
+
'এই', 'এটি', 'এটা', 'এর', 'তার', 'তারা', 'আমি', 'তুমি', 'সে', 'আমরা',
|
|
454
|
+
'এবং', 'কিন্তু', 'বা', 'না', 'হ্যাঁ', 'যে', 'কি', 'কে', 'কী', 'থেকে',
|
|
455
|
+
'দিয়ে', 'জন্য', 'সাথে', 'মধ্যে', 'উপর', 'নিচে', 'আছে', 'ছিল', 'হয়',
|
|
456
|
+
'করা', 'করে', 'করেছে', 'হবে', 'হয়েছে', 'একটি', 'একটা', 'অনেক', 'সব',
|
|
423
457
|
]);
|
|
424
458
|
// CJK Unicode ranges used for bigram extraction
|
|
425
459
|
const CJK_RE = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;
|
|
@@ -433,6 +467,12 @@ const ARABIC_CHAR_RE = /[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\uf
|
|
|
433
467
|
const FARSI_CHAR_RE = /[\u067e\u0686\u0698\u06af\u06cc]/;
|
|
434
468
|
// Devanagari (Hindi, Sanskrit, Marathi …) — U+0900–U+097F + extended
|
|
435
469
|
const DEVANAGARI_RE = /[\u0900-\u097f]/;
|
|
470
|
+
// Cyrillic (Russian, Bulgarian, Ukrainian, Serbian …) — U+0400–U+04FF
|
|
471
|
+
const CYRILLIC_RE = /[\u0400-\u04ff]/;
|
|
472
|
+
// Turkish uses Latin alphabet but has unique chars (ğ, ş, ı, ö, ü, ç) — detected by these
|
|
473
|
+
const TURKISH_CHAR_RE = /[\u011f\u015f\u0131\u0130\u00e7]/; // ğ ş ı İ ç
|
|
474
|
+
// Bengali (Bangla) — U+0980–U+09FF
|
|
475
|
+
const BENGALI_RE = /[\u0980-\u09ff]/;
|
|
436
476
|
// ── Katakana → Romaji conversion table (Hepburn system) ──────────────────────
|
|
437
477
|
// Digraphs must be listed before single chars so they match first.
|
|
438
478
|
const KATA_ROMAJI_TABLE = [
|
|
@@ -610,55 +650,323 @@ function hindiLightStem(word) {
|
|
|
610
650
|
if (result.endsWith('\u0907\u092f\u093e\u0902') && result.length > 5)
|
|
611
651
|
return result.slice(0, -4); // \u0907\u092f\u093e\u0902 (iyāṃ) f plural
|
|
612
652
|
if (result.endsWith('\u0940\u092f\u093e\u0902') && result.length > 5)
|
|
613
|
-
return result.slice(0, -4); // \u0940\u092f\u093e\
|
|
653
|
+
return result.slice(0, -4); // \u0940\u092f\u093e\u0102 (īyāṃ)
|
|
614
654
|
return result;
|
|
615
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Russian light stemmer — strips common inflectional suffixes.
|
|
658
|
+
* Handles the most frequent verb/noun/adjective endings to improve recall.
|
|
659
|
+
* Only strips when result is still ≥ 3 chars.
|
|
660
|
+
*
|
|
661
|
+
* Covers:
|
|
662
|
+
* ошибки/ошибка → ошибк (noun plural/genitive)
|
|
663
|
+
* развёртывание → развёртыва (gerund → stem)
|
|
664
|
+
* установить → установ (infinitive)
|
|
665
|
+
* настройки → настройк (genitive plural)
|
|
666
|
+
*/
|
|
667
|
+
function russianLightStem(word) {
|
|
668
|
+
let w = word;
|
|
669
|
+
// Longest first to avoid partial stripping
|
|
670
|
+
// Verb infinitives / gerunds
|
|
671
|
+
if (w.endsWith('ывание') && w.length > 7)
|
|
672
|
+
return w.slice(0, -6);
|
|
673
|
+
if (w.endsWith('ивание') && w.length > 7)
|
|
674
|
+
return w.slice(0, -6);
|
|
675
|
+
if (w.endsWith('ование') && w.length > 7)
|
|
676
|
+
return w.slice(0, -6);
|
|
677
|
+
if (w.endsWith('вание') && w.length > 6)
|
|
678
|
+
return w.slice(0, -5);
|
|
679
|
+
if (w.endsWith('ение') && w.length > 5)
|
|
680
|
+
return w.slice(0, -4);
|
|
681
|
+
if (w.endsWith('ание') && w.length > 5)
|
|
682
|
+
return w.slice(0, -4);
|
|
683
|
+
if (w.endsWith('ить') && w.length > 4)
|
|
684
|
+
return w.slice(0, -3);
|
|
685
|
+
if (w.endsWith('ать') && w.length > 4)
|
|
686
|
+
return w.slice(0, -3);
|
|
687
|
+
if (w.endsWith('еть') && w.length > 4)
|
|
688
|
+
return w.slice(0, -3);
|
|
689
|
+
if (w.endsWith('уть') && w.length > 4)
|
|
690
|
+
return w.slice(0, -3);
|
|
691
|
+
// Noun plural/genitive
|
|
692
|
+
if (w.endsWith('ки') && w.length > 4)
|
|
693
|
+
return w.slice(0, -2);
|
|
694
|
+
if (w.endsWith('ги') && w.length > 4)
|
|
695
|
+
return w.slice(0, -2);
|
|
696
|
+
if (w.endsWith('ов') && w.length > 4)
|
|
697
|
+
return w.slice(0, -2);
|
|
698
|
+
if (w.endsWith('ев') && w.length > 4)
|
|
699
|
+
return w.slice(0, -2);
|
|
700
|
+
if (w.endsWith('ей') && w.length > 4)
|
|
701
|
+
return w.slice(0, -2);
|
|
702
|
+
if (w.endsWith('ий') && w.length > 4)
|
|
703
|
+
return w.slice(0, -2);
|
|
704
|
+
if (w.endsWith('ый') && w.length > 4)
|
|
705
|
+
return w.slice(0, -2);
|
|
706
|
+
if (w.endsWith('ая') && w.length > 4)
|
|
707
|
+
return w.slice(0, -2);
|
|
708
|
+
if (w.endsWith('ое') && w.length > 4)
|
|
709
|
+
return w.slice(0, -2);
|
|
710
|
+
if (w.endsWith('ую') && w.length > 4)
|
|
711
|
+
return w.slice(0, -2);
|
|
712
|
+
// Verb present tense
|
|
713
|
+
if (w.endsWith('ет') && w.length > 4)
|
|
714
|
+
return w.slice(0, -2);
|
|
715
|
+
if (w.endsWith('ют') && w.length > 4)
|
|
716
|
+
return w.slice(0, -2);
|
|
717
|
+
if (w.endsWith('ут') && w.length > 4)
|
|
718
|
+
return w.slice(0, -2);
|
|
719
|
+
if (w.endsWith('ят') && w.length > 4)
|
|
720
|
+
return w.slice(0, -2);
|
|
721
|
+
return w;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Turkish light stemmer — strips common agglutinative suffixes.
|
|
725
|
+
* Turkish is highly agglutinative; this covers the most common inflectional ends.
|
|
726
|
+
*
|
|
727
|
+
* Covers:
|
|
728
|
+
* hatalar → hata (-lar/-ler plural)
|
|
729
|
+
* sunucuda → sunucu (-da/-de locative)
|
|
730
|
+
* dağıtımı → dağıtım (-ı/-i/-u/-ü accusative)
|
|
731
|
+
* yüklemek → yükle (-mek/-mak infinitive)
|
|
732
|
+
*/
|
|
733
|
+
function turkishLightStem(word) {
|
|
734
|
+
let w = word;
|
|
735
|
+
// Suffixes longest-first
|
|
736
|
+
if (w.endsWith('lardaki') && w.length > 7)
|
|
737
|
+
return w.slice(0, -7);
|
|
738
|
+
if (w.endsWith('lerdeki') && w.length > 7)
|
|
739
|
+
return w.slice(0, -7);
|
|
740
|
+
if (w.endsWith('ların') && w.length > 6)
|
|
741
|
+
return w.slice(0, -5);
|
|
742
|
+
if (w.endsWith('lerin') && w.length > 6)
|
|
743
|
+
return w.slice(0, -5);
|
|
744
|
+
if (w.endsWith('larda') && w.length > 6)
|
|
745
|
+
return w.slice(0, -5);
|
|
746
|
+
if (w.endsWith('lerde') && w.length > 6)
|
|
747
|
+
return w.slice(0, -5);
|
|
748
|
+
if (w.endsWith('ları') && w.length > 5)
|
|
749
|
+
return w.slice(0, -4);
|
|
750
|
+
if (w.endsWith('leri') && w.length > 5)
|
|
751
|
+
return w.slice(0, -4);
|
|
752
|
+
if (w.endsWith('mek') && w.length > 4)
|
|
753
|
+
return w.slice(0, -3);
|
|
754
|
+
if (w.endsWith('mak') && w.length > 4)
|
|
755
|
+
return w.slice(0, -3);
|
|
756
|
+
if (w.endsWith('ler') && w.length > 4)
|
|
757
|
+
return w.slice(0, -3);
|
|
758
|
+
if (w.endsWith('lar') && w.length > 4)
|
|
759
|
+
return w.slice(0, -3);
|
|
760
|
+
if (w.endsWith('nın') && w.length > 4)
|
|
761
|
+
return w.slice(0, -3);
|
|
762
|
+
if (w.endsWith('nin') && w.length > 4)
|
|
763
|
+
return w.slice(0, -3);
|
|
764
|
+
if (w.endsWith('nun') && w.length > 4)
|
|
765
|
+
return w.slice(0, -3);
|
|
766
|
+
if (w.endsWith('nün') && w.length > 4)
|
|
767
|
+
return w.slice(0, -3);
|
|
768
|
+
if (w.endsWith('da') && w.length > 4)
|
|
769
|
+
return w.slice(0, -2);
|
|
770
|
+
if (w.endsWith('de') && w.length > 4)
|
|
771
|
+
return w.slice(0, -2);
|
|
772
|
+
if (w.endsWith('ta') && w.length > 4)
|
|
773
|
+
return w.slice(0, -2);
|
|
774
|
+
if (w.endsWith('te') && w.length > 4)
|
|
775
|
+
return w.slice(0, -2);
|
|
776
|
+
if (w.endsWith('dan') && w.length > 4)
|
|
777
|
+
return w.slice(0, -3);
|
|
778
|
+
if (w.endsWith('den') && w.length > 4)
|
|
779
|
+
return w.slice(0, -3);
|
|
780
|
+
if (w.endsWith('tan') && w.length > 4)
|
|
781
|
+
return w.slice(0, -3);
|
|
782
|
+
if (w.endsWith('ten') && w.length > 4)
|
|
783
|
+
return w.slice(0, -3);
|
|
784
|
+
if (w.endsWith('ın') && w.length > 4)
|
|
785
|
+
return w.slice(0, -2);
|
|
786
|
+
if (w.endsWith('in') && w.length > 4)
|
|
787
|
+
return w.slice(0, -2);
|
|
788
|
+
if (w.endsWith('un') && w.length > 4)
|
|
789
|
+
return w.slice(0, -2);
|
|
790
|
+
if (w.endsWith('ün') && w.length > 4)
|
|
791
|
+
return w.slice(0, -2);
|
|
792
|
+
if (w.endsWith('ı') && w.length > 4)
|
|
793
|
+
return w.slice(0, -1);
|
|
794
|
+
if (w.endsWith('i') && w.length > 4)
|
|
795
|
+
return w.slice(0, -1);
|
|
796
|
+
if (w.endsWith('u') && w.length > 4)
|
|
797
|
+
return w.slice(0, -1);
|
|
798
|
+
if (w.endsWith('ü') && w.length > 4)
|
|
799
|
+
return w.slice(0, -1);
|
|
800
|
+
return w;
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Bengali (Bangla) light stemmer — strips common verbal and nominal suffixes.
|
|
804
|
+
* Bengali is an Indo-Aryan language with moderate morphological complexity.
|
|
805
|
+
* Only strips when result is still ≥ 2 chars.
|
|
806
|
+
*
|
|
807
|
+
* Covers:
|
|
808
|
+
* করছে/করেছে → কর (progressive/perfect aspect)
|
|
809
|
+
* সার্ভারগুলো → সার্ভার (-গুলো plural)
|
|
810
|
+
* সমস্যাটি → সমস্যা (-টি singular marker)
|
|
811
|
+
*/
|
|
812
|
+
function bengaliLightStem(word) {
|
|
813
|
+
let w = word;
|
|
814
|
+
// Plural / collective markers (longest first)
|
|
815
|
+
if (w.endsWith('\u0997\u09c1\u09b2\u09cb') && w.length > 5)
|
|
816
|
+
return w.slice(0, -4); // গুলো (-gulo plural)
|
|
817
|
+
if (w.endsWith('\u0997\u09c1\u09b2\u09bf') && w.length > 5)
|
|
818
|
+
return w.slice(0, -4); // গুলি (-guli plural)
|
|
819
|
+
if (w.endsWith('\u09a6\u09c7\u09b0') && w.length > 4)
|
|
820
|
+
return w.slice(0, -3); // দের (genitive plural)
|
|
821
|
+
if (w.endsWith('\u09a6\u09bf\u0997\u09c7') && w.length > 5)
|
|
822
|
+
return w.slice(0, -4); // দিগে
|
|
823
|
+
// Definiteness / case markers
|
|
824
|
+
if (w.endsWith('\u099f\u09bf') && w.length > 3)
|
|
825
|
+
return w.slice(0, -2); // টি (singular definite)
|
|
826
|
+
if (w.endsWith('\u099f\u09be') && w.length > 3)
|
|
827
|
+
return w.slice(0, -2); // টা (singular definite)
|
|
828
|
+
if (w.endsWith('\u0996\u09be\u09a8\u09be') && w.length > 5)
|
|
829
|
+
return w.slice(0, -4); // খানা
|
|
830
|
+
// Verbal suffixes
|
|
831
|
+
if (w.endsWith('\u099b\u09c7') && w.length > 3)
|
|
832
|
+
return w.slice(0, -2); // ছে (progressive)
|
|
833
|
+
if (w.endsWith('\u099b\u09bf\u09b2') && w.length > 4)
|
|
834
|
+
return w.slice(0, -3); // ছিল (past progressive)
|
|
835
|
+
if (w.endsWith('\u09af\u09be\u09ac\u09c7') && w.length > 5)
|
|
836
|
+
return w.slice(0, -4); // যাবে (future)
|
|
837
|
+
if (w.endsWith('\u0995\u09b0\u09be') && w.length > 4)
|
|
838
|
+
return w.slice(0, -3); // করা (infinitive)
|
|
839
|
+
if (w.endsWith('\u0995\u09b0\u09c7') && w.length > 4)
|
|
840
|
+
return w.slice(0, -3); // করে (present)
|
|
841
|
+
if (w.endsWith('\u09b9\u09df') && w.length > 3)
|
|
842
|
+
return w.slice(0, -2); // হয় (is/becomes)
|
|
843
|
+
if (w.endsWith('\u09b9\u09ac\u09c7') && w.length > 4)
|
|
844
|
+
return w.slice(0, -3); // হবে (will be)
|
|
845
|
+
return w;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Pre-process text BEFORE tokenization to split code identifiers.
|
|
849
|
+
* Handles camelCase, PascalCase, snake_case, and kebab-case.
|
|
850
|
+
*
|
|
851
|
+
* Examples:
|
|
852
|
+
* deployServer → deploy Server (then lowercased → deploy server)
|
|
853
|
+
* HTMLParser → HTML Parser
|
|
854
|
+
* my_api_key → my api key
|
|
855
|
+
* get-user-by-id → get user by id (hyphens preserved in regex, spaces also fine)
|
|
856
|
+
* BackendServiceImpl → Backend Service Impl
|
|
857
|
+
*/
|
|
858
|
+
function preprocessText(text) {
|
|
859
|
+
return text
|
|
860
|
+
// camelCase boundary: lowercase/digit → uppercase
|
|
861
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
862
|
+
// Consecutive uppercase → uppercase+lowercase boundary: HTMLParser → HTML Parser
|
|
863
|
+
.replace(/([A-Z]{2,})([A-Z][a-z])/g, '$1 $2')
|
|
864
|
+
// snake_case: replace underscores with spaces
|
|
865
|
+
.replace(/_/g, ' ');
|
|
866
|
+
}
|
|
616
867
|
// Maps tokens (English, Japanese katakana, Chinese, Korean, Arabic, Hebrew)
|
|
617
868
|
// to their equivalents in other languages. Used to expand tokens at search time
|
|
618
869
|
// so "deploy" finds documents containing "デプロイ" / "部署" / "배포", and vice versa.
|
|
619
870
|
//
|
|
620
871
|
// Keys must be lowercase. CJK values will be bigram-expanded at use time.
|
|
621
872
|
const CROSS_LINGUAL_MAP = new Map([
|
|
873
|
+
// ── Tech / Ecosystem synonyms (language-agnostic) ─────────────────────────
|
|
874
|
+
['javascript', ['js', 'node', 'nodejs', 'ecmascript']],
|
|
875
|
+
['js', ['javascript', 'node', 'nodejs']],
|
|
876
|
+
['typescript', ['ts', 'javascript', 'js', 'tsc']],
|
|
877
|
+
['ts', ['typescript', 'javascript', 'js']],
|
|
878
|
+
['python', ['py', 'pip', 'django', 'flask', 'fastapi']],
|
|
879
|
+
['py', ['python', 'pip']],
|
|
880
|
+
['golang', ['go', 'gopher', 'goroutine']],
|
|
881
|
+
['go', ['golang', 'goroutine']],
|
|
882
|
+
['rust', ['cargo', 'rustlang', 'crates']],
|
|
883
|
+
['cargo', ['rust', 'rustlang']],
|
|
884
|
+
['java', ['jvm', 'maven', 'gradle', 'spring']],
|
|
885
|
+
['kotlin', ['jvm', 'android', 'coroutine']],
|
|
886
|
+
['dotnet', ['csharp', 'asp', 'nuget', 'aspnet']],
|
|
887
|
+
['postgresql', ['postgres', 'pg', 'psql']],
|
|
888
|
+
['postgres', ['postgresql', 'pg', 'psql']],
|
|
889
|
+
['mysql', ['mariadb', 'sql']],
|
|
890
|
+
['mongodb', ['mongo', 'nosql', 'bson', 'mongoose']],
|
|
891
|
+
['mongo', ['mongodb', 'nosql', 'bson']],
|
|
892
|
+
['elasticsearch', ['elastic', 'opensearch', 'lucene', 'kibana']],
|
|
893
|
+
['elastic', ['elasticsearch', 'opensearch']],
|
|
894
|
+
['kubernetes', ['k8s', 'kube', 'kubectl', 'helm', 'k3s']],
|
|
895
|
+
['k8s', ['kubernetes', 'kube', 'kubectl', 'helm']],
|
|
896
|
+
['helm', ['kubernetes', 'k8s', 'chart']],
|
|
897
|
+
['terraform', ['tf', 'hcl', 'iac', 'opentofu']],
|
|
898
|
+
['ansible', ['playbook', 'automation']],
|
|
899
|
+
['grafana', ['dashboard', 'visualization', 'metrics']],
|
|
900
|
+
['prometheus', ['metrics', 'alert', 'scrape', 'grafana']],
|
|
901
|
+
['nginx', ['proxy', 'webserver', 'ingress']],
|
|
902
|
+
['traefik', ['proxy', 'ingress', 'router']],
|
|
903
|
+
['rabbitmq', ['amqp', 'queue', 'broker', 'messaging']],
|
|
904
|
+
['kafka', ['messaging', 'stream', 'broker']],
|
|
905
|
+
['grpc', ['protobuf', 'proto', 'rpc']],
|
|
906
|
+
['graphql', ['gql', 'resolver', 'schema']],
|
|
907
|
+
['react', ['jsx', 'hooks', 'component', 'redux']],
|
|
908
|
+
['nextjs', ['next', 'react', 'ssr', 'vercel']],
|
|
909
|
+
['vue', ['vuejs', 'vite', 'nuxt']],
|
|
910
|
+
['angular', ['ng', 'rxjs', 'typescript']],
|
|
911
|
+
['aws', ['amazon', 'ec2', 's3', 'lambda', 'cloudwatch', 'ecs', 'eks']],
|
|
912
|
+
['gcp', ['google cloud', 'gke', 'bigquery']],
|
|
913
|
+
['azure', ['microsoft cloud', 'aks', 'devops']],
|
|
914
|
+
['s3', ['bucket', 'object storage', 'aws']],
|
|
915
|
+
['lambda', ['serverless', 'function', 'faas', 'aws']],
|
|
916
|
+
['jwt', ['token', 'bearer', 'oauth', 'auth']],
|
|
917
|
+
['oauth', ['oidc', 'auth', 'token', 'sso']],
|
|
918
|
+
['webhook', ['callback', 'event', 'trigger']],
|
|
919
|
+
['cron', ['schedule', 'job', 'timer']],
|
|
920
|
+
['yaml', ['yml', 'config', 'manifest']],
|
|
921
|
+
['dotenv', ['env', 'environment', 'envfile']],
|
|
922
|
+
['github', ['git', 'actions', 'repo', 'ci']],
|
|
923
|
+
['gitlab', ['git', 'pipeline', 'runner']],
|
|
924
|
+
['wireguard', ['vpn', 'tunnel', 'wg']],
|
|
925
|
+
['prisma', ['orm', 'database', 'schema', 'migration']],
|
|
926
|
+
['npm', ['node', 'package', 'registry', 'yarn', 'pnpm']],
|
|
927
|
+
['yarn', ['npm', 'package', 'node']],
|
|
928
|
+
['pip', ['python', 'package', 'pypi']],
|
|
929
|
+
['brew', ['homebrew', 'macos', 'package']],
|
|
622
930
|
// English → all
|
|
623
|
-
['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação']],
|
|
624
|
-
['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação']],
|
|
931
|
+
['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação', 'развёртывание', 'развертывание', 'dağıtım', 'dağıtmak']],
|
|
932
|
+
['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação', 'развёртывание', 'dağıtım']],
|
|
625
933
|
['container', ['コンテナ', '容器', '컨테이너', 'docker']],
|
|
626
|
-
['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת', 'سرور', 'सर्वर']],
|
|
934
|
+
['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת', 'سرور', 'सर्वर', 'сервер', 'sunucu']],
|
|
627
935
|
['database', ['データベース', '数据库', '데이터베이스', 'db', 'قاعدة البيانات', 'datenbank', 'پایگاه داده', 'डेटाबेس', 'base de données', 'base de datos', 'banco de dados']],
|
|
628
|
-
['cache', ['キャッシュ', '缓存', '캐시', 'كاش', 'מטמון', 'کش', 'कैश']],
|
|
629
|
-
['error', ['エラー', '错误', '오류', 'خطأ', '
|
|
936
|
+
['cache', ['キャッシュ', '缓存', '캐시', 'كاش', 'מטמון', 'کش', 'कैश', 'кэш', 'önbellek']],
|
|
937
|
+
['error', ['エラー', '错误', '오류', 'خطأ', 'שגיאה', 'خطا', 'त्रुटि', 'गलती', 'exception', 'err', 'fehler', 'erreur', 'fallo', 'errore', 'erro', 'ошибка', 'hata', 'hatalı']],
|
|
630
938
|
['bug', ['バグ', '缺陷', '버그', 'issue', 'defect', 'خلل', 'اشکال', 'बग']],
|
|
631
|
-
['fix', ['修正', '修复', '수정', 'bugfix', 'patch', 'hotfix', 'إصلاح', 'תיקון', 'رفع', 'सुधार', 'beheben', 'behoben', 'réparer', 'correction', 'arreglar', 'corrección', 'correggere', 'corrigir']],
|
|
632
|
-
['build', ['ビルド', '构建', '빌드', 'بناء', 'בנייה', 'ساخت', 'निर्माण', 'bauen', 'construire', 'construir', 'costruire']],
|
|
633
|
-
['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'آزمایش', 'परीक्षण', 'testen', 'tester', 'probar', 'testare', 'testar']],
|
|
634
|
-
['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação']],
|
|
635
|
-
['authentication', ['auth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', '認証', '认证', '인증', 'login', 'oauth']],
|
|
636
|
-
['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente']],
|
|
637
|
-
['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave']],
|
|
638
|
-
['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', '
|
|
939
|
+
['fix', ['修正', '修复', '수정', 'bugfix', 'patch', 'hotfix', 'إصلاح', 'תיקון', 'رفع', 'सुधार', 'beheben', 'behoben', 'réparer', 'correction', 'arreglar', 'corrección', 'correggere', 'corrigir', 'исправить', 'исправление', 'düzeltmek', 'düzeltme']],
|
|
940
|
+
['build', ['ビルド', '构建', '빌드', 'بناء', 'בנייה', 'ساخت', 'निर्माण', 'bauen', 'construire', 'construir', 'costruire', 'сборка', 'собрать', 'derleme', 'derlemek']],
|
|
941
|
+
['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'آزمایش', 'परीक्षण', 'testen', 'tester', 'probar', 'testare', 'testar', 'тест', 'тестирование', 'test', 'testlemek']],
|
|
942
|
+
['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação', 'аутентификация', 'авторизация', 'kimlik doğrulama', 'yetkilendirme']],
|
|
943
|
+
['authentication', ['auth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', '認証', '认证', '인증', 'login', 'oauth', 'аутентификация', 'авторизация', 'kimlik doğrulama']],
|
|
944
|
+
['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente', 'среда', 'окружение', 'ortam']],
|
|
945
|
+
['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave', 'секрет', 'ключ', 'gizli', 'anahtar']],
|
|
946
|
+
['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', '問題', '오류', 'fehler', 'problème', 'problema', 'проблема', 'ошибка', 'sorun', 'problem']],
|
|
639
947
|
['kubernetes', ['クベルネテス', 'k8s', 'kube']],
|
|
640
|
-
['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'شبکه', 'नेटवर्क', 'netzwerk', 'réseau', 'red', 'rete', 'rede']],
|
|
948
|
+
['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'شبکه', 'नेटवर्क', 'netzwerk', 'réseau', 'red', 'rete', 'rede', 'сеть', 'ağ']],
|
|
641
949
|
['timeout', ['タイムアウト', '超时', '타임아웃', 'مهلة']],
|
|
642
|
-
['memory', ['メモリ', '内存', '메모리', 'ram', 'ذاكرة', 'זיכרון', 'حافظه', 'मेमोरी', 'speicher', 'mémoire', 'memoria', 'memória']],
|
|
643
|
-
['config', ['設定', '配置', '설정', 'configuration', 'settings', 'conf', 'إعدادات', 'הגדרות', 'پیکربندی', 'कॉन्फ़िग', 'konfiguration', 'einstellungen', 'configuración', 'configurazione', 'configuração']],
|
|
644
|
-
['install', ['インストール', '安装', '설치', 'تثبيت', 'התקנה', 'نصب', 'इंस्टॉल', 'installieren', 'installer', 'instalar', 'installare']],
|
|
645
|
-
['update', ['アップデート', '更新', '업데이트', 'upgrade', 'تحديث', 'עדכון', 'بهروزرسانی', 'अपडेट', 'aktualisieren', 'aktualisierung', 'actualizar', 'aggiornare', 'atualizar']],
|
|
646
|
-
['log', ['ログ', '日志', '로그', 'logging', 'سجل', 'יומן', 'ثبت', 'लॉग', 'protokoll', 'protokolle', 'journal', 'registro']],
|
|
950
|
+
['memory', ['メモリ', '内存', '메모리', 'ram', 'ذاكرة', 'זיכרון', 'حافظه', 'मेमोरी', 'speicher', 'mémoire', 'memoria', 'memória', 'память', 'bellek', 'hafıza']],
|
|
951
|
+
['config', ['設定', '配置', '설정', 'configuration', 'settings', 'conf', 'إعدادات', 'הגדרות', 'پیکربندی', 'कॉन्फ़िग', 'konfiguration', 'einstellungen', 'configuración', 'configurazione', 'configuração', 'конфигурация', 'настройки', 'yapılandırma', 'ayarlar']],
|
|
952
|
+
['install', ['インストール', '安装', '설치', 'تثبيت', 'התקנה', 'نصب', 'इंस्टॉल', 'installieren', 'installer', 'instalar', 'installare', 'установить', 'установка', 'yüklemek', 'kurulum']],
|
|
953
|
+
['update', ['アップデート', '更新', '업데이트', 'upgrade', 'تحديث', 'עדכון', 'بهروزرسانی', 'अपडेट', 'aktualisieren', 'aktualisierung', 'actualizar', 'aggiornare', 'atualizar', 'обновление', 'обновить', 'güncelleme']],
|
|
954
|
+
['log', ['ログ', '日志', '로그', 'logging', 'سجل', 'יומן', 'ثبت', 'लॉग', 'protokoll', 'protokolle', 'journal', 'registro', 'журнал', 'лог', 'günlük']],
|
|
647
955
|
['port', ['ポート', '端口', '포트', 'منفذ', 'פורט']],
|
|
648
956
|
['file', ['ファイル', '文件', '파일', 'ملف', 'קובץ']],
|
|
649
957
|
['image', ['イメージ', '镜像', '이미지', 'صورة', 'תמונה', 'abbild', 'imagen', 'imagem']],
|
|
650
958
|
['volume', ['ボリューム', '卷', '볼륨']],
|
|
651
959
|
['cluster', ['クラスター', '集群', '클러스터']],
|
|
652
960
|
['node', ['ノード', '节点', '노드']],
|
|
653
|
-
['service', ['サービス', '服务', '서비스', 'svc', 'خدمة', 'שירות', 'dienst', 'servicio', 'servizio', 'serviço']],
|
|
961
|
+
['service', ['サービス', '服务', '서비스', 'svc', 'خدمة', 'שירות', 'dienst', 'servicio', 'servizio', 'serviço', 'сервис', 'служба', 'servis', 'hizmet']],
|
|
654
962
|
['certificate', ['証明書', '证书', '인증서', 'cert', 'ssl', 'tls', 'شهادة', 'תעודה']],
|
|
655
963
|
['password', ['パスワード', '密码', '비밀번호', 'passwd', 'pwd', 'كلمة المرور', 'סיסמה']],
|
|
656
964
|
['token', ['トークン', '令牌', '토큰', 'jwt', 'secret', 'رمز', 'אסימון']],
|
|
657
965
|
['health', ['ヘルス', '健康', '헬스', 'healthcheck', 'probe', 'صحة']],
|
|
658
966
|
['migration', ['マイグレーション', '迁移', '마이그레이션', 'migrate', 'هجرة']],
|
|
659
|
-
['backup', ['バックアップ', '备份', '백업', 'نسخ احتياطي', 'גיבוי', 'پشتیبانگیری', 'बैकअप', 'sicherung', 'sauvegarde', 'respaldo', 'cópia de segurança']],
|
|
660
|
-
['monitor', ['モニター', '监控', '모니터링', 'monitoring', 'metrics', 'alert', 'مراقبة', 'ניטור', 'نظارت', 'निगरानी', 'überwachung', 'surveiller', 'monitoreo', 'monitorare', 'monitorar']],
|
|
661
|
-
['performance', ['パフォーマンス', '性能', '성능', 'latency', 'throughput', 'عملکرد', 'प्रदर्शन', 'leistung', 'performances', 'rendimiento', 'prestazioni', 'desempenho']],
|
|
967
|
+
['backup', ['バックアップ', '备份', '백업', 'نسخ احتياطي', 'גיבוי', 'پشتیبانگیری', 'बैकअप', 'sicherung', 'sauvegarde', 'respaldo', 'cópia de segurança', 'резервная копия', 'резерв', 'yedekleme']],
|
|
968
|
+
['monitor', ['モニター', '监控', '모니터링', 'monitoring', 'metrics', 'alert', 'مراقبة', 'ניטור', 'نظارت', 'निगरानी', 'überwachung', 'surveiller', 'monitoreo', 'monitorare', 'monitorar', 'мониторинг', 'наблюдение', 'izleme']],
|
|
969
|
+
['performance', ['パフォーマンス', '性能', '성능', 'latency', 'throughput', 'عملکرد', 'प्रदर्शन', 'leistung', 'performances', 'rendimiento', 'prestazioni', 'desempenho', 'производительность', 'быстродействие', 'performans']],
|
|
662
970
|
['connection', ['接続', '连接', '연결', 'conn', 'socket', 'اتصال', 'חיבור', 'اتصال', 'कनेक्शन', 'verbindung', 'connexion', 'conexión', 'connessione', 'conexão']],
|
|
663
971
|
['queue', ['キュー', '队列', '큐', 'طابور', 'warteschlange', 'file d\'attente', 'cola', 'coda', 'fila']],
|
|
664
972
|
['redis', ['レディス', '레디스']],
|
|
@@ -673,10 +981,10 @@ const CROSS_LINGUAL_MAP = new Map([
|
|
|
673
981
|
['git', ['version control', 'repo', 'repository', 'commit', 'push', 'pull']],
|
|
674
982
|
['ci', ['pipeline', 'github actions', 'gitlab', 'jenkins', 'build']],
|
|
675
983
|
['cd', ['deploy', 'deployment', 'release']],
|
|
676
|
-
['debug', ['デバッグ', '调试', '디버그', 'debugging', 'breakpoint', 'تصحيح', 'איתור באגים', 'اشکالزدایی', 'डीबग', 'debuggen', 'déboguer', 'depurar']],
|
|
677
|
-
['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'קריסה', 'خرابی', 'क्रैश', 'absturz', 'panne', 'plantage', 'caída', 'falha']],
|
|
984
|
+
['debug', ['デバッグ', '调试', '디버그', 'debugging', 'breakpoint', 'تصحيح', 'איתור באגים', 'اشکالزدایی', 'डीबग', 'debuggen', 'déboguer', 'depurar', 'отладка', 'дебаг', 'hata ayıklama']],
|
|
985
|
+
['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'קריסה', 'خرابی', 'क्रैश', 'absturz', 'panne', 'plantage', 'caída', 'falha', 'сбой', 'крэш', 'çökme', 'çöküş']],
|
|
678
986
|
['restart', ['再起動', '重启', '재시작', 'reboot', 'إعادة تشغيل', 'הפעלה מחדש', 'راهاندازی مجدد', 'पुنरारंभ', 'neustart', 'redémarrer', 'reiniciar', 'riavviare']],
|
|
679
|
-
['permission', ['権限', '权限', '권한', 'access', 'acl', 'chmod', 'صلاحية', 'הרשאה', 'مجوز', 'अनुमति', 'berechtigung', 'berechtigungen', 'permiso', 'permesso', 'permissão']],
|
|
987
|
+
['permission', ['権限', '权限', '권한', 'access', 'acl', 'chmod', 'صلاحية', 'הרשאה', 'مجوز', 'अनुमति', 'berechtigung', 'berechtigungen', 'permiso', 'permesso', 'permissão', 'разрешение', 'доступ', 'izin', 'yetki']],
|
|
680
988
|
// Japanese katakana → English
|
|
681
989
|
['デプロイ', ['deploy', 'deployment']],
|
|
682
990
|
['コンテナ', ['container', 'docker']],
|
|
@@ -1104,6 +1412,103 @@ const CROSS_LINGUAL_MAP = new Map([
|
|
|
1104
1412
|
['ambiente', ['environment', 'env']],
|
|
1105
1413
|
['fila', ['queue']],
|
|
1106
1414
|
['imagem', ['image']],
|
|
1415
|
+
// ── Russian (Cyrillic) → English ──────────────────────────────────────────
|
|
1416
|
+
['ошибка', ['error', 'err']],
|
|
1417
|
+
['ошибки', ['error', 'err']],
|
|
1418
|
+
['сбой', ['crash', 'failure', 'error']],
|
|
1419
|
+
['крэш', ['crash', 'panic']],
|
|
1420
|
+
['баг', ['bug', 'issue']],
|
|
1421
|
+
['исправить', ['fix', 'bugfix']],
|
|
1422
|
+
['исправление', ['fix', 'patch']],
|
|
1423
|
+
['сборка', ['build']],
|
|
1424
|
+
['собрать', ['build']],
|
|
1425
|
+
['тест', ['test']],
|
|
1426
|
+
['тестирование', ['test', 'testing']],
|
|
1427
|
+
['аутентификация', ['auth', 'authentication']],
|
|
1428
|
+
['авторизация', ['auth', 'authorization']],
|
|
1429
|
+
['конфигурация', ['config', 'configuration']],
|
|
1430
|
+
['настройки', ['config', 'settings']],
|
|
1431
|
+
['установить', ['install']],
|
|
1432
|
+
['установка', ['install']],
|
|
1433
|
+
['обновление', ['update', 'upgrade']],
|
|
1434
|
+
['обновить', ['update', 'upgrade']],
|
|
1435
|
+
['журнал', ['log']],
|
|
1436
|
+
['лог', ['log', 'logs']],
|
|
1437
|
+
['сервер', ['server']],
|
|
1438
|
+
['база данных', ['database', 'db']],
|
|
1439
|
+
['сеть', ['network']],
|
|
1440
|
+
['память', ['memory', 'ram']],
|
|
1441
|
+
['кэш', ['cache']],
|
|
1442
|
+
['отладка', ['debug', 'debugging']],
|
|
1443
|
+
['перезапуск', ['restart', 'reboot']],
|
|
1444
|
+
['перезагрузка', ['restart', 'reboot']],
|
|
1445
|
+
['разрешение', ['permission', 'access']],
|
|
1446
|
+
['доступ', ['permission', 'access']],
|
|
1447
|
+
['резерв', ['backup']],
|
|
1448
|
+
['производительность', ['performance']],
|
|
1449
|
+
['проблема', ['problem', 'issue', 'error']],
|
|
1450
|
+
['сервис', ['service']],
|
|
1451
|
+
['служба', ['service']],
|
|
1452
|
+
['подключение', ['connection', 'conn']],
|
|
1453
|
+
['соединение', ['connection', 'conn']],
|
|
1454
|
+
['развёртывание', ['deploy', 'deployment']],
|
|
1455
|
+
['развертывание', ['deploy', 'deployment']],
|
|
1456
|
+
['контейнер', ['container', 'docker']],
|
|
1457
|
+
['образ', ['image']],
|
|
1458
|
+
['кластер', ['cluster']],
|
|
1459
|
+
['узел', ['node']],
|
|
1460
|
+
['секрет', ['secret', 'key', 'token']],
|
|
1461
|
+
['ключ', ['key', 'token', 'secret']],
|
|
1462
|
+
['пароль', ['password']],
|
|
1463
|
+
['токен', ['token', 'secret']],
|
|
1464
|
+
['мониторинг', ['monitor', 'monitoring']],
|
|
1465
|
+
['наблюдение', ['monitor', 'monitoring']],
|
|
1466
|
+
['мигрировать', ['migrate', 'migration']],
|
|
1467
|
+
['миграция', ['migrate', 'migration']],
|
|
1468
|
+
// ── Turkish (Latin + special chars ğ/ş/ı) → English ─────────────────────
|
|
1469
|
+
['hata', ['error', 'err']],
|
|
1470
|
+
['hatalı', ['error', 'err']],
|
|
1471
|
+
['çökme', ['crash', 'panic']],
|
|
1472
|
+
['çöküş', ['crash', 'failure']],
|
|
1473
|
+
['düzeltmek', ['fix', 'bugfix']],
|
|
1474
|
+
['düzeltme', ['fix', 'patch']],
|
|
1475
|
+
['derleme', ['build']],
|
|
1476
|
+
['derlemek', ['build']],
|
|
1477
|
+
['test', ['test']],
|
|
1478
|
+
['testlemek', ['test', 'testing']],
|
|
1479
|
+
['kimlik doğrulama', ['auth', 'authentication']],
|
|
1480
|
+
['yetkilendirme', ['auth', 'authorization']],
|
|
1481
|
+
['yapılandırma', ['config', 'configuration']],
|
|
1482
|
+
['ayarlar', ['config', 'settings']],
|
|
1483
|
+
['yüklemek', ['install']],
|
|
1484
|
+
['kurulum', ['install']],
|
|
1485
|
+
['güncelleme', ['update', 'upgrade']],
|
|
1486
|
+
['günlük', ['log']],
|
|
1487
|
+
['sunucu', ['server']],
|
|
1488
|
+
['veritabanı', ['database', 'db']],
|
|
1489
|
+
['ağ', ['network']],
|
|
1490
|
+
['bellek', ['memory', 'ram']],
|
|
1491
|
+
['önbellek', ['cache']],
|
|
1492
|
+
['hata ayıklama', ['debug', 'debugging']],
|
|
1493
|
+
['yeniden başlatma', ['restart', 'reboot']],
|
|
1494
|
+
['izin', ['permission', 'access']],
|
|
1495
|
+
['yetki', ['permission', 'access', 'acl']],
|
|
1496
|
+
['yedekleme', ['backup']],
|
|
1497
|
+
['performans', ['performance']],
|
|
1498
|
+
['sorun', ['problem', 'issue', 'error']],
|
|
1499
|
+
['servis', ['service']],
|
|
1500
|
+
['hizmet', ['service']],
|
|
1501
|
+
['bağlantı', ['connection', 'conn']],
|
|
1502
|
+
['dağıtım', ['deploy', 'deployment']],
|
|
1503
|
+
['dağıtmak', ['deploy']],
|
|
1504
|
+
['konteyner', ['container', 'docker']],
|
|
1505
|
+
['küme', ['cluster']],
|
|
1506
|
+
['düğüm', ['node']],
|
|
1507
|
+
['gizli', ['secret', 'key']],
|
|
1508
|
+
['anahtar', ['key', 'token', 'secret']],
|
|
1509
|
+
['şifre', ['password']],
|
|
1510
|
+
['izleme', ['monitor', 'monitoring']],
|
|
1511
|
+
['göç', ['migrate', 'migration']],
|
|
1107
1512
|
]);
|
|
1108
1513
|
/**
|
|
1109
1514
|
* Expand a token to its cross-lingual synonyms.
|
|
@@ -1128,7 +1533,8 @@ function expandCrossLingual(token) {
|
|
|
1128
1533
|
*/
|
|
1129
1534
|
function tokenize(text) {
|
|
1130
1535
|
const tokens = [];
|
|
1131
|
-
|
|
1536
|
+
// Pre-process: split camelCase/PascalCase identifiers and snake_case before lowercasing
|
|
1537
|
+
const lower = preprocessText(text).toLowerCase();
|
|
1132
1538
|
for (const [seg] of lower.matchAll(SEGMENT_RE)) {
|
|
1133
1539
|
if (CJK_RE.test(seg)) {
|
|
1134
1540
|
// CJK segment — extract overlapping character bigrams
|
|
@@ -1182,10 +1588,8 @@ function tokenize(text) {
|
|
|
1182
1588
|
}
|
|
1183
1589
|
else if (DEVANAGARI_RE.test(seg)) {
|
|
1184
1590
|
// Devanagari segment (Hindi / Marathi) — naturally space-separated
|
|
1185
|
-
// Words don't need bigram expansion; stems reduce inflected forms.
|
|
1186
1591
|
const words = seg.trim().split(/[\s\u200c\u200d]+/); // handle zero-width joiners
|
|
1187
1592
|
for (const w of words) {
|
|
1188
|
-
// Keep Devanagari chars + digits; discard pure Latin portions (e.g. embedded numbers)
|
|
1189
1593
|
const deva = w.replace(/[^\u0900-\u097f0-9]/g, '');
|
|
1190
1594
|
if (deva.length <= 1 || STOPWORDS.has(deva))
|
|
1191
1595
|
continue;
|
|
@@ -1194,13 +1598,47 @@ function tokenize(text) {
|
|
|
1194
1598
|
tokens.push(stemmed);
|
|
1195
1599
|
}
|
|
1196
1600
|
}
|
|
1601
|
+
else if (BENGALI_RE.test(seg)) {
|
|
1602
|
+
// Bengali (Bangla) segment — space-separated words, Bengali script
|
|
1603
|
+
const words = seg.trim().split(/[\s\u200c\u200d]+/);
|
|
1604
|
+
for (const w of words) {
|
|
1605
|
+
const bn = w.replace(/[^\u0980-\u09ff0-9]/g, '');
|
|
1606
|
+
if (bn.length <= 1 || STOPWORDS.has(bn))
|
|
1607
|
+
continue;
|
|
1608
|
+
const stemmed = bengaliLightStem(bn);
|
|
1609
|
+
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1610
|
+
tokens.push(stemmed);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
else if (CYRILLIC_RE.test(seg)) {
|
|
1614
|
+
// Cyrillic segment (Russian, Bulgarian, Ukrainian, Serbian …)
|
|
1615
|
+
const words = seg.trim().split(/\s+/);
|
|
1616
|
+
for (const w of words) {
|
|
1617
|
+
const cyr = w.replace(/[^\u0400-\u04ff]/g, '');
|
|
1618
|
+
if (cyr.length <= 1 || STOPWORDS.has(cyr))
|
|
1619
|
+
continue;
|
|
1620
|
+
const stemmed = russianLightStem(cyr);
|
|
1621
|
+
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1622
|
+
tokens.push(stemmed);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1197
1625
|
else {
|
|
1198
|
-
// Latin / other —
|
|
1626
|
+
// Latin / other — includes Turkish (ğ/ş/ı), Polish (ą/ę/ł/ń/ó/ś/ź/ż/ć),
|
|
1627
|
+
// Czech (č/š/ž/ě/ů/ř), Hungarian (ő/ű), Romanian (ș/ț)
|
|
1199
1628
|
const words = seg
|
|
1200
|
-
.replace(/[^a-
|
|
1629
|
+
.replace(/[^a-záàâãäåæçéèêëíìîïñóòôõöúùûüýÿßœğşıİąćęłńśźżčšžěůřőűșț0-9:\-./]/g, ' ')
|
|
1201
1630
|
.split(/\s+/)
|
|
1202
1631
|
.filter(w => w.length > 1 && !STOPWORDS.has(w));
|
|
1203
|
-
|
|
1632
|
+
// Turkish: apply light stemmer to words with Turkish-specific chars
|
|
1633
|
+
for (const w of words) {
|
|
1634
|
+
if (TURKISH_CHAR_RE.test(w)) {
|
|
1635
|
+
const stemmed = turkishLightStem(w);
|
|
1636
|
+
if (stemmed !== w && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
|
|
1637
|
+
tokens.push(stemmed);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
tokens.push(w);
|
|
1641
|
+
}
|
|
1204
1642
|
}
|
|
1205
1643
|
}
|
|
1206
1644
|
// ── Cross-lingual expansion ──────────────────────────────────────────────
|
|
@@ -1242,10 +1680,36 @@ function tokenize(text) {
|
|
|
1242
1680
|
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1243
1681
|
expansions.push(stemmed);
|
|
1244
1682
|
}
|
|
1683
|
+
else if (BENGALI_RE.test(syn)) {
|
|
1684
|
+
// Bengali synonym
|
|
1685
|
+
const stemmed = bengaliLightStem(syn);
|
|
1686
|
+
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1687
|
+
expansions.push(stemmed);
|
|
1688
|
+
}
|
|
1689
|
+
else if (CYRILLIC_RE.test(syn)) {
|
|
1690
|
+
// Cyrillic synonym (Russian)
|
|
1691
|
+
const cyr = syn.replace(/[^\u0400-\u04ff]/g, '');
|
|
1692
|
+
const stemmed = russianLightStem(cyr);
|
|
1693
|
+
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1694
|
+
expansions.push(stemmed);
|
|
1695
|
+
}
|
|
1245
1696
|
else {
|
|
1246
|
-
// Latin synonym — split in case of multi-word
|
|
1247
|
-
const parts = syn.split(/\s+/).filter(w =>
|
|
1248
|
-
|
|
1697
|
+
// Latin synonym (includes Turkish) — split in case of multi-word
|
|
1698
|
+
const parts = syn.split(/\s+/).filter(w => {
|
|
1699
|
+
if (w.length <= 1 || STOPWORDS.has(w))
|
|
1700
|
+
return false;
|
|
1701
|
+
return true;
|
|
1702
|
+
});
|
|
1703
|
+
for (const p of parts) {
|
|
1704
|
+
expansions.push(p);
|
|
1705
|
+
// Apply Turkish stemmer if it has Turkish-specific characters
|
|
1706
|
+
if (TURKISH_CHAR_RE.test(p)) {
|
|
1707
|
+
const stemmed = turkishLightStem(p);
|
|
1708
|
+
if (stemmed !== p && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
|
|
1709
|
+
expansions.push(stemmed);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1249
1713
|
}
|
|
1250
1714
|
}
|
|
1251
1715
|
}
|
|
@@ -1271,8 +1735,8 @@ function splitMultiQuery(query) {
|
|
|
1271
1735
|
const semiParts = query.split(/[;\n]+/).filter(s => s.trim().length > 2);
|
|
1272
1736
|
if (semiParts.length >= 2)
|
|
1273
1737
|
return semiParts.map(s => s.trim());
|
|
1274
|
-
// Conjunctions (EN + DE + FR + ES)
|
|
1275
|
-
const conjParts = query.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso)\b/i).filter(s => s.trim().length > 2);
|
|
1738
|
+
// Conjunctions (EN + DE + FR + ES + IT + PT + RU + TR)
|
|
1739
|
+
const conjParts = query.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso|а также|и также|кроме того|плюс|ayrıca|bunun yanı sıra|همچنین|وأيضاً|وكذلك|وهمچنین|और भी|इसके अलावा)\b/i).filter(s => s.trim().length > 2);
|
|
1276
1740
|
if (conjParts.length >= 2)
|
|
1277
1741
|
return conjParts.map(s => s.trim());
|
|
1278
1742
|
// Comma-separated with 3+ parts (likely a list)
|
|
@@ -1401,7 +1865,9 @@ async function keywordSearch(redis, patterns, query, topK = 10) {
|
|
|
1401
1865
|
bigrams.add(`${tokens[j]}|${tokens[j + 1]}`);
|
|
1402
1866
|
}
|
|
1403
1867
|
const timestamp = extractTimestamp(content);
|
|
1404
|
-
|
|
1868
|
+
// Key tokens for title-boost: terms appearing in the Redis key get extra weight
|
|
1869
|
+
const keyTokens = new Set(tokenize(allKeys[i]));
|
|
1870
|
+
docs.push({ key: allKeys[i], content, tokens, tokenFreq, bigrams, keyTokens, timestamp });
|
|
1405
1871
|
totalTokens += tokens.length;
|
|
1406
1872
|
}
|
|
1407
1873
|
if (docs.length === 0)
|
|
@@ -1502,6 +1968,23 @@ async function keywordSearch(redis, patterns, query, topK = 10) {
|
|
|
1502
1968
|
score *= 1 + 0.5 * (bigramHits / queryBigrams.size);
|
|
1503
1969
|
}
|
|
1504
1970
|
}
|
|
1971
|
+
// Phrase-match boost: if the raw (lowercased) query appears verbatim in content, 2× boost
|
|
1972
|
+
// This rewards docs where the exact phrase exists (vs scattered tokens).
|
|
1973
|
+
if (sq.length >= 4 && doc.content.toLowerCase().includes(sq.toLowerCase())) {
|
|
1974
|
+
score *= 2.0;
|
|
1975
|
+
}
|
|
1976
|
+
// Key/title boost: if query terms appear in the Redis key (=title), 1.5× boost
|
|
1977
|
+
// Keys often encode the primary topic (e.g. "deploy:api:server"), so key hits are high-precision.
|
|
1978
|
+
if (score > 0) {
|
|
1979
|
+
let keyHits = 0;
|
|
1980
|
+
for (const qt of queryTokens) {
|
|
1981
|
+
if (doc.keyTokens.has(qt))
|
|
1982
|
+
keyHits++;
|
|
1983
|
+
}
|
|
1984
|
+
if (keyHits > 0) {
|
|
1985
|
+
score *= 1 + 0.5 * (keyHits / queryTokens.length);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1505
1988
|
// Recency boost
|
|
1506
1989
|
score *= recencyBoost(doc.timestamp);
|
|
1507
1990
|
if (score > 0) {
|