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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ocerebro",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "OCerebro - Sistema de Memoria para Agentes (Claude Code/MCP)",
5
5
  "main": "bin/ocerebro.js",
6
6
  "bin": {
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ocerebro"
7
- version = "0.3.2"
7
+ version = "0.3.3"
8
8
  description = "OCerebro - Sistema de Memoria para Agentes (Claude Code/MCP)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -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
- self.delete_entities_by_source(memory_id, "content")
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
- desc_match = re.search(r'description:\s*(.*)', content)
715
- type_match = re.search(r'type:\s*(.*)', content)
716
- project_match = re.search(r'project:\s*(.*)', content)
717
- tags_match = re.search(r'tags:\s*(.*)', content)
718
-
719
- desc = desc_match.group(1).strip() if desc_match else "sem descrição"
720
- m_type = type_match.group(1).strip() if type_match else "project"
721
- project = project_match.group(1).strip() if project_match else "unknown"
722
- tags = tags_match.group(1).strip() if tags_match else ""
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
- # BUG FIX: Registrar entidades no grafo (frontmatter + conteúdo)
758
+ # Registrar entidades no grafo (frontmatter + conteúdo)
737
759
  # ORDEM IMPORTANTE: content primeiro, frontmatter depois
738
- # extract_from_content() deleta entidades existentes, então frontmatter deve vir após
739
- if self.entities_db:
740
- import yaml
741
- frontmatter_match = re.match(r'^---\n(.*?)\n---\n(.*)$', content, re.DOTALL)
742
- if frontmatter_match:
743
- try:
744
- frontmatter = yaml.safe_load(frontmatter_match.group(1))
745
- body_content = frontmatter_match.group(2)
746
- # 1. Extrai entidades do conteúdo (spaCy NER) - pode deletar existentes
747
- self.entities_db.extract_from_content(
748
- memory_id=mem_name,
749
- content=body_content,
750
- use_spacy=True
751
- )
752
- # 2. Extrai entidades do frontmatter - NÃO são deletadas
753
- self.entities_db.extract_from_frontmatter(
754
- memory_id=mem_name,
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