diff options
| author | Elvis Claros Castro <elvis@claros.ar> | 2026-08-17 15:12:12 -0300 |
|---|---|---|
| committer | Elvis Claros Castro <elvis@claros.ar> | 2026-08-17 15:12:12 -0300 |
| commit | 0d1fe286ac6ea30b91c15b44c0872b57a864ea7f (patch) | |
| tree | 554d6c8a0bdcf1c30bfa2d752d557b39c1554d6e /tests/test_cli.py | |
| parent | bd3ca3a04fcd8d882d23deeb3f3a0d6f04b3f93f (diff) | |
| download | claude-logbook-0d1fe286ac6ea30b91c15b44c0872b57a864ea7f.tar.gz claude-logbook-0d1fe286ac6ea30b91c15b44c0872b57a864ea7f.zip | |
Explorar también las memorias de los proyectos
Claude Code deja, además de las sesiones, un directorio memory/ por proyecto:
un .md por recuerdo con frontmatter, y un MEMORY.md que hace de índice. Lo
que no figura en ese índice sigue en disco pero deja de cargarse en contexto,
así que la diferencia entre ambos es justamente lo que vale la pena mirar.
-m cambia de sesiones a memorias y reusa los mismos verbos:
claude-sesiones -m tabla de memorias
claude-sesiones -m docker busca en nombre, descripción y cuerpo
claude-sesiones -m -s 3 lee la nº 3 (o -s <nombre>)
claude-sesiones -m --check audita índices, enlaces y orígenes
claude-sesiones -m -D 3 la borra y la saca de MEMORY.md
claude-sesiones -m --type feedback filtra por tipo declarado
--check es la parte con criterio propio: reporta memorias que no están en
MEMORY.md, entradas del índice que apuntan a archivos que ya no existen,
enlaces [[...]] rotos y sesiones de origen que ya no están.
El registro de una memoria usa claves cortas como el de sesiones, por el
mismo motivo: viaja embebido en el HTML, que ahora tiene su propia pestaña
de memorias.
Claude-Session: https://claude.ai/code/session_01RmtZ9qBemrc9TncwVTG6ED
Diffstat (limited to 'tests/test_cli.py')
| -rw-r--r-- | tests/test_cli.py | 131 |
1 files changed, 127 insertions, 4 deletions
diff --git a/tests/test_cli.py b/tests/test_cli.py index 91be284..94aeac1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -9,7 +9,9 @@ from contextlib import redirect_stderr, redirect_stdout from claude_sesiones import cli -from .fixtures import simple_tree, ts, user, write_session +from .fixtures import ( + memory_tree, simple_tree, ts, user, write_memory, write_session, +) PAYLOAD_RE = re.compile( r'<script id="payload" type="application/json">(.*?)</script>', re.S) @@ -82,8 +84,9 @@ class TestExportar(CliCase): code, out, _ = self.run_cli("--json") data = json.loads(out) self.assertEqual(code, 0) - self.assertEqual(len(data), 3) - self.assertNotIn("project_dir", data[0]) + self.assertEqual(len(data["s"]), 3) + self.assertEqual(data["m"], []) + self.assertNotIn("project_dir", data["s"][0]) def test_html(self): simple_tree(self.root) @@ -93,7 +96,9 @@ class TestExportar(CliCase): self.assertIn("3 sesiones", err) with open(out_path, encoding="utf-8") as f: html = f.read() - self.assertEqual(len(json.loads(PAYLOAD_RE.findall(html)[0])), 3) + payload = json.loads(PAYLOAD_RE.findall(html)[0]) + self.assertEqual(len(payload["s"]), 3) + self.assertEqual(payload["m"], []) def test_html_no_toca_stdout(self): # El resumen va a stderr para que `--html /dev/stdout` siga sirviendo. @@ -207,5 +212,123 @@ class TestParser(unittest.TestCase): self.assertEqual(args.query, ["dos", "palabras"]) +class TestMemoria(CliCase): + def test_tabla(self): + simple_tree(self.root) + memory_tree(self.root) + code, out, _ = self.run_cli("-m") + self.assertEqual(code, 0) + self.assertIn("deploy-docker", out) + self.assertIn("4 memorias", out) + + def test_sin_memorias_avisa(self): + simple_tree(self.root) + code, _, err = self.run_cli("-m") + self.assertEqual(code, 1) + self.assertIn("memorias", err) + + def test_filtra_por_tipo(self): + simple_tree(self.root) + memory_tree(self.root) + code, out, _ = self.run_cli("-m", "--type", "reference") + self.assertEqual(code, 0) + self.assertIn("roles-db", out) + self.assertNotIn("deploy-docker", out) + + def test_la_query_busca_en_el_cuerpo(self): + simple_tree(self.root) + memory_tree(self.root) + code, out, _ = self.run_cli("-m", "make up") + self.assertEqual(code, 0) + self.assertIn("deploy-docker", out) + self.assertNotIn("roles-db", out) + + def test_show_por_nombre(self): + simple_tree(self.root) + memory_tree(self.root) + code, out, _ = self.run_cli("-m", "-s", "deploy", "--no-pager") + self.assertEqual(code, 0) + self.assertIn("Se despliega con", out) + self.assertIn("deploy-docker", out) + + def test_show_avisa_si_no_esta_indexada(self): + simple_tree(self.root) + memory_tree(self.root) + _, out, _ = self.run_cli("-m", "-s", "suelta", "--no-pager") + self.assertIn("MEMORY.md", out) + + def test_check_lista_los_problemas(self): + simple_tree(self.root) + memory_tree(self.root) + code, out, _ = self.run_cli("-m", "--check") + self.assertEqual(code, 1) # hay cosas para mirar + self.assertIn("sin MEMORY.md", out) + self.assertIn("no-existe", out) + + def test_check_limpio_sale_cero(self): + simple_tree(self.root) + write_memory(self.root, "-home-u-proj", "sola", body="sin enlaces") + from .fixtures import write_index + write_index(self.root, "-home-u-proj", ["sola"]) + code, out, _ = self.run_cli("-m", "--check") + self.assertEqual(code, 0) + self.assertIn("Todo en orden", out) + + def test_borrado_en_seco_no_toca_nada(self): + simple_tree(self.root) + memory_tree(self.root) + path = os.path.join(self.root, "-home-u-proj", "memory", + "deploy-docker.md") + code, out, _ = self.run_cli("-m", "-D", "deploy", "--dry-run") + self.assertEqual(code, 0) + self.assertIn("no se tocó nada", out) + self.assertTrue(os.path.exists(path)) + + def test_borra_y_desindexa(self): + simple_tree(self.root) + memory_tree(self.root) + path = os.path.join(self.root, "-home-u-proj", "memory", + "deploy-docker.md") + code, out, _ = self.run_cli("-m", "-D", "deploy", "-y") + self.assertEqual(code, 0) + self.assertFalse(os.path.exists(path)) + with open(os.path.join(self.root, "-home-u-proj", "memory", + "MEMORY.md"), encoding="utf-8") as f: + index = f.read() + self.assertNotIn("deploy-docker.md", index) + self.assertIn("roles-db.md", index) + self.assertIn("sacadas del índice", out) + + def test_borrado_sin_confirmar_cancela(self): + simple_tree(self.root) + memory_tree(self.root) + path = os.path.join(self.root, "-home-u-proj", "memory", + "deploy-docker.md") + with unittest.mock.patch.object(cli, "confirm", return_value=False): + code, _, err = self.run_cli("-m", "-D", "deploy") + self.assertEqual(code, 1) + self.assertIn("Cancelado", err) + self.assertTrue(os.path.exists(path)) + + def test_referencia_inexistente(self): + simple_tree(self.root) + memory_tree(self.root) + code, _, err = self.run_cli("-m", "-s", "no-existe-nada") + self.assertEqual(code, 2) + self.assertIn("ninguna memoria", err) + + def test_html_embebe_las_memorias(self): + simple_tree(self.root) + memory_tree(self.root) + out_path = os.path.join(self.home, "s.html") + code, _, err = self.run_cli("--html", out_path) + self.assertEqual(code, 0) + self.assertIn("4 memorias", err) + with open(out_path, encoding="utf-8") as f: + payload = json.loads(PAYLOAD_RE.findall(f.read())[0]) + self.assertEqual(len(payload["m"]), 4) + self.assertIn("deploy-docker", {m["name"] for m in payload["m"]}) + + if __name__ == "__main__": unittest.main() |