@cachly-dev/mcp-server 0.5.48 → 0.5.49
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.d.ts +3 -2
- package/dist/index.js +59 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +58 -7
package/dist/index.d.ts
CHANGED
|
@@ -33,8 +33,9 @@ declare function expandCrossLingual(token: string): string[];
|
|
|
33
33
|
* Features:
|
|
34
34
|
* • CJK → character bigrams
|
|
35
35
|
* • Katakana → additionally emits Hepburn romaji tokens (enables romaji queries)
|
|
36
|
-
* • Arabic
|
|
37
|
-
* •
|
|
36
|
+
* • Arabic → word tokenization + iterative prefix stemming (al-, wa-, bi-, li-, fa-)
|
|
37
|
+
* • Hebrew → word tokenization + iterative prefix stemming (ha-, ve-, be-, le-, mi-, ke-)
|
|
38
|
+
* • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE↔DE↔FR↔ES↔IT↔PT)
|
|
38
39
|
*/
|
|
39
40
|
declare function tokenize(text: string): string[];
|
|
40
41
|
/**
|
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.49';
|
|
51
51
|
/**
|
|
52
52
|
* ┌──────────────────────────────────────────────────────────────────────┐
|
|
53
53
|
* │ EMBEDDING PROVIDER — pluggable, client-side first │
|
|
@@ -409,6 +409,10 @@ const CJK_RE = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7
|
|
|
409
409
|
const SEGMENT_RE = /([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+|[^\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+)/g;
|
|
410
410
|
// RTL Unicode ranges: Arabic (U+0600–U+06FF + extended), Hebrew (U+0590–U+05FF)
|
|
411
411
|
const RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/;
|
|
412
|
+
// Distinguish Arabic from Hebrew within RTL segments
|
|
413
|
+
const HEBREW_CHAR_RE = /[\u0590-\u05ff\ufb1d-\ufb4f]/;
|
|
414
|
+
const ARABIC_CHAR_RE = /[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/;
|
|
415
|
+
;
|
|
412
416
|
// ── Katakana → Romaji conversion table (Hepburn system) ──────────────────────
|
|
413
417
|
// Digraphs must be listed before single chars so they match first.
|
|
414
418
|
const KATA_ROMAJI_TABLE = [
|
|
@@ -509,6 +513,33 @@ function arabicLightStem(word) {
|
|
|
509
513
|
}
|
|
510
514
|
return result;
|
|
511
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* Hebrew light stemmer — strips the definite article and common prefix particles
|
|
518
|
+
* that attach directly to words (no space) in Hebrew.
|
|
519
|
+
*
|
|
520
|
+
* Handles:
|
|
521
|
+
* ה (ha-) — definite article: הפריסה → פריסה
|
|
522
|
+
* ו (ve-/u-) — conjunction “and”: ופריסה → פריסה
|
|
523
|
+
* ב (be-/bi-) — preposition “in”: בסביבה → סביבה
|
|
524
|
+
* ל (le-/li-) — preposition “for”: לשרת → שרת
|
|
525
|
+
* מ (mi-/me-) — preposition “from”: מהשרת → השרת → שרת
|
|
526
|
+
* כ (ke-/ki-) — preposition “like”: כשרת → שרת
|
|
527
|
+
*
|
|
528
|
+
* Iterative (max 3 passes): מהפריסה → הפריסה → פריסה.
|
|
529
|
+
* Only strips when result is still ≥ 3 chars.
|
|
530
|
+
*/
|
|
531
|
+
function hebrewLightStem(word) {
|
|
532
|
+
let result = word;
|
|
533
|
+
for (let i = 0; i < 3; i++) {
|
|
534
|
+
const prev = result;
|
|
535
|
+
if (result.length > 3 && 'הובלמכ'.includes(result[0]) && HEBREW_CHAR_RE.test(result[1])) {
|
|
536
|
+
result = result.slice(1);
|
|
537
|
+
}
|
|
538
|
+
if (result === prev)
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
512
543
|
// ── Cross-lingual tech term dictionary ────────────────────────────────────────
|
|
513
544
|
// Maps tokens (English, Japanese katakana, Chinese, Korean, Arabic, Hebrew)
|
|
514
545
|
// to their equivalents in other languages. Used to expand tokens at search time
|
|
@@ -517,8 +548,8 @@ function arabicLightStem(word) {
|
|
|
517
548
|
// Keys must be lowercase. CJK values will be bigram-expanded at use time.
|
|
518
549
|
const CROSS_LINGUAL_MAP = new Map([
|
|
519
550
|
// English → all
|
|
520
|
-
['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação']],
|
|
521
|
-
['deployment', ['デプロイ', '部署', '배포', 'deploy', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação']],
|
|
551
|
+
['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação']],
|
|
552
|
+
['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação']],
|
|
522
553
|
['container', ['コンテナ', '容器', '컨테이너', 'docker']],
|
|
523
554
|
['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת']],
|
|
524
555
|
['database', ['データベース', '数据库', '데이터베이스', 'db', 'قاعدة البيانات', 'datenbank', 'base de données', 'base de datos', 'banco de dados']],
|
|
@@ -530,6 +561,9 @@ const CROSS_LINGUAL_MAP = new Map([
|
|
|
530
561
|
['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'testen', 'tester', 'probar', 'testare', 'testar']],
|
|
531
562
|
['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação']],
|
|
532
563
|
['authentication', ['auth', 'مصادقة', 'אימות', '認証', '认证', '인증', 'login', 'oauth']],
|
|
564
|
+
['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente']],
|
|
565
|
+
['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave']],
|
|
566
|
+
['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', 'بعيا', '問題', '問題', '오류', 'fehler', 'problème', 'problema']],
|
|
533
567
|
['kubernetes', ['クベルネテス', 'k8s', 'kube']],
|
|
534
568
|
['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'netzwerk', 'réseau', 'red', 'rete', 'rede']],
|
|
535
569
|
['timeout', ['タイムアウト', '超时', '타임아웃', 'مهلة']],
|
|
@@ -707,6 +741,13 @@ const CROSS_LINGUAL_MAP = new Map([
|
|
|
707
741
|
['قرص', ['disk', 'storage']],
|
|
708
742
|
['خادم', ['server']],
|
|
709
743
|
['برنامج', ['application', 'software', 'app']],
|
|
744
|
+
// Arabic terms from blog examples
|
|
745
|
+
['مشكلة', ['error', 'issue', 'bug', 'problem', 'failure']],
|
|
746
|
+
['بيئة', ['environment', 'env']],
|
|
747
|
+
['متغيرات', ['variables', 'env', 'environment']],
|
|
748
|
+
['إنتاج', ['production', 'prod']],
|
|
749
|
+
['سري', ['secret', 'key', 'token']],
|
|
750
|
+
['مفتاح سري', ['secret', 'key']],
|
|
710
751
|
// Hebrew → English
|
|
711
752
|
['שגיאה', ['error']],
|
|
712
753
|
['תיקון', ['fix']],
|
|
@@ -742,6 +783,13 @@ const CROSS_LINGUAL_MAP = new Map([
|
|
|
742
783
|
['ממשק תכנות', ['api', 'interface']],
|
|
743
784
|
['ביצועים', ['performance']],
|
|
744
785
|
['אחסון', ['storage', 'disk']],
|
|
786
|
+
// Hebrew terms from blog examples
|
|
787
|
+
['פריסה', ['deploy', 'deployment']],
|
|
788
|
+
['בעיה', ['error', 'issue', 'bug', 'problem']],
|
|
789
|
+
['סביבה', ['environment', 'env']],
|
|
790
|
+
['ייצור', ['production', 'prod']],
|
|
791
|
+
['סודי', ['secret', 'key', 'token']],
|
|
792
|
+
['מפתח סודי', ['secret', 'key']],
|
|
745
793
|
// ── European languages → English ─────────────────────────────────────────
|
|
746
794
|
// German (Deutsch) → English
|
|
747
795
|
['fehler', ['error', 'err']],
|
|
@@ -939,8 +987,9 @@ function expandCrossLingual(token) {
|
|
|
939
987
|
* Features:
|
|
940
988
|
* • CJK → character bigrams
|
|
941
989
|
* • Katakana → additionally emits Hepburn romaji tokens (enables romaji queries)
|
|
942
|
-
* • Arabic
|
|
943
|
-
* •
|
|
990
|
+
* • Arabic → word tokenization + iterative prefix stemming (al-, wa-, bi-, li-, fa-)
|
|
991
|
+
* • Hebrew → word tokenization + iterative prefix stemming (ha-, ve-, be-, le-, mi-, ke-)
|
|
992
|
+
* • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE↔DE↔FR↔ES↔IT↔PT)
|
|
944
993
|
*/
|
|
945
994
|
function tokenize(text) {
|
|
946
995
|
const tokens = [];
|
|
@@ -979,12 +1028,15 @@ function tokenize(text) {
|
|
|
979
1028
|
}
|
|
980
1029
|
}
|
|
981
1030
|
else if (RTL_RE.test(seg)) {
|
|
982
|
-
// RTL segment
|
|
1031
|
+
// RTL segment — split on spaces, apply language-specific prefix stemming
|
|
1032
|
+
// Arabic: strips ال/و/ب/ل/ف/ك prefixes iteratively
|
|
1033
|
+
// Hebrew: strips ה/ו/ב/ל/מ/כ prefixes iteratively
|
|
1034
|
+
const isHebrew = HEBREW_CHAR_RE.test(seg);
|
|
983
1035
|
const words = seg.trim().split(/\s+/);
|
|
984
1036
|
for (const w of words) {
|
|
985
1037
|
if (w.length <= 1 || STOPWORDS.has(w))
|
|
986
1038
|
continue;
|
|
987
|
-
const stemmed = arabicLightStem(w);
|
|
1039
|
+
const stemmed = isHebrew ? hebrewLightStem(w) : arabicLightStem(w);
|
|
988
1040
|
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
989
1041
|
tokens.push(stemmed);
|
|
990
1042
|
}
|