stratum-cli 0.5.0 → 0.7.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.stratumrc.json.example +72 -7
- package/CHANGELOG.md +222 -0
- package/dist/index.js +8269 -3334
- package/package.json +2 -1
package/.stratumrc.json.example
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
"baseUrl": "http://localhost:11434/v1",
|
|
8
8
|
"model": "qwen3.5:9b",
|
|
9
9
|
"apiKey": "ollama",
|
|
10
|
-
"contextWindow": 32768
|
|
10
|
+
"contextWindow": 32768,
|
|
11
|
+
"timeouts": { "headersMs": 120000, "idleMs": 300000 }
|
|
11
12
|
},
|
|
12
13
|
"litellm-proxy": {
|
|
13
14
|
"type": "openai-compatible",
|
|
@@ -55,7 +56,21 @@
|
|
|
55
56
|
"tavilyApiKey": "${TAVILY_API_KEY}",
|
|
56
57
|
"maxResults": 10
|
|
57
58
|
},
|
|
58
|
-
"
|
|
59
|
+
"webFetch": {
|
|
60
|
+
"allowHosts": ["localhost:3000"]
|
|
61
|
+
},
|
|
62
|
+
"destructivePatterns": [
|
|
63
|
+
"rm",
|
|
64
|
+
"rmdir",
|
|
65
|
+
"dd",
|
|
66
|
+
"mkfs",
|
|
67
|
+
"format",
|
|
68
|
+
"DROP",
|
|
69
|
+
"DELETE",
|
|
70
|
+
"truncate",
|
|
71
|
+
"shred",
|
|
72
|
+
"wipefs"
|
|
73
|
+
],
|
|
59
74
|
"guardedCommands": {
|
|
60
75
|
"gitPushForce": "confirm",
|
|
61
76
|
"gitResetHard": "confirm",
|
|
@@ -76,8 +91,11 @@
|
|
|
76
91
|
{
|
|
77
92
|
"name": "filesystem",
|
|
78
93
|
"package": "@modelcontextprotocol/server-filesystem@2025.8.21",
|
|
79
|
-
"args": [
|
|
80
|
-
|
|
94
|
+
"args": [
|
|
95
|
+
"/home/user/projects"
|
|
96
|
+
],
|
|
97
|
+
"startupTimeout": 15000,
|
|
98
|
+
"toolTimeout": 120000
|
|
81
99
|
},
|
|
82
100
|
{
|
|
83
101
|
"name": "chrome-devtools",
|
|
@@ -86,7 +104,10 @@
|
|
|
86
104
|
{
|
|
87
105
|
"name": "legacy-npx",
|
|
88
106
|
"command": "npx",
|
|
89
|
-
"args": [
|
|
107
|
+
"args": [
|
|
108
|
+
"-y",
|
|
109
|
+
"some-mcp-server@latest"
|
|
110
|
+
]
|
|
90
111
|
}
|
|
91
112
|
]
|
|
92
113
|
},
|
|
@@ -94,11 +115,13 @@
|
|
|
94
115
|
"maxIterations": 50,
|
|
95
116
|
"maxToolRetries": 3,
|
|
96
117
|
"toolErrorFormat": "xml",
|
|
97
|
-
"compressionKeepRounds": 6
|
|
118
|
+
"compressionKeepRounds": 6,
|
|
119
|
+
"compressionTimeoutMs": 120000
|
|
98
120
|
},
|
|
99
121
|
"agents": {
|
|
100
122
|
"defaultProfile": "general",
|
|
101
|
-
"maxConcurrency": 1
|
|
123
|
+
"maxConcurrency": 1,
|
|
124
|
+
"subagentRetentionDays": 30
|
|
102
125
|
},
|
|
103
126
|
"skills": {
|
|
104
127
|
"enabled": true,
|
|
@@ -144,6 +167,12 @@
|
|
|
144
167
|
}
|
|
145
168
|
},
|
|
146
169
|
"desktop": {
|
|
170
|
+
"maxConcurrentTurns": 2,
|
|
171
|
+
"notifications": {
|
|
172
|
+
"enabled": true,
|
|
173
|
+
"minSeconds": 10
|
|
174
|
+
},
|
|
175
|
+
"globalHotkey": "CommandOrControl+Shift+Space",
|
|
147
176
|
"workspaces": {
|
|
148
177
|
"root": "~/.stratum/desktop/workspaces",
|
|
149
178
|
"maxFileMB": 25,
|
|
@@ -151,5 +180,41 @@
|
|
|
151
180
|
"compressAfterDays": 7,
|
|
152
181
|
"deleteAfterDays": 30
|
|
153
182
|
}
|
|
183
|
+
},
|
|
184
|
+
"environments": {
|
|
185
|
+
"prod": {
|
|
186
|
+
"match": [
|
|
187
|
+
"ssh:prod-*"
|
|
188
|
+
],
|
|
189
|
+
"tier": "production",
|
|
190
|
+
"requirePlan": true
|
|
191
|
+
},
|
|
192
|
+
"staging": {
|
|
193
|
+
"match": [
|
|
194
|
+
"ssh:stg-*"
|
|
195
|
+
],
|
|
196
|
+
"tier": "staging"
|
|
197
|
+
},
|
|
198
|
+
"lab": {
|
|
199
|
+
"match": [
|
|
200
|
+
"ssh:dev-*"
|
|
201
|
+
],
|
|
202
|
+
"policy": "allow"
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"session": {
|
|
206
|
+
"profile": "auto",
|
|
207
|
+
"planRetentionDays": 30,
|
|
208
|
+
"profiles": {
|
|
209
|
+
"ops": {
|
|
210
|
+
"description": "guardias",
|
|
211
|
+
"allowedTools": [
|
|
212
|
+
"exec",
|
|
213
|
+
"read_file",
|
|
214
|
+
"grep",
|
|
215
|
+
"mcp__*"
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
}
|
|
154
219
|
}
|
|
155
220
|
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Changelog — Stratum CLI
|
|
2
|
+
|
|
3
|
+
Cambios de cada versión del paquete [`stratum-cli`](https://www.npmjs.com/package/stratum-cli), de la más reciente a la más antigua. Stratum Desktop se versiona aparte: ver [`stratum-desktop/CHANGELOG.md`](../stratum-desktop/CHANGELOG.md).
|
|
4
|
+
|
|
5
|
+
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y las versiones, [SemVer](https://semver.org/lang/es/) (mientras la versión sea `0.x`, una minor puede traer cambios incompatibles, que se señalan en «Cambios a tener en cuenta»). Las notas de cada versión también están en su [GitHub Release](https://github.com/choruzo/CLI/releases).
|
|
6
|
+
|
|
7
|
+
> Las versiones anteriores a la 0.2.1-beta.0 solo existen como tags de git: la primera publicación en npm fue la 0.2.1-beta.0.
|
|
8
|
+
|
|
9
|
+
## [0.7.0-beta.0] — 2026-09-27
|
|
10
|
+
|
|
11
|
+
Pre-release para pruebas (`npm install -g stratum-cli@beta`); `latest` sigue en la 0.6.0.
|
|
12
|
+
|
|
13
|
+
Endurecimiento de la persistencia de sesiones, subagentes (`.stratum/subagents/`), planes (`.stratum/plans/`), decisiones (`decisions.json`), su índice semántico y host keys SSH (`known_hosts.json`), de la escritura de ficheros del usuario (`write_file` / `edit_file`), de la carpeta gestionada de MCP servers (`~/.stratum/mcp/`) y de su uso en la sesión, del cliente del LLM y de `web_fetch`.
|
|
14
|
+
|
|
15
|
+
### Corregido
|
|
16
|
+
- **Memoria semántica**: una respuesta del endpoint de embeddings (`memory.embeddingEndpoint`) con menos vectores que textos, índices repetidos o fuera de rango, o vectores de distinto tamaño ya no se aprovecha a medias. Antes podía guardar el vector de una decisión bajo otra (y el recall devolvía decisiones sin relación con la búsqueda); ahora se descarta y se usa el modelo local. El error del endpoint se muestra recortado y sin credenciales.
|
|
17
|
+
- **`web_search`**: la respuesta del buscador se lee con un tope de 2 MB. Un proxy o un portal cautivo que devolviese algo enorme ya no se acumula en memoria.
|
|
18
|
+
- **Seguridad (`exec` en Windows)**: borrar con PowerShell (`Remove-Item`, `del`, `erase`, `ri`, `rd`, `RM`, también dentro de `pwsh -Command` o `cmd /c`) no pedía confirmación, porque los patrones destructivos solo reconocían nombres POSIX en minúsculas. Ahora pide confirmación, igual que `rm`, también con `Clear-Content`, `Format-Volume` o `Clear-Disk`, y aunque `tools.destructivePatterns` esté personalizado. `Remove-Item -Recurse` sobre la raíz de una unidad, el home o el directorio actual se bloquea siempre, como `rm -rf /`.
|
|
19
|
+
- **Cancelar (Ctrl+C)**: en `stratum run` y `stratum init`, un Ctrl+C con una confirmación, una pregunta o la aprobación del plan en pantalla dejaba el proceso colgado (hacían falta tres Ctrl+C). Ahora cuenta como «no» y cancela el turno.
|
|
20
|
+
- **Cancelar (Ctrl+C)**: en el chat, Ctrl+C en una confirmación, una pregunta o una aprobación de plan responde «no» y además detiene el turno, como en cualquier otro momento. `Esc` sigue respondiendo «no» y dejando continuar al agente.
|
|
21
|
+
- **Cancelar (Ctrl+C)**: tras cancelar ya no se lanza ninguna tool que no hubiese empezado (antes, un `write_file` de la misma tanda podía llegar a escribir), no se abre la tanda de preguntas ni la aprobación del plan, y un subagente en cola no pide confirmación.
|
|
22
|
+
- **Cancelar (Ctrl+C)**: cancelar varias veces una tool lenta ya no la deshabilita para el resto de la sesión.
|
|
23
|
+
- **Cancelar (Ctrl+C)**: la conversación sigue funcionando después de cancelar. Una petición cancelada antes de que el modelo respondiese ya no deja dos mensajes de usuario seguidos (que rechazan las plantillas de chat de Mistral y otras), y ninguna llamada a una tool se queda sin respuesta en el historial.
|
|
24
|
+
- **`stratum init`**: cierra las conexiones SSH antes de salir.
|
|
25
|
+
- **`stratum run`**: un turno que termina con un error fatal (el provider caído y el fallback agotado) sale con código 1. Antes salía con 0 y un script que encadenaba `stratum run` lo daba por bueno.
|
|
26
|
+
- **Compresión de contexto**: en una tarea larga con muchas tool calls, la petición original del usuario ya no se pierde al comprimir: se conserva literal junto a las últimas iteraciones.
|
|
27
|
+
- **Compresión de contexto**: el historial comprimido ya no pone dos mensajes seguidos del asistente ni empieza por uno, algo que las plantillas de chat de algunos modelos (Mistral, Gemma) rechazan con un error que dejaba la sesión inutilizable.
|
|
28
|
+
- **Compresión de contexto**: el resumen ya no se cortaba a los 30 s. Un modelo local con razonamiento tarda más y siempre acababa en el truncado duro; ahora el límite es `agent.compressionTimeoutMs` (120 s) y, si el resumen falla, se avisa (`context_summary_failed`) en vez de truncar en silencio. Cancelar el turno mientras se resume no toca el historial.
|
|
29
|
+
- **Compresión de contexto**: el resumen ahora sabe qué ficheros se leyeron y qué comandos se ejecutaron (antes solo veía el texto de los mensajes), no incluye el razonamiento `<think>` del modelo, y un resumen vacío ya no sustituye al historial. `/compact` dice cuándo no pudo resumir.
|
|
30
|
+
- **`exec` en Windows**: cancelar un comando (Ctrl+C) o que venza su timeout ya no deja vivos los procesos que lanzó (`node`, los workers de un `npm test`, un servidor de desarrollo que seguía ocupando el puerto). Se termina el árbol entero, y la cancelación responde en menos de un segundo en vez de esperar ~6 s. El exit code de un comando matado ya no aparece como 1.
|
|
31
|
+
- **Config**: un `.stratumrc.json` guardado con BOM (el Bloc de notas de Windows lo añade) ya no falla con «Unexpected token»; se lee con normalidad, también en Ajustes de Desktop.
|
|
32
|
+
- **Config**: un JSON roto dice qué fichero es (el global o el del proyecto), la línea y la columna. Un valor inválido lista cada clave con su motivo y el fichero que la define, en vez de volcar el error de validación entero. Los comandos que no lo capturaban (`sessions`, `logs`) ya no enseñan una traza.
|
|
33
|
+
- **Config**: una variable `${VAR}` que no está definida se sigue sustituyendo por vacío, pero ahora `chat` y `run` avisan de cuál es, en qué clave y en qué fichero. Antes una `apiKey` con el nombre de variable mal escrito acababa en un 401 sin pista.
|
|
34
|
+
- **Config**: `stratum config set` y `/config set` validan el resultado junto con la config global, como la verá Stratum: un valor del proyecto que se apoya en la global (p. ej. un `jumpHost` definido allí) ya no se rechaza. `/config set` escribe de forma atómica, como `stratum config set`, y ninguno acepta claves como `__proto__` o `a..b`.
|
|
35
|
+
- **MCP**: un server que se cae durante la sesión se reconecta solo. Antes se quedaba en «reconnecting» hasta salir, y sus tools respondían que no estaban disponibles. Una llamada que estaba en curso cuando cayó avisa de que la acción pudo llegar a hacerse, para que el agente la compruebe antes de repetirla.
|
|
36
|
+
- **MCP**: un server colgado (que no responde ni al heartbeat) se relanza.
|
|
37
|
+
- **MCP**: las tools MCP ya no se cortan a los 30 s. Cada server tiene su `toolTimeout` (120 s por defecto) y, al vencer, se cancela la llamada en el server.
|
|
38
|
+
- **MCP**: un nombre de tool de más de 64 caracteres ya no rompe todas las peticiones al modelo (las APIs OpenAI-compatible rechazan la petición entera); se recorta con un hash.
|
|
39
|
+
- **MCP**: dos tools cuyos nombres coincidían al sanitizarse (`a.b` y `a_b`, o dos servers `my server` y `my_server`) se pisaban en silencio. Ahora los nombres que la sanitización altera llevan un hash del original, y un nombre que ya está en uso se omite con aviso en vez de sustituir a la otra tool.
|
|
40
|
+
- **MCP**: un server con muchas tools ya no pierde las que no caben en la primera página de `tools/list`.
|
|
41
|
+
- **MCP**: si el server añade o quita tools durante la sesión (`tools/list_changed`), el agente las ve al momento; tras una reconexión también se retiran las que desaparecieron.
|
|
42
|
+
- **MCP**: el contenido de un recurso embebido (p. ej. un fichero que devuelve la tool) llega al modelo; antes solo veía `[resource: unknown]`. Los binarios se describen con su tipo y tamaño, y un resultado que solo trae `structuredContent` se muestra como JSON.
|
|
43
|
+
- **MCP**: un server que falla al arrancar o al listar sus tools ya no deja su proceso vivo. Cerrar `chat` (o `/mcp reload`) mientras un server se reconecta ya no lo vuelve a lanzar después.
|
|
44
|
+
- **MCP**: que un server no esté conectado no cuenta como fallo de sus tools, así que no acaban deshabilitadas por un corte temporal.
|
|
45
|
+
- **Seguridad (`web_fetch`)**: ya no alcanza direcciones privadas, de loopback ni link-local (`localhost`, `10.x`, `192.168.x`, `169.254.169.254` —metadatos de la nube—, `[::ffff:127.0.0.1]`, `http://2130706433/`…), tampoco a través de una redirección ni de un nombre que resuelve a una IP privada (DNS rebinding): la IP se comprueba al conectar. Para un servidor local o interno legítimo, `tools.webFetch.allowHosts` (`["localhost:3000", "*.corp.example"]`). Un host rechazado no cuenta como fallo de la tool.
|
|
46
|
+
- **LLM**: un corte de conexión a mitad de respuesta ya no reinicia el stream desde el principio. Antes el texto salía duplicado y los argumentos de una tool call llegaban mezclados de dos intentos (JSON corrupto); ahora el error se muestra.
|
|
47
|
+
- **LLM**: los errores que no se arreglan reintentando (400 por contexto desbordado, 401, 404) fallan en el acto con el mensaje del backend. Antes se esperaban 7 s de reintentos y se reenviaba el prompt cuatro veces. Los transitorios (conexión rechazada, 429, 503 «Loading model», 502 de un proxy) se siguen reintentando, respetando `Retry-After`, y cancelar durante la espera corta en el acto.
|
|
48
|
+
- **LLM**: un backend colgado (sin responder o parado a mitad del stream) ya no bloquea el turno para siempre: timeouts de inactividad de 120 s hasta las cabeceras y 300 s sin recibir nada, configurables por provider con `timeouts.{headersMs,idleMs}` (`0` desactiva). Una respuesta larga que sigue llegando nunca se corta. Tras un timeout se prueba el siguiente provider si hay más.
|
|
49
|
+
- **LLM**: un error que el backend manda a mitad de generación (`{"error": …}` en el stream, p. ej. llama.cpp o LiteLLM) se muestra como error; antes el turno terminaba vacío sin explicación. Un fragmento del stream que no es JSON se descarta con un aviso visible en vez de en silencio.
|
|
50
|
+
- **LLM**: los mensajes de error son legibles y seguros: el `error.message` del backend en vez del cuerpo entero (una página HTML de un proxy ya no llega a la pantalla ni al historial), recortado, redactado y sin credenciales de la `baseUrl`.
|
|
51
|
+
- **Seguridad**: si el chequeo previo de una tool (`preflight`: vetos inapelables de `exec`, rutas de claves, confinamiento de Desktop) falla por un error interno, la llamada se rechaza; antes se dejaba pasar. Lo mismo con la política de entornos, y una tool cuyo chequeo de «¿es destructiva?» falla se trata como destructiva y se pregunta.
|
|
52
|
+
- **Tool calls**: con backends que cierran una respuesta con tool calls con `finish_reason: "stop"` (algunas versiones de Ollama y llama.cpp), o que no mandan `finish_reason`, las tool calls se perdían y el turno acababa como si el modelo no hubiese pedido nada. Ahora se ejecutan. Con `finish_reason: "length"` (argumentos cortados por el límite de salida) el modelo recibe un error recuperable.
|
|
53
|
+
- **Tool calls**: unos argumentos vacíos (`""`) se aceptan como `{}`, y unos que no son un objeto JSON (`null`, un array) son un error de parseo recuperable en vez de tumbar el turno.
|
|
54
|
+
- **Sesiones**: `chat` guarda la sesión al terminar cada turno y cada 30 s, no solo al salir. Cerrar la ventana, un `kill` o un fallo del proceso ya no pierden la conversación entera; `SIGTERM`/`SIGHUP` guardan antes de salir. El guardado final va antes del cierre de MCP y SSH, así que un fallo al cerrarlos tampoco lo impide.
|
|
55
|
+
- **`grep`**: nunca devuelve el contenido de claves, certificados, `.ssh/`, `.env` o `secrets/` (salvo `tools.sensitivePathAllowlist` para los de nivel confirmación), y avisa de cuántos omitió; buscar con la raíz en `~/.ssh` se veta. Antes era un rodeo para leer lo que `read_file` tiene bloqueado.
|
|
56
|
+
- **`ssh_upload` / `ssh_download`**: aplican las mismas rutas sensibles que `read_file`/`write_file` (subir una clave privada se veta; un `.env` pide confirmación). La descarga es atómica —un corte a mitad ya no deja el fichero local truncado—, conserva symlinks y no sobrescribe un fichero que cambió desde que el agente lo leyó. Cada transferencia cierra su canal SFTP (antes quedaban abiertos en la conexión del pool).
|
|
57
|
+
- **MCP**: un `npm install` cortado a mitad (Ctrl+C, cierre, corte de red) dejaba el server como «instalado» con dependencias ausentes, y fallaba en cada arranque sin repararse. La instalación se hace ahora en una carpeta temporal que solo sustituye a la definitiva cuando está completa, con un marcador `.stratum-install.json`.
|
|
58
|
+
- **MCP**: cambiar la versión de `package` en la config no actualizaba el server; ahora se reinstala (`stratum mcp install` lo hace sin `--force`).
|
|
59
|
+
- **MCP**: si reinstalar falla, la instalación anterior sigue funcionando. Una instalación hecha con versiones anteriores de Stratum se reinstala una vez; sin red o con `autoInstall: false` se sigue usando.
|
|
60
|
+
- **MCP**: dos `chat` arrancando a la vez ya no ejecutan `npm install` sobre la misma carpeta.
|
|
61
|
+
- **MCP**: `npm install` tiene un límite de 5 minutos, y tras un fallo no se relanza en cada reconexión durante un minuto.
|
|
62
|
+
- **MCP**: dos servers cuyos nombres coinciden al sanitizarse (`a.b` y `a_b`) dan un error claro en vez de reinstalarse el uno encima del otro.
|
|
63
|
+
- **`write_file` / `edit_file`**: la escritura es atómica (temporal + fsync + rename). Un cierre, un corte o un Ctrl+C a mitad ya no puede dejar el fichero del usuario truncado.
|
|
64
|
+
- **`edit_file`**: un `new_string` con `$&`, `$$` o `$1` (shell, PowerShell, PHP, plantillas JS) se insertaba alterado; ahora se inserta literalmente.
|
|
65
|
+
- **`edit_file`**: en ficheros con finales de línea CRLF, un `old_string` de varias líneas no casaba nunca porque el modelo lo escribe con `\n`. Ahora casa, y el texto nuevo se adapta a CRLF en vez de dejar líneas LF sueltas.
|
|
66
|
+
- **`edit_file`**: un fichero que no es UTF-8 (Latin-1, UTF-16) o que es binario se rechaza sin tocarlo. Antes se decodificaba con reemplazo y al guardar se corrompían todos sus caracteres no ASCII, no solo la línea editada.
|
|
67
|
+
- **`edit_file`**: si el fichero cambia en disco entre la lectura y la escritura (un editor guarda justo en ese momento), no se escribe encima.
|
|
68
|
+
- **`write_file`**: se niega a sobrescribir un fichero que cambió desde que el agente lo leyó (lo editó el usuario, un formateador u otro proceso) y le pide que lo relea. Un fichero que el agente nunca leyó no se comprueba.
|
|
69
|
+
- **`write_file` / `edit_file`**: se conservan el BOM, los finales de línea CRLF, los permisos (el bit de ejecución) y los symlinks del fichero original; con hard links se escribe en sitio para no romperlos.
|
|
70
|
+
- **`read_file`**: ya no muestra los `\r` de los ficheros CRLF ni el BOM.
|
|
71
|
+
- **Sesiones**: se guardan de forma atómica; un cierre a mitad de escritura ya no deja la conversación truncada e irrecuperable.
|
|
72
|
+
- **Sesiones**: con la misma sesión abierta en dos terminales, la que guarda en segundo lugar ya no pisa a la otra: su conversación se guarda como sesión nueva (`forkedFrom`) y se avisa con el id para reanudarla.
|
|
73
|
+
- **Sesiones**: una sesión dañada ya no rompe `sessions list`, `/sessions list` ni `sessions prune`: se omite y se dice cuál. Al cargar se valida su forma y un error lo explica («está dañada (…)»).
|
|
74
|
+
- **Sesiones**: `sessions prune` borra por último uso (`updatedAt`), no por fecha de creación: una sesión larga retomada ayer ya no se poda. Nunca borra una sesión que no puede leer ni una de un Stratum más nuevo.
|
|
75
|
+
- **Sesiones**: el id se valida antes de usarlo como ruta; `sessions delete ../x` ya no puede borrar ficheros fuera de la carpeta de sesiones.
|
|
76
|
+
- Si guardar la sesión al salir de `chat` falla, se dice en vez de perderla en silencio.
|
|
77
|
+
- Al reanudar una sesión solo se avisa de los subagentes interrumpidos **de esa sesión**. Antes se adoptaban los de cualquier sesión del proyecto, y con dos `chat` abiertos se daba por interrumpido un subagente que seguía corriendo en la otra terminal.
|
|
78
|
+
- Cada registro lleva el proceso dueño y un latido; un subagente solo cuenta como interrumpido si su proceso murió (o dejó de latir hace más de 3 minutos).
|
|
79
|
+
- `/sessions resume` dentro del chat también avisa de los subagentes interrumpidos, igual que `chat --resume`.
|
|
80
|
+
- El aviso ya no se pierde si el proceso muere antes de guardar la sesión: los registros se marcan después de guardarla, y un aviso que ya está en el historial no se repite.
|
|
81
|
+
- Los registros se validan al leerlos (`schemaVersion`); uno roto se ignora y uno de un Stratum más nuevo no se reescribe ni se borra.
|
|
82
|
+
- Un plan dañado ya no impide reanudar la sesión: se avisa y se reanuda sin él (antes `chat --resume` salía con error). Los planes también se validan y llevan `schemaVersion`.
|
|
83
|
+
- La referencia al plan guardada en la sesión se valida antes de usarla como ruta: ya no puede leer ni escribir fuera de `.stratum/plans/`.
|
|
84
|
+
- `/sessions resume` dentro del chat retoma también el plan a medias de la sesión cargada, igual que `chat --resume`.
|
|
85
|
+
- Reanudar una sesión desde otra carpeta encuentra su plan y sus subagentes: se buscan en el proyecto de la sesión, no en el directorio actual.
|
|
86
|
+
- **Decisiones**: un `decisions.json` dañado ya no se sobrescribe con la siguiente decisión, que borraba todas las anteriores. Se aparta a `decisions.json.corrupt-<fecha>` y se avisa.
|
|
87
|
+
- **Decisiones**: cada entrada se valida al leerla. Las que no validan (por ejemplo, de un Stratum más nuevo) no se muestran, pero se conservan al reescribir el fichero, y un fichero con otro formato (`schemaVersion`) no se modifica.
|
|
88
|
+
- **Decisiones**: cada escritura parte del contenido que hay en disco y usa un temporal único por proceso; dos procesos que guardaban a la vez podían pisarse el temporal.
|
|
89
|
+
- **Memoria semántica**: las decisiones que faltan en el índice se indexan al buscar y al guardar. Antes solo se reparaba un índice vacío, así que con un índice incompleto (índice dañado, decisiones guardadas con el embedder caído, dos procesos escribiendo a la vez) esas decisiones no aparecían nunca en el recall y el dedup no las veía.
|
|
90
|
+
- **Memoria semántica**: cambiar `memory.embeddingDimension` recrea el índice `sqlite-vec` en vez de hacer fallar todas las inserciones; el índice brute-force descarta las entradas de otra dimensión o con forma inválida.
|
|
91
|
+
- **Memoria semántica**: el índice brute-force relee el disco antes de escribir y cuando cambia, así que dos procesos ya no se borran las entradas entre sí; escritura con `writeFileAtomic`.
|
|
92
|
+
- **SSH**: un `known_hosts.json` dañado ya no se trata como vacío. Antes, todos los hosts `tofu` volvían a «primera conexión» (se aceptaba cualquier clave) y la siguiente confirmación borraba las huellas guardadas. Ahora la conexión se aborta sin preguntar, el fichero no se toca y `stratum ssh list`/`trust` explican qué pasa.
|
|
93
|
+
|
|
94
|
+
### Añadido
|
|
95
|
+
- `sessions delete` y `sessions prune` borran también los registros de subagente y el plan de esas sesiones (un plan que otra sesión todavía puede reanudar se conserva). `chat` poda al arrancar los registros de más de `agents.subagentRetentionDays` días y los planes de más de `session.planRetentionDays` (30 por defecto en ambos; `0` lo desactiva).
|
|
96
|
+
|
|
97
|
+
### Cambios a tener en cuenta
|
|
98
|
+
- Las tools MCP de un server o tool cuyo nombre tiene caracteres fuera de `[a-zA-Z0-9_-]` (espacios, puntos…) cambian de nombre: llevan un sufijo `_<hash>` (`mcp__my_server_3a158f__read_file`). Si un perfil las nombra en `allowedTools`, usa el nombre nuevo (`/tools` lo muestra) o un glob (`mcp__my_server_*`). Los nombres que ya eran válidos no cambian.
|
|
99
|
+
- `web_fetch` rechaza ahora `localhost` y cualquier dirección privada. Si el agente consultaba un servidor de desarrollo o un servicio interno, añade su host a `tools.webFetch.allowHosts` (por ejemplo `"localhost:3000"`).
|
|
100
|
+
|
|
101
|
+
## [0.6.0] — 2026-09-25
|
|
102
|
+
|
|
103
|
+
Centrada en el **Hito 17**: entornos con *blast radius*, modo read-only y perfil de sesión.
|
|
104
|
+
|
|
105
|
+
### Añadido
|
|
106
|
+
- **Entornos** (`environments` en `.stratumrc.json`): cada entorno casa por glob con `local` o `ssh:<alias>` y declara `tier`, `policy` (`allow` / `ask` / `confirm-always`), `requirePlan`, `readOnly` y `confirmation` (`typed` / `simple`). Solo afectan a lo que cambia algo: leer en producción nunca pregunta.
|
|
107
|
+
- `confirm-always` fuerza la confirmación aunque haya `--allow-destructive` o allow-all de sesión. Confirmación con nombre: en los entornos críticos se teclea el alias para aprobar.
|
|
108
|
+
- `requirePlan` escala el turno a modo plan antes de tocar ese entorno.
|
|
109
|
+
- **Modo read-only** (`--read-only` en `chat` y `run`, `/readonly`): inapelable, heredado por los subagentes y guardado en la sesión. Clasificador de comandos de solo lectura por lista blanca (git, kubectl, docker, systemctl, curl, sed, cmdlets `Get-*`…); la fase de exploración del modo plan admite estos comandos.
|
|
110
|
+
- **Perfil de sesión** `code` / `infra` / `full` / `auto` y propios en `session.profiles` (`--profile`, `--infra`, `--code`, `/profile`), combinado con el perfil de agente.
|
|
111
|
+
- Badges `⬢ entorno`, `RO` y `⬡ perfil` en la barra de estado y comando `/env`.
|
|
112
|
+
- **Razonamiento del modelo** (`reasoning_content`, `reasoning` o `<think>` inicial) plegado en una línea (`⊙ razonando…` / `⊙ razonó · N palabras`) y entero con `/debug`. Nunca entra en el historial.
|
|
113
|
+
- Core de Stratum Desktop D5–D7: panel de Ajustes (lectura/escritura del `.stratumrc.json` global con secretos enmascarados), notificaciones y atajo global (`desktop.notifications`, `desktop.globalHotkey`, gramática en `config/accelerator.ts`), razonamiento en el transcript y `desktop.updates.autoCheck`. Sin cambios de comportamiento en la CLI.
|
|
114
|
+
|
|
115
|
+
### Cambiado
|
|
116
|
+
- `stratum config set` escribe el fichero de forma atómica.
|
|
117
|
+
|
|
118
|
+
### Cambios a tener en cuenta
|
|
119
|
+
- Con `environments` definidos, `stratum run` sin TTY deniega los cambios en entornos `confirm-always` aunque el plan se apruebe con `--yes`.
|
|
120
|
+
|
|
121
|
+
## [0.5.0] — 2026-09-23
|
|
122
|
+
|
|
123
|
+
Centrada en el **Hito 16**: ejecución unificada, auditoría universal y redacción de salidas.
|
|
124
|
+
|
|
125
|
+
### Añadido
|
|
126
|
+
- Tool **`exec`** con `target` (`local` o `ssh:<alias>`) y backends con capacidades declaradas; descripción generada con los targets de la configuración.
|
|
127
|
+
- Cancelación estructurada y `maxBytes` en local que descarta la salida sobrante sin matar el proceso.
|
|
128
|
+
- Exit code real en Windows (`pwsh`), con contrato *best-effort* documentado.
|
|
129
|
+
- **Auditoría universal** de toda ejecución en `~/.stratum/logs/exec-audit.jsonl` (`tools.auditLog`), con el comando redactado y sin `stdin`.
|
|
130
|
+
- **Redacción de secretos** en las salidas (PEM, `Authorization`, `Bearer`, `sk-…`, `xox?-`, JWT, tokens de GitHub) con núcleo no desactivable y literales propios en `tools.redaction.extraPatterns`.
|
|
131
|
+
- Core compartido con Stratum Desktop D0–D4: `schemaVersion` en config y sesiones, preset de prompt `assistant`, confinamiento de las tools de fichero a un workspace e `importOptional()` para las dependencias nativas.
|
|
132
|
+
|
|
133
|
+
### Cambiado
|
|
134
|
+
- Un comando que se ejecutó y falló es un `tool_error` recuperable que no consume reintento, y el contador de reintentos pasa a ser consecutivo.
|
|
135
|
+
|
|
136
|
+
### Corregido
|
|
137
|
+
- Lag de la UI en streams largos.
|
|
138
|
+
- Los tests de guardas ya no escriben en la auditoría real del usuario.
|
|
139
|
+
- `tsc --noEmit` en verde.
|
|
140
|
+
|
|
141
|
+
### Cambios a tener en cuenta
|
|
142
|
+
- Las tools `bash` y `ssh_exec` desaparecen en favor de `exec`. Los perfiles de agente que las listen muestran un aviso en `/agents` y `stratum agents list`; hay que cambiarlas a mano.
|
|
143
|
+
- `ssh.auditLog` queda obsoleto y se migra solo a `tools.auditLog`.
|
|
144
|
+
|
|
145
|
+
## [0.4.0] — 2026-09-14
|
|
146
|
+
|
|
147
|
+
Hitos 11 a 15.
|
|
148
|
+
|
|
149
|
+
### Añadido
|
|
150
|
+
- **Disciplina operativa** (Hito 11): bloque `# Work routing` en el system prompt; guardas por capas (hard-deny no configurable, `tools.guardedCommands` y rutas sensibles) evaluadas antes de pedir confirmación; tool `todo` con panel `<TodoView>`, `/todo` y `Ctrl+T`.
|
|
151
|
+
- **Skills** (Hito 12): descubrimiento en `~/.stratum/skills`, `~/.claude/skills` y sus equivalentes de proyecto, con índice en el prompt y cuerpo bajo demanda. **Riesgo del cambio**: aviso `large_change` al superar las 400 líneas autoradas.
|
|
152
|
+
- **TDD estricto** (Hito 13) con `tools.testCommand`: tool `test_evidence` que valida el ciclo RED → GREEN → REFACTOR. **Panel de cambios** `+N/-M` en la barra de estado y `/changes`. **Contabilidad de tokens** con estado (`Σ` real, `Σ n/d` si el backend no informa).
|
|
153
|
+
- **Transversales de prompting** (Hito 14): saneado de `GIT_DIR`/`GIT_WORK_TREE` heredados, opciones de `question` con token opaco y dominio cerrado, contrato de identidad y guías por puntero (`prompt.guides: 'pointers'`).
|
|
154
|
+
- **Perfiles de agente de primera clase** (Hito 15): `description` y `mode`, `@perfil tarea` en el chat, `stratum run --delegate` y `--agent`, `/agent`, `/agents` y `stratum agents list [--json]`.
|
|
155
|
+
|
|
156
|
+
### Corregido
|
|
157
|
+
- La capa de rutas sensibles también se aplica a los comandos de shell (`cat`, `Get-Content`, redirecciones…).
|
|
158
|
+
- `/context` usaba «tokens» para dos cosas distintas.
|
|
159
|
+
- `token_budget_unmetered` se emite también en turnos de una sola iteración.
|
|
160
|
+
|
|
161
|
+
## [0.3.0] — 2026-09-11
|
|
162
|
+
|
|
163
|
+
Primera versión estable en npm, con el mismo contenido que la 0.2.1-beta.0. La etiqueta `latest` apunta desde aquí a versiones estables.
|
|
164
|
+
|
|
165
|
+
## [0.2.1-beta.0] — 2026-09-11
|
|
166
|
+
|
|
167
|
+
Primera publicación en npm. Hitos 7 a 10.
|
|
168
|
+
|
|
169
|
+
### Añadido
|
|
170
|
+
- **Plan & Execute** (Hito 7): `/plan <tarea>` y `stratum run --plan` (`--yes`); plan de solo lectura, aprobación con edición inline y ejecución con checklist, persistido en `.stratum/plans/` y reanudable con `chat --resume`.
|
|
171
|
+
- **Subagentes** (Hito 8): tool `delegate_task` con contexto aislado y perfiles en `.stratum/agents/`; presupuesto de tokens, persistencia y reanudación; ejecución en paralelo acotada (`agents.maxConcurrency`), árbol vivo `<AgentTree>` e inspector `/subagents`.
|
|
172
|
+
- **SSH nativo** (Hito 9) sobre `ssh2`: pool de conexiones, verificación de host keys (TOFU/strict), jump hosts, `ssh_exec`, `ssh_upload`/`ssh_download`, auditoría y `stratum ssh list|trust`.
|
|
173
|
+
- **Cierre de la UI base** (Hito 10): `/clear`, `/compact`, `/context`, `/debug`, `/mcp reload`, `/sessions`, `/config`; `Ctrl+L`, `Ctrl+U` e historial de inputs; `<FatalError>`, `<InitProgressBlock>` y `<MCPStartup>`.
|
|
174
|
+
- Tool **`question`** (Hito 2.5 F7): una tanda de preguntas al usuario; sin TTY el agente sigue con supuestos.
|
|
175
|
+
|
|
176
|
+
### Corregido
|
|
177
|
+
- La autocompactación medía mal el contexto y rompía el historial.
|
|
178
|
+
- Parpadeo del logo al arrancar.
|
|
179
|
+
|
|
180
|
+
## [0.2.0] — 2026-06-19
|
|
181
|
+
|
|
182
|
+
Hitos 2 a 6. Solo tag de git.
|
|
183
|
+
|
|
184
|
+
### Añadido
|
|
185
|
+
- **Memoria** (Hitos 2 y 5): `STRATUM.md` global y de proyecto en el system prompt, decision store `decisions.json`, índice semántico `sqlite-vec` con embeddings ONNX locales, tools `store_decision` y `recall_decisions`, extracción automática y `stratum memory list|search|forget`.
|
|
186
|
+
- **Init estilo opencode** (Hito 2.5): `stratum init` y `/init` con `INITIALIZE_PROMPT`, tools `glob`/`list_directory`/`grep`, `read_file` con líneas numeradas y compresión conservadora.
|
|
187
|
+
- **Tools completas** (Hito 3): `edit_file` con diff unificado, `web_search` (DuckDuckGo + Tavily), `web_fetch`, confirmación destructiva y timeouts con cancelación.
|
|
188
|
+
- **Providers** (Hitos 3.5 y 6): asistente `stratum provider add`, `/model` con descubrimiento en vivo, `/provider`, fallback automático entre providers y health check.
|
|
189
|
+
- **MCP** (Hitos 4 y 4.1): cliente con heartbeat y reconexión, tools `mcp__<server>__<tool>`, carpeta gestionada `~/.stratum/mcp/` y arranque `lazy`/`eager`.
|
|
190
|
+
- Logging estructurado con niveles, fichero JSONL rotado y `stratum logs`.
|
|
191
|
+
|
|
192
|
+
## [0.1.4] — 2026-05-29
|
|
193
|
+
|
|
194
|
+
### Cambiado
|
|
195
|
+
- CI: se retira el paso de publicación en npm hasta configurar `NPM_TOKEN`.
|
|
196
|
+
|
|
197
|
+
## [0.1.3] — 2026-05-29
|
|
198
|
+
|
|
199
|
+
### Corregido
|
|
200
|
+
- Un timeout mata el grupo de procesos entero: los huérfanos ya no bloquean los streams en Linux.
|
|
201
|
+
- El script de release gestiona el commit y el tag directamente (problemas de npm con git en Windows).
|
|
202
|
+
|
|
203
|
+
## [0.1.2] — 2026-05-28
|
|
204
|
+
|
|
205
|
+
Primera versión etiquetada. Hitos 0 y 1.
|
|
206
|
+
|
|
207
|
+
### Añadido
|
|
208
|
+
- Scaffolding: TypeScript, tsup (ESM + CJS), Vitest y Commander.js.
|
|
209
|
+
- **Core agent loop** (Hito 1): loop ReAct en streaming con cliente OpenAI-compatible propio, `StreamBuffer` para tool calls fragmentadas, `ToolRegistry` y tools básicas, y UI con Ink.
|
|
210
|
+
- `/init` para generar o actualizar `STRATUM.md`.
|
|
211
|
+
- Render de markdown de las respuestas.
|
|
212
|
+
|
|
213
|
+
[0.7.0-beta.0]: https://github.com/choruzo/CLI/compare/v0.6.0...v0.7.0-beta.0
|
|
214
|
+
[0.6.0]: https://github.com/choruzo/CLI/compare/v0.5.0...v0.6.0
|
|
215
|
+
[0.5.0]: https://github.com/choruzo/CLI/compare/v0.4.0...v0.5.0
|
|
216
|
+
[0.4.0]: https://github.com/choruzo/CLI/compare/v0.3.0...v0.4.0
|
|
217
|
+
[0.3.0]: https://github.com/choruzo/CLI/compare/v0.2.1-beta.0...v0.3.0
|
|
218
|
+
[0.2.1-beta.0]: https://github.com/choruzo/CLI/compare/v0.2.0...v0.2.1-beta.0
|
|
219
|
+
[0.2.0]: https://github.com/choruzo/CLI/compare/v0.1.4...v0.2.0
|
|
220
|
+
[0.1.4]: https://github.com/choruzo/CLI/compare/v0.1.3...v0.1.4
|
|
221
|
+
[0.1.3]: https://github.com/choruzo/CLI/compare/v0.1.2...v0.1.3
|
|
222
|
+
[0.1.2]: https://github.com/choruzo/CLI/releases/tag/v0.1.2
|