@jossuealcala/madre 0.4.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -4,10 +4,89 @@ Todas las versiones publicadas de `@jossuealcala/madre`. Fechas en ISO.
4
4
 
5
5
  Una versión se cierra cuando está en npm: hasta entonces su sección se llama **Sin publicar** y puede crecer. Cada versión publicada tiene exactamente una etiqueta `vX.Y.Z`, una release en GitHub y una sección aquí; el parche puede llegar a dos dígitos (`0.2.10`) antes de subir el menor. Ver `docs/ROADMAP.md` para el criterio de qué sube cada número.
6
6
 
7
+ ## 0.5.0 · 2026-09-28
8
+
9
+ **Por qué menor y no parche.** Cambia a dónde sale lo que sale de tu máquina —el colector vive ahora bajo `madre.run`— y, sobre todo, **puede impedir que algo salga**: si tienes `OPENAI_BASE_URL` o `ANTHROPIC_BASE_URL` apuntando a un gateway, esos turnos quedan detenidos hasta que quites la variable o autorices ese endpoint con `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS`. Es el arreglo correcto, pero un número de parche se lee como «actualiza sin mirar», y este no lo es. El ledger y la memoria de 0.4.x se siguen leyendo igual.
10
+
11
+ ### Cambiar de conversación deja de recargar la página
12
+
13
+ - Abrir otra conversación hacía `window.location.reload()`: la sala entera otra vez — cada consulta, cada panel, el flujo de eventos desde cero. Era la forma bruta de asegurarse de que nada de la anterior quedara colgando.
14
+ - Ahora se repinta en sitio, y eso solo es seguro si **de verdad se suelta todo**: lo visto, los mensajes, las calificaciones, los turnos en vuelo, los planes, las estadísticas por agente, los archivos marcados, las condiciones registradas, los adjuntos pendientes, la cita de respuesta y el cursor del flujo. La lista está escrita —no adivinada— y hay una prueba que falla si alguien agrega estado por conversación y olvida soltarlo. Y el flujo se vuelve a apuntar, cerrando el anterior: dos abiertos a la vez entregarían cada evento dos veces.
15
+ - Si la sala no se puede releer, todavía recarga. Quedarse mostrando la conversación vieja sería peor que tardar.
16
+
17
+ ### Dos cosas que se leían a medias
18
+
19
+ - En el menú de modos la cabecera se cortaba en `TEC…`, y lo que escondía era **el techo del agente**. Ahora dice `@CODEX · TECHO #4` y cabe en un renglón: la lista de abajo son literalmente los modos, así que «modo de este mensaje» no informaba de nada, y que la elección valga solo para este mensaje ya lo dice el globo del chip que abre el menú. La cabecera se queda con los dos datos que nada más lleva: quién, y hasta dónde.
20
+ - **LEER EL SDK** llevaba al archivo en GitHub. Va a `madre.run/sdk/` en español y `madre.run/en/sdk/` en inglés.
21
+
22
+ ### La barra sigue diciendo en qué proyecto estás
23
+
24
+ - Dos nombres comparten ese rincón y solo uno te dice dónde estás. Los dos encogían por igual, así que una conversación con título largo dejaba el proyecto en **`pul…`** — una sala que dejó de decir qué sala es.
25
+ - Ahora el proyecto **no cede nunca** y la conversación es la que se recorta. Tiene dónde: su panel lleva el nombre entero. El proyecto no tiene otro sitio donde leerse.
26
+ - Y `EN VIVO` se partía en dos renglones cuando la barra se apretaba. Ya no.
27
+
28
+ ### La fila de @madre cabe en un renglón
29
+
30
+ - Al elegir `@madre`, la fila sobre el campo se partía en dos: `PARA @MADRE` con una nota de tres cláusulas, el chip de modo, y un `modelo por defecto ▾` empujado abajo.
31
+ - **Ese chip no tenía nada que ofrecer.** `@madre` contesta con el modelo de chat que tenga Ollama, que se decide en la ficha de Ollama; aquí abría un menú vacío. Un agente sin modelos que elegir ya no trae selector — y era justo la pieza que rompía el renglón.
32
+ - La nota pasó de «memoria · contesta y le pregunta a la tripulación · nunca escribe» a **«memoria · nunca escribe»**. La frase entera sigue en su globo, que es donde estaba de todos modos.
33
+ - Y la fila ya no puede envolver. Si algún día vuelve a faltar espacio, lo que cede es la nota, con puntos suspensivos: un modo que no puedes leer es peor que una nota que no puedes.
34
+
35
+ ### El cursor caía dentro de la píldora
36
+
37
+ - **Y en tema claro el código era ilegible.** Los colores del visor se eligieron para fósforo sobre negro: ese verde de las cadenas y ese amarillo de los números desaparecen sobre blanco. Ahora cada rol es una variable con su valor propio para cada fondo, como todo lo demás del tema — azul profundo, verde oscuro, ámbar tostado y magenta sobre claro.
38
+ - **La píldora respira.** Tenía el contorno pegado al texto, y el cursor quedaba encima del anillo en vez de después de él. Ahora lleva aire adentro y **lo paga con un margen negativo igual**: el siguiente carácter empieza exactamente donde empezaba. Esa cuenta también quedó en la prueba, porque relleno sin su compensación es la misma deriva por otro camino.
39
+ - **La píldora se comía el espacio de después.** El relleno lateral con margen negativo devuelve el sitio al *texto*, pero el fondo sí se pinta ahí: la píldora tapaba el espacio y la siguiente palabra llegaba pegada al borde. Y una sombra hacia afuera hace lo mismo, solo que más callada. Ahora crece **hacia arriba** —el relleno vertical no mueve un carácter— y su anillo se dibuja **hacia adentro**. Abraza sus letras, y el hueco que sigue es el espacio que tecleaste, visible.
40
+ - El corrector del navegador se queda encendido. Subraya las referencias, sí; perder la corrección en español y en inglés para ganar eso era mal negocio.
41
+
42
+ - Escribías una referencia y el cursor aparecía **en medio** de ella: `!public/brands.js|14`. No era el texto — era la capa que dibuja las píldoras encima del campo, desalineada del campo mismo. El cursor lo coloca el textarea con sus propias métricas; la píldora la dibujaba otra tipografía, y dos medidas distintas del mismo texto no pueden terminar en el mismo sitio.
43
+ - Dos causas, y la primera era gruesa. **Teclear `#2` dibujaba `#2 CREATE`**: siete caracteres que nadie escribió, así que todo lo que venía después quedaba siete lugares a la derecha de su propio cursor. La capa ahora dibuja solo lo que hay; el nombre del modo vive en el globo y en el chip sobre el campo, donde ya estaba.
44
+ - La segunda: cada píldora se re-tipografiaba —`font-family: mono`, `font-size: 13px`, `letter-spacing`, `font-weight`— mientras el campo real corre a 15px con la fuente de la interfaz. Ahora una píldora puede tomar el color que quiera y **ninguna métrica**: color, fondo, radio y sombra pintan sin mover nada.
45
+ - La regla quedó escrita en una prueba, porque una sola línea de CSS puede volver a romperlo: ninguna regla sobre el campo puede tocar familia, tamaño, peso, espaciado ni transformación, y el campo y su capa siguen compartiendo una sola declaración de forma.
46
+
47
+ ### Tres detalles del menú de revisar
48
+
49
+ - **MADRE te ponía palabras en la boca, y en inglés.** Elegías un rango, elegías un agente, y el compositor se llenaba con `review this:` — una frase en inglés dentro de una sala en español, y peor: lo que escribías después caía *detrás* de ella y se leía como si alguien más lo hubiera empezado por ti. Ahora entra la referencia y el cursor. Nada más. Acabas de elegir un archivo, unas líneas y un agente: ya sabes qué quieres preguntar.
50
+ - **`@codex Codex` dice una cosa dos veces.** La arroba **es** el nombre. Al lado va solo lo que la arroba no te dice: de quién es el agente, que es el mismo que acaba de hablar, o que no tiene sesión. Pasaba en los dos menús —el del visor y el de responder desde una burbuja—; los dos.
51
+ - **La cabecera se cortaba a media palabra.** `REVISAR !public/app.js:24 CON` dejaba el verbo en una punta y su preposición en la otra, y el menú cortaba justo en «CON». Ahora son dos renglones: qué se manda, y debajo la pregunta. La referencia es una ruta y puede ser larga, así que envuelve en vez de empujar el menú o quedarse a medias.
52
+
53
+ ### El árbol dice quién tocó qué, y el visor lee por lo que el archivo es
54
+
55
+ - Y el panel de archivos se rompió al estrenar ese punto: `no se pudo listar: Cannot access 'touched' before initialization`. La misma zona muerta temporal que ayer — una `const` declarada al fondo del archivo, leída por una función que corre durante el arranque. **Dos veces el mismo error en dos días**, y las dos veces con la suite en verde: el panel **atrapa sus propios fallos y los dibuja como una línea de texto**, así que nada lanzaba y la prueba de humo nunca abría el árbol. Ahora arranca con el panel abierto y **afirma que pintó**, no solo que nada explotó. Comprobado: con el error reintroducido, falla.
56
+
57
+ - **Un punto en el color del agente**, junto a cada archivo que un agente escribió en esta sala. Sale de lo que la sala ya registró —los artefactos de un permiso de creación y los archivos que cambió un turno de CONTROL—: no se guarda nada nuevo y no se deduce nada del disco. Un archivo que MADRE no vio cambiar no lleva marca, que es lo honesto.
58
+ - **El visor resalta por extensión**, con un resaltador propio de doscientas líneas: JavaScript, JSON, CSS, HTML, Markdown, Python, Shell, Config y SQL. Cero dependencias, como todo lo demás. La regla que lo mantiene honesto es que **nunca reescribe el archivo**: devuelve tramos sobre los mismos caracteres, en el mismo orden, así que lo que ves y lo que hay en disco son los mismos bytes — y una selección que le mandas a un agente es el archivo, no una versión dibujada de él. La prueba lo sostiene sobre nueve familias. Lo que no reconoce se queda en texto plano en vez de adivinarse.
59
+ - **Y preguntarle a un agente sobre un trozo dejó de ser un secreto.** `REVIEW WITH` existía desde siempre, pero aparecía solo *después* de seleccionar, y nadie adivina que un número de línea se puede clicar. Ahora, mientras no hay selección, el visor dice cómo: «clic en un número de línea para seleccionar · shift para un rango». Y dice qué está leyendo.
60
+
61
+ ### `/module` sin `#2` contesta en la sala
62
+
63
+ - Escribir `/module` sin CREATE solo lanzaba un aviso que se desvanecía. Un rechazo que solo parpadea es un rechazo que la sala olvida. Ahora la respuesta cae **en el hilo**, donde caen todas las decisiones de la sala, dice que tu petición sigue en el compositor, y trae el botón que arma el modo. **El comando pide; el clic concede** — escribir un comando nunca arma un permiso, y la prueba lo sostiene.
64
+
65
+ ### El briefing ya no sale por una puerta que nadie nombró
66
+
67
+ - Codex y Claude heredan del shell las direcciones base de sus APIs. Eso permite usar gateways legítimos, pero también hizo que una sala que mostraba «OpenAI» o «Anthropic» pudiera enviar el briefing a otro host sin decirlo. MADRE ahora enseña el destino efectivo en CONEXIONES y en QUÉ SALIÓ DE ESTA MÁQUINA; solo conserva el hostname, nunca la ruta, la consulta ni una credencial.
68
+ - Un endpoint personalizado queda bloqueado antes de armar o entregar el briefing. Para volver al servicio oficial basta con quitar `OPENAI_BASE_URL` o `ANTHROPIC_BASE_URL`; quien sí verificó su gateway puede autorizar por agente con `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS=codex` o `=claude`. Bedrock, Vertex AI y Foundry se nombran como los proveedores explícitos que son.
69
+ - MU/TH/UR reconoce el 403 que exige unirse a Telegram como **MU-055**: explica que viene del gateway, no de MADRE ni del proveedor oficial, y no recomienda suscribirse ni entregar credenciales.
70
+ - Codex ya no se reduce a «salió con código 1» cuando su JSON trae `error` o `turn.failed`: la sala conserva el motivo que el propio CLI reportó. Si no trae ninguno, se mantiene el código de salida como último dato honesto.
71
+
72
+ ### El SDK deja de tener trampas
73
+
74
+ Antes de que alguien pueda pedirle a un agente «hazme un módulo», el contrato tiene que perdonar los tres errores que cualquiera comete. Medí ocho módulos —uno bueno y siete rotos— y seis de los siete ya contestaban con precisión. Estos eran los que no.
75
+
76
+ - **`/module` ya es la entrada explícita para construir.** `/module <qué debe hacer>` requiere `#2 CREATE`: si falta, MADRE lo pide y conserva el texto en el compositor; nunca se concede el permiso solo por escribir un comando. Con `#2` activo, conserva el agente elegido y convierte la petición en el contrato de un único `<id>.module.mjs` que el humano revisa e instala desde su tarjeta. Mientras se escribe, el compositor cambia a morado MADRE eléctrico con una transformación breve de píxeles; el estado queda limpio y legible después de la transición, y respeta movimiento reducido. La zona de escritura reserva ahora cinco píxeles laterales para que el contorno del chip no se recorte.
77
+ - **Un campo mal escrito pasaba en silencio.** Escribe `sumary` en vez de `summary` y el módulo instala sin una queja, con la ficha vacía y sin manera de saber por qué. Con treinta y dos campos opcionales ese es *el* error que va a cometer todo el mundo, un agente incluido. Ahora MADRE dice qué campos no conoce — **dice, no rechaza**: un módulo escrito para una MADRE más nueva puede traer campos que esta todavía no aprendió, y eso no debe impedirle cargar.
78
+ - La advertencia salía al subir un archivo desde MODULES, pero no al instalar el mismo archivo desde la tarjeta que deja un agente en la conversación. Las dos entradas pasan por el mismo verificador y ahora también terminan en la misma advertencia; `sumary` ya no vuelve a quedar en silencio según quién escribió el archivo.
79
+ - `install` figuraba como campo entendido aunque `defineModule` no hacía nada con él. El contrato documentado pone esa línea en el resultado de `status(ctx)` y reserva `installCommand` para el comando confirmado; el campo superior fantasma salió de la lista y ahora se señala como desconocido en vez de prometer un efecto que no existe.
80
+ - **DESINSTALAR ya vive en la tarjeta del módulo.** El backend protegía los módulos integrados y la acción existía escondida en la tarjeta `</>`, pero la ficha `DEV` no la ofrecía. Ahora cada módulo externo confirma su ruta y puede quitarse ahí mismo; borra su archivo y el registro que recuerda de dónde actualizarlo, recarga el registro y deja intactos los módulos que MADRE trae de fábrica.
81
+ - **La documentación prometía un `import` que el instalador rechaza.** `SDK.md` decía que podías `import { defineModule } from '@jossuealcala/madre/sdk'`. El paquete lo exporta bien, pero MADRE copia tu archivo a una carpeta aparte para revisarlo antes de instalarlo —así sabe qué es sin que corra donde vive— y ahí no hay `node_modules`: ningún paquete resuelve. Ahora la guía enseña la forma que sí funciona, que ya existía: exporta una función y **MADRE te entrega el SDK**.
82
+ - **Y la trampa que solo le pasa a un agente.** Los módulos que vienen con MADRE escriben `import { defineModule } from './sdk.mjs'`, porque viven dentro del paquete. Un agente al que le pides un módulo lee `ripley.mjs` antes que cualquier documento y copia esa línea — que es correcta ahí e imposible fuera. Node contestaba solo «no encuentro el archivo», que manda a buscar lo que no es. Ahora el error termina diciendo qué hacer en su lugar, y el ejemplo y la guía lo advierten con esas palabras.
83
+
7
84
  ## 0.4.1 · 2026-09-27
8
85
 
9
86
  ### MADRE tiene casa: madre.run
10
87
 
88
+ - **Y lo que trae una versión se lee en esa casa.** `QUÉ TRAE 0.4.2 ↗` llevaba a la página de releases de GitHub, que está escrita para quien ya trabaja ahí; quien aprieta ese botón solo quería saber qué cambió. Ahora va a `madre.run/cambios/` en español y a `madre.run/en/changelog/` en inglés, con la versión en el ancla (`#v0.4.2`) para que la página lo deje parado en la sección que le toca.
89
+
11
90
  - El colector de errores vivía en `madre-reports.jossue-alcala-o.workers.dev`, y **ese host se le enseña al usuario** en el registro de salidas del núcleo. Un subdominio de `workers.dev` con un nombre de cuenta pegado parece un endpoint improvisado; `madre.run` parece el producto. La dirección es parte de lo que se le pide confiar a alguien.
12
91
  - **La dirección vieja sigue contestando, y tiene que seguir.** Cada sala en 0.4.0 y anteriores la lleva compilada dentro: apagarla detendría sus reportes en silencio. Queda escrita en el código y en la prueba, en vez de desaparecer del registro.
13
92
  - **Dos puertas para cada reporte humano, siempre.** Un fallo con traza pertenece a GitHub, donde se deduplica y la respuesta le sirve al siguiente; pero pedirle una cuenta a quien llegó de un grupo en español para decir «no me detecta Codex» es perderlo. En español manda el formulario y el issue queda a un clic; en inglés, al revés. Nadie choca con un muro de login con un reporte en la mano.
package/docs/REFERENCE.md CHANGED
@@ -197,7 +197,7 @@ Cada módulo es un archivo. Los tuyos van en `~/.pulse/modules/` (todas las sala
197
197
  ## LO QUE SALE DE LA MÁQUINA
198
198
 
199
199
  - **Nada por sí solo.** MADRE no tiene nube, cuenta ni backend. No guarda credenciales.
200
- - **Lo que un agente lee, viaja a su proveedor.** Codex a OpenAI, Claude Code a Anthropic, Gemini CLI a Google, OpenCode a quien tenga configurado. Aplican su cuenta, sus límites y sus términos. `@madre` y el archivista con Ollama no salen de la máquina.
200
+ - **Lo que un agente lee, viaja a su proveedor.** Codex a OpenAI, Claude Code a Anthropic, Gemini CLI a Google, OpenCode a quien tenga configurado. Si `OPENAI_BASE_URL` o `ANTHROPIC_BASE_URL` cambia ese destino, MADRE enseña solo el hostname y bloquea el turno antes de armar el briefing; un gateway verificado se autoriza por agente con `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS`. Aplican la cuenta, los límites y los términos del destino efectivo. `@madre` y el archivista con Ollama no salen de la máquina.
201
201
  - **Dos envíos propios, ambos bajo tu interruptor.** El sentinel, apagado por defecto, envía reportes redactados al colector del proyecto. El canal de liberación, encendido por defecto, pregunta a npm por la última versión: viaja el nombre del paquete, nada más, la misma petición que hace `npx`. `PULSE_UPDATE_CHECK=0` lo apaga.
202
202
  - **Escritura.** En `#1` nadie escribe. En `#2` solo se añade: lo que existía se restaura al terminar el turno. En `#3` todo el proyecto salvo las zonas prohibidas, con checkpoint y `UNDO`. En un proyecto sin git, MADRE guarda sus fotografías en un repositorio sombra fuera del proyecto.
203
203
  - **Memoria.** Todo lo dicho fuera de GHOST queda en `~/.pulse/rooms/<sala>/` y vuelve a los prompts de todos los agentes de esa sala. GHOST es la salida para lo que no debe recordarse; PRIVACY, para los nombres que nunca deben aparecer.
@@ -237,6 +237,7 @@ Cada módulo es un archivo. Los tuyos van en `~/.pulse/modules/` (todas las sala
237
237
  | `PULSE_UPDATE_CHECK` | `1` | `0` apaga la consulta diaria a npm |
238
238
  | `PULSE_REPORT_URL` · `PULSE_AUTO_REPORT` | colector del proyecto · `0` | Sentinel |
239
239
  | `PULSE_AGENT_TIMEOUT_MS` · `PULSE_<AGENTE>_TIMEOUT_MS` | `180000` · — | Timeouts |
240
+ | `PULSE_ALLOW_CUSTOM_AGENT_ENDPOINTS` | — | Lista separada por comas (`codex`, `claude`) de gateways que el humano verificó y permite; sin ella, una dirección base no oficial se bloquea |
240
241
  | `PULSE_MAX_MESSAGE_CHARS` | `20000` | Tamaño máximo de un mensaje |
241
242
  | `PULSE_DELEGATION` · `PULSE_MAX_PLAN_STEPS` | `1` · `4` | Delegación |
242
243
  | `PULSE_ESCALATION_MS` | `180000` | Cronómetro de la escalación |
@@ -246,4 +247,4 @@ Cada módulo es un archivo. Los tuyos van en `~/.pulse/modules/` (todas las sala
246
247
 
247
248
  Cómo funcionan por dentro el ledger, el stream, la memoria, los adaptadores y la recuperación: [`docs/INTERNALS.md`](INTERNALS.md).
248
249
 
249
- ---
250
+ ---
package/docs/SDK.md CHANGED
@@ -26,7 +26,19 @@ export default {
26
26
  };
27
27
  ```
28
28
 
29
- Si prefieres importar el SDK, también vale: `import { defineModule } from '@jossuealcala/madre/sdk'` y exporta el resultado. Y si necesitas hacer algo antes de definirlo, exporta una función `({ defineModule }) => defineModule({ … })`.
29
+ **Tu módulo no importa nada.** Ni a MADRE, ni al SDK. Antes de instalarlo, MADRE copia tu archivo a una carpeta temporal aparte y lo carga ahí —así revisa qué es sin que corra donde vive— y en esa carpeta no hay `node_modules`: un `import` por nombre de paquete no resuelve y la instalación falla.
30
+
31
+ Si necesitas `defineModule` —para calcular algo antes de definir el módulo, por ejemplo— **MADRE te lo entrega**: exporta una función y lo recibes como argumento.
32
+
33
+ ```js
34
+ export default ({ defineModule }) => defineModule({
35
+ id: 'mi-modulo',
36
+ name: 'MI MÓDULO',
37
+ // …lo que hayas calculado arriba
38
+ });
39
+ ```
40
+
41
+ > Los módulos que vienen con MADRE sí escriben `import { defineModule } from './sdk.mjs'`, porque viven dentro del paquete. **Si le pides a un agente que te escriba uno, va a leer esos archivos y copiar esa línea** — y no va a funcionar. Dile que exporte un objeto plano, o la función de arriba.
30
42
 
31
43
  ## Lo que un módulo puede declarar
32
44
 
@@ -38,7 +50,7 @@ Si prefieres importar el SDK, también vale: `import { defineModule } from '@jos
38
50
  | `updatePlan(ctx, { latest })` | Cómo se trae esa versión nueva a esta computadora: `{ command, args, display, note, after }`. MADRE enseña `display` y no corre nada hasta que la humana lo leyó; la salida cae en la sala línea por línea. Sin comando, devuelve `{ command: null, note, download }` y la ficha manda a descargarlo |
39
51
  | `updates` | `{ url }` https donde publicas **tu propio módulo**. Con eso su ficha trae un botón que va por el archivo, lo verifica igual que una instalación y lo reemplaza si pasa. Si lo instalaste desde un archivo, MADRE recuerda cuál y no necesitas declarar nada: edítalo y pide una copia nueva |
40
52
  | `settings` | Valores por defecto. Viven en `~/.pulse/config.json` bajo `modules.<idEnCamelCase>`; `enabled` es el interruptor |
41
- | `status(ctx)` | Qué muestra la tarjeta: `{ status: { installed, detail }, preflight: { ok, problems }, install: { display } }` |
53
+ | `status(ctx)` | Qué muestra la tarjeta: `{ status: { installed, detail }, preflight: { ok, problems }, install: { display } }`. `install` se devuelve desde aquí; no es un campo superior del módulo |
42
54
  | `status(ctx)` → `runs` | Lo que tu módulo maneja y no es MADRE: `[{ name, version, target }]`. `version` es lo que encontraste en esta computadora (`null` si no está), `target` lo que instalarías. Si coincide con `tracks.name`, esa es la versión de la ficha |
43
55
  | `toggle(ctx, payload)` | Sustituye el interruptor por defecto; `confirm: 'texto'` pide confirmación antes de encender |
44
56
  | `onToggle(ctx, enabled)` | Reacciona al interruptor |
@@ -68,7 +80,7 @@ Todas las fichas de MODULES tienen los mismos pisos, en el mismo orden. No dibuj
68
80
  | 4 · Ajustes | lo tuyo: selectores, interruptores, campos | `controls`, y lo que tu módulo lea de sí mismo |
69
81
  | 5 · El interruptor | install, enable o disable. Solo, y siempre abajo | `toggle` / `installCommand` |
70
82
 
71
- El estado es una palabra y un punto —`ON` u `OFF`—, nunca un botón: lo único que se presiona en una ficha es lo de abajo. Un módulo apagado se atenúa entero menos ese botón.
83
+ El estado es una palabra y un punto —`ON` u `OFF`—, nunca un botón: las acciones se presionan abajo. La principal queda al final; un módulo `DEV` también ofrece `DESINSTALAR`, mientras que uno integrado solo puede apagarse. Un módulo apagado se atenúa entero menos esa fila.
72
84
 
73
85
  ## El `ctx`
74
86
 
@@ -95,11 +107,13 @@ ctx = {
95
107
 
96
108
  ## Que lo construya tu IA, en la sala
97
109
 
98
- MADRE es modular y la sala puede construirse a sí misma. En `#2` o más, pídele a un agente: «crea un módulo que lea mis correos y lo prepare para instalar». Su briefing le dice dónde está esta guía y el ejemplo, y la regla: escribe **un solo archivo** llamado `<id>.module.mjs` en su carpeta de borrador. MADRE lo reconoce por el nombre y pone una tarjeta en la sala: `INSTALL FOR EVERY ROOM` o `INSTALL FOR THIS PROJECT`. Léelo, decide, un clic. MADRE lo valida en una copia, lo guarda como `<id>.mjs` en la carpeta que elegiste y aparece en MODULES con la etiqueta `DEV`.
110
+ Escribe `/module <lo que debe hacer>` en el compositor. Es la entrada explícita al flujo guiado: si `#2 CREATE` no está activo, MADRE te pide elegirlo y conserva intacta tu petición. Con `#2` activo, mantiene el agente que elegiste y le entrega el contrato del SDK y el ejemplo. El agente debe escribir **un solo archivo** llamado `<id>.module.mjs` en su carpeta de borrador; no puede instalarlo por su cuenta.
111
+
112
+ MADRE reconoce ese nombre y pone una tarjeta en la sala: `INSTALL FOR EVERY ROOM` o `INSTALL FOR THIS PROJECT`. Léelo, decide, un clic. MADRE lo valida en una copia, lo guarda como `<id>.mjs` en la carpeta que elegiste y aparece en MODULES con la etiqueta `DEV`. También puedes pedir lo mismo en lenguaje natural mientras estés en `#2` o más; `/module` hace explícito el formato y no concede permisos por sí solo.
99
113
 
100
114
  Los agentes nunca escriben en `~/.pulse/modules` ni en `.madre/modules`: proponen, tú instalas.
101
115
 
102
- Un módulo tuyo se quita desde MODULES → tarjeta `</>` → `REMOVE`; borra su archivo. Los módulos que vienen con MADRE no se quitan, se apagan.
116
+ Un módulo tuyo lleva `DEV` y se quita desde su propia tarjeta con `DESINSTALAR` —también aparece en la tarjeta `</>`—. MADRE confirma el archivo exacto, borra ese archivo y su registro de origen para actualizaciones, y lo retira de la sala sin reiniciarla. No borra archivos que el módulo haya creado ni sus ajustes guardados. Los módulos que vienen con MADRE no muestran ese botón: no se quitan, se apagan.
103
117
 
104
118
  ## Lo que un módulo no puede tocar
105
119
 
@@ -6,6 +6,14 @@
6
6
  //
7
7
  // The default export is a plain object: MADRE wraps it with defineModule.
8
8
  // Everything is optional except id and name.
9
+ //
10
+ // A module imports nothing. MADRE loads your file from a scratch folder to check it before
11
+ // installing, and there is no node_modules there: `import … from '@jossuealcala/madre/sdk'`
12
+ // cannot resolve and the install fails. If you need defineModule, export a function and MADRE
13
+ // hands it to you: ({ defineModule }) => defineModule({ … }).
14
+ //
15
+ // MADRE's own modules do write `import { defineModule } from './sdk.mjs'` — they live inside the
16
+ // package. Copying that line from them is the one mistake that looks right and never works.
9
17
 
10
18
  export default {
11
19
  id: 'hello', // kebab-case; also the key under modules in ~/.pulse/config.json (camelCased)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jossuealcala/madre",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "MADRE · one local room where the AI coding agents already on your machine (Codex, Claude Code, Gemini CLI, OpenCode) work on a project together, with a shared memory every one of them recalls and a local @madre that speaks for it. Read-only by default, per-message permission modes up to a checkpointed CONTROL. Nothing leaves your machine on its own.",
5
5
  "keywords": [
6
6
  "ai-agents",