ocerebro 0.3.2 → 0.3.3
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/cerebro/index/entities.db +0 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/index/entities_db.py +5 -1
- package/src/mcp/server.py +49 -32
|
Binary file
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/src/index/entities_db.py
CHANGED
|
@@ -614,14 +614,18 @@ class EntitiesDB:
|
|
|
614
614
|
cached_hash = self.get_cached_hash(memory_id)
|
|
615
615
|
current_hash = self._compute_hash(content)
|
|
616
616
|
|
|
617
|
+
skip_delete = False
|
|
617
618
|
if cached_hash == current_hash:
|
|
618
619
|
# Conteúdo igual, verifica se já tem entidades
|
|
619
620
|
existing = self.get_entities_by_memory(memory_id)
|
|
620
621
|
if existing:
|
|
621
622
|
return [] # Já processado, sem mudanças
|
|
623
|
+
# Cache bate mas entidades vazias (ex: banco limpo) - reprocessa sem delete
|
|
624
|
+
skip_delete = True
|
|
622
625
|
|
|
623
626
|
# Conteúdo novo ou mudou - remove apenas entidades de conteúdo e reprocessa
|
|
624
|
-
|
|
627
|
+
if not skip_delete:
|
|
628
|
+
self.delete_entities_by_source(memory_id, "content")
|
|
625
629
|
|
|
626
630
|
entity_ids = []
|
|
627
631
|
|
package/src/mcp/server.py
CHANGED
|
@@ -693,6 +693,7 @@ Uma chamada por memória. O sistema salva e indexa automaticamente.
|
|
|
693
693
|
def _capture_memory(self, args: Dict[str, Any]) -> str:
|
|
694
694
|
"""Salva uma memória no diretório nativo do Claude Code."""
|
|
695
695
|
import re
|
|
696
|
+
import yaml
|
|
696
697
|
from datetime import datetime
|
|
697
698
|
from src.core.paths import get_memory_index
|
|
698
699
|
|
|
@@ -711,15 +712,36 @@ Uma chamada por memória. O sistema salva e indexa automaticamente.
|
|
|
711
712
|
file_path = mem_dir / f"{mem_name}.md"
|
|
712
713
|
file_path.write_text(content, encoding="utf-8")
|
|
713
714
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
715
|
+
# Parse frontmatter uma única vez com yaml.safe_load
|
|
716
|
+
frontmatter_match = re.match(r'^---\n(.*?)\n---\n(.*)$', content, re.DOTALL)
|
|
717
|
+
frontmatter = {}
|
|
718
|
+
body_content = ""
|
|
719
|
+
if frontmatter_match:
|
|
720
|
+
try:
|
|
721
|
+
frontmatter = yaml.safe_load(frontmatter_match.group(1)) or {}
|
|
722
|
+
body_content = frontmatter_match.group(2)
|
|
723
|
+
except Exception:
|
|
724
|
+
pass # Fallback para regex se yaml falhar
|
|
725
|
+
|
|
726
|
+
# Extrai variáveis do frontmatter parseado (fallback para regex se necessário)
|
|
727
|
+
m_type = frontmatter.get('type', '')
|
|
728
|
+
project = frontmatter.get('project', '')
|
|
729
|
+
tags = frontmatter.get('tags', '')
|
|
730
|
+
desc = frontmatter.get('description', '')
|
|
731
|
+
|
|
732
|
+
# Fallback via regex se frontmatter parsing falhou
|
|
733
|
+
if not m_type:
|
|
734
|
+
type_match = re.search(r'type:\s*(.*)', content)
|
|
735
|
+
m_type = type_match.group(1).strip() if type_match else "project"
|
|
736
|
+
if not project:
|
|
737
|
+
project_match = re.search(r'project:\s*(.*)', content)
|
|
738
|
+
project = project_match.group(1).strip() if project_match else "unknown"
|
|
739
|
+
if not tags:
|
|
740
|
+
tags_match = re.search(r'tags:\s*(.*)', content)
|
|
741
|
+
tags = tags_match.group(1).strip() if tags_match else ""
|
|
742
|
+
if not desc:
|
|
743
|
+
desc_match = re.search(r'description:\s*(.*)', content)
|
|
744
|
+
desc = desc_match.group(1).strip() if desc_match else "sem descrição"
|
|
723
745
|
|
|
724
746
|
ts = datetime.now().strftime("%Y-%m-%d")
|
|
725
747
|
entry = f"- [{m_type}] {mem_name}.md ({ts}): {desc}\n"
|
|
@@ -733,30 +755,25 @@ Uma chamada por memória. O sistema salva e indexa automaticamente.
|
|
|
733
755
|
else:
|
|
734
756
|
index_path.write_text(f"# Memórias do Projeto\n\n{entry}", encoding="utf-8")
|
|
735
757
|
|
|
736
|
-
#
|
|
758
|
+
# Registrar entidades no grafo (frontmatter + conteúdo)
|
|
737
759
|
# ORDEM IMPORTANTE: content primeiro, frontmatter depois
|
|
738
|
-
# extract_from_content() deleta entidades
|
|
739
|
-
if self.entities_db:
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
frontmatter=frontmatter or {},
|
|
756
|
-
project=project
|
|
757
|
-
)
|
|
758
|
-
except Exception as e:
|
|
759
|
-
pass # Falha silenciosa se frontmatter inválido
|
|
760
|
+
# extract_from_content() deleta apenas entidades 'content', preservando 'frontmatter'
|
|
761
|
+
if self.entities_db and frontmatter_match:
|
|
762
|
+
try:
|
|
763
|
+
# 1. Extrai entidades do conteúdo (spaCy NER)
|
|
764
|
+
self.entities_db.extract_from_content(
|
|
765
|
+
memory_id=mem_name,
|
|
766
|
+
content=body_content,
|
|
767
|
+
use_spacy=True
|
|
768
|
+
)
|
|
769
|
+
# 2. Extrai entidades do frontmatter - preservadas
|
|
770
|
+
self.entities_db.extract_from_frontmatter(
|
|
771
|
+
memory_id=mem_name,
|
|
772
|
+
frontmatter=frontmatter,
|
|
773
|
+
project=project
|
|
774
|
+
)
|
|
775
|
+
except Exception:
|
|
776
|
+
pass # Falha silenciosa se frontmatter inválido
|
|
760
777
|
|
|
761
778
|
return f"✅ Memória '{mem_name}' salva em {file_path}"
|
|
762
779
|
|