Política de compatibilidad:
PRE_RELEASE_PRODUCT. Se mantiene la declaración de 6.36.0: no consta adopción externa, por lo que no existe un contrato público de compatibilidad establecido por terceros. Los cambios descritos abajo son aditivos (superficies nuevas, parámetros opcionales) y no eliminan ni re-typian ninguna superficie previa, lo que sustenta la clasificación MINOR y no MAJOR.
Alcance: el canal WORK (.work/) completo —contenedor documental,
lector/escritor de estado y motor de verificación de verdicts—, dos
correcciones de la frontera de ejecución, y la identidad pública del
proyecto. 15 commits desde v6.36.0 (72aeb79).
.work/)work_context.py: contenedor .work/<id>/ con los documentos canónicos
state.md, decisions.md y assertions.md. Escritor atómico (temporal en el
mismo directorio + os.replace): si algo falla antes del reemplazo, el
contenido anterior queda intacto.work_verdict.py: adaptador Git de solo lectura (GitAnchor con
tree_sha, CurrentGitState), productor canónico producir_verdict() y
evaluador puro evaluar_validez_verdict() (VALID / OBSOLETE /
UNDETERMINED). Si Git no es observable lanza EstadoGitIndisponibleError
y nunca degrada a un estado de validez.work_obsolencia.py: detectar_obsolescencia() explícita, append-only e
idempotente. La obsolescencia significa únicamente que el contenido efectivo
del árbol dejó de coincidir con el tree_sha que produjo la verificación.work_state — lee state.md de un trabajo. Solo lectura, no pide permiso.work_state_update — actualiza campos declarativos. Es una capacidad de
mutación: requiere permiso explícito.ReactAgent(work_id=…): el agente ReAct (F4) puede vincularse a un
trabajo del canal WORK; al ejecutar, captura el estado Git previo, produce el
Verdict, evalúa su validez y persiste la última verificación. El resultado
F4 incorpora las claves verdict, validity y verificacion_persistida
(más *_error si procede). Cambio aditivo: las claves y semántica
preexistentes no cambian..work excluido del contexto PROJECT (B11-E): añadido a las listas de
directorios ignorados de graph_rag.py, graph_lsp_integrator.py y
seguridad.py, y a la exclusión del staging automático de Git.exceptions.py: ContratoEstadoInvalidoError,
EstadoGitIndisponibleError (expone motivo) y AutoridadInsuficienteError.CONTAINER
ya no delega en _envolver_sandbox, que devolvía el comando intacto cuando
el sandbox explícito no estaba activo. Un comando clasificado como sandbox
se ejecutaba sin aislamiento y sobre el árbol equivocado; con este
cambio la decisión de política gobierna la ejecución. Se elimina además la
sustitución del directorio solicitado por Path.cwd(). Sin fallback
silencioso a host.veredictos_obsoletos) se rechazan antes
que la allowlist genérica y ninguna autorización los salva;
ciclo_de_vida y cierre_estado exigen autorizacion=True. La decisión se
toma sobre la operación completa, por lo que nunca hay escritura parcial.pip-audit) deja de ser
continue-on-error y pasa a bloqueante, al medirse 0 advisories sobre el
grafo de dependencias declarado.git add . ":(exclude).work" se clasificaba como
sandbox porque el ( del pathspec magic se interpretaba como metacarácter
de shell, con lo que el staging viajaba al contenedor y el commit se
ejecutaba en el host sobre un índice vacío («nothing to commit» y un
diagnóstico engañoso). El staging se ejecuta ahora por argv con
shell=False; si el argv no fuera directo se aborta explícitamente.configuracion.py y diagnostico.py ya no
recomiendan extras que no existen (snapcontext[anthropic],
snapcontext[interactive], snapcontext[embeddings], snapcontext[lsp]) y
pasan a indicar el paquete a instalar directamente.work_context, work_verdict y work_obsolencia se
declaran en [tool.setuptools] py-modules. Sin ellos, el wheel publicado no
contenía el canal WORK y las herramientas work_state / work_state_update
fallaban en una instalación limpia. verify_release.py los incluye ahora en
MODULOS_WHEEL para que el invariante I10 detecte su ausencia en el futuro.pyproject.toml corrige el nombre del
autor (mojibake Nicolás → Nicolás Bruna) y añade [project.urls] con
Homepage y Repository. El plugin.xml de JetBrains pasa de vendor
«SnapContext Contributors» a Nicolás Bruna Fuentealba (nicobrunaf.dev),
con descripción reescrita y enlaces al perfil público.docs/RELEASE.md documenta que parte del
metadata del listing de JetBrains vive fuera del repositorio (descripción
editada desde la UI, vendor, enlaces, versión publicada) y añade la
verificación post-release de JetBrains. PUBLISHING.md queda como nota
histórica y remite a docs/RELEASE.md como autoridad vigente.--lsp usa servidores LSP externos ya instalados en PATH.backend_xpu.py) no detecta
específicamente «Arc B» ni «Battlemage»; comprueba torch.xpu e IPEX de
forma genérica. El soporte de Battlemage depende de ipex-llm>=2.2.0,
una dependencia externa. Los tests de integración real se saltan sin GPU
Intel. La capacidad es, por tanto, parcialmente soportada y delegada en el
proveedor de la librería.Política de compatibilidad:
PRE_RELEASE_PRODUCT. SnapContext no declara usuarios externos ni consumidores publicados a la fecha de este release, por lo que aún no existe un contrato público de compatibilidad establecido por adopción externa. Esta es una afirmación del mantenedor sobre el estado del producto —no una propiedad técnica verificable desde el repositorio— y es la base por la que este release se clasifica como MINOR pese a contener cambios que serían incompatibles sobre superficies ya adoptadas. Si apareciera un consumidor externo, esta clasificación quedaría invalidada.Alcance: baseline de seguridad del Gateway Web (B9.61), integridad de artefactos y fuente única de versión (B9.63), e integración del repositorio (B9.64), además de C2 (sandbox default-deny) y C3 (punto único de escritura segura), que hasta ahora figuraban bajo
Unreleaseddesde las entradas6.36.0/6.37.0que nunca fueron publicadas. Este es el contenido que la tagv6.36.0(commit72aeb79) publica por primera vez; la última tag real anterior a ella erav6.35.3.
Restricciones de diseño sin ruta de migración:
DENY ALL en M1. web/remota.py aplica política
deny-by-default: la allowlist remota (sandbox_allowlist_remota) está
vacía por diseño (OD-1), por lo que toda ejecución remota se rechaza.
Los shells e intérpretes quedan prohibidos. No existe ruta de migración en
M1: no hay allowlist poblada, ni signing, ni sandbox de red, ni workers
distribuidos. Cualquier despliegue que dependiera de ejecución remota deja de
funcionar.tests y pr_review → no ejecutables por el worker
(TIPOS_PERMITIDOS = {query, plan}). No existe migración (ver
Limitaciones conocidas).Con migración disponible:
web/seguridad.py). Una credencial ausente,
vacía o de menos de 32 caracteres deja de ser utilizable: las superficies
autenticadas responden 401/1008. Antes el webhook podía aceptarse en modo
fail-open. Migración: preparar_credencial_inicio() genera la credencial y
corrige a 0600 toda superficie que no lo esté. Requiere acción del
usuario: las configuraciones que confiaban en acceso anónimo se rompen.generar_credencial(), cargar_credencial()
(relee configuración en cada llamada) y rotar_credencial().CAPABILIDADES, 9 de B9.59 §7). Sin
capability nueva; un cliente sin la capacidad requerida recibe 403.clasificar_exposicion): distingue loopback de
exposición remota, valida Host/Origin (host_valido, origin_admitido,
es_loopback_hostname) y aplica rate limiting por cliente.web/filesystem.py): validación de forma
→ resolve (realpath) → containment semántico (no startswith, que
confundiría /workspace con /workspace-other) → política. Fuera de loopback
se exige --workspace-root explícito; sin él el arranque aborta
(fail-closed). Sin valor por defecto fuera de loopback por diseño. Códigos de
error explícitos: invalid_path / outside_workspace.TaskSecurityContext inmutable con
revalidación en la frontera de ejecución./interactive y WS /ws/interactive
pasan por el protector de exposición.Cobertura: no completa. Ver Excepción de seguridad conocida más abajo.
BREAKING (comportamiento): el modelo de decisión del sandbox cambió de
blocklist a default-deny, con clasificación en 3 niveles
(sandbox_utils.clasificar_comando):
| ; > & $(...) \ $VAR)
cuyo binario base está en sandbox_allowlist_binarios` → ejecución directa
(fricción cero).eval,
base64 -d | sh, mkfs, shred, truncate, escrituras a /dev/*) →
sandbox Docker obligatorio, sin confirmación adicional más allá de la que ya
aplique permisos.json.es_comando_peligroso, intacta): defensa en profundidad;
ya no decide sandbox sí/no, solo dispara un warning más explícito (con el
patrón que disparó) antes de confirmar.BREAKING (procesos en background): _lanzar_proceso_fondo (estado.py) sin
sandbox activo aplica ahora la misma clasificación: los comandos que antes
corrían simplemente por no estar en la blocklist (p. ej. flutter run)
se rechazan si su binario no está en la allowlist.
sandbox_allowlist_binarios (nivel superior de
~/.snapcontext/config.json; ejemplo en config.example.json): lista de
binarios con ejecución directa. Si se define sobrescribe completa la lista
por defecto (no hace merge). Por defecto: ls, cat, head, tail, wc, stat,
file, diff, tree, grep, rg, git, pytest, ruff, mypy, black, isort, npm, pip,
pip3, echo, which, date.--no-sandbox sigue forzando ejecución directa, pero los comandos fuera de la
allowlist ya no pasan en silencio: piden confirmación explícita mostrando el
motivo y aborta en modo --auto / stdin no interactivo. Este efecto sobre
el modo no interactivo es el cambio con mayor probabilidad de afectar a un
flujo existente.echo <b64> | base64 -d | sh, python -c 'shutil.rmtree("/")',
find / -delete, eval "$VAR", heredocs, expansión de variables). Tests
nuevos en tests/test_sandbox_inteligente.py (un caso por evasión, allowlist
con metacaracteres, --no-sandbox y gate de background).BREAKING (menor): todas las escrituras dentro del proyecto pasan por
utils.escribir_archivo_seguro(), que valida la ruta y abre el descriptor en
la misma operación con O_NOFOLLOW: no hay ventana entre validación y escritura
(escritura atómica). Si algún módulo escribía con write_text() sobre una
ruta provista por el LLM, ahora lanza RutaInseguraError en vez de seguir
silenciosamente un symlink.
Call-sites migrados: snapcontext.py (editor propio y snapshots de rollback),
agentes.py (_rollback de AgenteEditorPropio), react_agent.py
(_tool_editar_archivo), autocorrector.py (aplicar_correccion).
Migración: las rutas absolutas dentro del proyecto deben pasar a relativas; los
snapshots de rollback ahora validan el directorio antes de restaurar (usan el
raiz del proyecto). Si alguna vez viste que SnapContext escribía donde no
debía, ya no debería ocurrir.
VERSION (raíz) es la única fuente de verdad. pyproject.toml usa
dynamic = ["version"] con version = {file = ["VERSION"]}; la versión del
paquete se deriva en build. La versión en runtime (snapcontext.VERSION) y la
de FastAPI se derivan de ella.scripts/version_sync.py: check (solo lectura, sale con código ≠ 0 ante
cualquier divergencia; es el gate de CI) y sync (reescribe las superficies
derivadas). Sincroniza VS Code (manifest + lock) y JetBrains
(gradle.properties, build.gradle.kts, plugin.xml).scripts/verify_release.py — 12 comprobaciones fail-closed (I1–I12):
tag == VERSION; correspondencia del artefacto; snapcontext.VERSION del wheel
instalado; importlib.metadata.version; coherencia VS Code; coherencia
JetBrains; entrada de CHANGELOG publicada; presencia de los 6 módulos de test de
seguridad; sdist → wheel sin intervención; el wheel contiene los módulos
runtime y web/static; instalación limpia; y web/static/* presente en el
paquete instalado.verify-release precede a publish-pypi y a
publish-vscode. Si falla, la publicación no puede ejecutarse.exceptions.py y
prompt_profiles.py. Antes, una wheel instalada no podía importar
snapcontext; este es un fix, no un cambio de comportamiento. El paquete
incluye además web/seguridad.py, web/filesystem.py y web/remota.py.Los módulos de seguridad del Gateway Web y sus módulos de test estaban presentes
en el árbol de trabajo pero ausentes de Git (hallazgos P0 F-01 y F-02 de
B9.62). Este release los incorpora al control de versiones: web/seguridad.py,
web/filesystem.py, web/remota.py y los 6 módulos de test de seguridad
(test_gateway_seguridad.py, test_gateway_filesystem.py,
test_gateway_remota.py, test_web_riesgo.py, test_task_queue.py,
test_github_gateway.py) están ahora trackeados, y el release se validó desde
un checkout limpio. F-01 y F-02 quedan cerrados.
flujo_principal sin el
TaskSecurityContext congelado. Esa ruta no pasa por task_queue ni por
la frontera de contexto de tareas introducida en B9.61. Constituye una
excepción de seguridad conocida, aceptada de forma explícita y NO resuelta en
6.36.0; se difiere a un release posterior.TIPOS_PERMITIDOS en el worker), la
autenticación fail-closed y la frontera de sistema de ficheros. Lo que queda
fuera del perímetro de B9.61 es precisamente el TaskSecurityContext congelado
en la entrada de Telegram.tests / pr_review que el worker después
deniega. El usuario recibe una confirmación de encolado de algo que no llegará
a ejecutarse. Es comportamiento conocido, no resuelto en 6.36.0 y diferido
al siguiente release. No debe interpretarse como una capacidad operativa
válida._TAREAS_API registra owner/contexto que la ruta in-process no
consume para revalidar. Deuda arquitectónica post-release, sin bypass._validar_ruta_segura: la validación y la apertura ahora son atómicas.O_NOFOLLOW).tests/test_file_safety.py.mcp_client: KeyError no manejado en _enviar/_esperar_respuesta al
reutilizar un proceso muerto tras un fallo de stdin.mcp_client.list_tools: valida el tipo de los elementos y filtra los que no
son dict; cobertura del módulo 22% → 87%.sandbox_utils.clasificar_comando):
| ; > & $(...) \
$VAR) cuyo binario base está en sandbox_allowlist_binarios` →
ejecución directa (fricción cero).eval, base64 -d | sh, mkfs, shred, truncate, escrituras a
/dev/*) → sandbox Docker obligatorio, sin confirmación adicional más
allá de la que ya aplique permisos.json.es_comando_peligroso, intacta): defensa en
profundidad — ya no decide sandbox sí/no; si un comando la matchea se
muestra un warning más explícito (con el patrón que disparó) antes de
confirmar._lanzar_proceso_fondo (estado.py)
sin sandbox activo aplica ahora la misma clasificación: los comandos que
antes corrían simplemente por no estar en la blocklist (p. ej.
flutter run) se rechazan si su binario no está en la allowlist.sandbox_allowlist_binarios (nivel superior
de ~/.snapcontext/config.json; ejemplo en config.example.json): lista
de binarios con ejecución directa. Si se define sobrescribe completa la
lista por defecto (no hace merge). Por defecto:
ls, cat, head, tail, wc, stat, file, diff, tree, grep, rg, git, pytest,
ruff, mypy, black, isort, npm, pip, pip3, echo, which, date.--no-sandbox sigue forzando ejecución directa, pero los comandos fuera de
la allowlist ya no pasan en silencio: piden confirmación explícita
mostrando el motivo (y abortan en modo --auto/stdin no interactivo).echo <b64> | base64 -d | sh, python -c 'shutil.rmtree("/")',
find / -delete, eval "$VAR", heredocs, expansión de variables). Tests
nuevos en tests/test_sandbox_inteligente.py (un caso por evasión,
allowlist con metacaracteres, --no-sandbox y gate de background).sandbox_allowlist_binarios en tu ~/.snapcontext/config.json
y añade los binarios específicos de tu stack (p. ej. flutter, dart, cargo, go).
Recuerda que la lista definida reemplaza la por defecto: copia primero
la lista base de config.example.json y agrega los tuyos.--workspace-root explícito si no es loopback, y genera
la credencial con preparar_credencial_inicio() (permisos 0600).tests/pr_review.license = "Apache-2.0" sigue siendo la fuente de verdad.Todos los cambios notables para SnapContext se documentarán en este archivo.
El formato sigue las directrices de Keep a Changelog.
qwen2.5:0.5b).tests/test_benchmark.py).benchmarks/README.md.snapcontext --demo sin API key, documentado pipx install.--demo).tests/test_demo.py, 11 tests).github_gateway y curador_proactivo.benchmarks/ del type checking (no son parte del paquete).benchmarks/tasks/ y mcp_client/demo.addopts en pyproject.toml no incluye --cov-fail-under.--cov-fail-under=50 via variable COV_MIN en el comando del job build-and-test.~/.snapcontext/mcp_servers.json.snapcontext --demo funciona en 0.3s sin API key, mostrando el valor de la herramienta en 30 segundos. Documentación de pipx install como método recomendado.docs/MCP.md y benchmarks/README.md añadidos. Quick Start de 30 segundos actualizado en README.c669351 feat: cliente MCP estándar (Fase 3)f4aafb5 feat: onboarding zero-config con –demo (Fase 4)7250688 fix: –demo se ejecuta antes del background indexing9d95a87 feat: benchmark de edición público con 10 tareas (Fase 5)876fb16 feat: benchmark ampliado a 50 tareas (Fase 5b)test_version_es_* / test_version_*_coherente (14 archivos): dejan de
fijar sc.VERSION a un número concreto y verifican el formato X.Y.Z,
para no romper con cada release.test_diagnostico_310.py: los mocks se actualizan al namespace real
(configuracion.py) tras el traslado de hay_api_key_configurada,
_estado_ollama y _listar_modelos_ollama (Fase 4).test_autocorrector.py: acepta el runner actual de detector_tests
(python -m unittest discover para proyectos python-unittest).test_v010.py, test_plan_012.py, test_mcp_014.py: comandos de fallo
via sh -c 'exit N' (los comandos simples se ejecutan con shell=False).test_vscode_016.py: main del manifiesto actualizado al valor real
(./extension/out/extension.js).test_volumen9..18.py a la lista del gate
(medición local: 51%); COV_MIN se mantiene en '50' (seguro, margen 1%;
subir gradualmente a medida que crezca la lista del gate).v6.34.14), VS Code Marketplace y JetBrains Marketplace.LICENSE y
.vscodeignore (requisitos del Marketplace); workflow vsce-publish
reactivado con trigger por tag.publishPlugin
lista (requiere publishToken en gradle.properties o JETBRAINS_TOKEN).docs/landing/index.html desplegable
vía GitHub Pages (workflow pages-deploy.yml).docs/RELEASE.md con el proceso completo de
publicación en los tres canales; README enlaza PyPI, Marketplaces y demo.snapcontext.py reducido un 19%.shell=False, permisos 0o600, path traversal validado.ruff y mypy pasan con 0 errores.configuracion, planificador,
permisos, hooks y mcp_tools (con re-exports para compatibilidad).snapcontext.py reducido de 14.113 a ~11.400 líneas._validar_ruta_segura): las escrituras y los +++ de los parches deben
quedar dentro del proyecto (M1 de la auditoría).ruff (lint + format), mypy y pytest-cov configurados en
pyproject.toml, con job no bloqueante de calidad en CI.quality en el workflow (ruff check/format, mypy, tests) con
continue-on-error mientras se reduce la deuda de hallazgos.List en configuracion.pyList a la importación de typing en configuracion.py.__getattr__
en configuracion.py causaba un ciclo de importación cuando snapcontext.py
ejecutaba from configuracion import (...) durante su propia inicialización.
Reemplazado por imports diferidos explícitos dentro de cada función
(patrón ya probado en fases anteriores), eliminando el ciclo y restaurando
el build en CI para Python 3.10–3.13.tests/test_import.py) con instalación base (pip install -e .,
sin extras).tests/test_import.py: smoke tests mínimos — importa snapcontext
(verifica VERSION), valida el formato de la versión y comprueba que
python -m snapcontext --help responde correctamente.twine check
se mantienen en el workflow, y publish-pypi sigue dependiendo de que
los tests pasen.UnicodeDecodeError al importar snapcontext en CI/Linux: el commit de
bump de versión (d0b2e63) reescribió snapcontext.py en Latin-1/Windows-1252,
dejando 2.067 bytes no-UTF-8 (tildes, ñ, emojis) ilegibles para Python en
locales UTF-8. Todos los archivos .py del repositorio han sido convertidos
a UTF-8 sin BOM y verificados (py_compile + suite de tests).?? por conversiones ANSI anteriores fueron
restaurados desde el historial de git, y 9 em-dashes (—) sueltos en
comentarios/docstrings (bytes 0x97) fueron reparados..gitattributes: *.py text eol=lf encoding=utf-8 — Git normaliza y
verifica la codificación de todos los .py en futuros commits..editorconfig: charset = utf-8, end_of_line = lf para *.py,
de forma que todos los editores guarden en UTF-8.ModuleNotFoundError al usar funcionalidades clave:
sandbox_session.py → --sandbox-session (persistencia de Docker por sesión).tui_hub.py / tui_app.py → --tui (interfaz TUI con Textual).lsp_client.py → --lsp / --graph-rag-lsp (Language Server Protocol).qa_tester_logic.py → sub-agente QA de --multi-agent.session_manager.py, memory_store.py, tui_interactiva.py,
autocorrector.py (código fuente del proyecto).[tool.setuptools] py-modules en
pyproject.toml. Se ha regenerado el wheel y verificado que todos los
módulos viajan dentro del artefacto.sandbox_utils.py
(ejecutar_comando_seguro y ejecutar_comando_con_politica) que eliminan el
uso de subprocess.run(..., shell=True) cuando es innecesario:
shell=False y lista de argumentos (shlex.split), evitando la
inyección de comandos controlados por el LLM o el usuario.shell=True (imprescindible)
pero se validan con es_comando_peligroso y requieren confirmación.sandbox_session.ejecutar_en_sesion ya no duplica capa de shell
(shlex.join + shell=True): pasa la lista docker exec ... sh -c ....autocorrector, curador_proactivo y las herramientas MCP de plugins
usan el helper. _ejecutar_comando pide confirmación ante comandos
peligrosos que se ejecutarían en el host (p. ej. --no-sandbox).tests/test_sandbox_utils.py (y actualizados
test_sandbox_430.py, test_sandbox_session.py, test_sandbox_inteligente.py)graph_lsp_integrator.py: Integra Graph RAG y LSP para
obtener contexto preciso por símbolos (v6.33.0):
GraphLSPIntegrator(grafo, config, proveedor_lsp): clase principal con
caché de llamadas LSP y expansión por dependencias del grafo.obtener_contexto_preciso(archivo, linea, tipo, max_simbolos): obtiene
símbolos precisos usando LSP + Graph RAG; prioriza por frecuencia de
llamadas.inyectar_contexto_preciso(contexto_actual, simbolos): inyecta símbolos
extraídos en el prompt (reemplaza archivos completos).configuracion_graph_lsp(config): fusiona valores por defecto con
config["graph_lsp"].snapcontext.py:
_graph_lsp_activo(args): resuelve el estado (flag > entorno
SNAPCONTEXT_GRAPH_RAG_LSP=1; requiere --graph-rag y --lsp)._configurar_graph_lsp(args): devuelve configuración efectiva.obtener_simbolos_lsp(archivo, linea, tipo, grafo, config): helper
público que delega en graph_lsp_integrator (nunca lanza).orquestador.py: con --graph-rag-lsp activo, el
planificador usa obtener_contexto_preciso para inyectar símbolos precisos
en el prompt del LLM.react_agent.py: nueva herramienta obtener_simbolo
que devuelve definición y referencias de un símbolo específico vía LSP.config.json: sección graph_lsp con
activo, profundidad (2 por defecto) y simbolos_max (10 por defecto).--graph-rag-lsp (requiere --graph-rag y --lsp),
--lsp-profundidad N y --lsp-simbolos-max N.🔗 Usando Graph RAG + LSP para contexto preciso
(profundidad {N}, máx. {M} símbolos). y 📖 Inyectando símbolo: {nombre}
({archivo}:{linea}) en modo --depurar.tests/test_graph_lsp_integrator.py (más de 20 casos):
configuración, caché, expansión con grafo, inyección de contexto, flags CLI
e integración con snapcontext.--graph-rag-lsp el comportamiento es idéntico al
actual (se usan archivos completos). Las llamadas al LSP son perezosas y con
caché.6.33.0 en snapcontext.py y pyproject.toml;
graph_lsp_integrator añadido a py-modules; aserciones de versión de
los tests de coherencia actualizadas a 6.33.0.context_pruner.py: Pruning proactivo de contexto — poda
los datos de herramientas (logs, salidas, diffs) después de cada uso,
reemplazándolos por un resumen de una línea para reducir drásticamente el
consumo de tokens:
prune_resultado(resultado, tipo_herramienta, umbral_lineas, ...): poda un
resultado extenso (más de N líneas) reemplazando cada campo podable por un
resumen de una línea; añade _pruned: True y _resumen para trazabilidad;
nunca muta el original.resumir_linea(texto, max_lineas, usar_llm, proveedor_llm): genera un
resumen de una línea usando el LLM si está disponible (categoría
"resumen") o una heurística simple (primera línea + “ (y N líneas más)”).es_resultado_extenso(resultado, umbral_lineas, tipos_podables): detecta si
un resultado supera el umbral en stdout, stderr, contenido, diff o texto.obtener_metadatos_clave(resultado, tipo_herramienta): extrae información
crítica (código de retorno, archivo afectado, error) que se preserva siempre.configuracion_pruning(config): fusiona valores por defecto con
config["pruning"]._enviar_al_proveedor_unico (snapcontext.py): con
--prune-context activo, los resultados extensos de herramientas se podan
después del paso de Prompt Caching (no interfiere con cache_control).config.json: sección pruning con activo,
umbral_lineas (10 por defecto), usar_llm y tipos_podables.--prune-context / --no-prune-context (activado por
defecto) y --prune-umbral N (configura el umbral de líneas)._configurar_pruning, _resolver_pruning,
_pruning_activo, _umbral_pruning, podar_si_extenso (wrapper seguro) y
_podar_resultados_extensos (poda mensajes tool/assistant en el historial).✂️ Podando contexto (resultados extensos → resumen 1
línea) en modo --depurar.tests/test_context_pruner.py (más de 25 casos): detección de
resultados extensos, resumen con LLM y heurística, metadatos clave, poda,
configuración personalizada, flags CLI e integración con snapcontext.--prune-context (o con --no-prune-context) el
comportamiento es idéntico al actual; el pruning es rápido (heurística simple
si el LLM no está disponible) y no pierde información crítica para el agente.6.32.0 en snapcontext.py y pyproject.toml; context_pruner
añadido a py-modules; aserciones de versión de los tests de coherencia
actualizadas a 6.32.0.prompt_cache.py: Prompt Caching por Capas — el prompt se
estructura en tres capas inmutables para maximizar el prefijo idéntico entre
peticiones y activar la caché de la API (Anthropic, DeepSeek) con la máxima
eficiencia:
ensamblar_prompt_estructurado(sistema, contexto_estatico,
contexto_semi_estatico, mensajes_recientes, config): orden estricto
(estática → semi-estática → volátil) con cache_control:
{"type": "ephemeral"} en las capas inmutables; nunca muta las entradas.es_capa_estatica / es_capa_semi_estatica / es_capa_volatil:
detección por marcadores de roles/contenido (rápida, sin IA); prioridad
estática > semi-estática > volátil (un mensaje solo pertenece a una capa).clasificar_mensajes(mensajes, config): reparte una lista plana en las 3
capas preservando el orden relativo.metricas_capas(mensajes, config): tokens estimados por capa (1 token ≈ 4
caracteres) para --depurar._enviar_al_proveedor_unico (snapcontext.py): con las
capas activas se usa ensamblar_prompt_estructurado en lugar del marcado
plano; con --no-prompt-caching-capas se usa el caching básico de v6.16.0
(_aplicar_cache_control, sin cambios). Degradación graceful al caching
básico si el módulo falta o falla.config.json: sección prompt_caching con
activo y capas (estatica, semi_estatica, volatil) — el usuario
puede ajustar qué partes son estáticas/semi-estáticas/volátiles.
_resolver_prompt_caching ahora tolera prompt_caching como bool (v6.16.0)
o como sección dict.--prompt-caching-capas /
--no-prompt-caching-capas (por defecto: activado si --prompt-caching lo
está; configurable con prompt_caching.capas_activo o la variable de
entorno SNAPCONTEXT_PROMPT_CACHING_CAPAS).🧠 Prompt Caching por Capas activado (estática +
semi-estática + volátil). al inicio de la sesión (línea adicional tras el
mensaje básico de v6.16.0, que no cambia) y
📊 Capa estática: X tokens, semi-estática: Y tokens, volátil: Z tokens.
en modo --depurar.tests/test_prompt_cache.py (más de 20 casos): ensamblado
en orden estricto, asignación de cache_control por capa, detección de
capas (incluida configuración personalizada), métricas, integración en
_enviar_al_proveedor (capas vs básico), flags CLI y compatibilidad con
v6.16.0.--prompt-caching-capas (o con
--no-prompt-caching-capas) el comportamiento es idéntico al caching básico
de v6.16.0; para proveedores sin soporte (Gemini, Groq, Ollama) el flujo no
cambia. La detección de capas no añade latencia significativa (solo in
sobre el contenido) y las capas estáticas/semi-estáticas son inmutables
durante la sesión.6.31.0 en snapcontext.py y pyproject.toml; prompt_cache
añadido a py-modules; aserciones de versión de los tests de coherencia
actualizadas a 6.31.0.model_router.py: los modelos
locales (Ollama) atienden las tareas simples y repetitivas y la nube
(Gemini, Claude, DeepSeek) solo recibe las complejas — ahorrando costes sin
sacrificar calidad.
es_tarea_compleja(consulta, contexto, config): detección de complejidad
con heurísticas rápidas (sin llamadas a la IA): longitud de la consulta
(>100 palabras por defecto), archivos grandes (>1000 líneas), múltiples
archivos a editar (>3) y presencia de comandos complejos (deploy,
migraciones, docker, sudo, &&…). Umbrales configurables vía
umbral_complejidad.obtener_orden_prioridad(compleja, config): cadena de
(proveedor, modelo) — simple → prioridad_local + prioridad_nube;
compleja → prioridad_nube + prioridad_local (fallback graceful en
ambos sentidos, sin duplicados).seleccionar_modelo_con_fallback(categoria, config, compleja): primer
modelo de la cadena; sin prioridades configuradas delega en
seleccionar_modelo (compatibilidad total con v6.24.0).es_proveedor_local(proveedor, config): ¿es un proveedor local?
(ampliable con proveedores_locales en config.json)._enviar_al_proveedor (snapcontext.py): la
función se divide en envoltorio (enrutamiento + cadena) y núcleo de un solo
intento _enviar_al_proveedor_unico. Ante un error de API/timeout se prueba
el siguiente modelo de la cadena con el aviso
⚠️ Fallo en x/y. Reintentando con z/w.; los errores de autenticación
(401/403, clave ausente o inválida) NO se reintentan; si todos los modelos
fallan se lanza un RuntimeError claro y se sale con código 1. Mensajes de
usuario: 🧠 Tarea simple. Usando modelo local: … y
🧠 Tarea compleja detectada. Usando modelo cloud: ….config.json (sección model_routing):
prioridad_local, prioridad_nube, umbral_complejidad
(longitud_consulta, tamano_archivo, num_archivos) y
fallback_automatico.--model-fallback / --no-model-fallback (activado
por defecto; configurable con fallback_automatico),
--complejidad-umbral N (por defecto 100),
--model-prioridad-local prov/model … y
--model-prioridad-nube prov/model … (sobrescriben config.json)._configuracion_routing_efectiva()
(config.json + overrides CLI), _extraer_consulta_mensajes(),
_es_error_autenticacion(), _configurar_model_fallback() y
_configurar_hibrido_cli().tests/test_model_router.py ampliado a 88 casos: detección de
complejidad (consulta larga, archivos grandes reales, nº de archivos,
comandos, umbrales configurables), cadena de prioridad local/nube,
selección con fallback, integración de la cadena en _enviar_al_proveedor
(fallo de API → reintento; auth → aborta; todos fallan → error claro),
mensajes de usuario, flags CLI y configuración efectiva.enrutar_tarea() informa también compleja (bool) y usa la selección
híbrida cuando hay prioridades configuradas; sin ellas el resultado es el
de v6.24.0.prioridad_local/prioridad_nube (o con
--no-model-fallback) el comportamiento es idéntico al de v6.24.0; los
flags --model/--provider explícitos siguen teniendo prioridad máxima
(sin enrutado ni fallback). La detección de complejidad no hace llamadas
a la IA (solo heurísticas y lectura local de archivos).6.30.0 en snapcontext.py y pyproject.toml; aserciones de
versión de los tests de coherencia actualizadas a 6.30.0.autocorrector.py: sistema de autocuracion que integra
sandbox persistente, bucle de pruebas y correccion automatica.
ejecutar_bucle_correccion(): ejecuta pruebas, analiza errores con LLM
y aplica correcciones hasta exito o max_iteraciones.analizar_error(): extrae archivo, linea, tipo y sugerencia del error.aplicar_correccion(): aplica cambios usando el editor propio.Autocorrector: interfaz de alto nivel.--autocorregir/--no-autocorregir, --max-ciclos N.tests/test_autocorrector.py con 14 casos.session_manager.py: gestion de sesiones persistentes que
mantiene agentes vivos entre conexiones.
Session: historial, estado, plan, archivos modificados.SessionManager: crear, obtener, eliminar, persistir, cargar sesiones.~/.snapcontext/sesiones.db).--new-session, --attach <id>, --session-timeout N,
--list-sessions.tests/test_session_manager.py con 20 casos.tui_interactiva.py: extiende la TUI con dos nuevas pestanas:
esquema_pasos_a_texto, texto_a_esquema_pasos,
grafo_a_texto, validar_paso.--tui-plan-editor/--no-tui-plan-editor,
--tui-grafo/--no-tui-grafo.tests/test_tui_interactiva.py con 19 casos.memory_store.py: memoria a largo plazo que guarda decisiones
pasadas en SQLite (historial_decisiones) y las reutiliza para enriquecer
el contexto del agente.
guardar_decision(): almacena tarea, archivos, razonamiento, resultado.buscar_decisiones(): busca por similitud de palabras clave.obtener_contexto_memoria(): devuelve resumen textual de decisiones previas.listar_decisiones() / limpiar_historial(): gestion del historial.--memoria/--no-memoria, --memoria-limite N,
--memoria-ver.historial_decisiones con indices para busqueda rapida.tests/test_memory_store.py con 19 casos.qa_tester: revisor adversarial y destructivo de código
que se integra en el flujo del Supervisor después del Programador.
qa_tester_logic.py: módulo con revisar_codigo(), generar_pruebas(),
aplicar_correcciones() y clase QA_Tester.sub_agent_prompts.py con estrategias de revisión
(seguridad, rendimiento, lógica, estilo).SubAgentRegistry y ROLES.--qa-tester/--no-qa-tester, --qa-iteraciones N,
--qa-severidad {baja,media,alta}.tests/test_qa_tester.py con 23 casos.model_router.py: orquestación inteligente de modelos que
clasifica cada tarea por complejidad/tipo y asigna el modelo más adecuado.
clasificar_tarea(consulta, contexto): heurísticas rápidas (sin llamadas a
la IA) que devuelven una categoría entre indexacion, busqueda_semantica,
planificacion_simple, edicion_critica, razonamiento_complejo, chat_general.seleccionar_modelo(categoria, config): elige (proveedor, modelo) según la
sección model_routing de config.json. Sin configuración → (None, None)
(usa el modelo por defecto actual, compatibilidad total).enrutar_tarea(consulta, contexto, config): combina ambas y devuelve un dict
con provider, model, categoria, enrutado.--model-routing / --no-model-routing: activado por defecto, permite
desactivar el enrutamiento y usar el modelo único configurado._enviar_al_proveedor: consulta al router antes de enviar
peticiones cuando el enrutamiento está activo. Flags explícitos --model /
--provider tienen prioridad absoluta.🧠 Modelo enrutado: {categoria} → {provider}/{model}.tests/test_model_router.py con 22 casos (clasificación, selección,
default, integración con snapcontext)._detectar_modo_operacion(consulta, args): detecta automáticamente la
complejidad de la tarea y selecciona el modo (chat, plan, react,
react_paralelo) a partir de la consulta. Respeta los flags explícitos
(--plan, --react, --auto): si el usuario los usó, no se sobrescriben._configurar_comportamiento_por_defecto(args): aplica valores por
defecto inteligentes — --local automático si no hay API key,
--mostrar-razonamiento activado por defecto, --auto cuando el modo es
plan, --paralelo 3 cuando el modo es react_paralelo._mostrar_plan_resumido(plan): resumen del plan en 3-5 líneas
(📋 Plan: ...) antes de ejecutar, en lugar de la lista completa.SNAPCONTEXT_MODO_DEFAULT (inteligente | manual,
por defecto inteligente). Con manual, el comportamiento es idéntico al
anterior: se requieren flags explícitos.🧠 Modo inteligente activado (detectado: {modo}).tests/test_modo_inteligente.py (detección de modo, defaults,
compatibilidad con flags, variable de entorno).6.23.0 en snapcontext.py y pyproject.toml.marketplace.py: capa de ecosistema sobre el sistema de plugins (v4.0.0):
obtener_index() (índice remoto en GitHub con caché local de 1 h y
degradación a caché caducada si no hay red), buscar_plugins() (por nombre,
descripción, autor o tags), resolver_plugin(),
instalar_plugin() (resuelve nombres contra el índice y delega en el
instalador local), instalar_dependencias() (pip install --user; si falla,
deshabilita el plugin por seguridad), listar_plugins(),
habilitar_plugin()/deshabilitar_plugin(), actualizar_plugin() y
cargar_plugins_instalados() (idempotente, solo habilitados).snapcontext plugin search <termino> (nuevo) y
plugin uninstall (alias de remove); plugin install <nombre> ahora
resuelve nombres simples contra el marketplace.📦 Descargando índice de plugins...,
✅ Plugin {nombre} instalado correctamente., ❌ Error instalando....SNAPCONTEXT_MARKETPLACE_INDEX.tests/test_marketplace.py (36 casos).parallel_executor.py: nuevo módulo con ParallelExecutor
(ThreadPoolExecutor, grafo de dependencias, límite de workers) y
resolver_workers (--paralelo 0 → nº de núcleos de CPU, mínimo 2).🚀 Ejecutando N tareas en paralelo (máx. W)...,
✅ Tarea {nombre} completada y ❌ Tarea {nombre} falló.Supervisor.ejecutar_tareas_paralelo(tareas) (multi_agent.py): delega en
ParallelExecutor según max_parallel; degrada con error claro si el módulo
no está disponible.--paralelo N (por defecto 1 = secuencial; 0 = núcleos de CPU) ya
integrado con _ejecutar_plan_en_paralelo para pasos sin dependencias.tests/test_parallel_executor.py (29 casos: paralelismo real,
dependencias, workers, excepciones, mensajes, Supervisor, CLI y plan).--paralelo 0 se interpretaba como 1 en el planificador (or 1 masticaba
el cero); ahora se resuelve al nº de núcleos vía resolver_workers._generar_mensaje_commit(diff, tarea): genera mensajes de commit en formato
Conventional Commits con el proveedor de IA configurado; degrada a
paso: {descripcion} si no hay proveedor disponible._commit_paso(paso, args): commit atómico tras cada paso exitoso del plan
(o acción ReAct que modifica archivos). Inicializa el repo con git init si
hace falta, no commitea si no hay cambios (idempotente) y registra el hash en
la BD. Muestra 📝 Commit automático: {mensaje} ({hash})._revertir_paso(step_id) / snapcontext revert <step>: deshace un paso
concreto con git revert --no-commit + commit revert: paso N; sin argumento,
revierte el último paso commiteado. Ante conflictos sugiere git mergetool.
Muestra ↩️ Revertido paso N: {mensaje}.pasos en SQLite (migración idempotente _db_migrar_pasos):
id, tarea_id, tipo, descripcion, commit_hash, creado + índice por tarea_id.--git-commit / --no-git-commit (activado por defecto),
--git-revert [STEP] y --git-mensaje TEXTO. Comando gateway revert <step>.editar_archivo/aplicar_parche exitosas, el hash
del commit se añade al historial de la sesión ([COMMIT] <hash>) cuando el
agente se instancia con git_commit=True._sanear_mensaje_commit): claves
tipo sk-..., tokens largos y asignaciones api_key/secret/password=... se
sustituyen por [REDACTADO].tests/test_git_profundo.py con 26 casos (sanear mensajes, generación
con IA mockeada, commit/revert reales en repos temporales, BD aislada, flags,
integración ReAct, migración idempotente)._commit_paso (antes _git_commit_paso), que
registra el hash en la BD; un fallo de git avisa pero no bloquea el plan.snapcontext.py, pyproject.toml, TUI, plugins
VS Code/JetBrains y tests de versión.sub_agent_prompts.py (módulo nuevo): prompts de sistema canónicos de
los sub-agentes por defecto (scout, debugger, reviewer, documentador).
sub_agent.py los importa como fuente única.sub_agent.SubAgentRegistry (v6.18.0): registro consultable y extensible
de sub-agentes (registrar / obtener / listar) con un registro por
defecto (scout, debugger, reviewer, documentador). Admite roles nuevos:
SubAgente acepta un config propio, por lo que se pueden definir roles sin
modificar el código (plugins / --sub-agente-nuevo).reviewer en sub_agent.ROLES: revisor de PRs/diffs con herramientas
de lectura y ejecución de pruebas (mínimo privilegio).Supervisor.invocar_sub_agente(nombre, consulta) (multi_agent.py):
instancia y ejecuta un sub-agente registrado con contexto aislado y publica
su resultado en el Buzon.invocar_sub_agente(nombre, consulta) (react_agent.py):
el agente ReAct puede delegar una tarea especializada en un sub-agente. Está
disponible por defecto (sub_agents=True) y los sub-agentes la filtran de su
propio conjunto (no se pueden anidar).snapcontext.py): flags --sub-agente-nuevo <nombre> <descripcion>
(registra un sub-agente como plugin) y --sub-agente-listar (lista los
registrados y sale).🧠 Creando sub-agente: {nombre}... al instanciar y
✅ Sub-agente {nombre} completado: {resultado} al finalizar.tests/test_sub_agent.py ampliado (52 casos) con registro,
prompts, invocación desde Supervisor y desde ReAct, flags nuevos y versión.pyproject.toml: sub_agent y sub_agent_prompts añadidos a py-modules
para que se empaqueten en el .whl.VERSION actualizada a 6.18.0 en snapcontext.py, pyproject.toml,
tui_app.py, plugins VS Code y JetBrains.reviewer, el registro, la invocación ReAct y los flags nuevos.v6.18.0.--sub-agents el pipeline multi-agente y el ReAct son
idénticos a los anteriores; los sub-agentes son totalmente opcionales.--tui) basada en Textual (textual>=0.50.0,
grupo opcional [tui]). Ofrece pestañas de Logs (tiempo real con colores
por nivel), Control (estado del agente, pasos, tiempo total y botones
Pausar / Reanudar / Cancelar) y Diffs (+ verde / − rojo), más un árbol
de archivos colapsable del proyecto (DirectoryTree).tui_hub (put_nowait); si la TUI
está inactiva o la cola está llena se descartan, coste ~0 para el CLI normal.🖥️ Interfaz TUI inmersiva (Textual) — Ctrl+C
para salir.Ctrl+Q salir · Ctrl+L limpiar logs · Ctrl+D limpiar
diffs · Ctrl+T mostrar/ocultar el árbol.VERSION actualizada a 6.17.0 en snapcontext.py, pyproject.toml,
tui_app.py, plugins VS Code (package.json, extension.ts) y JetBrains
(build.gradle.kts, gradle.properties).v6.17.0.--tui) sigue funcionando exactamente igual: la TUI
es un modo adicional y Textual es una dependencia opcional.--tui muestra un error
claro y devuelve código 2 sin abrir ninguna interfaz.--depurar): al enviar peticiones a
proveedores compatibles (Anthropic, DeepSeek), se muestra una estimación de
tokens cacheados por categoría (sistema, herramientas, CLAUDE.md /
SNAPCONTEXT.md) y el total no cacheado. Ejemplo:
ℹ Prompt Caching activado (anthropic): sistema (145 tokens), herramientas (230 tokens), CLAUDE.md (890 tokens)._contar_tokens(): heurística ligera (1 token ≈ 4 caracteres)
para estimar tokens sin dependencias externas._calcular_metricas_caching(): categoriza mensajes cacheables y
suma tokens estimados. Prioridad: sistema > memoria > herramientas (evita
duplicar el recuento cuando un mensaje del sistema también define herramientas).--prompt-caching (acción store_true, activado por defecto) y
--no-prompt-caching (acción store_false) para controlar el comportamiento
desde la CLI.tests/test_prompt_caching.py (14 casos): detección de
proveedores, aplicación de cache_control, resolución de estado
(flag/entorno/config), integración en _enviar_al_proveedor, mensajes de
sesión, resumen automático preservando marcas, métricas y no duplicación._enviar_al_proveedor(): corregida indentación del bloque de Prompt Caching
para mantener la coherencia del flujo.VERSION actualizada a 6.16.0 en snapcontext.py y pyproject.toml.--depurar.v6.16.0.snapcontext-ai de VS Code)SyntaxError: invalid syntax al enviar una consulta. Los
procesos se lanzaban con shell: true en Windows, por lo que cmd.exe
interpretaba caracteres especiales de la consulta (paréntesis, &,
comillas) y el comando llegaba roto a Python. Ahora se usa shell: false
con el array de argumentos intacto (Node hace el escaping correcto), tanto
para python -m snapcontext ... como para el script -c del servidor
del chat.snapcontext.pythonPath en lugar de
path.basename(...), para que funcione con rutas que contienen espacios.snapcontext-ai de VS Code)snapcontext con vista webview
snapcontext.chat (“Chat”) e icono propio media/snapcontext-icon.svg
(24x24, mono para theming claro/oscuro de VS Code).arrancarServidorChat,
ahora lazy y con error claro si no responde en 10 s) sin duplicar procesos.lsp_client.py (módulo nuevo): integración con Language Server Protocol.
LSPClient: cliente JSON-RPC puro sobre stdio (sin dependencias
obligatorias), con iniciar, enviar_peticion (con timeout),
obtener_definicion, obtener_referencias, obtener_tipo, cerrar y
soporte de contexto (with).CacheLSP: caché en memoria + persistente (~/.snapcontext/lsp_cache.db,
SQLite) con clave (archivo, linea, columna, tipo_consulta) e
invalidación por hash del contenido del archivo..py, .ts/.js, .go, .rs,
.java, .cs) y de servidores instalados vía shutil.which
(pyright-langserver, typescript-language-server, gopls,
rust-analyzer, jdtls, OmniSharp).obtener_cliente_lsp): el servidor solo se lanza en
la primera consulta, nunca al inicio de la sesión.lsp_definicion, lsp_referencias y
lsp_tipo, disponibles en el agente ReAct y en los sub-agentes dinámicos
cuando --lsp está activo.--lsp y variable de entorno SNAPCONTEXT_LSP=1.[lsp] en pyproject.toml
(python-lsp-server, pygls).tests/test_lsp_client.py.react_agent.py: nuevo parámetro lsp y herramientas LSP registradas
condicionalmente (sin --lsp devuelven un error claro que sugiere el flag).sub_agent.py / multi_agent.py: propagación de lsp a los sub-agentes.shutil.which antes de lanzarlos.sub_agent.py (módulo nuevo): sub-agentes ReAct dinámicos.
SubAgente: encapsula un ReactAgent con historial propio
(contexto aislado), prompt de sistema del rol y herramientas
restringidas (mínimo privilegio).enviar_mensaje() / recibir_mensajes(): buzón individual para
comunicación con el Supervisor y otros agentes.ROLES con 5 roles predefinidos: scout, debugger,
frontender, tester y documentador (cada uno con su prompt,
sus herramientas y su límite de iteraciones).ejecutar_sub_agentes_paralelo(): hilos con semáforo y límite de
concurrencia; los errores por hilo no abortan al resto y los
resultados llegan en orden.encolar_sub_agente,
ejecutar_tarea_sub_agente, tipo sub_agente).multi_agent.py: el Supervisor ahora puede crear sub-agentes.
Supervisor.crear_sub_agente(rol): instancia y registra sub-agentes.Supervisor._detectar_sub_tareas(plan): heurística por palabras clave
sobre el plan del Arquitecto (documentación → scout, errores →
debugger, pruebas → tester, CSS/UI → frontender, docs → documentador).Supervisor.ejecutar_sub_tareas(plan): detecta y ejecuta en paralelo
las sub-tareas delegables y publica los resultados en el Buzon
(resultado_sub_agente, sub_tarea_completada).sub_agents y max_parallel (fase opcional entre
el plan y el bucle Programador→Tester).snapcontext.py): flags --sub-agents (activa la delegación)
y --max-parallel N (concurrencia, por defecto 3).Sub-agente '{rol}' instanciado. /
Sub-agente '{rol}' completó su tarea. /
Ejecutando N sub-agentes en paralelo....tests/test_sub_agent.py con 29 casos (roles, aislamiento,
comunicación, paralelismo con límite, buzón, cola de tareas, Supervisor
y flags CLI).snapcontext.py y pyproject.toml; tests de
coherencia de versión actualizados.--tui (snapcontext.py): lanza la TUI inmersiva basada en Textual.
El agente ejecuta el flujo habitual (ReAct por defecto) en un hilo demonio
mientras la TUI muestra logs, pasos, diffs y estado en tiempo real. Sin
Textual instalado muestra un error claro y devuelve código 2.tui_app.py: aplicación SnapContextTUI con pestañas (Logs con
RichLog coloreado por nivel, Control con estado/pasos/tiempo y botones
Pausar/Reanudar/Cancelar, Diffs con visor coloreado), árbol de archivos
(DirectoryTree) y atajos Ctrl+Q/Ctrl+L/Ctrl+D/Ctrl+T.tui_hub.py: cola de eventos no bloqueante entre el agente y la TUI
(enviar_log, enviar_paso_react, enviar_estado, enviar_diff,
enviar_fin). Sin Textual como dependencia: testeable de forma aislada.tui_hub (misma interfaz
que web.interactive) sin bloquear al agente.info/exito/aviso/error reenvían los logs a la TUI
(coste ~0 cuando está inactiva); _mostrar_diff_parche envía los diffs
generados por el editor propio a la pestaña Diffs.tui = ["textual>=0.50.0"].6.12.0 en snapcontext.py y pyproject.toml._enviar_al_proveedor (snapcontext.py): mantiene en caché
el mensaje del sistema, las herramientas MCP y la memoria del proyecto
(CLAUDE.md) añadiendo la marca cache_control: {"type": "ephemeral"} para los
proveedores compatibles (Anthropic y DeepSeek). Reduce drásticamente
coste y latencia en sesiones largas.soporta_caching en PROVEEDORES
(True para anthropic y deepseek). Gemini, Groq y Ollama se envían tal cual
(compatibilidad total garantizada)._soporta_prompt_caching(proveedor): ¿el proveedor soporta cache_control?_resolver_prompt_caching(explicito): resuelve el estado (flag > entorno >
config.json > defecto True)._aplicar_cache_control(mensajes): añade las marcas sin mutar los mensajes._mensaje_caching_inicio(proveedor): mensaje de sesión.prompt_caching: bool = True en ~/.snapcontext/config.json.--prompt-caching / --no-prompt-caching.SNAPCONTEXT_PROMPT_CACHING=0|1 para desactivar/activar._comprimir_historial preserva las
marcas cache_control en el resumen si el proveedor soporta caching.🧠 Prompt Caching activado para <proveedor> (o
no soportado) al inicio del chat y del modo ReAct.tests/test_prompt_caching.py (más de 15 casos).6.11.0 en snapcontext.py, pyproject.toml, README.md
y las 22 aserciones de versión de los tests de coherencia.cache_control no modifican el contenido de los mensajes: solo
añaden la instrucción de caché. Ningún dato se almacena en local.mcp_tools_browser.py: herramientas MCP de navegador con Playwright que permiten al agente ReAct ver y depurar interfaces visuales:
browser_abrir(url, wait_for?, timeout?): abre una URL (espera opcional a un selector CSS).browser_screenshot(url?, full_page?, selector?): captura de pantalla en base64 PNG (página completa o un elemento concreto).browser_click(selector) / browser_type(selector, texto): interacción con la página (clic y escritura en campos).browser_get_text(selector): extrae el texto de un elemento.browser_analizar_imagen(imagen_base64, pregunta): análisis visual con modelos de visión (Gemini 2.5 Pro, Claude 3.7 Sonnet+). Si el modelo no soporta visión devuelve un error claro.browser_cerrar(): cierra el navegador y libera recursos.--browser: activa el modo navegador (inicialización perezosa de Playwright). Sin el flag, el agente no puede usar herramientas de navegador. Flag adicional --browser-headed para ejecutar con interfaz visible (por defecto headless por seguridad).browser_abrir, browser_screenshot, browser_click, browser_type, browser_get_text y browser_analizar_imagen (documentadas en el prompt del sistema).[browser] en pyproject.toml (playwright>=1.40.0), con instrucciones automáticas (playwright install chromium) si falta.tests/test_mcp_tools_browser.py (15 casos, Playwright mockeado).--browser no se importa nunca.--benchmark: mide y muestra el tiempo de cada fase (inicio, CLI, escaneo, selección con embeddings, plan, edición fuzzy, detección de pruebas y total) en una tabla con rich. No necesita API key.~/.snapcontext/embeddings.db con tabla embeddings(archivo, hash, embedding BLOB). Si el hash del contenido no cambia, el embedding se reutiliza (≈80% más rápido en re-escaneos). Si falla la escritura, se degrada silenciosamente.~/.snapcontext/graph_cache.pkl con fingerprint por archivo; en la segunda sesión solo se reparsean los archivos modificados (≈70% más rápido).REACT_MAX_HISTORIAL: variable de entorno para el límite de iteraciones del historial ReAct (por defecto 20). Al superarlo se genera un resumen LLM automático con prompt específico (≈30% menos memoria en sesiones largas).tests/test_rendimiento.py con 15 casos cubriendo las cachés, el fuzzy matching, el worker sin polling, el límite de historial y --benchmark.sentence-transformers, tree-sitter, graph_rag, multi_agent, …) convertidos a lazy imports; --help pasa de ~1.2s a <0.3s.MAX_CONTEXTO_DIFUSO_LINEAS = 20 y resincronización de bloques vía difflib.get_close_matches (≈50% más rápido en archivos grandes).threading.Event (_WORKER_DESPERTAR) en lugar de time.sleep; se despierta al instante con event.set() desde encolar_tarea (CPU idle ≈0%).6.9.0.github_gateway.py: integración bidireccional con GitHub:
validar_firma: verificación criptográfica de firmas HMAC SHA-256 (X-Hub-Signature-256) y SHA-1 (X-Hub-Signature) contra peticiones falsificadas.parsear_evento: extracción normalizada de metadatos para eventos pull_request, issues, push, issue_comment.procesar_evento: encolado automático de tareas asíncronas (pr_review, plan, tests) a partir de eventos de webhook.obtener_pr_diff y comentar_pr: integración con la API REST de GitHub para inspeccionar diffs y comentar resoluciones de PRs e issues.configurar_webhook: registro automatizado de webhooks en repositorios remotos.snapcontext github setup|estado|webhook-registrar.task_queue.py: sistema de cola SQLite persistente para tareas en segundo plano:
tareas (id, tipo, estado, datos, resultado, chat_id, canal, creado, actualizado).encolar_tarea, consumir_tarea, actualizar_estado_tarea, obtener_tarea, listar_tareas, cancelar_tarea.iniciar_worker / _daemon_tick) para consumir y ejecutar tareas pesadas sin bloquear el CLI.✅ Tarea {id} completada, ❌ Tarea {id} falló)./pr <numero>: encola la revisión del Pull Request./tests [rama]: encola la ejecución de pruebas en segundo plano./status: consulta el estado de las tareas en cola./cancel <id>: cancela una tarea pendiente.enviar_notificacion(chat_id, mensaje, canal)./webhook/github y /api/github/webhook en la interfaz web FastAPI.--github-webhook-secreto, --github-token, --webhook-url.tests/test_github_gateway.py (15 casos).tests/test_task_queue.py (15 casos).tests/test_omnicanalidad_avanzada.py (10 casos).mcp_tools_db.py: herramientas MCP nativas de solo lectura para bases de datos:
db_connect: conexión perezosa a SQLite (nativo), PostgreSQL (psycopg2) y MySQL (pymysql).db_query: ejecución de consultas de solo lectura (SELECT, SHOW, DESCRIBE, EXPLAIN, PRAGMA) con validación estricta y confirmación interactiva (¿Ejecutar consulta: ...? (s/n)). En modo --auto no solicita confirmación manteniendo el bloqueo de consultas de escritura (INSERT, UPDATE, DELETE, etc.).db_schema: inspección completa del esquema de base de datos (tablas, columnas, tipos, primary keys).db_disconnect: cierre y limpieza de conexión de sesión.mcp_tools_api.py: herramientas MCP para inspección y consumo seguro de APIs externas:
api_request: peticiones HTTP (GET, POST, HEAD, OPTIONS, etc.) usando httpx, con soporte para parseo JSON automático, límite de tamaño de respuesta y filtrado de cabeceras sensibles (Authorization, Cookie, X-Api-Key, etc.).api_inspect: análisis de rendimiento y metadatos de endpoints (código de estado HTTP, tiempo de respuesta, tamaño de payload, headers del servidor).db_query, db_schema, api_request y api_inspect como acciones nativas en ReactAgent y en el dispatcher MCP de snapcontext.py.--db-url <url>: URL de conexión de base de datos (sqlite:///..., postgresql://..., mysql://...).--db-driver <driver>: especificación o forzado de driver (sqlite, postgresql, mysql).[db] en pyproject.toml (psycopg2-binary, pymysql).tests/test_mcp_tools_db.py (22 casos).tests/test_mcp_tools_api.py (12 casos).tests/test_mcp_expansion.py (5 casos).skill_abstraction.py: el Curador ya no guarda pasos fijos
(frágiles ante renombrados y cambios de estructura), sino reglas
abstractas extraídas de planes exitosos: patron, accion,
archivos_afectados y dependencias.
extraer_regla(plan, contexto): usa el LLM y, si falla, una heurística de
respaldo (archivos más editados, confianza 0.6).aplicar_regla(regla, tarea): devuelve pasos sugeridos si la tarea
coincide con el patrón (similitud ≥ 0.45), o None.guardar_regla: persiste en la nueva tabla reglas (SQLite) y refuerza
reglas similares (similitud ≥ 0.85) en vez de duplicarlas (+0.05 confianza,
+1 uso).inyectar_en_claudemd / inyectar_todas_las_reglas: añade reglas con
confianza > 0.8 a la sección ## Reglas aprendidas de CLAUDE.md/
SNAPCONTEXT.md, de forma idempotente y sanitizada (sin ```
ni caracteres de control)._enriquecer_prompt_con_reglas):
antes de generar un plan, se inyectan en el prompt las reglas cuyo patrón
coincide con la tarea, priorizadas por confianza (máx. 3, encabezado
REGLAS APRENDIDAS).snap-skills-dinamicos), sin
bloquear al usuario. Mensajes: 🧠 Extrayendo regla abstracta...,
📝 Nueva regla aprendida: ..., 📄 Regla inyectada en CLAUDE.md.reglas (patrón, acción,
archivos/dependencias JSON, confianza, usos, fecha).--skills-dinamicos (activado por defecto) /
--sin-skills-dinamicos, y --inyectar-reglas (fuerza la inyección de
todas las reglas en CLAUDE.md y termina).--sin-skills-dinamicos el comportamiento es idéntico al de v6.5.0. La
extracción es asíncrona y solo se ejecuta tras planes exitosos.tests/test_skill_abstraction.py: 25 casos (extracción LLM/heurística,
aplicación de reglas, inyección idempotente, migración de BD, curador,
enriquecimiento del planificador y flags CLI).--web-interactive, junto a --web):
http://localhost:8000/interactive):
cada paso (🟡 Pensamiento → 🔵 Acción → 🟢 Observación / 🔴 Error) se
muestra como tarjeta coloreada con marca de tiempo relativa (“hace Xs”) y
detalles expandibles.sobrescribir tras confirmación explícita).web/interactive.py: hub thread-safe y no bloqueante
entre el agente y la web (cola de eventos con put_nowait; esperas por
threading.Event para los diffs), con validación y recorte de contenidos
(máx. 400k caracteres). Si el modo está inactivo, todo es un no-op.web/static/interactive.html y
web/static/interactive.js.GET /interactive,
GET /interactive/health, WS /ws/interactive y montaje de /static.ReactAgent(web_interactive=...): emite react_step / agent_status en
cada fase del bucle sin ralentizarlo.--web-interactive, la web actual (--web) funciona exactamente igual;
el flag es opt-in y los endpoints nuevos no se registran.tests/test_web_interactive.py: 31 casos (hub, timeline, conflictos de
diff, endpoints y flags, integración con ReAct y con el editor propio).sandbox_session.py: ciclo de vida completo de una sesión
Docker persistente (crear_sesion, obtener_sesion, ejecutar_en_sesion,
destruir_sesion, limpiar_huérfanos). El contenedor se lanza con
docker run -d --name snap-session-<id> -v "<proyecto>:/workspace"
-w /workspace <imagen> tail -f /dev/null, de modo que el sistema de
archivos y las dependencias instaladas persisten entre comandos
(npm install → npm test, pip install -r requirements.txt → pytest).--sandbox-session: mantiene un único contenedor vivo
durante toda la tarea (plan de varios pasos o bucle ReAct) en lugar de un
docker run --rm por comando. La sesión se crea de forma perezosa en el
primer comando, se reutiliza para todos los demás (con docker exec) y se
destruye al finalizar (éxito, aborto o error), incluido en Ctrl+C/SIGTERM.--sandbox-session-clean: busca y elimina contenedores
snap-session-* huérfanos de sesiones anteriores (con confirmación en modo
interactivo, automáticamente en --auto) y sale.~/.snapcontext/session_id.txt, lo que permite
recuperar sesiones entre invocaciones._ejecutar_comando, el planificador (_ejecutar_plan,
_ejecutar_paso_plan) y el agente ReAct (ReactAgent(sesion_docker=...)).Ctrl+C, evitando contenedores huérfanos.--sandbox-session, el comportamiento es idéntico al de la versión
anterior (docker run --rm por comando). El contenedor de sesión monta
solo el directorio del proyecto en /workspace, igual que el sandbox.tests/test_sandbox_session.py: 26 casos (creación, reutilización,
destrucción, huérfanos, integración en plan/ReAct, compatibilidad, Ctrl+C)._aplicar_hunks_incremental(): la
búsqueda exacta (con strip()) ya no es el único método. Ahora, cuando un
hunk no encaja en la posición declarada, se prueban, en orden y solo cuando
la anterior falla:
#///), tolerando reindentaciones y comentarios añadidos/eliminados.difflib.SequenceMatcher (ratio medio de las
líneas de contexto ≥ UMBRAL_DIFUSO_HUNKS = 0.85, y ≥
UMBRAL_DIFUSO_LINEA = 0.90 por línea), tolerando variables renombradas.UMBRAL_DIFUSO_BLOQUE = 0.80) y se reemplaza conservando las líneas de
contexto locales del usuario.UMBRAL_DIFUSO_HUNKS (0.85),
UMBRAL_DIFUSO_LINEA (0.90) y UMBRAL_DIFUSO_BLOQUE (0.80).--mostrar-diff: muestra el diff propuesto (coloreado con
rich.syntax.Syntax, lenguaje diff) ANTES de aplicar un parche y pregunta si
aplicarlo ([a]), cancelarlo ([c]) o editarlo manualmente ([e]). En modo
--auto muestra el diff sin bloquear. Sin el flag, el parche se aplica sin
preguntar (comportamiento histórico).snapcontext.py:_variantes_linea(),
_lineas_equivalentes(), _quitar_comentario(), _ratio_bloque(),
_contar_cambios_parche() y _mostrar_diff_parche(); y en ui.py
mostrar_diff() y preguntar_interactivo().--editor aider
o edición manual). Con --mostrar-diff se visualiza el diff antes de fallar.tests/test_editor_parches.py (17 casos): fuzzy matching con espacios
cambiados, comentarios añadidos, variables renombradas, hunk de añadido puro,
desplazamiento acumulativo, resincronización de bloques, fallo controlado,
umbrales expuestos, --mostrar-diff (aplicar/cancelar/editar/fallo) y modo sin
preguntar.pyproject.toml y VERSION → 6.3.0.agentes.py y orquestador.py: el flag mostrar_diff se propaga desde la CLI
a ejecutar() → estrategia de parche → _aplicar_con_conflicto().difflib.SequenceMatcher solo se usa cuando el hunk falla en las
etapas exactas/variantes (el caso normal no paga el coste).--mostrar-razonamiento y variable de entorno
SNAPCONTEXT_MOSTRAR_RAZONAMIENTO=1 (valores 1/true/yes) para mostrar
el razonamiento del modelo antes de cada acción o respuesta.ui.mostrar_razonamiento(): panel con el razonamiento (borde verde, texto
gris, truncado a 500 caracteres con aviso [ver más])._extraer_razonamiento() en snapcontext.py: detecta los campos
reasoning, thinking, chain_of_thought, reasoning_content,
thoughts (top-level o anidados tipo OpenAI/Ollama) y bloques
<think>…</think> en texto plano.--chat), planificador (_generar_plan y paso
consultar), editor propio (AST/parche/sobrescribir) y ReAct (razonamiento
completo por turno en lugar del pensamiento resumido).<think>…</think> se eliminan siempre del texto útil antes de
parsear JSON o parches (evita fallos con DeepSeek-R1 y similares).pyproject.toml y VERSION → 6.2.0.context_utils.py: manejo de contexto inteligente para no
desbordar la ventana de tokens del modelo (crítico en modelos locales como
deepseek-r1:14b, con 4096 tokens).
estimar_tokens(texto, modelo): usa tiktoken si está disponible; si no,
la regla práctica 1 token ≈ 4 caracteres.estimar_tokens_de_archivo(ruta): estimación leyendo el archivo de disco.extraer_bloques_relevantes(contenido, lenguaje, objetivo): extrae
funciones/clases con tree-sitter (vía parser_universal) o con regex
básico como respaldo; devuelve (resumen_ast, bloques) y coloca primero
el bloque objetivo si se indica.seleccionar_contexto(contenido, lenguaje, objetivo, max_tokens=3000):
si el archivo cabe en el presupuesto se devuelve completo; si no, se
compone resumen AST + bloque objetivo + bloques relevantes hasta llenar
max_tokens.objetivo_en_mensaje(...): detecta la función/clase mencionada en la
tarea para priorizar el bloque correcto.es_error_contexto(exc): detección unificada de errores de límite de
contexto (Anthropic exceed_context_size_error, OpenAI/Ollama/DeepSeek
context length, Gemini context window, …).agentes.py): _aplicar_modo_parche
y _aplicar_modo_sobrescribir estiman los tokens del archivo antes de llamar
al proveedor; si supera --max-context-tokens envían solo el bloque
relevante + resumen (el parche devuelto se reinserta en el archivo original).
Si el proveedor falla por límite de contexto se reintenta con el archivo
completo (el modelo real puede tener más contexto del estimado) y, si
vuelve a fallar, se pasa a la siguiente estrategia
(AST → Parche → Sobrescritura).snapcontext.py): _editor_ast acepta max_context_tokens,
reduce el contenido enviado con seleccionar_contexto y descarta la
operación completo cuando el contexto está truncado (las operaciones
renombrar/insertar_import se aplican sobre el archivo completo, nunca
sobre el fragmento).--editor-fallback, si el editor propio no puede
editar un archivo se invoca Aider automáticamente (si está instalado) para
ese archivo, o se muestra una sugerencia clara al usuario.snapcontext.py): el contenido de CLAUDE.md incluido en
_generar_plan se limita por tokens con seleccionar_contexto (antes:
recorte bruto a 3000 caracteres); _ejecutar_paso_plan propaga
--max-context-tokens y --editor-fallback al editor propio, igual que el
orquestador en el flujo clásico.--max-context-tokens N (3000): límite máximo de tokens a enviar al modelo
en una sola petición.--editor-fallback: cuando el editor propio falla por contexto, invoca
Aider automáticamente (si está instalado) para ese archivo.tests/test_context_utils.py (24 tests): estimación de tokens (con y sin
tiktoken), extracción de bloques (tree-sitter, ast y fallback regex),
selección de contexto (archivo pequeño devuelve todo, grande devuelve
fragmento dentro del presupuesto, objetivo priorizado), objetivo_en_mensaje,
constantes compartidas entre módulos, flags CLI, _editor_ast con
max_context_tokens e integración del editor propio con proveedor mockeado
(contexto selectivo y reintento tras error de contexto).VERSION en snapcontext.py y pyproject.toml → 6.1.0. Se actualizaron
las 21 aserciones de versión de los tests de coherencia (20 ficheros).context_utils añadido a py-modules (pyproject.toml) y a MANIFEST.in.multi_agent.py: sistema multi-agente con roles
especializados, activado con --multi-agent o SNAPCONTEXT_MULTI_AGENT=1.
Supervisor (Supervisor): coordina el flujo, descompone la tarea y
combina los resultados de los agentes con bucle de realimentación.Arquitecto (Arquitecto): usa el LLM para generar un plan en JSON
(objetivo, módulos, archivos a tocar y pasos). Si el LLM no devuelve JSON
válido, degrada a un plan mínimo con la tarea (nunca rompe el flujo).Programador (Programador): implementa el código con el editor propio
(cadena AST → Parche → Sobrescritura) siguiendo el plan del Arquitecto.Tester (Tester): ejecuta las pruebas con la detección automática de
v5.3.0 (detector_tests) y devuelve éxito/fallo + salida.Buzon (Buzon): buzón de mensajes thread-safe para la comunicación
entre agentes (publicar/recibir/vaciar/historial).max_reintentos, por defecto 3).
Si no hay pruebas detectadas en el proyecto, se da por completado.snapcontext.py): flag --multi-agent, variable
SNAPCONTEXT_MULTI_AGENT=1 y función _ejecutar_multi_agent enrutada desde
_ejecutar_modo_tarea. El modo es opcional: --plan, ReAct y el flujo
clásico siguen intactos. En modo interactivo el Supervisor pide confirmación
del plan; con --auto la omite.🧠 Arquitecto, 💻 Programador,
🧪 Tester, 🤖 Supervisor).snapcontext.py):
extraída a _advertencia_directorio_proyecto(args); en --auto ahora
continúa sin preguntar (muestra el aviso y sigue).tests/test_multi_agent.py (33 tests): activación por flag/env, Buzon,
Arquitecto, Programador, Tester, Supervisor (flujo completo, realimentación,
sin pruebas, abortos, --auto, cancelación interactiva), integración CLI y
enrutamiento, versionado/packaging.tests/test_proyecto_verificacion.py (22 tests): detección de raíz de
proyecto y advertencia temprana (continuar/demo/salir, --auto,
--no-validar-proyecto).python -m unittest discover tests → 855 OK.VERSION en snapcontext.py y pyproject.toml → 6.0.0. Se actualizaron
las 19 aserciones de versión de los tests de coherencia.multi_agent añadido a py-modules (pyproject.toml) y a MANIFEST.in.parser_universal.py: editor AST multi-lenguaje basado en
tree-sitter (language pack), con fallback elegante cuando la librería no
está instalada o el archivo es inválido.
detectar_lenguaje_por_extension(archivo): .py, .js, .ts/.tsx,
.jsx, .go, .rs, .java, .kt, .rb, .php, .c/.h,
.cpp/.hpp, .cs, .swift, .dart, etc.parsear_archivo(contenido, lenguaje): AST tree-sitter o None.extraer_nodos(archivo, tipo_nodo): funciones, clases, métodos e imports
(nombres de gramática comunes: function_definition,
function_declaration, class_definition, class_declaration, …).aplicar_parche_arbol(contenido, nodo_viejo, nodo_nuevo): reemplazo
seguro por bytes exactos del nodo.agentes.py, snapcontext.py):
_resumen_ast y _extraer_bloques_ast aceptan ahora archivos no-Python
vía parser_universal (Python sigue usando ast de la stdlib)._extraer_contexto_selectivo y _puede_ast soportan todos los
lenguajes del pack; sin tree-sitter caen a parche/sobrescritura como
siempre.pyproject.toml, extras opcionales): tree-sitter,
tree-sitter-languages y tree-sitter-language-pack.graph_rag.py (Grafo de Conocimiento): combina AST y la
búsqueda semántica para que el agente entienda la arquitectura del proyecto.
_extraer_nodos_y_aristas(directorio): nodos = archivos/funciones/clases;
aristas = imports, llamadas y herencia (resolución de módulos dotted,
relativos y paquetes).construir_grafo(directorio, forzar=False): cache en
~/.snapcontext/graph_cache.pkl con fingerprint (mtime_ns + tamaño de cada
.py); solo se reconstruye cuando cambia el código. Cache corrupto o
ilegible → reconstrucción silenciosa.expandir_contexto(archivos, grafo, max_adicionales=3): añade dependencias
entrantes (quienes importan) y salientes (lo que importa), priorizadas por
número de conexiones. Nunca lanza excepciones.--graph-rag y variable de entorno SNAPCONTEXT_GRAPH_RAG=1
(prioridad: flag > entorno). Completamente opcional: sin él, comportamiento
idéntico a 5.4.0.react_agent.py): nuevo parámetro graph_rag=False
en ReactAgent.__init__; las herramientas buscar_codigo y leer_archivo
expanden el contexto con archivos relacionados del grafo.orquestador.py): con --graph-rag, los
candidatos del pre-filtro semántico se amplían con el grafo antes de la
selección del LLM (best-effort: nunca rompe el pipeline clásico).🔗 Grafo de conocimiento: expandiendo contexto con
{n} archivo(s) relacionado(s).tests/test_graph_rag.py: construcción del grafo
(imports/llamadas/herencia, sintaxis inválida, directorios ignorados),
expansión de contexto, cache (hit, invalidación, corrupto, forzar), flag
CLI/env y integración con ReAct y el planificador (mockeando).sandbox_utils.py): regex compiladas
para rm -rf /, dd/mkfs/fdisk, curl|wget ... | sh/bash,
chmod 777/chown -R, fork bomb, sudo + destructivo, escritura en
dispositivos de bloque (> /dev/sda) y kill -9/pkill. Registro
extensible (_PATRONES_PELIGROSOS) y sin dependencias externas.🔒 Comando potencialmente peligroso detectado...); los seguros corren
directamente (cero fricción).--no-sandbox: desactiva todo el sandbox (prioridad máxima,
incluso ante --sandbox y comandos peligrosos).SNAPCONTEXT_SANDBOX: 1 fuerza el sandbox
siempre; 0 lo desactiva por completo._ejecutar_comando (planificador, ReAct, plugins, MCP),
_bucle_test y procesos en segundo plano.--auto.tests/test_sandbox_inteligente.py (26 casos).--sandbox explícito sigue funcionando exactamente igual (todo al
contenedor).5.4.0 (los 18 tests de coherencia de versión
actualizados).detector_tests.py (sin dependencias externas): escanea la
raíz del proyecto, detecta el lenguaje/framework (detectar_lenguaje) y
devuelve el comando de test exacto (detectar_comando_test), la estructura
de tests (detectar_estructura_tests) y un dict completo
(detectar_automaticamente). Extensible: basta añadir una entrada al
registro _LENGUAJES y su archivo identificador.ejecutar_pruebas): el comando se resuelve
por prioridad (argumento explícito → SNAPCONTEXT_COMANDO_TEST → detección
automática → pytest de archivo → por defecto). Si nada funciona, devuelve un
error claro pidiendo que se especifique el comando manualmente.--test-loop: si el usuario no pasa --comando-test, se
detecta el lenguaje del proyecto automáticamente. El comando explícito
siempre tiene prioridad (compatibilidad hacia atrás).--comando-test ahora es opcional (antes por defecto "flutter test"): se
detecta automáticamente y se mantiene flutter test como último recurso.ui.py, react_agent.py y curador_proactivo.py
ahora están incluidos en py-modules de [tool.setuptools] (pyproject.toml)
y en MANIFEST.in, por lo que viajan en el .whl/.tar.gz.ModuleNotFoundError: No module named 'ui' al instalar
SnapContext desde PyPI.5.2.1 (build local verificado: ui.py aparece en el .whl).--plan. El flujo snapcontext "tarea" instancia
ReactAgent (react_agent.py) en lugar del planificador estático.--react se mantiene por compatibilidad aunque sea redundante;
--react-max-iter N sigue afinando el tope de iteraciones.--plan), preservado
100 % para scripts/integraciones existentes (Telegram /plan, Discord /plan,
extensiones VS Code/JetBrains, web, etc.). --plan activa el planificador
clásico sin cambios en su comportamiento.--auto funciona idénticamente en ambos modos (sin preguntas interactivas).tests/test_react_510.py verifica que sin flags se ejecuta ReAct
(_ejecutar_modo_tarea → _ejecutar_react); y que --plan sigue mapeando
al planificador estático. Los 18 tests de coherencia de versión se ajusturaron
a 5.2.0.curador_proactivo.py (FEATURES)UMBRAL_TOKENS, con ≥ 3 usos), pide al LLM un
prompt más eficiente/clara/robusto, lo prueba en el sandbox de v4.3.0 y,
solo si pasa las pruebas Y reduce tokens, guarda la nueva versión.historial_skills (trazabilidad completa) y se incrementa version.historial_skills._db_migrar_curador() añade idempotentemente a skills las columnas:
exitos, tokens_promedio, tiempo_promedio_ms, ultimo_uso, version
y activo; crea la tabla historial_skills
(skill_id, version, prompt, motivo, fecha)._skill_registrar_exito()/_fallo()
actualizan exitos/fallos, medias ponderadas de tokens/tiempo y ultimo_uso
(integrado en el pipeline de skills sin alterar la lógica del editor).daemon_proactivo) que ejecuta una pasada completa cada
CURADOR_INTERVALO_HORAS horas (defecto 6; configurable por entorno).
Espera fraccionada de 30 s, espera ANTES de la primera pasada (arranque
instantáneo), respeta el interruptor persistente del curador y nunca muere.main() (sin bloquear el CLI); se desactiva con
CURADOR_DAEMON=0 y se omite bajo test runners.snapcontext curador estado → estadísticas (usos, fallos, tokens,
candidatos, mejoras totales, peor skill).snapcontext curador ejecutar → pasada manual del motor.snapcontext curador desactivar / activar → interruptor persistente.TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID) o Discord
(DISCORD_WEBHOOK_URL). Best-effort: sin credenciales es silencioso.tests/test_curador_500.py (≥ 10 casos): migración idempotente,
registro de métricas, evaluación de candidatos, refactorización exitosa/fallida
(LLM error, prompt inválido, sandbox falla, sin mejora de tokens), guardado con
historial, notificaciones, comandos CLI y daemon.SNAPCONTEXT_REPO. Esto permite que los forks y los
usuarios personalicen la URL sin modificar el código fuente.https://github.com/NicolasBruna24/snapcontext), así que el banner se ve
exactamente igual que antes (compatibilidad hacia atrás).ui.py (ui.REPO_URL, usado por mostrar_banner() tanto en
modo Rich como en el fallback plano sin Rich).tests/test_ui_480.py: el banner muestra REPO_URL,
el fallback sin Rich también lo usa, y SNAPCONTEXT_REPO sobreescribe el
valor por defecto (con importlib.reload y mock.patch.dict).ui.py (FEATURES)ui.py que centraliza toda la presentación de terminal
sobre Rich (nueva dependencia
rich>=13.0.0): banner, progreso, tablas, diffs y prompts.mostrar_banner(): logotipo ASCII + versión + tabla de comandos
principales (reemplaza los print(_LOGO) planos en --version y en el
arranque sin argumentos).mostrar_progreso(): barra de progreso con ETA para bucles largos;
integrada en el escaneo del repositorio (escanear_repositorio).mostrar_tabla_impacto(): tabla 📁 Archivo Afectado · 🔗 Dependencia ·
📊 Acción Sugerida para el análisis de impacto (v4.7.0), filas críticas en
amarillo; integrada en AgenteEditorPropio.preguntar_interactivo(): reemplaza el input() de continuar/abortar/
añadir usando rich.prompt.Prompt. Contrato intacto: devuelve la tecla
'c', 'a' o 's'; fallback a input() plano sin Rich.mostrar_diff() (Syntax lenguaje diff: verde +/rojo −) y
mostrar_error() (panel rojo). Ambos visibles también en modo auto.ui.configurar_auto(True/False): sincronizado con --auto en main().
Con auto: sin barras de progreso, preguntas devuelven 'c' por defecto
sin preguntar; errores y diffs se muestran siempre.rich instalado todo sigue funcionando con
print() plano (nunca rompe el CLI).tests/test_ui_480.py: verifica llamadas a Console.print,
silencio de progreso en auto, 'c' por defecto en auto, menú de impacto y
fallback plano sin Rich.rich>=13.0.0 declarado en pyproject.toml (dependencies) y en
requirements.txt.4.7.0 a
4.8.0 para reflejar el bump de versión. Suite completa: 628 tests OK.AgenteEditorPropio.ejecutar():
antes de editar, usa el grafo de dependencias (_grafo_dependencias) para
detectar qué archivos importan de los que se van a modificar.⚠️ Atención: El cambio en 'X' afecta a los
siguientes archivos: [...] y pregunta: continuar / abortar / añadir los
dependientes a la edición (para actualizarlos también y no romper nada).--auto no pregunta: solo registra la advertencia y continúa.MAX_CONTEXT_LINES = 600: los archivos con más líneas ya
NO se inyectan completos en el prompt del proveedor._extraer_contexto_selectivo(): reutiliza _resumen_ast_python para
el resumen de alto nivel (imports/clases/funciones) e incluye únicamente los
bloques relevantes (función/clase mencionada en la tarea; si no hay coincidencia,
los primeros bloques por proximidad) con ±5 líneas de contexto, más una
[RESTRICCIÓN] que obliga al modelo a generar el diff solo del bloque.sobrescribir sobre archivos grandes: el modelo devuelve el bloque entre
marcadores <<<ANTES>>>/<<<DESPUES>>>/<<<FIN>>> y se reinserta en el archivo
original con la nueva _splicear_bloque() (alineación difusa, ratio ≥ 0.80)._construir_prompt_edicion() (agentes.py) usado por
los modos parche y sobrescribir; sin cambios en firmas públicas.tests/test_editor_470.py: advertencia de dependientes (main.py →
utils.py), menú interactivo (añadir/abortar), modo auto sin input(),
contexto selectivo en archivo de 1200 líneas (contiene resumen AST, no el
archivo completo), splicing de bloque y flujo completo de sobrescritura
truncada.AgenteEditorPropio.ejecutar() toma un
snapshot de todos los archivos antes de editar; si cualquier archivo falla o
se lanza una excepción, se restauran TODOS los archivos a su estado original
(nuevo método _rollback). Ya no quedan ediciones parciales a medias.~/.snapcontext/backups/, la edición se ABORTA (antes solo avisaba y
escribía igualmente). Nunca se escribe sin backup._aplicar_hunks_incremental() ya no
escribe archivos con hunks parcialmente aplicados; si algún hunk no puede
aplicarse, la operación se aborta dejando el archivo intacto.difflib.SequenceMatcher
con umbral global 0.85 (y 0.90 por línea): tolera comentarios añadidos,
cambios menores de espacios y pequeñas variaciones del código circundante.
Antes solo había igualdad exacta tras strip(), y un comentario nuevo rompía
el hunk.tests/test_editor_460.py: rollback multiarchivo, fuzzy matching con
comentario intercalado y aborto cuando el directorio de backups no permite
escritura.discord_gateway.py: recibe Slash Commands de Discord
(interacciones), los procesa con el motor interno de SnapContext y responde
en el mismo canal. Sin discord.py: solo httpx + cryptography.~/.snapcontext/config.json
clave "discord"): DISCORD_PUBLIC_KEY, DISCORD_APPLICATION_ID,
DISCORD_BOT_TOKEN y DISCORD_WEBHOOK_URL (opcional).verify_signature): Ed25519 con headers
X-Signature-Ed25519/X-Signature-Timestamp; firma inválida o mal formada
lanza ValueError (protección contra peticiones falsificadas).send_discord_message): follow-up vía
/webhooks/{app_id}/{interaction_token} cuando hay token de interacción, o
webhook estándar del canal; contenido > 2000 caracteres se envía como
archivo .txt; errores de red tolerados.handle_discord_interaction): PING de Discord → {"type": 1};
comandos → respuesta diferida {"type": 5} y ejecución del agente con
asyncio.create_task (límite de respuesta <3 s). Comandos: /start,
/help, /snap, /fix (→ --test-loop) y /plan (→ --plan).POST /webhook/discord en web/app.py: verifica la
firma (401 si es inválida), devuelve 503 sin DISCORD_PUBLIC_KEY, y
responde el PONG/diferido inmediato mientras el pipeline corre en segundo plano.tests/test_discord_450.py (17 tests): configuración, verificación
de firma Ed25519 (vector RFC 8032, inválida/malformada/sin clave), handler
(PONG, diferido, bienvenida, mapeo de comandos), envío (webhook, follow-up,
archivo por longitud, error de red) y endpoint webhook (503/401/PING firmado).4.5.0 (metadatos y badges).telegram_gateway.py: recibe mensajes de Telegram, los
procesa con el motor interno de SnapContext y responde al mismo chat.~/.snapcontext/config.json
clave "telegram"): TELEGRAM_BOT_TOKEN y TELEGRAM_WEBHOOK_URL.send_telegram_message): httpx.AsyncClient; mensajes
4096 caracteres se envían como documento
.txt; errores de red tolerados.
handle_telegram_update): /start con bienvenida; comandos
/fix y /plan mapeados a --test-loop/--plan; el pipeline corre con
asyncio.create_task para no bloquear al webhook (timeout de Telegram ~30 s).run_agent_async(query): usa la API interna del núcleo
(flujo_principal / _ejecutar_planificador) en un executor, capturando su
salida — no lanza el CLI por subprocess.POST /webhook/telegram en web/app.py. Devuelve
200 OK inmediato; 503 Service Unavailable sin TELEGRAM_BOT_TOKEN.snapcontext telegram setup --token <TOKEN> --webhook-url <URL>
(persiste en config.json y registra el webhook con setWebhook), más
telegram estado y telegram webhook-registrar.httpx>=0.27.0 en pyproject.toml.tests/test_telegram_440.py (16 tests): resolución de configuración,
mapeo de comandos, envío (ok/largo/error/sin token), handler (/start,
updates inválidos, tarea en segundo plano) y endpoint webhook (200/503).--sandbox (booleano, por defecto False): todos los comandos
que ejecuta SnapContext (bucle de pruebas, MCP execute_command, pasos
"ejecutar" del planificador, plugins y herramientas de usuario) se lanzan
dentro de un contenedor Docker aislado._docker_disponible() verifica docker --version
(binario en el PATH) y docker info (daemon en ejecución). Nunca lanza
excepciones.--sandbox-imagen <imagen>: imagen Docker personalizada.SNAPCONTEXT_SANDBOX_IMAGE: imagen por defecto vía variable de entorno
(prioridad: flag > entorno > python:3.11-slim).--sandbox-comando <cmd>: comando de preparación antes del principal
(ej.: apt update && apt install -y make), anteponiéndolo con &&./workspace
(-v "<proyecto>:/workspace" -w /workspace) con --rm (contenedor efímero).*_API_KEY, OLLAMA_URL,
SNAPCONTEXT_SANDBOX_IMAGE) se pasan al contenedor automáticamente (-e)._ejecutar_comando() y _lanzar_proceso_fondo() envuelven el comando con
_envolver_sandbox() cuando el sandbox está activo; log:
ℹ [sandbox] Ejecutando en contenedor: ....--test-loop + --sandbox): las pruebas corren dentro
del contenedor vía _ejecutar_pruebas_argv(); se omite la comprobación del
binario en el PATH del host; los resultados se procesan igual que siempre.execute_command (foreground y background) usa el sandbox; las
herramientas de solo lectura (grep, read_file, list_files, ast,
git_status, git_diff, …) siguen en el host para mayor velocidad
(context manager interno _sandbox_pausado).--plan --sandbox, los pasos ejecutar y mcp con
comandos corren en el contenedor; editar y consultar no cambian.--sandbox explícito y Docker no disponible → error claro
(RuntimeError con instrucciones) y código de salida 1.--sandbox, SnapContext se comporta exactamente igual que en 4.2.0;
CLI, web, extensiones, API y resto de funcionalidades sin cambios.tests/test_sandbox_430.py (20 tests): detección de Docker simulada,
activación estricta/no estricta, resolución de imagen (flag/env),
envoltura docker run, ejecución en sandbox (_ejecutar_comando,
execute_command, paso ejecutar del plan, bucle de pruebas,
AgenteTester) y herramientas de solo lectura fuera del sandbox.os.system(...) y subprocess con shell=True.../ construidas dinámicamente.innerHTML = y dangerouslySetInnerHTML.range(len(...)) · concatenación de cadenas con
+= en bucles · consultas N+1 del ORM (.objects.get( en bucle) · lectura
completa de archivos grandes en memoria. Tag ⚡ Rendimiento.--asesor-profundo: ejecuta el análisis completo (heurísticas
básicas + seguridad + rendimiento). Sin él, --asesor se comporta como en
v3.5.0."seguridad" y "rendimiento"
(en --auto solo informan, sin interacción)./seguridad y /rendimiento.analizar_seguridad() y
analizar_rendimiento().--editor ahora vale propio por defecto; --editor aider sigue
disponible y documentado para quien prefiera Aider (no se elimina nada).ℹ Editor propio: usando estrategia AST...).AgenteEditorPropio.ejecutar(), no en el orquestador).--editor aider), más registro local opcional del fallo en
~/.snapcontext/logs/editor_fallos.log.--modelo-ligero para forzarlos con cualquier proveedor.[a]plicar de todas formas · [v]er diff · [r]eintentar con IA · [c]ancelar.--auto no se pregunta: se pasa automáticamente a la siguiente
estrategia. Funciona igual desde la CLI que desde --chat.--editor aider no cambia de comportamiento; CLI, web, extensiones y API
pública siguen funcionando igual.~/.snapcontext/plugins/<nombre>/ con un plugin.json:
nombre, version, autor, descripcion, permisos
(archivos|red|red_escrita|ejecucion|entorno), habilitado y
herramientas (lista con nombre, descripcion, script Python o
comando shell, requiere_permiso y parametros).snapcontext plugin <accion>):
| Acción | Descripción |
|—|—|
| list | Lista plugins instalados y sus herramientas. |
| install <nombre\|usuario/repo\|url\|ruta> | Instala desde carpeta local o GitHub (ZIP codeload). |
| remove <nombre> | Desinstala (con confirmación). |
| create [nombre] | Genera la estructura básica (manifest + script ejemplo). |
| update <nombre> | Reinstala desde el origen registrado. |
| enable / disable <nombre> | Habilita/deshabilita individualmente. |/plugin lista los plugins; /plugin <plugin>.<herramienta>
'{"arg": ...}' ejecuta una herramienta directamente.plugins (listar), plugin_install y plugin_remove;
emiten el evento {"tipo": "plugins", "plugins": [...]} para el panel.plugin install <nombre> resuelve contra
https://github.com/NicolasBruna24/snapcontext-plugins (ver README para
publicar plugins propios).snapcontext --api (alias --api-server),
sobre FastAPI/uvicorn reutilizando la infraestructura de web/app.py.
--api-puerto (8001 por defecto, la web sigue en 8000),
--api-host (127.0.0.1) y --api-token./docs (Swagger) y /redoc./api/v1/...):
| Endpoint | Método | Descripción |
|—|—|—|
| /health | GET | Estado del servidor (público). |
| /query | POST | Ejecuta una consulta → 202 Accepted + task_id. |
| /plan | POST | Ejecuta un plan → 202 Accepted + task_id. |
| /chat | POST | Mensaje al proveedor de IA (síncrono, con historial). |
| /skills | GET | Lista las skills aprendidas (?archivados=true). |
| /daemon | POST | Gestiona el daemon: estado / iniciar / detener. |
| /tasks/{task_id} | GET | Estado de una tarea asíncrona. |X-API-Key (o query param api_key)
obligatorio en todos los endpoints salvo /health, /docs y /redoc.
snapcontext --api-generate-key: genera una clave segura (32 bytes,
url-safe), la guarda en ~/.snapcontext/config.json ("api_key") y la
muestra. Al arrancar sin clave configurada se genera automáticamente.query y plan devuelven 202 con task_id
(threading en segundo plano); el estado se consulta en
/tasks/{task_id} (pendiente → ejecutando → completada/fallida/error).pip install snapcontext[web]. CLI, web y extensiones no cambian.except: desnudo (prioridad alta), == None,
.has_key() — disponibles para todos los lenguajes.ast; JS/TS, Dart, Go, Rust y Java mediante
heurísticas regex. Sin validador disponible el análisis se omite sin error.--asesor (alias --sugerir): analiza y muestra; nunca modifica código.--asesor-auto: aplica automáticamente las mejoras seguras (renombrar
símbolos); cada cambio se valida con _validar_sintaxis antes de
guardarse y se descarta si rompe la sintaxis.--asesor-umbral N: sensibilidad del detector de funciones largas.~/.snapcontext/config.json
bajo la clave "asesor" (p. ej. {"asesor": {"funcion_larga": 30}}).{"accion":
"asesor"}; cada sugerencia se presenta al usuario para aceptarla o
rechazarla individualmente (en --auto solo se informan)./asesor (alias /sugerir) en snapcontext --chat.asesor que emite el evento {"tipo": "asesor",
"sugerencias": [...]} para el panel de resultados de la interfaz.AgenteAsesor en agentes.py, integrado en el
Orquestador (orch.agente_asesor)._validar_sintaxis(archivo, contenido, directorio) que escribe
el contenido en un archivo temporal y ejecuta el validador del lenguaje
detectado por _lenguaje_archivo:
Python (python -m py_compile), JavaScript/TypeScript (node --check),
Dart (dart analyze → dart format), Go (go build -n → gofmt -e),
Rust (rustc --parse-only), Java (javac -Xlint:none) y C/C++ (gcc /
clang -fsyntax-only). Si no hay validador o comando disponible, se omite
la validación (aviso en logs de depuración)._validar_sintaxis captura stdout/stderr y maneja subprocess y timeouts,
devolviendo (exito: bool, mensaje_error: str). Nunca toca el archivo original.AgenteEditorPropio.ejecutar(): tras generar el nuevo
contenido, antes de _editor_sobrescribir() / _aplicar_parche_con_resolucion().
Si la validación falla, se envía el error al proveedor para que corrija, hasta
MAX_INTENTOS_VALIDACION (por defecto 3) o hasta que pase. Si se agotan los
intentos se cancela la edición (nada se guarda)._aplicar_parche_preview) antes de aplicar el parche real.--validar (por defecto activado) y --no-validar-sintaxis para desactivar la
validación (comportamiento previo). Nota: no se usa --no-validar porque ese
alias ya está reservado por --iniciar-proyecto.--max-intentos-validacion N para ajustar los reintentos.--help y en las categorías de ayuda.ℹ Validando sintaxis de archivo.py..., ✔ Sintaxis válida.,
✖ Error de sintaxis: ... Reintentando (1/3)... y
✖ No se pudo validar tras 3 intentos. Edición cancelada.tests/test_validacion_sintaxis_340.py (15 tests): _validar_sintaxis
con mocks de subprocess para Python/JS/Dart/Java (incluido fallback de Dart,
timeout y comando no disponible), flags de CLI, flujo de reintentos en
_aplicar_modo_sobrescribir (fallo→éxito y agotamiento de intentos) y
_aplicar_parche_preview._detectar_lenguaje_contenido,
_lenguaje_archivo) para scripts sin extensión y proyectos mixtos._resumen_ast ahora detecta Python también por contenido (shebang/def)._validar_parche_previo): comprueba que el
archivo coincide con el contenido usado para generar el parche antes de
aplicarlo (evita corrupción por cambios concurrentes)._aplicar_hunks_incremental): si git apply
y patch fallan, aplica el parche línea a línea en Python puro con
búsqueda por desfase y contexto difuso; los hunks irresolubles se omiten
con aviso (aplicación parcial informada)._aplicar_parche_con_resolucion orquesta validación → git apply → patch →
resolución incremental; ya no cae directamente a sobrescritura._editor_clasificar_tarea):
renombrar, añadir_import, refactorizar_clase, añadir_funcion,
corregir_error o general.editor-<patrón>
(_skill_editor_guardar) con la estrategia que funcionó._skill_editor_estrategia) acelerando ediciones repetidas sin IA.--editor propio) y la cadena de
modos auto mantiene la heurística AST → parche → sobrescritura.tests/test_editor_330.py (31 tests): clasificación de tareas,
detección de lenguaje, extracción de ruta del parche, validación previa,
parseo/aplicación incremental de hunks (incluido desfase), flujo de
resolución, skills del editor, integración en ejecutar() y prompts.vscode/extension.js → vscode/src/extension.ts con tipos completos
(vscode.ExtensionContext, vscode.Disposable, vscode.OutputChannel,
ChildProcessWithoutNullStreams, …) y modo strict activado.vscode/tsconfig.json (ES2020, commonjs, strict,
sourceMap, declaration, salida en out/, raíz src/).package.json: "main": "./out/extension.js" y scripts compile
(tsc -p ./), watch, package y vscode:prepublish que compila.typescript, @types/vscode, @types/node.scripts/empaquetar.ps1 / .sh: ejecutan npm install +
npm run compile antes de vsce package y verifican que exista
out/extension.js.tests/test_vscode_ts_320.py: opciones obligatorias del
tsconfig, entry point, scripts, devDependencies, registro de comandos,
webview y compilación real (tsc --noEmit) cuando hay compilador.tests/test_vscode_016.py actualizado a la nueva estructura.snapcontext sin consulta ni flags muestra ahora una ayuda resumida y
amigable (comandos comunes + ejemplos listos para copiar) con código 0,
en lugar del error de argparse por falta de consulta.~/.snapcontext/estado.json con la clave
primer_uso (_cargar_estado(), _guardar_estado(),
_primer_uso_pendiente()).--bienvenida) y se guarda primer_uso = False.--bienvenida explícito también actualiza el estado.tests/test_bienvenida_311.py (10 tests): ayuda sin
argumentos, helpers de estado, bienvenida automática (primera vez,
segunda vez y entrada no interactiva) y flag explícito.llama3.2:1b, llama3.2, phi3, gemma2:2b, qwen2.5:0.5b).snapcontext --init).hay_api_key_configurada(), _estado_ollama(),
_elegir_modelo_ligero() y _proveedor_offline()..db.corrupto) y ajusta el PATH en Windows via –setup-path.--bienvenida: tutorial interactivo de primeros pasos.--init ampliado: configurar Ollama (ofrece abrir ollama.com), crear un
proyecto de prueba y lanzar el tutorial interactivo.tests/test_diagnostico_310.py (19 tests) para los nuevos
comandos y el modo offline; versiones actualizadas en tests existentes.~/.snapcontext/memoria.db (stdlib sqlite3: cero dependencias
nuevas) con tablas skills, historial_aprendizaje, contexto_kv y cola._db_init(), _db_query(), _db_insert() y
_db_ejecutar() (RLock reentrante, WAL, filas como dict)._skill_buscar() encuentra el skill mas similar (embeddings o
Jaccard/contencion) y lo reutiliza en tareas repetidas._curador_ejecutar() archiva skills sin uso > 30 dias, fusiona similares
(sim >= 0.90, conserva el mas usado) y notifica skills en revision por la
CLI. Manual (--curador) o programado via daemon._daemon_tick / _daemon_bucle) que corre el
curador segun --daemon-intervalo (168 h = semanal) y procesa la cola de
skills pendientes (_cola_encolar()), descartando los archivados._aprender_de_tarea) y
del orquestador; desactivable con --sin-aprendizaje. Nunca rompe el
pipeline (errores de memoria solo avisan).AgenteAprendizaje en agentes.py; integrado en el Orquestador.tests/test_memoria_300.py (27 tests): capa DB, skills, busqueda,
aprendizaje, curador, daemon, agente de aprendizaje y flags CLI.install.ps1 y install.sh buscan Python en el PATH, con el lanzador py, y en rutas típicas de instalación. Si no lo encuentran, dan instrucciones claras para instalarlo.uv: detectan si la carpeta de uv está vacía o sin los archivos necesarios y la eliminan automáticamente antes de instalar, evitando el error Invalid environment ... directory is empty.uv, el instalador pregunta si se desea eliminar.pip: si la instalación con uv falla, el instalador intenta automáticamente con pip.%USERPROFILE%\.local\bin al PATH del usuario sin duplicados; en Linux/macOS, añade ~/.local/bin al perfil del shell."accion": "mcp": ejecuta cualquier herramienta MCP
del registro (campos herramienta y args) y guarda el resultado en el
contexto del plan.y, si el paso define
`variable`, tambien bajo ese nombre; los pasos siguientes sustituyen
marcadores en descripcion, comando, archivos,
contenido y args._generar_plan() / prompt actualizado para que el proveedor pueda
proponer pasos mcp con dependencias, condiciones y variables._evaluar_condicion() acepta comparaciones == / != sobre:
pasos[0].resultado == 'ok'.resultados.mi_variable != ''.variable_existe('nombre').archivo_existe, archivo_contiene,
comando_exito) siguen funcionando igual.background=True devuelve un pid consultable con
execute_command_status.capture_output=True (por defecto) decide entre capturar
stdout/stderr o mostrar la salida en tiempo real.--paralelo N, un paso cuya condicion referencia una variable que
otro paso pendiente puede producir se bloquea hasta que este
disponible (sin deadlocks: si nada es lanzable, se marca saltado).tests/test_plan_mcp_230.py (21 tests): contexto dinamico,
pasos MCP, condiciones dinamicas, marcadores ``,
execute_command background/capture y planificador paralelo con
dependencias dinamicas.--modo-edicion ast (además de sobrescribir, parche y auto):
ast: edita comprendiendo la estructura sintáctica del archivo y cae a
sobrescritura si no se puede aplicar._editor_ast):
ast; otros lenguajes con
tree-sitter si está instalado) y lo pasa al proveedor junto con la tarea._renombrar_identificador (por token, sin tocar cadenas)._insertar_import.{"tipo": "completo", "codigo": "..."} (extraer
función, mover código, añadir funciones, etc.)._resumen_ast usa tree-sitter (si está
instalado) para archivos no-Python y hace fallback a ast/parche/sobrescritura.autoauto, el agente elige estrategia según el lenguaje y la tarea:
ast → parche → sobrescribir.parche → sobrescribir.AgenteEditorAST en agentes.py e integrada en el Orquestador.AgenteEditorPropio ahora soporta el modo ast con fallback.--modo-edicion ampliado a {sobrescribir,parche,auto,ast}.tests/test_editor_ast_220.py (16 tests): resumen AST, renombrado,
interpretación de operaciones, _editor_ast (renombrar/completo/fallbacks),
clase AgenteEditorAST, cadenas de estrategias, heurística auto y flags._generar_parche(original, nuevo, ruta_archivo) con difflib.unified_diff()._aplicar_parche(parche, directorio) que intenta aplicar con git apply --whitespace=nowarn y fallback a patch -p1.--modo-edicion {sobrescribir,parche,auto} (por defecto auto):
auto: intenta primero aplicar parche unificado; si falla o no es diff, hace fallback a sobrescritura.parche: aplica exclusivamente parches unificados.sobrescribir: sobrescritura completa directa de archivos (Fase 1).AgenteEditorPropio y Orquestador:
--- a/ y +++ b/).tests/test_diff_editor_210.py (9 tests): generación de diffs unificados, aplicación con mocks de git apply / patch, ejecución de AgenteEditorPropio en modo parche y fallback a sobrescritura, y validación de flags.--editor {aider,propio}:
aider (por defecto): mantiene el flujo original con Aider sin romper nada.propio: usa el editor integrado de SnapContext para escribir/sobrescribir código directamente sin requerir herramientas externas._editor_sobrescribir() con validación de rutas y protección estricta contra path traversal (.. / /).~/.snapcontext/backups/<timestamp>_<nombre_archivo>.AgenteEditorPropio integrada en la arquitectura de agentes (agentes.py) y en el Orquestador (orquestador.py).--plan con --editor propio, los pasos de edición generan el código con el proveedor de IA configurado y lo aplican directamente.ThreadPoolExecutor:
_indexar_proyecto() ahora lee y hashea archivos concurrentemente acelerando proyectos medianos y grandes.node_modules, .git, build, etc.).2.0.0 en snapcontext.py, pyproject.toml, web/app.py, vscode/package.json y jetbrains/build.gradle.kts.Production/Stable.tests/test_editor_propio_200.py (9 tests): creación de archivos nuevos, backups automáticos en sobrescrituras, protección contra rutas fuera de repo, flags CLI y clase AgenteEditorPropio.jetbrains/, Kotlin + Gradle) con la misma
experiencia que la de VS Code:
Alt+Shift+S): pipeline
completo sobre el proyecto abierto.--plan --auto.--test-loop (Aider → pruebas → reparar).snapcontext --web y abre
http://localhost:8000 en el navegador cuando Uvicorn está listo./add; usa el mismo sufijo
«Revisa especialmente estos archivos: …» que la extensión VS Code).python -m snapcontext (o el
comando configurado) con ProcessBuilder, pasando --directorio <proyecto>,
--provider y --no-confirmar según los ajustes, e inyecta la clave API
opcional como variables de entorno. Sin dependencias nuevas en tiempo de
ejecución del plugin.tests/test_jetbrains_170.py (12 tests): estructura de ficheros,
validez de plugin.xml (tool window, configurable, acciones), coherencia
Gradle/Kotlin y paridad del mecanismo de contexto con VS Code.Ctrl+S) se pide
confirmación antes de sobrescribir el archivo en disco._comando_para_monaco)
se aplica también a los archivos abiertos desde el grafo y el historial.d3.zoom, escala 0.2–4×).flutter test) para lanzar la suite del proyecto.Ctrl+Enter ejecutar · Ctrl+S guardar ·
Ctrl+D dependencias · Ctrl+R/Ctrl+O modal de comandos · Esc cerrar.textarea; sin d3 → lista de
enlaces en texto; sin filtros aplicados → grafo completo.vscode/webview/index.html) sincronizada con la nueva interfaz.tests/test_web_160.py (12 tests): confirmación de guardado, toasts,
historial, atajos, zoom, filtros y resaltado del grafo, botón Tests y campo
lenguaje en los nodos del grafo (base del filtro).snapcontext.exe generado con PyInstaller
(snapcontext.spec): incluye el código y las dependencias ligeras
(google-generativeai, openai, questionary, fastapi, uvicorn y el
estático de la interfaz web). El usuario final no necesita Python.SnapContext-Setup-<versión>.exe (installer.nsi):
%LOCALAPPDATA%\Programs\SnapContext (por usuario, sin admin).~\.snapcontext con claves e historial).scripts/empaquetar_exe.ps1
(y empaquetar_exe.sh para CI/Linux) que ejecuta PyInstaller + NSIS de una
sola vez y verifica que el exe responde a --version.-Full (o SNAPCONTEXT_EXE_FULL=1) incluye los
extras pesados (sentence-transformers, tree-sitter); por defecto se
excluyen y SnapContext usa sus fallbacks (ast, aviso en búsqueda
semántica), manteniendo el instalador ligero.web/app.py resuelve su estático vía sys._MEIPASS cuando corre como exe
y vía __file__ en desarrollo: --web funciona igual en ambos modos.tests/test_exe_150.py: coherencia de artefactos (spec/NSIS/scripts)
y resolución del estático web en modo desarrollo/frozen.ast_avanzado: análisis sintáctico multi-lenguaje con tree-sitter
(funciones, clases, imports y llamadas en Python, JS/TS, Dart, Go, Rust,
Java, C/C++, Ruby, PHP…). Import diferido; sin tree-sitter hace
fallback al módulo ast de la stdlib (solo Python) y para otros
lenguajes devuelve un error descriptivo sin romper al agente.
Dependencia opcional: pip install snapcontext[mcp_avanzado].semantic_search: la búsqueda semántica por embeddings (v1.1.0) queda
integrada en el registro de herramientas MCP, de modo que el agente puede
usarla automáticamente como contexto. Falla elegantemente si no está el
extra embeddings.rg) preferente en grep: ya se detectaba con
shutil.which('rg'); ahora se documenta como alternativa ultrarrápida que
respeta .gitignore, con fallback a grep/findstr."dependencias": [índices].
Un paso solo se ejecuta si todas sus dependencias tuvieron éxito; si alguna
falló o se saltó, el paso queda marcado como saltado."condicion" con las funciones
archivo_existe('ruta'), archivo_contiene('ruta', 'texto') y
comando_exito('comando'). Si la condición es falsa, el paso se salta.--paralelo N (por defecto 1). En modo
--plan --auto, lanza hasta N pasos independientes simultáneos con logs
identificados [paso N]; los pasos dependientes esperan a sus rondas.--chat)/grafo: grafo de dependencias del proyecto en formato texto ASCII
(reutiliza _grafo_dependencias de v1.2.0)./dependencias <archivo>: imports directos y dependencias inversas
(«importado por») de un archivo./buscar <consulta>: alias de /search (búsqueda semántica).tests/test_mcp_140.py (24 tests): condiciones del planificador,
normalización de dependencias, nuevas herramientas MCP, planificador
paralelo con dependencias, flag --paralelo y comandos del chat.--iniciar-proyecto (alias --no-validar): desactiva por
completo la validación de carpeta de proyecto, para empezar un proyecto
desde cero en una carpeta vacía. Muestra el aviso
⚠️ Modo iniciar-proyecto: se omite la validación de carpeta...._es_proyecto_valido()): ahora
también valida si hay carpetas típicas (lib/, src/, supabase/,
app/, packages/, backend/) vacías, archivos de código en la raíz
(.py, .dart, .js, .ts, .go, .rs, .java, …) vacíos, o
archivos de configuración típicos (pubspec.yaml, package.json,
requirements.txt, go.mod, Cargo.toml, setup.py, pyproject.toml)
vacíos.--local y --directorio explícito ya no bloquean: si no se detecta
estructura de proyecto, solo se muestra un aviso y se continúa (antes se
abortaba).--iniciar-proyecto,
--local o --directorio <ruta>.--help documenta el nuevo flag y aclara que --local desactiva la
validación.install.ps1): detecta instalaciones previas vía
uv tool list / %USERPROFILE%\.local\bin\snapcontext.exe y las elimina
(evita que snapcontext --version muestre una versión antigua de uv);
persiste ~\.local\bin en el PATH del usuario.install.sh): misma limpieza de instalaciones
uv previas y añade ~/.local/bin al perfil del shell (.bashrc/.zshrc)
si falta.activationEvents explícitos por comando
(corrige problemas de activación) y títulos de comandos sin duplicar el
prefijo en la paleta.--iniciar-proyecto y --local.web/static/index.html
desde CDN, con resaltado de sintaxis para Python, JS/TS, Dart, Go, Rust,
Java, C/C++, C#, Swift, etc.archivo_seleccionado con contenido + lenguaje.guardar_archivo) que escribe en
disco; fallback a <textarea> si Monaco no carga.snapcontext: _comando_para_monaco() (mapa
extensión → lenguaje) y el protocolo de lectura/escritura en web/app.py._extraer_dependencias() extrae los imports por lenguaje (Python import,
JS/TS import/require, Dart, Go, Rust, Java/Kotlin)._grafo_dependencias() construye nodos + enlaces resolviendo los imports
contra los archivos del repositorio (_resolver_dependencia)._buscar_en_codigo() centraliza la exploración por rg/grep/findstr.accion_ejecutada.web/app.py amplía el protocolo WebSocket con leer_archivo,
guardar_archivo, dependencias, semantica, explorar y accion,
respondiendo archivo_seleccionado, archivo_guardado,
dependencias_actualizadas, semanticos, exploracion y accion_ejecutada.consulta/tarea preexistente.vscode/webview/ sigue
siendo copia de web/static/index.html.tests/test_web_120.py (mapa de lenguajes, extracción de imports,
grafo de dependencias, búsqueda en código, versionado).1.2.0 en todos los tests.pip install "snapcontext[embeddings]" activa un
indexador local basado en sentence-transformers (modelo all-MiniLM-L6-v2)
que genera embeddings para fragmentos de ~512 tokens de cada archivo de
código (.py, .js, .ts, .dart, .go, .rs, …)._buscar_semanticamente() que genera un
embedding de la consulta y calcula la similitud de coseno con todos los
fragmentos indexados, devolviendo los archivos más relevantes._seleccionar_archivos_con_embeddings()
filtra por un umbral de similitud (0.6 por defecto) y completa con resultados
locales si no alcanza max_archivos./search en --chat: ejecuta búsqueda semántica interactiva y
muestra los archivos con su puntuación de similitud.~/.snapcontext/index/ con un hash del proyecto; si detecta cambios,
reindexa automáticamente (con aviso). Los archivos sin cambios reutilizan sus
embeddings cacheados._planificar() (orquestador), antes de llamar al proveedor de IA:
carga (o indexa) el índice, ejecuta _seleccionar_archivos_con_embeddings()
y reordena los candidatos locales para priorizar los archivos más similares a
la consulta, reduciendo la carga sobre el proveedor y mejorando la precisión./search y API directa desde
Python.pip install "snapcontext[embeddings]" añadido a la sección de
instalación._patrones_gitignore) en
_guardar_indice() que hacía referencia a la variable no definida
patrones.SnapContext 1.0.0 consolida todas las funcionalidades desarrolladas desde la 0.4.0 en un lanzamiento estable y documentado.
--test-loop),
bucles con servidor (--server-loop/--manual-loop) y revisión experta.fix, review, server, interactive.--chat): REPL con herramientas MCP (/tool,
/tools), alias del pipeline, historial de sesión y /save.grep, read_file, list_files, ast, git_status,
git_diff, execute_command + herramientas de usuario en
~/.snapcontext/mcp_tools.json.--plan): descomposición en pasos JSON
(editar/ejecutar/consultar) con menú continuar/reintentar/saltar.--auto): ejecución sin confirmaciones paso a paso con
reintentos automáticos (3) respetando permisos guardados.--confirmar/--no-confirmar con preferencias persistentes
(permisos.json, opciones s/n/t/a).CLAUDE.md/SNAPCONTEXT.md cargado automáticamente;
generación con --init-claude (IA + fallback offline) y actualización
propuesta tras tareas exitosas.historial.json con --historial /
--historial-limpiar.--web), extensión VS Code
(vscode/, canal “SnapContext Output”, webview del chat).--demo), empaquetado PyPI y .vsix.Ninguna: 1.0.0 es retrocompatible con las configuraciones y archivos de versiones 0.x (config.json, permisos.json, historial.json, mcp_tools.json).
--auto)--auto para el planificador: ejecuta los pasos del plan sin
confirmación inicial ni menú paso a paso.permisos.json: un tipo marcado como
“nunca” se deniega automáticamente (nueva función _permiso_recordado()).
Con --no-confirmar no añade diferencia adicional (todo ya está permitido).vscode/ con la extensión nativa: package.json
(comandos, menús y configuración), extension.js, webview (copia de la
interfaz web + servidor_webview.py) y scripts de empaquetado.--plan --no-confirmar) y Configurar API key.CLAUDE.md (o SNAPCONTEXT.md) en la raíz del proyecto y lo usa como
contexto persistente del agente.snapcontext --init-claude: escanea el proyecto
(estructura vía MCP, tipo detectado, estado git) y genera la memoria con el
proveedor de IA; sin conexión cae a una plantilla básica offline./claude muestra la memoria; /context muestra memoria + archivos en
contexto; cada mensaje al proveedor incluye la memoria como contexto.grep, read_file, list_files, ast, git_status, git_diff,
execute_command) más herramientas de usuario definidas en
~/.snapcontext/mcp_tools.json (comandos shell)._ejecutar_herramienta_mcp() con confirmación integrada
(reutiliza _confirmar_accion; execute_command y herramientas de usuario
requieren permiso; las de lectura no)./tools lista las disponibles, /tool <nombre> [args|JSON] las
ejecuta mostrando el resultado coloreado y lo añade al contexto de la
conversación. Mensajes de exploración (“busca…”, “estado de git”…) activan
automáticamente herramientas de solo lectura como contexto del proveedor._generar_plan() explora el proyecto (git_status + list_files)
antes de pedir el plan para generar pasos más precisos.--confirmar / --no-confirmar)_confirmar_accion(descripcion, tipo, detalles): muestra un
resumen de la acción y pregunta ¿Permitir esta acción? (s/n/t/a):
s permitir una vez · n saltar · t permitir todas las del tipo ·
a no permitir ninguna del tipo.t/a se guardan en ~/.snapcontext/permisos.json
({"<tipo>": "siempre"|"nunca"}) y se respetan en sesiones futuras.--plan, los tres tipos de
acción), en /run y /edit del chat. /explore sigue sin pedir permiso
(solo lectura). Con --no-confirmar se omiten todas las preguntas
(modo automático).--plan)snapcontext --plan "tarea" pide al proveedor de IA un
plan en JSON (descripcion, accion: editar/ejecutar/consultar, archivos,
comando), muestra los pasos numerados y pide confirmación antes de actuar.editar reutiliza el orquestador (_planificar +
_bucle_test), ejecutar usa _ejecutar_comando, consultar pregunta al
proveedor. Menú por paso (continuar/reintentar/saltar/abortar) y resumen
final registrado en ~/.snapcontext/historial.json.--branch <nombre> crea la rama antes de empezar
y --git-commit/--no-git-commit controla commits automáticos
(paso: <descripción>) tras cada paso exitoso (por defecto: activado)."anthropic" en PROVEEDORES (tipo anthropic, clave
ANTHROPIC_API_KEY, modelo por defecto claude-3-5-sonnet-20241022).seleccionar_archivos_con_anthropic() que usa el SDK oficial
(client.messages.create()); import diferido con aviso claro si falta la
librería: pip install snapcontext[anthropic].seleccionar_archivos() redirige al nuevo tipo "anthropic"; también
soportado en --init (prueba de conexión) y en el menú interactivo.anthropic = ["anthropic>=0.30.0"] en pyproject.toml.--chat)snapcontext --chat abre un REPL (💬 SnapContext Chat) con comandos:
/salir, /archivos, /limpiar, /seleccion <consulta>,
/provider <proveedor>, /historial y /ayuda. Cualquier otro texto se
envía al proveedor actual manteniendo el historial de conversación de la
sesión (últimos 20 turnos por petición).historial.json)--historial (muestra las últimas 20 tareas) y
--historial-limpiar (borra el archivo)._cargar_historial() / _guardar_historial() persisten en
~/.snapcontext/historial.json; cada tarea ejecutada se registra
automáticamente (fecha, consulta, archivos, resultado y duración) en un
hilo secundario para no bloquear la salida._leer_archivo(ruta): lee rutas relativas/absolutas (devuelve None con
aviso si falla)._ejecutar_comando(comando, directorio): ejecuta comandos de shell con
timeout y devuelve (codigo_retorno, stdout, stderr). Base para el
planificador autónomo y disponible desde el chat.--demo)_ejecutar_demo() que muestra el valor de SnapContext en ~1
minuto, sin necesidad de API key ni Aider:
tempfile.mkdtemp()), con un saludar(nombre) con bug y un test que
falla.--vista-previa --local y la
muestra en tiempo real.main(): snapcontext --demo. No rompe ningún flag existente.pubspec.yaml, package.json,
requirements.txt/pyproject.toml, go.mod, Cargo.toml, etc.) que ajusta
automáticamente las carpetas y extensiones por defecto. Es transparente para
el usuario (solo se informa con --depurar). Si no se detecta ningún tipo,
se mantiene el comportamiento actual (lib/, supabase/, …).listar_archivos_candidatos, escanear_repositorio).snapcontext fix "…" → --test-loopsnapcontext review "…" → --vista-previa --expertosnapcontext server "…" → --server-loopsnapcontext interactive → --webInterfaz web en tiempo real: indicador de estado (spinner/barra de
progreso), cronómetro con el tiempo transcurrido, contador de archivos
escaneados y seleccionados, y renderizado con colores de los nuevos eventos
(inicio, escaneo_inicio/fin, seleccion_inicio/fin, test_inicio/fin).
_LOGO y un crear_parser duplicado.--init con proveedores Groq y DeepSeekquestionary.text(password=True) que no funciona.questionary.password() para ingresar claves API de forma segura.~/.snapcontext/config.json estaba corrupto o no existía, el programa fallaba silenciosamente.try/except explícito para FileNotFoundError y json.JSONDecodeError.pyproject.toml: version = "0.6.0"snapcontext.py: VERSION = "0.6.0"README.md y index.html: badges actualizadosraw.githubusercontent.com en README.md e index.html.pip.$PROFILE si el PATH no se actualiza automáticamente.~/.snapcontext/config.json con datos corruptos, se mostrará un aviso al iniciar SnapContext. Esto es normal; el programa continuará funcionando con un nuevo perfil vacío si lo deseas.lib/, src/, supabase/, app/, packages/, backend/) y avisa si no (sale con código 1).questionary con flechas y Enter): elige Gemini, Ollama, DeepSeek o Groq sin escribir --provider.~/.snapcontext/config.json y lo reutiliza en las siguientes ejecuciones.ollama list, muestra los modelos locales disponibles para elegir.--init): guía el alta de claves API, proveedor y modelo favorito, y una prueba opcional de conexión.| Versión | Fecha | Estado |
|---|---|---|
| 0.6.0 | 2026-08-20 | 🟢 Lista para publicar |
| 0.5.0 | TBA | 🔵 Publicado (primera versión) |
| 0.4.x | Beta | ⚪ No publicado |
Generado automáticamente por SnapContext. Cada cambio se documentará aquí antes del siguiente release.