diff options
| author | Elvis Claros Castro <elvis@claros.ar> | 2026-08-16 19:57:17 -0300 |
|---|---|---|
| committer | Elvis Claros Castro <elvis@claros.ar> | 2026-08-16 19:57:17 -0300 |
| commit | bd3ca3a04fcd8d882d23deeb3f3a0d6f04b3f93f (patch) | |
| tree | a9e0dd65940de54c8f956befe9d86b80350bde2e /tests/fixtures.py | |
| parent | da1c60458b0d28e84739475491a3f2d61ed8eff8 (diff) | |
| download | claude-logbook-bd3ca3a04fcd8d882d23deeb3f3a0d6f04b3f93f.tar.gz claude-logbook-bd3ca3a04fcd8d882d23deeb3f3a0d6f04b3f93f.zip | |
Preparar el proyecto para publicarlo
El script suelto pasa a ser un paquete instalable, con tests y documentación.
El comportamiento del CLI no cambia: mismos flags, misma salida.
Estructura
- claude_sesiones/{sessions,terminal,webpage,cli}.py separa parseo,
presentación, generación del HTML y argumentos. El template pasa a ser
data del paquete.
- pyproject.toml con el entry point claude-sesiones, sin dependencias.
- build.sh se disuelve en `claude-sesiones --html [ARCHIVO]`: el HTML se
arma en proceso, sin subprocess ni data.json intermedio. `--open` lo
abre en el navegador.
Arreglos
- El template no tenía doctype ni <meta charset>: abierto como file://
quedaba en quirks mode y con la codificación del sistema, así que los
acentos salían rotos. Tampoco tenía viewport, con lo que en el celular
se veía a escala de escritorio.
- `delete_sessions()` se llamaba con un argumento de menos (lo encontró
el test de borrado).
- El orden de la tabla comparaba timestamps como strings; ahora compara
los datetimes ya parseados.
- `mark()` buscaba el texto crudo dentro del HTML ya escapado, así que
resaltar algo con & o < nunca encontraba nada. `esc()` no escapaba la
comilla simple.
- El caché no tenía versión: al cambiar el esquema del registro se leían
registros de la forma anterior. Ahora se invalida solo. El temporal
lleva el pid, para que dos corridas simultáneas no se pisen.
- `pick()` cortaba el proceso con sys.exit desde adentro; ahora levanta
SessionError y el código de salida lo decide la CLI.
Mejoras
- Respeta CLAUDE_CONFIG_DIR.
- La página tiene botón de tema claro/oscuro que recuerda la elección,
deep links (#uuid abre esa conversación), atajos de teclado, trampa de
foco en el lector y aviso si el JS está apagado. Las tres copias de la
paleta quedaron en dos, una por tema.
- 92 tests con unittest, sin dependencias, contra árboles de .jsonl
falsos: nunca tocan ~/.claude. CI en GitHub Actions, Python 3.9 a 3.13.
- README en inglés y español, con el esquema del JSON y una advertencia
sobre lo que hay adentro de sesiones.html.
- Apache-2.0.
Claude-Session: https://claude.ai/code/session_01RmtZ9qBemrc9TncwVTG6ED
Diffstat (limited to 'tests/fixtures.py')
| -rw-r--r-- | tests/fixtures.py | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/tests/fixtures.py b/tests/fixtures.py new file mode 100644 index 0000000..9b55c4b --- /dev/null +++ b/tests/fixtures.py @@ -0,0 +1,70 @@ +"""Sesiones .jsonl de mentira para los tests.""" + +import json +import os + +BASE_TS = "2025-08-14T10:00:00.000Z" + + +def ts(minute=0, hour=10, day=14): + return f"2025-08-{day:02d}T{hour:02d}:{minute:02d}:00.000Z" + + +def user(text, at=BASE_TS, **extra): + ev = { + "type": "user", + "timestamp": at, + "cwd": "/home/u/proj", + "gitBranch": "main", + "version": "1.0.0", + "message": {"role": "user", "content": [{"type": "text", "text": text}]}, + } + ev.update(extra) + return ev + + +def assistant(text=None, tools=(), at=BASE_TS, **extra): + content = [] + if text is not None: + content.append({"type": "text", "text": text}) + for name, args in tools: + content.append({"type": "tool_use", "name": name, "input": args}) + ev = { + "type": "assistant", + "timestamp": at, + "message": {"role": "assistant", "content": content}, + } + ev.update(extra) + return ev + + +def ai_title(title, at=BASE_TS): + return {"type": "ai-title", "aiTitle": title, "timestamp": at} + + +def write_session(root, project_dir, session_id, events): + """Escribe un .jsonl y devuelve su ruta.""" + d = os.path.join(root, project_dir) + os.makedirs(d, exist_ok=True) + path = os.path.join(d, session_id + ".jsonl") + with open(path, "w", encoding="utf-8") as f: + for ev in events: + f.write(json.dumps(ev, ensure_ascii=False) + "\n") + return path + + +def simple_tree(root): + """Un árbol chico y variado: una charla, una vacía y una sin cwd.""" + write_session(root, "-home-u-proj", "aaaaaaaa-0000-0000-0000-000000000001", [ + ai_title("Arreglar el build"), + user("¿por qué falla el build?", at=ts(0)), + assistant("Miro el log.", tools=[("Bash", {"command": "make"})], at=ts(3)), + user("gracias", at=ts(12)), + ]) + write_session(root, "-home-u-proj", "bbbbbbbb-0000-0000-0000-000000000002", [ + {"type": "system", "timestamp": ts(0, hour=9), "cwd": "/home/u/proj"}, + ]) + write_session(root, "-home-u-otro", "cccccccc-0000-0000-0000-000000000003", [ + user("hola", at=ts(0, hour=8), cwd="/home/u/otro"), + ]) + return root |