@cachly-dev/mcp-server 0.5.47 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cachly-dev/mcp-server",
3
- "version": "0.5.47",
3
+ "version": "0.5.49",
4
4
  "mcpName": "io.github.cachly-dev/mcp-server",
5
5
  "description": "AI memory brain for Claude Code, Cursor, Copilot & Windsurf — persistent sessions, lessons learned, semantic search, team brain. 51 MCP tools.",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -55,7 +55,7 @@ import { Redis } from 'ioredis';
55
55
  const API_URL = process.env.CACHLY_API_URL ?? 'https://api.cachly.dev';
56
56
  const JWT = process.env.CACHLY_JWT ?? '';
57
57
  const EMBED_MODEL = process.env.CACHLY_EMBED_MODEL ?? '';
58
- const CURRENT_VERSION = '0.5.26';
58
+ const CURRENT_VERSION = '0.5.49';
59
59
  /**
60
60
  * ┌──────────────────────────────────────────────────────────────────────┐
61
61
  * │ EMBEDDING PROVIDER — pluggable, client-side first │
@@ -425,6 +425,9 @@ const SEGMENT_RE = /([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00
425
425
 
426
426
  // RTL Unicode ranges: Arabic (U+0600–U+06FF + extended), Hebrew (U+0590–U+05FF)
427
427
  const RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/;
428
+ // Distinguish Arabic from Hebrew within RTL segments
429
+ const HEBREW_CHAR_RE = /[\u0590-\u05ff\ufb1d-\ufb4f]/;
430
+ const ARABIC_CHAR_RE = /[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/;;
428
431
 
429
432
  // ── Katakana → Romaji conversion table (Hepburn system) ──────────────────────
430
433
  // Digraphs must be listed before single chars so they match first.
@@ -504,12 +507,49 @@ function katakanaToRomaji(kata: string): string {
504
507
  /**
505
508
  * Arabic light stemmer — strips definite article and common prefix particles.
506
509
  * Handles: ال (al-), و (wa-), ب (bi-), ل (li-), ف (fa-), ك (ka-).
510
+ * Runs iteratively (max 3 passes) so compound prefixes like فال- are fully
511
+ * resolved: فالخطأ → الخطأ → خطأ.
507
512
  * Only strips when the result is still ≥ 3 chars to avoid over-stemming.
508
513
  */
509
514
  function arabicLightStem(word: string): string {
510
- if (word.startsWith('ال') && word.length > 4) return word.slice(2);
511
- if (word.length > 3 && 'وبلفك'.includes(word[0]) && RTL_RE.test(word[1])) return word.slice(1);
512
- return word;
515
+ let result = word;
516
+ for (let i = 0; i < 3; i++) {
517
+ const prev = result;
518
+ if (result.startsWith('ال') && result.length > 4) {
519
+ result = result.slice(2);
520
+ } else if (result.length > 3 && 'وبلفك'.includes(result[0]) && RTL_RE.test(result[1])) {
521
+ result = result.slice(1);
522
+ }
523
+ if (result === prev) break; // stable — no more prefixes to strip
524
+ }
525
+ return result;
526
+ }
527
+
528
+ /**
529
+ * Hebrew light stemmer — strips the definite article and common prefix particles
530
+ * that attach directly to words (no space) in Hebrew.
531
+ *
532
+ * Handles:
533
+ * ה (ha-) — definite article: הפריסה → פריסה
534
+ * ו (ve-/u-) — conjunction “and”: ופריסה → פריסה
535
+ * ב (be-/bi-) — preposition “in”: בסביבה → סביבה
536
+ * ל (le-/li-) — preposition “for”: לשרת → שרת
537
+ * מ (mi-/me-) — preposition “from”: מהשרת → השרת → שרת
538
+ * כ (ke-/ki-) — preposition “like”: כשרת → שרת
539
+ *
540
+ * Iterative (max 3 passes): מהפריסה → הפריסה → פריסה.
541
+ * Only strips when result is still ≥ 3 chars.
542
+ */
543
+ function hebrewLightStem(word: string): string {
544
+ let result = word;
545
+ for (let i = 0; i < 3; i++) {
546
+ const prev = result;
547
+ if (result.length > 3 && 'הובלמכ'.includes(result[0]) && HEBREW_CHAR_RE.test(result[1])) {
548
+ result = result.slice(1);
549
+ }
550
+ if (result === prev) break;
551
+ }
552
+ return result;
513
553
  }
514
554
 
515
555
  // ── Cross-lingual tech term dictionary ────────────────────────────────────────
@@ -520,8 +560,8 @@ function arabicLightStem(word: string): string {
520
560
  // Keys must be lowercase. CJK values will be bigram-expanded at use time.
521
561
  const CROSS_LINGUAL_MAP = new Map<string, string[]>([
522
562
  // English → all
523
- ['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação']],
524
- ['deployment', ['デプロイ', '部署', '배포', 'deploy', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação']],
563
+ ['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação']],
564
+ ['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação']],
525
565
  ['container', ['コンテナ', '容器', '컨테이너', 'docker']],
526
566
  ['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת']],
527
567
  ['database', ['データベース', '数据库', '데이터베이스', 'db', 'قاعدة البيانات', 'datenbank', 'base de données', 'base de datos', 'banco de dados']],
@@ -532,6 +572,10 @@ const CROSS_LINGUAL_MAP = new Map<string, string[]>([
532
572
  ['build', ['ビルド', '构建', '빌드', 'بناء', 'בנייה', 'bauen', 'construire', 'construir', 'costruire']],
533
573
  ['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'testen', 'tester', 'probar', 'testare', 'testar']],
534
574
  ['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação']],
575
+ ['authentication', ['auth', 'مصادقة', 'אימות', '認証', '认证', '인증', 'login', 'oauth']],
576
+ ['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente']],
577
+ ['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave']],
578
+ ['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', 'بعيا', '問題', '問題', '오류', 'fehler', 'problème', 'problema']],
535
579
  ['kubernetes', ['クベルネテス', 'k8s', 'kube']],
536
580
  ['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'netzwerk', 'réseau', 'red', 'rete', 'rede']],
537
581
  ['timeout', ['タイムアウト', '超时', '타임아웃', 'مهلة']],
@@ -570,7 +614,7 @@ const CROSS_LINGUAL_MAP = new Map<string, string[]>([
570
614
  ['ci', ['pipeline', 'github actions', 'gitlab', 'jenkins', 'build']],
571
615
  ['cd', ['deploy', 'deployment', 'release']],
572
616
  ['debug', ['デバッグ', '调试', '디버그', 'debugging', 'breakpoint', 'تصحيح', 'איתור באגים', 'debuggen', 'déboguer', 'depurar']],
573
- ['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'absturz', 'panne', 'plantage', 'caída', 'falha']],
617
+ ['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'קריסה', 'absturz', 'panne', 'plantage', 'caída', 'falha']],
574
618
  ['restart', ['再起動', '重启', '재시작', 'reboot', 'إعادة تشغيل', 'הפעלה מחדש', 'neustart', 'redémarrer', 'reiniciar', 'riavviare']],
575
619
  ['permission', ['権限', '权限', '권한', 'access', 'acl', 'chmod', 'صلاحية', 'הרשאה', 'berechtigung', 'berechtigungen', 'permiso', 'permesso', 'permissão']],
576
620
  // Japanese katakana → English
@@ -671,43 +715,93 @@ const CROSS_LINGUAL_MAP = new Map<string, string[]>([
671
715
  ['재시작', ['restart']],
672
716
  ['권한', ['permission']],
673
717
  // Arabic → English
674
- ['خطأ', ['error']],
675
- ['إصلاح', ['fix']],
676
- ['بناء', ['build']],
677
- ['اختبار', ['test']],
678
- ['مصادقة', ['auth']],
679
- ['إعدادات', ['config']],
680
- ['تثبيت', ['install']],
681
- ['تحديث', ['update']],
682
- ['سجل', ['log']],
683
- ['صورة', ['image']],
684
- ['خدمة', ['service']],
685
- ['نسخ احتياطي', ['backup']],
686
- ['مراقبة', ['monitor']],
687
- ['اتصال', ['connection']],
688
- ['ذاكرة', ['memory']],
689
- ['تصحيح', ['debug']],
690
- ['شبكة', ['network']],
718
+ ['خطأ', ['error']],
719
+ ['إصلاح', ['fix']],
720
+ ['بناء', ['build']],
721
+ ['اختبار', ['test']],
722
+ ['مصادقة', ['auth', 'authentication']],
723
+ ['إعدادات', ['config', 'configuration']],
724
+ ['تثبيت', ['install']],
725
+ ['تحديث', ['update', 'upgrade']],
726
+ ['سجل', ['log']],
727
+ ['صورة', ['image']],
728
+ ['خدمة', ['service']],
729
+ ['نسخ احتياطي', ['backup']],
730
+ ['مراقبة', ['monitor', 'monitoring']],
731
+ ['اتصال', ['connection']],
732
+ ['ذاكرة', ['memory']],
733
+ ['تصحيح', ['debug', 'debugging']],
734
+ ['شبكة', ['network']],
735
+ // Additional Arabic → English (covering blog post examples + common terms)
736
+ ['نشر', ['deploy', 'deployment']],
737
+ ['انهيار', ['crash', 'panic']],
738
+ ['طابور', ['queue']],
739
+ ['رمز', ['token', 'secret']],
740
+ ['كاش', ['cache']],
741
+ ['منفذ', ['port']],
742
+ ['سيرفر', ['server']],
743
+ ['قاعدة البيانات', ['database', 'db']],
744
+ ['إعادة تشغيل', ['restart', 'reboot']],
745
+ ['صلاحية', ['permission', 'access']],
746
+ ['تطبيق', ['application', 'app']],
747
+ ['مفتاح', ['key', 'token', 'secret']],
748
+ ['واجهة برمجية', ['api', 'interface']],
749
+ ['فحص الصحة', ['healthcheck', 'health']],
750
+ ['حاوية', ['container', 'docker']],
751
+ ['عقدة', ['node']],
752
+ ['سرعة', ['performance', 'speed']],
753
+ ['قرص', ['disk', 'storage']],
754
+ ['خادم', ['server']],
755
+ ['برنامج', ['application', 'software', 'app']],
756
+ // Arabic terms from blog examples
757
+ ['مشكلة', ['error', 'issue', 'bug', 'problem', 'failure']],
758
+ ['بيئة', ['environment', 'env']],
759
+ ['متغيرات', ['variables', 'env', 'environment']],
760
+ ['إنتاج', ['production', 'prod']],
761
+ ['سري', ['secret', 'key', 'token']],
762
+ ['مفتاح سري', ['secret', 'key']],
691
763
  // Hebrew → English
692
- ['שגיאה', ['error']],
693
- ['תיקון', ['fix']],
694
- ['בנייה', ['build']],
695
- ['בדיקה', ['test']],
696
- ['אימות', ['auth']],
697
- ['הגדרות', ['config']],
698
- ['התקנה', ['install']],
699
- ['עדכון', ['update']],
700
- ['יומן', ['log']],
701
- ['שרת', ['server']],
702
- ['שירות', ['service']],
703
- ['גיבוי', ['backup']],
704
- ['ניטור', ['monitor']],
705
- ['חיבור', ['connection']],
706
- ['זיכרון', ['memory']],
707
- ['רשת', ['network']],
708
- ['תמונה', ['image']],
709
- ['סיסמה', ['password']],
710
- ['הרשאה', ['permission']],
764
+ ['שגיאה', ['error']],
765
+ ['תיקון', ['fix']],
766
+ ['בנייה', ['build']],
767
+ ['בדיקה', ['test']],
768
+ ['אימות', ['auth', 'authentication']],
769
+ ['הגדרות', ['config', 'configuration']],
770
+ ['התקנה', ['install']],
771
+ ['עדכון', ['update', 'upgrade']],
772
+ ['יומן', ['log']],
773
+ ['שרת', ['server']],
774
+ ['שירות', ['service']],
775
+ ['גיבוי', ['backup']],
776
+ ['ניטור', ['monitor', 'monitoring']],
777
+ ['חיבור', ['connection']],
778
+ ['זיכרון', ['memory']],
779
+ ['רשת', ['network']],
780
+ ['תמונה', ['image']],
781
+ ['סיסמה', ['password']],
782
+ ['הרשאה', ['permission', 'access']],
783
+ // Additional Hebrew → English (covering blog post examples + common terms)
784
+ ['קריסה', ['crash', 'panic']],
785
+ ['תור', ['queue']],
786
+ ['מטמון', ['cache']],
787
+ ['אסימון', ['token', 'secret']],
788
+ ['פורט', ['port']],
789
+ ['איתור באגים', ['debug', 'debugging']],
790
+ ['הפעלה מחדש', ['restart', 'reboot']],
791
+ ['מיכל', ['container', 'docker']],
792
+ ['יישום', ['application', 'app']],
793
+ ['מפתח', ['key', 'token', 'secret']],
794
+ ['בדיקת תקינות', ['healthcheck', 'health']],
795
+ ['ממשק תכנות', ['api', 'interface']],
796
+ ['ביצועים', ['performance']],
797
+ ['אחסון', ['storage', 'disk']],
798
+ // Hebrew terms from blog examples
799
+ ['פריסה', ['deploy', 'deployment']],
800
+ ['בעיה', ['error', 'issue', 'bug', 'problem']],
801
+ ['סביבה', ['environment', 'env']],
802
+ ['ייצור', ['production', 'prod']],
803
+ ['סודי', ['secret', 'key', 'token']],
804
+ ['מפתח סודי', ['secret', 'key']],
711
805
 
712
806
  // ── European languages → English ─────────────────────────────────────────
713
807
  // German (Deutsch) → English
@@ -912,8 +1006,9 @@ function expandCrossLingual(token: string): string[] {
912
1006
  * Features:
913
1007
  * • CJK → character bigrams
914
1008
  * • Katakana → additionally emits Hepburn romaji tokens (enables romaji queries)
915
- * • Arabic/Hebrew → word tokenization with light Arabic stemming
916
- * • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE)
1009
+ * • Arabic → word tokenization + iterative prefix stemming (al-, wa-, bi-, li-, fa-)
1010
+ * • Hebrew → word tokenization + iterative prefix stemming (ha-, ve-, be-, le-, mi-, ke-)
1011
+ * • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE↔DE↔FR↔ES↔IT↔PT)
917
1012
  */
918
1013
  function tokenize(text: string): string[] {
919
1014
  const tokens: string[] = [];
@@ -951,11 +1046,14 @@ function tokenize(text: string): string[] {
951
1046
  }
952
1047
  }
953
1048
  } else if (RTL_RE.test(seg)) {
954
- // RTL segment (Arabic / Hebrew) — space-separated words with light stemming
1049
+ // RTL segment — split on spaces, apply language-specific prefix stemming
1050
+ // Arabic: strips ال/و/ب/ل/ف/ك prefixes iteratively
1051
+ // Hebrew: strips ה/ו/ב/ל/מ/כ prefixes iteratively
1052
+ const isHebrew = HEBREW_CHAR_RE.test(seg);
955
1053
  const words = seg.trim().split(/\s+/);
956
1054
  for (const w of words) {
957
1055
  if (w.length <= 1 || STOPWORDS.has(w)) continue;
958
- const stemmed = arabicLightStem(w);
1056
+ const stemmed = isHebrew ? hebrewLightStem(w) : arabicLightStem(w);
959
1057
  if (stemmed.length > 1 && !STOPWORDS.has(stemmed)) tokens.push(stemmed);
960
1058
  }
961
1059
  } else {