@jossuealcala/madre 0.5.1 → 0.6.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.
Binary file
package/public/es.js CHANGED
@@ -15,6 +15,173 @@ export const ES = {
15
15
  'CREATE encendido: di qué crear. Los archivos nuevos caen donde les toca en el proyecto; nada de lo que ya existe se toca.',
16
16
  'Compact prose. Nothing you write is altered; only the answers get shorter.':
17
17
  'Respuestas compactas. Lo que tú escribes no cambia; lo que se acorta son las respuestas.',
18
+ 'In this room: {on} output tokens is the middle turn with ASH ({onTurns} turns), {off} without it ({offTurns}). You choose when to ask for compact prose, so these are different tasks, not the same task twice.':
19
+ 'En esta sala: {on} tokens de salida es el turno de en medio con ASH ({onTurns} turnos), {off} sin ASH ({offTurns}). Tú decides cuándo pedir prosa compacta, así que son tareas distintas, no la misma tarea dos veces.',
20
+ '{n} uncharged': '{n} no cobrados',
21
+ '{cached} tokens this CLI read back from its own cache instead of charging them again (measured). {unsent} tokens of briefing the room never sent (estimated at {rate} characters per token). Neither is Ash: Ash shortens the answer, and that is the figure above the bubble.':
22
+ '{cached} tokens que este CLI leyó de su propia caché en vez de volver a cobrarlos (medido). {unsent} tokens de briefing que la sala nunca envió (estimado a {rate} caracteres por token). Ninguno de los dos es Ash: Ash acorta la respuesta, y esa cifra está arriba de la burbuja.',
23
+ 'TOKENS SAVED': 'TOKENS AHORRADOS',
24
+ 'input the CLI did not charge again · {pct} of the input': 'entrada que el CLI no volvió a cobrar · {pct} de la entrada',
25
+ 'SPENT IN': 'GASTADO EN ENTRADA',
26
+ 'input tokens actually charged': 'tokens de entrada realmente cobrados',
27
+ '@madre can answer this from the room archive, on this computer, for no tokens · it read {why}':
28
+ '@madre puede contestar esto desde el archivo de la sala, en esta computadora, sin gastar tokens · leyó {why}',
29
+ 'ASK @madre': 'PREGÚNTALE A @madre',
30
+ 'what was decided': 'qué se decidió',
31
+ 'whether this came up before': 'si esto ya había salido',
32
+ 'where the room left off': 'dónde se quedó la sala',
33
+ 'why something was chosen': 'por qué se eligió algo',
34
+ 'what somebody said': 'qué dijo alguien',
35
+ 'what is still open': 'qué sigue abierto',
36
+ 'TURNS THE ROOM ANSWERED ITSELF': 'TURNOS QUE LA SALA CONTESTÓ SOLA',
37
+ 'FREE TURNS': 'TURNOS SIN COSTO',
38
+ 'answered by @madre on this computer · no provider, no bill':
39
+ 'contestados por @madre en esta computadora · sin proveedor, sin factura',
40
+ 'OF EVERY TURN': 'DEL TOTAL',
41
+ 'of the turns weighed in this room': 'de los turnos pesados en esta sala',
42
+ 'A PAID TURN': 'UN TURNO PAGADO',
43
+ 'the middle paid turn here · what the others cost, not what these would have':
44
+ 'el turno pagado de en medio · lo que costaron los otros, no lo que habrían costado estos',
45
+ 'These turns have no bill because nothing left this computer to answer them. MADRE does not say what they would have cost somewhere else: nobody measured that.':
46
+ 'Estos turnos no tienen factura porque nada salió de esta computadora para contestarlos. MADRE no dice cuánto habrían costado en otro lado: eso nadie lo midió.',
47
+ '{pct} shorter with ASH, wider than this agent varies here (±{on} and ±{off})':
48
+ '{pct} más corta con ASH, más que lo que este agente varía aquí (±{on} y ±{off})',
49
+ 'the difference fits inside how much this agent varies anyway (±{on} and ±{off}) · nothing to read yet':
50
+ 'la diferencia cabe dentro de lo que este agente varía de todos modos (±{on} y ±{off}) · todavía no hay nada que leer',
51
+ 'on · agents may ask you to choose': 'encendido · los agentes pueden pedirte que elijas',
52
+ 'off · agents answer in prose': 'apagado · los agentes contestan en prosa',
53
+ 'Lets an agent hand a decision back to you as buttons instead of a paragraph, when the answer turns on three or more real options. Costs about 135 tokens of instruction per turn while it is on, counted in the economy like every other block.':
54
+ 'Deja que un agente te devuelva una decisión como botones en vez de un párrafo, cuando la respuesta depende de tres o más opciones reales. Cuesta unos 135 tokens de instrucción por turno mientras está encendido, contados en la economía como cualquier otro bloque.',
55
+ 'Writes it into the composer · nothing is sent until you press send': 'Lo escribe en el compositor · no se manda nada hasta que le des enviar',
56
+ '◉ decided here · {n}': '◉ decidido aquí · {n}',
57
+ 'TURNS WEIGHED': 'TURNOS PESADOS',
58
+ 'every turn this room has been billed for': 'cada turno por el que cobraron a esta sala',
59
+ 'INPUT CHARGED': 'ENTRADA COBRADA',
60
+ 'tokens the CLIs charged as fresh reading': 'tokens que los CLIs cobraron como lectura nueva',
61
+ 'OUTPUT CHARGED': 'SALIDA COBRADA',
62
+ 'tokens written back · the dearer half': 'tokens escritos de vuelta · la mitad más cara',
63
+ 'read back from a cache, plus what was never sent': 'leído de una caché, más lo que nunca se envió',
64
+ 'CAME FROM CACHE': 'VINO DE CACHÉ',
65
+ 'of everything read, the share nobody charged twice': 'de todo lo leído, la parte que nadie cobró dos veces',
66
+ 'CH PER TOKEN': 'CAR POR TOKEN',
67
+ 'what MADRE wrote against what the CLIs were charged for reading · not a tokenizer':
68
+ 'lo que MADRE escribió contra lo que a los CLIs les cobraron por leer · no es un tokenizador',
69
+ 'AGENT': 'AGENTE',
70
+ 'INPUT': 'ENTRADA',
71
+ 'OUTPUT': 'SALIDA',
72
+ 'CACHE': 'CACHÉ',
73
+ 'CACHED %': '% CACHEADO',
74
+ 'CH / TOKEN': 'CAR / TOKEN',
75
+ '◉ still open here': '◉ sigue abierto aquí',
76
+ 'The room has carried this into {n} turn(s) and still has no answer.':
77
+ 'La sala ha arrastrado esto a {n} turno(s) y sigue sin respuesta.',
78
+ 'The archivist recorded this as open and nothing has answered it.':
79
+ 'El archivista lo registró como abierto y nada lo ha contestado.',
80
+ '@{agent} says this needs #{n} {label}': '@{agent} dice que esto necesita #{n} {label}',
81
+ 'ARM #{n}': 'ARMAR #{n}',
82
+ 'SET #{n}': 'PONER #{n}',
83
+ 'Opens the override: you type the project designation, as always.': 'Abre la anulación: tú escribes la designación del proyecto, como siempre.',
84
+ 'Arms the composer for your next message. Nothing is sent.': 'Arma el compositor para tu siguiente mensaje. No se manda nada.',
85
+ 'SERVERS': 'SERVIDORES',
86
+ 'MADRE version': 'Versión de MADRE',
87
+ 'Local servers answering on this computer': 'Servidores locales que contestan en esta computadora',
88
+ 'COULD NOT READ THE PORTS': 'NO SE PUDIERON LEER LOS PUERTOS',
89
+ 'NOTHING IS ANSWERING ON THIS COMPUTER · START YOUR SERVER AND OPEN THIS AGAIN':
90
+ 'NADA CONTESTA EN ESTA COMPUTADORA · LEVANTA TU SERVIDOR Y ABRE ESTO DE NUEVO',
91
+ 'ONLY WHAT LISTENS ON THIS COMPUTER AND ANSWERS HTTP · MADRE RUNS NOTHING TO FIND THEM':
92
+ 'SOLO LO QUE ESCUCHA EN ESTA COMPUTADORA Y CONTESTA HTTP · MADRE NO EJECUTA NADA PARA ENCONTRARLOS',
93
+ '{what} · refuses to be framed': '{what} · se niega a ser enmarcado',
94
+ 'Resize the browser': 'Cambiar el ancho del navegador',
95
+ 'Crew': 'Tripulación',
96
+ 'Crew · {ready} of {total} ready · {who}': 'Tripulación · {ready} de {total} lista · {who}',
97
+ 'The destination is outside this project.': 'El destino está fuera de este proyecto.',
98
+ 'There is already something at {path}.': 'Ya hay algo en {path}.',
99
+ 'Search files': 'Buscar archivos',
100
+ 'Search files…': 'Buscar archivos…',
101
+ 'Copy': 'Copiar',
102
+ 'Move': 'Mover',
103
+ 'Paste here': 'Pegar aquí',
104
+ 'Paste beside it': 'Pegar al lado',
105
+ 'Rename': 'Renombrar',
106
+ 'New file': 'Archivo nuevo',
107
+ 'New folder': 'Carpeta nueva',
108
+ 'NEW NAME': 'NOMBRE NUEVO',
109
+ 'NEW FILE': 'ARCHIVO NUEVO',
110
+ 'NEW FOLDER': 'CARPETA NUEVA',
111
+ 'PROJECT DESIGNATION': 'DESIGNACIÓN DEL PROYECTO',
112
+ 'OK': 'LISTO',
113
+ 'MOVE': 'MOVER',
114
+ 'That could not be done.': 'Eso no se pudo hacer.',
115
+ 'NOTHING MATCHES {q}': 'NADA COINCIDE CON {q}',
116
+ 'MADRE GUARDS THIS PATH · IT WILL ASK FOR THE DESIGNATION': 'MADRE PROTEGE ESTA RUTA · VA A PEDIR LA DESIGNACIÓN',
117
+ '{path} is a place MADRE guards.': '{path} es un lugar que MADRE protege.',
118
+ '{host} will not be framed': '{host} no se deja enmarcar',
119
+ 'The site answers with a rule that forbids any page from putting it inside a frame. It is the standard defence against clickjacking, and RIPLEY neither can nor should override it.':
120
+ 'El sitio responde con una regla que prohíbe a cualquier página meterlo dentro de un marco. Es la defensa estándar contra el clickjacking, y RIPLEY ni puede ni debe saltársela.',
121
+ 'This server answers with a rule that forbids any page from putting it inside a frame — your own dev server may be setting it without you noticing. RIPLEY neither can nor should override it.':
122
+ 'Este servidor responde con una regla que prohíbe a cualquier página meterlo dentro de un marco — tu propio servidor de desarrollo puede estar poniéndola sin que lo notes. RIPLEY ni puede ni debe saltársela.',
123
+ 'OPEN IN A TAB': 'ABRIR EN UNA PESTAÑA',
124
+ 'COPY THE ADDRESS': 'COPIAR LA DIRECCIÓN',
125
+ 'Address copied.': 'Dirección copiada.',
126
+ 'Browser · local servers and the web': 'Navegador · servidores locales y la web',
127
+ 'Browser': 'Navegador',
128
+ 'RIPLEY browser': 'Navegador de RIPLEY',
129
+ 'new tab': 'pestaña nueva',
130
+ 'New tab': 'Pestaña nueva',
131
+ 'Address': 'Dirección',
132
+ 'Only http and https.': 'Solo http y https.',
133
+ 'That is not an address.': 'Eso no es una dirección.',
134
+ 'RIPLEY reaches this computer only · turn the web on in MODULES to open an address outside it':
135
+ 'RIPLEY solo alcanza esta computadora · enciende la web en MÓDULOS para abrir una dirección fuera de ella',
136
+ 'SEE THE ECONOMY': 'VER LA ECONOMÍA',
137
+ 'ECONOMY': 'ECONOMÍA',
138
+ 'MADRE · WHAT THIS ROOM SPENT AND WHAT IT NEVER SPENT': 'MADRE · LO QUE ESTA SALA GASTÓ Y LO QUE NUNCA GASTÓ',
139
+ 'MEASURED FROM WHAT THE CLIs CHARGED · A SAVING NOBODY MEASURED IS NEVER SHOWN':
140
+ 'MEDIDO SOBRE LO QUE COBRARON LOS CLIs · UN AHORRO QUE NADIE MIDIÓ NO SE MUESTRA NUNCA',
141
+ 'Token economy': 'Economía de tokens',
142
+ 'NEVER CHARGED FOR': 'NUNCA COBRADO',
143
+ 'FROM THE CACHE': 'DE LA CACHÉ',
144
+ 'the CLI said it read these back instead of charging them again · measured':
145
+ 'el CLI dijo que los leyó de vuelta en vez de volver a cobrarlos · medido',
146
+ 'briefing a turn had no use for · estimated from characters, not measured':
147
+ 'briefing que el turno no iba a usar · estimado a partir de caracteres, no medido',
148
+ 'OF THE INPUT': 'DE LA ENTRADA',
149
+ 'the share of everything read that came back from a cache':
150
+ 'la parte de todo lo leído que volvió de una caché',
151
+ 'One half is measured and the other is estimated, and they are never added without saying so. Neither of them is Ash: Ash shortens the answer, which is the next reading.':
152
+ 'Una mitad es medida y la otra estimada, y nunca se suman sin decirlo. Ninguna de las dos es Ash: Ash acorta la respuesta, que es la lectura siguiente.',
153
+ 'ASH ADDS': 'ASH AÑADE',
154
+ 'to every prompt it is on · measured, not estimated': 'a cada prompt donde está encendido · medido, no estimado',
155
+ 'IN TOKENS': 'EN TOKENS',
156
+ 'at {rate} characters per token · an estimate': 'a {rate} caracteres por token · una estimación',
157
+ 'TURNS CARRYING IT': 'TURNOS QUE LO LLEVAN',
158
+ 'of the {n} weighed in this room': 'de los {n} pesados en esta sala',
159
+ 'What Ash costs is certain and measured here. What it saves is not: the shorter answer below is observed, never promised. Output is the dearer half of every bill, so the trade is usually favourable — MADRE does not turn it into money because it does not know your prices.':
160
+ 'Lo que Ash cuesta es seguro y está medido aquí. Lo que ahorra no lo es: la respuesta más corta de abajo se observa, nunca se promete. La salida es la mitad más cara de cualquier factura, así que el cambio suele convenir — MADRE no lo convierte en dinero porque no conoce tus precios.',
161
+ 'WHAT ASH DOES TO AN ANSWER': 'QUÉ LE HACE ASH A UNA RESPUESTA',
162
+ 'No turns with the switch recorded yet. Leave Ash on for a few turns and off for a few more, and this fills.':
163
+ 'Aún no hay turnos con el interruptor registrado. Deja Ash encendido unos turnos y apagado otros tantos, y esto se llena.',
164
+ 'WHERE EACH PROMPT GOES': 'A DÓNDE VA CADA PROMPT',
165
+ '{pct} of each prompt is the unchanging head a cache can match. MADRE wrote {chars} characters of the {input} input tokens you were charged for; the rest is what the CLIs read on their own.':
166
+ '{pct} de cada prompt es la cabecera que no cambia y que una caché puede reconocer. MADRE escribió {chars} caracteres de los {input} tokens de entrada que te cobraron; el resto es lo que los CLIs leyeron por su cuenta.',
167
+ 'BY AGENT': 'POR AGENTE',
168
+ 'with ASH': 'con ASH',
169
+ 'without ASH': 'sin ASH',
170
+ '{n}↑ · {turns} turns': '{n}↑ · {turns} turnos',
171
+ '{n} turns with ASH, {m} without · {min} of each before this can be read':
172
+ '{n} turnos con ASH, {m} sin ASH · hacen falta {min} de cada lado para poder leerlo',
173
+ 'The middle turn of each side, not an average. You choose when to ask for compact prose, so the two sides are different tasks, not the same task twice — MADRE does not claim a percentage saved.':
174
+ 'El turno de en medio de cada lado, no un promedio. Tú decides cuándo pedir prosa compacta, así que los dos lados son tareas distintas y no la misma tarea dos veces: MADRE no afirma un porcentaje ahorrado.',
175
+ 'NEVER CHARGED': 'NUNCA COBRADO',
176
+ 'REVIEW · the local check found: {details}':
177
+ 'REVISAR · la comprobación local encontró: {details}',
178
+ 'empty response': 'respuesta vacía',
179
+ 'unclosed code fence': 'bloque de código sin cerrar',
180
+ 'text after ```pulse block': 'hay texto después del bloque ```pulse',
181
+ 'missing negation': 'falta una negación',
182
+ '{count} {unit}, maximum {maximum}': '{count} {unit}, máximo {maximum}',
183
+ 'lines': 'líneas',
184
+ 'missing {value}': 'falta {value}',
18
185
  'Off the record. Ask anything; nothing is saved, nobody else will remember it.':
19
186
  'Fuera de registro. Pregunta lo que quieras: no se guarda nada y nadie más se va a acordar.',
20
187
  'Control armed. Say what to change in the project; every action runs without asking.':
@@ -82,8 +249,8 @@ export const ES = {
82
249
  'Attach an image or file (or drop it here)': 'Adjunta una imagen o un archivo (o arrástralo aquí)',
83
250
  'Send': 'Enviar',
84
251
  'Agent': 'Agente',
85
- 'Consultation mode · Project writes stay under your control: agents create files only with CREATE or an opt-in standing lease, only inside .pulse/out/ · Content an agent reads may be sent to its configured model provider.':
86
- 'Modo consulta · Tú decides qué se escribe en tu proyecto: los agentes crean archivos solo con CREATE o con un permiso permanente que tú hayas activado, y solo dentro de .pulse/out/ · Lo que un agente lee puede llegar al proveedor de su modelo.',
252
+ 'Consultation mode · Agents write only with CREATE or a standing lease, only inside .pulse/out/ · What an agent reads may reach its configured model provider.':
253
+ 'Modo consulta · Los agentes escriben solo con CREATE o con un permiso permanente, y solo dentro de .pulse/out/ · Lo que un agente lee puede llegar al proveedor de modelo que tenga configurado.',
87
254
 
88
255
  // Quién habla, delante del campo.
89
256
  'HUMAN ›': 'HUMANO ›',
@@ -310,13 +477,13 @@ export const ES = {
310
477
  'a push only when you type /git push confirm, after it shows what would leave':
311
478
  'un push solo cuando escribes /git push confirm, después de enseñarte qué saldría',
312
479
 
313
- 'Asks every agent for compact prose. The rest of the economy is always on: the briefing carries only what a turn can use, what never changes is read first so a cache can match it, and the transcript holds still instead of sliding.':
314
- 'Le pide a cada agente respuestas compactas. El resto de la economía está siempre encendida: el briefing carga solo lo que el turno puede usar, lo que nunca cambia se lee primero para que una caché lo reconozca, y la transcripción se queda quieta en vez de irse recorriendo.',
480
+ 'Asks every agent for compact prose without altering what you write. MADRE shows each turn\'s input, output and cache use; savings depend on the agent, task and cache, so no fixed percentage is promised.':
481
+ 'Pide a cada agente prosa compacta sin alterar lo que escribes. MADRE muestra la entrada, la salida y el uso de caché de cada turno; el ahorro depende del agente, la tarea y el caché, así que no promete un porcentaje fijo.',
315
482
  'nothing in the project': 'nada en el proyecto',
316
483
  'a switch in ~/.pulse/config.json': 'un interruptor en ~/.pulse/config.json',
317
484
 
318
- 'Renders HTML, SVG and Markdown from the project and from .pulse/out in the file viewer, inside a sealed frame.':
319
- 'Dibuja el HTML, el SVG y el Markdown del proyecto y de .pulse/out en el visor de archivos, dentro de un marco sellado.',
485
+ 'Renders HTML, SVG and Markdown from the project in the file viewer, inside a sealed frame, and opens a browser on the servers answering on this computer.':
486
+ 'Renderiza HTML, SVG y Markdown del proyecto en el visor de archivos, dentro de un marco sellado, y abre un navegador sobre los servidores que contestan en esta computadora.',
320
487
  'scripts run in the frame · nothing leaves, nothing is stored, nothing reaches MADRE':
321
488
  'los scripts corren dentro del marco · no sale nada, no se guarda nada, nada llega a MADRE',
322
489
 
@@ -858,7 +1025,7 @@ export const ES = {
858
1025
  ' · {n} existing files put back, CREATE only adds: {files}': ' · {n} archivos que ya existían se restauraron, CREATE solo agrega: {files}',
859
1026
  ' · {n} writes into forbidden zones reverted': ' · {n} escrituras en zonas prohibidas revertidas',
860
1027
  ' · need to change existing files? ask again in #3 CONTROL': ' · ¿necesitas cambiar archivos que ya existen? pídelo otra vez en #3 CONTROL',
861
- 'CONTROL · ': 'CONTROL · ',
1028
+ 'CONTROL': 'CONTROL',
862
1029
  ' holds the project · checkpoint ': ' tiene el proyecto · checkpoint ',
863
1030
  'MU/TH/UR › @{agent} holds CONTROL. Checkpoint taken; UNDO will be one click.':
864
1031
  'MU/TH/UR › @{agent} tiene CONTROL. Checkpoint tomado; DESHACER va a ser un clic.',
@@ -1747,7 +1914,6 @@ export const ES = {
1747
1914
 
1748
1915
  // ── LA SALA EN MOVIMIENTO: PLANES, FRENOS, ADJUNTOS Y AVISOS ─────────────
1749
1916
  'answering @{agent}': 'contestándole a @{agent}',
1750
- ' · {n} saved': ' · {n} ahorrados',
1751
1917
  ' wrote ': ' escribió ',
1752
1918
  'CHECK AGAIN': 'MEDIR OTRA VEZ',
1753
1919
  'CHECK IT AGAINST THIS ROOM': 'MEDIRLO CONTRA ESTA SALA',
@@ -1805,6 +1971,12 @@ export const ES = {
1805
1971
  '/module writes a file, so it needs #2 CREATE. Your request is still in the composer.':
1806
1972
  '/module escribe un archivo, así que necesita #2 CREATE. Tu petición sigue en el compositor.',
1807
1973
  'ARM #2 CREATE': 'ARMAR #2 CREATE',
1974
+ // Lo que un agente puede hacer, dicho dentro de una frase: infinitivo, no el imperativo de
1975
+ // la etiqueta suelta de su ficha. «puede crea» era el botón metido en una oración.
1976
+ 'read the project': 'leer el proyecto',
1977
+ 'take images': 'recibir imágenes',
1978
+ 'generate images': 'generar imágenes',
1979
+ 'reach the web': 'alcanzar la web',
1808
1980
  'the room · local': 'la sala · local',
1809
1981
  '@{agent} may {what}': '@{agent} puede {what}',
1810
1982
  ' (cannot {what})': ' (no puede {what})',
@@ -2030,8 +2202,8 @@ export const ES = {
2030
2202
  'MU/TH/UR › /module needs #2 CREATE. Choose #2 in the mode chip, then send again.':
2031
2203
  'MU/TH/UR › /module necesita #2 CREATE. Elige #2 en el chip de modo y vuelve a enviar.',
2032
2204
  'MU/TH/UR · MODULE · NEEDS #2 ›': 'MU/TH/UR · MODULE · REQUIERE #2 ›',
2033
- 'Create a MADRE module for this request: {request} Write exactly one <id>.module.mjs file for review. Do not install it; MADRE will show the human an install card.':
2034
- 'Crea un módulo de MADRE para esta petición: {request} Escribe exactamente un archivo <id>.module.mjs para revisión. No lo instales; MADRE le mostrará al humano una tarjeta de instalación.',
2205
+ 'Create a MADRE module for this request: {request} Write exactly one <id>.module.mjs file for review. Set vendor to whoever wrote it — the human\'s name or team if you know it, otherwise leave it out; never the word "you". Do not install it; MADRE will show the human an install card.':
2206
+ 'Crea un módulo de MADRE para esta petición: {request} Escribe exactamente un archivo <id>.module.mjs para revisión. Pon en vendor a quien lo escribió —el nombre o el equipo del humano si lo sabes, y si no, déjalo fuera; nunca la palabra «you»—. No lo instales; MADRE le va a mostrar al humano una tarjeta de instalación.',
2035
2207
  'MU/TH/UR › unknown command /{name}. Type "/" to see what this room offers.':
2036
2208
  'MU/TH/UR › comando desconocido /{name}. Escribe «/» para ver lo que ofrece esta sala.',
2037
2209
  '{name} · uploading…': '{name} · subiendo…',
@@ -2091,20 +2263,14 @@ export const ES = {
2091
2263
  'THIS RUNS ON THIS COMPUTER, OUTSIDE THE PROJECT:': 'ESTO CORRE EN ESTA COMPUTADORA, FUERA DEL PROYECTO:',
2092
2264
 
2093
2265
  // La economía de la sala y la ficha de Ollama.
2094
- 'TOKENS SAVED': 'TOKENS AHORRADOS',
2095
2266
  'read back from the CLI cache, plus what was never sent': 'leídos de la caché del CLI, más lo que nunca se mandó',
2096
2267
  'FROM CACHE': 'DE LA CACHÉ',
2097
- 'input the CLI did not charge again · {pct} of the input': 'entrada que el CLI no volvió a cobrar · {pct} de la entrada',
2098
2268
  'NEVER SENT': 'NUNCA SE MANDÓ',
2099
2269
  'briefing a turn had no use for': 'briefing que ese turno no necesitaba',
2100
- 'SPENT IN': 'GASTADO EN ENTRADA',
2101
- 'input tokens actually charged': 'tokens de entrada realmente cobrados',
2102
2270
  'SPENT OUT': 'GASTADO EN SALIDA',
2103
2271
  'output tokens, the dearer half': 'tokens de salida, la mitad más cara',
2104
2272
  'TURNS': 'TURNOS',
2105
2273
  'weighed so far': 'pesados hasta ahora',
2106
- '{pct} OF EACH PROMPT IS THE UNCHANGING HEAD A CACHE CAN MATCH · MADRE WROTE {chars} CHARACTERS OF THE {input} INPUT TOKENS YOU WERE CHARGED FOR; THE REST IS WHAT THE CLIs READ ON THEIR OWN':
2107
- '{pct} DE CADA PROMPT ES LA CABECERA QUE NO CAMBIA Y QUE UNA CACHÉ PUEDE RECONOCER · MADRE ESCRIBIÓ {chars} CARACTERES DE LOS {input} TOKENS DE ENTRADA QUE TE COBRARON; EL RESTO ES LO QUE LOS CLIs LEYERON POR SU CUENTA',
2108
2274
  'SERVER': 'SERVIDOR',
2109
2275
  'running · {host}': 'corriendo · {host}',
2110
2276
  'not running': 'no está corriendo',
package/public/index.html CHANGED
@@ -20,6 +20,10 @@
20
20
  <span id="project" class="project" title="Project room"></span>
21
21
  </div>
22
22
  <div id="agents" class="agents" aria-label="Agents"></div>
23
+ <button id="agents-compact" class="bar-icon agents-compact" type="button" title="Crew" aria-label="Crew">
24
+ <svg viewBox="0 0 20 20" aria-hidden="true"><rect x="3.5" y="6.5" width="13" height="9" rx="3" fill="none" stroke="currentColor" stroke-width="1.6"/><circle cx="7.6" cy="11" r="1.25" fill="currentColor"/><circle cx="12.4" cy="11" r="1.25" fill="currentColor"/><path d="M10 3.4v3.1M6.2 15.5v1.3M13.8 15.5v1.3" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
25
+ <span id="agents-count" class="bar-count"></span>
26
+ </button>
23
27
  <div id="connection" class="connection" data-state="connecting" title="Live updates">
24
28
  <span class="connection-dot"></span><span class="connection-label">connecting</span>
25
29
  </div>
@@ -28,10 +32,10 @@
28
32
  <span class="stop-all-glyph" aria-hidden="true"></span>STOP ALL
29
33
  </button>
30
34
  <button id="modules-button" class="mother-button" type="button" title="Modules · optional integrations for this project" aria-haspopup="dialog">
31
- <span class="mother-glyph modules-glyph" aria-hidden="true"></span>MODULES<span id="modules-count" class="modules-count" hidden></span>
35
+ <span class="mother-glyph modules-glyph" aria-hidden="true"></span><svg class="bar-glyph" viewBox="0 0 20 20" aria-hidden="true"><path d="M8.1 3.2h3.8v1.6a1.5 1.5 0 0 0 3 0V3.2h1.9v3.6h-1.4a1.5 1.5 0 0 0 0 3h1.4v3.6h-3.6v-1.5a1.5 1.5 0 0 0-3 0v1.5H6.8V9.8H5.4a1.5 1.5 0 0 1 0-3h1.4V3.2z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>MODULES<span id="modules-count" class="modules-count" hidden></span>
32
36
  </button>
33
37
  <button id="mother-button" class="mother-button" type="button" title="Troubleshooting · MU/TH/UR" aria-haspopup="dialog">
34
- <span class="mother-glyph" aria-hidden="true"></span>MU/TH/UR<span id="mother-count" class="mother-count" hidden></span>
38
+ <span class="mother-glyph" aria-hidden="true"></span><svg class="bar-glyph" viewBox="0 0 20 20" aria-hidden="true"><path d="M1.8 10h3.4l1.6-4.6 2.6 9.2 2-4.6h1.5l1.3-2.6 1.2 2.6h2.8" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>MU/TH/UR<span id="mother-count" class="mother-count" hidden></span>
35
39
  </button>
36
40
  <button id="lang-button" class="tree-button lang-button" type="button" data-language="es" aria-label="Language">EN</button>
37
41
  <button id="theme-button" class="tree-button theme-button" type="button" title="Theme · auto (follows the system)" data-theme="auto" aria-label="Theme">
@@ -39,6 +43,9 @@
39
43
  <svg class="t-light" viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="3.6" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M10 2.5v2M10 15.5v2M2.5 10h2M15.5 10h2M4.7 4.7l1.4 1.4M13.9 13.9l1.4 1.4M4.7 15.3l1.4-1.4M13.9 6.1l1.4-1.4" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
40
44
  <svg class="t-dark" viewBox="0 0 20 20" aria-hidden="true"><path d="M15.5 12.4A6.5 6.5 0 0 1 7.6 4.5a6.5 6.5 0 1 0 7.9 7.9z" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>
41
45
  </button>
46
+ <button id="browser-button" class="tree-button" type="button" aria-pressed="false" aria-controls="browser" title="Browser · local servers and the web" aria-label="Browser">
47
+ <svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="7.2" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M2.8 10h14.4M10 2.8c1.9 2 2.9 4.5 2.9 7.2s-1 5.2-2.9 7.2c-1.9-2-2.9-4.5-2.9-7.2s1-5.2 2.9-7.2z" fill="none" stroke="currentColor" stroke-width="1.6"/></svg>
48
+ </button>
42
49
  <button id="tree-button" class="tree-button" type="button" title="Project files panel" aria-pressed="false" aria-controls="tree">
43
50
  <svg viewBox="0 0 20 20" aria-hidden="true"><rect x="2.75" y="3.75" width="14.5" height="12.5" rx="2.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.75v12.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M13.8 7h1.6M13.8 9.6h1.6" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity=".7"/></svg>
44
51
  </button>
@@ -65,7 +72,10 @@
65
72
  <span class="tree-title">FILES <span id="tree-root" class="tree-root"></span></span>
66
73
  <button id="tree-close" class="tree-close" type="button" aria-label="Close files">×</button>
67
74
  </header>
75
+ <form id="tree-search" class="tree-search"><input id="tree-q" type="search" spellcheck="false" autocomplete="off" aria-label="Search files" placeholder="Search files…"></form>
76
+ <div id="tree-clip" class="tree-clip" hidden></div>
68
77
  <div id="tree-body" class="tree-body" role="tree"></div>
78
+ <div id="tree-menu" class="tree-menu" role="menu" hidden></div>
69
79
  </aside>
70
80
 
71
81
  <dialog id="core" class="mother core" aria-label="The core">
@@ -84,6 +94,20 @@
84
94
  </div>
85
95
  </dialog>
86
96
 
97
+ <dialog id="economy" class="mother economy" aria-label="Token economy">
98
+ <div class="mother-frame">
99
+ <header class="mother-head">
100
+ <span class="mother-title">ECONOMY</span>
101
+ <span class="mother-sub">MADRE · WHAT THIS ROOM SPENT AND WHAT IT NEVER SPENT</span>
102
+ <span class="mother-actions">
103
+ <button id="economy-close" class="mother-close" type="button">CLOSE ×</button>
104
+ </span>
105
+ </header>
106
+ <section id="economy-body" class="mother-section"></section>
107
+ <footer class="mother-foot">MEASURED FROM WHAT THE CLIs CHARGED · A SAVING NOBODY MEASURED IS NEVER SHOWN</footer>
108
+ </div>
109
+ </dialog>
110
+
87
111
  <dialog id="modules" class="mother modules" aria-label="Modules">
88
112
  <div class="mother-frame">
89
113
  <header class="mother-head">
@@ -134,6 +158,7 @@
134
158
 
135
159
  <main id="messages" class="thread" aria-live="polite">
136
160
  <div id="thread-inner" class="thread-inner">
161
+ <div id="settled" class="settled" hidden></div>
137
162
  <div class="empty">
138
163
  <svg class="empty-mark" viewBox="0 0 72 20" aria-hidden="true">
139
164
  <path class="beat" d="M1 10 H16 L20 10 L23.5 2 L28 18 L32 10 L35 10 L37 6 L39 10 H52" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" pathLength="100"/>
@@ -159,6 +184,8 @@
159
184
  <div id="picker" class="picker" role="radiogroup" aria-label="Agent"></div>
160
185
  <select id="target" aria-label="Agent" class="visually-hidden"></select>
161
186
  <div id="attachments" class="attachments" hidden></div>
187
+ <div id="free-offer" class="free-offer" hidden></div>
188
+ <div id="openq" class="openq" hidden></div>
162
189
  <div class="field">
163
190
  <div id="reply-quote" class="reply-quote" hidden></div>
164
191
  <span id="crew-label" class="crew-label" aria-hidden="true">HUMAN ›</span>
@@ -183,7 +210,8 @@
183
210
  </button>
184
211
  </div>
185
212
  </form>
186
- <p class="safety">Consultation mode · Project writes stay under your control: agents create files only with CREATE or an opt-in standing lease, only inside .pulse/out/ · Content an agent reads may be sent to its configured model provider.</p>
213
+ <p class="safety">Consultation mode · Agents write only with CREATE or a standing lease, only inside .pulse/out/ · What an agent reads may reach its configured model provider.</p>
214
+ <small id="colophon" class="colophon" aria-label="MADRE version"></small>
187
215
  <div id="toast" class="toast" role="status" hidden></div>
188
216
  <div id="agent-pop" class="agent-pop" role="dialog" aria-label="Agent usage" hidden></div>
189
217
  <dialog id="override" class="mother override" aria-label="Emergency command override">
@@ -298,6 +326,23 @@
298
326
  <p id="nostromo-empty" class="nostromo-empty" hidden>NO MEMORIES YET. THE ARCHIVIST WRITES THE FIRST ONES AFTER A FEW EXCHANGES.</p>
299
327
  </div>
300
328
  </dialog>
329
+ <aside id="browser" class="browser-dock" aria-label="Browser" hidden>
330
+ <div id="browser-grip" class="dock-grip" role="separator" aria-orientation="vertical" aria-label="Resize the browser"></div>
331
+ <header class="viewer-head browser-head">
332
+ <span class="viewer-nav" id="browser-nav">
333
+ <button id="browser-back" class="nav" type="button" title="Back" aria-label="Back" disabled>‹</button>
334
+ <button id="browser-reload" class="nav" type="button" title="Reload" aria-label="Reload">↻</button>
335
+ <button id="browser-servers" class="nav ports" type="button" aria-expanded="false" aria-haspopup="menu" title="Local servers answering on this computer"><i class="ports-dot" aria-hidden="true"></i><span>SERVERS</span><i class="ports-caret" aria-hidden="true"></i></button>
336
+ </span>
337
+ <div id="browser-ports-menu" class="ports-menu" role="menu" hidden></div>
338
+ <span id="browser-where" class="browser-where"></span>
339
+ <span id="browser-sizes" class="viewer-sizes"></span>
340
+ <button id="browser-close" class="mother-close" type="button">CLOSE ×</button>
341
+ </header>
342
+ <div id="browser-tabs" class="browser-tabs" role="tablist"></div>
343
+ <div id="browser-body" class="viewer-body browsing"></div>
344
+ </aside>
345
+
301
346
  <dialog id="viewer" class="viewer" aria-label="File viewer">
302
347
  <header class="viewer-head">
303
348
  <span class="viewer-nav" id="viewer-nav" hidden>
@@ -0,0 +1,74 @@
1
+ // Which questions the room can answer without paying for them.
2
+ //
3
+ // @madre runs on Ollama, on this computer. A turn it answers costs nothing: no input tokens, no
4
+ // output tokens, no provider. Measured against the paid CLIs on the same five questions, the
5
+ // room's own bill for those turns is exactly zero, so the saving here is not an estimate or a
6
+ // comparison — it is the absence of a charge.
7
+ //
8
+ // What this file does NOT do: decide. It recognises a shape of question that the room's own
9
+ // archive is the right place to answer, and says so. Sending it anywhere is the human's, always.
10
+ // A wrong guess costs a click; a guess acted on without asking would cost trust.
11
+
12
+ // The shape: a question about what this room already said, decided or left open. Not "how does
13
+ // X work" — that needs the project read, which is what the paid agents are for.
14
+ const PATTERNS = [
15
+ // Spanish
16
+ { re: /\b(qu[eé]|cu[aá]l(es)?)\s+(hab[ií]amos\s+)?(decidimos|decidido|acordamos|acordado|quedamos|concluimos)\b/i, why: 'decision' },
17
+ { re: /\b(ya|alguna vez)\s+(hab[ií]amos\s+)?(hablamos|hablado|discutimos|discutido|vimos|visto|tratamos)\b/i, why: 'discussed' },
18
+ { re: /\b(d[oó]nde|en qu[eé] punto)\s+(nos\s+)?(quedamos|qued[oó]|dejamos)\b/i, why: 'where' },
19
+ { re: /\bpor\s+qu[eé]\s+(elegimos|escogimos|decidimos|usamos|optamos)\b/i, why: 'why' },
20
+ { re: /\b(qu[eé]\s+)?(dijo|dijimos|dije)\s+\S+\s+(sobre|de|acerca)\b/i, why: 'said' },
21
+ { re: /\bqu[eé]\s+(qued[oó]|quedaba)\s+pendiente\b/i, why: 'open' },
22
+ // English
23
+ { re: /\bwhat\s+(did|have)\s+we\s+(decide|decided|agree|agreed|conclude|concluded)\b/i, why: 'decision' },
24
+ { re: /\b(did|have)\s+we\s+(ever\s+)?(discuss|discussed|talk|talked|cover|covered)\b/i, why: 'discussed' },
25
+ { re: /\bwhere\s+(did\s+we|do\s+we)\s+(leave|left|stand)\b/i, why: 'where' },
26
+ { re: /\bwhy\s+(did\s+we|do\s+we)\s+(choose|chose|pick|picked|use|go with)\b/i, why: 'why' },
27
+ { re: /\bwhat\s+(did|does)\s+\S+\s+say\s+about\b/i, why: 'said' },
28
+ { re: /\bwhat('s| is| was)\s+(still\s+)?(open|pending|unresolved)\b/i, why: 'open' },
29
+ ];
30
+
31
+ // A question aimed at the archive rather than at the project. Returns the reason it matched, or
32
+ // null: a caller that cannot say WHY it is suggesting something should not suggest it.
33
+ export function archiveQuestion(text = '') {
34
+ const question = String(text ?? '').trim();
35
+ if (question.length < 8 || question.length > 400) return null;
36
+ // An explicit address wins over any guess: the human already chose who answers.
37
+ if (/(^|\s)@[a-z0-9_-]+/i.test(question)) return null;
38
+ // A request to do something is not a question about what was said, however it is worded.
39
+ if (/\b(crea|escribe|implementa|arregla|corre|ejecuta|borra|create|write|implement|fix|run|delete|refactor)\b/i.test(question)) return null;
40
+ for (const pattern of PATTERNS) if (pattern.re.test(question)) return pattern.why;
41
+ return null;
42
+ }
43
+
44
+ // An agent saying, in prose, that it cannot do this at the mode it was given.
45
+ //
46
+ // The room could only ever ask for one escalation: a plan step that wants #2 (room.mjs calls
47
+ // askForMode with the number written in). An agent in a direct turn that needs #3 has no channel
48
+ // at all — it can only say so in a sentence and hope the human reads it, leaves the message, and
49
+ // finds the mode selector. That gap is what a real session turned into a loop: the human granted
50
+ // #2 twice while the reply kept saying the fix was editing a file that already exists, which is
51
+ // #3, and the turn went nowhere until they worked it out themselves.
52
+ //
53
+ // So this reads the reply. It is a heuristic and it is narrow on purpose: a bare "#3" is not
54
+ // enough, because an agent explaining the ladder mentions every rung. There has to be a word of
55
+ // need beside it, and the mode has to be above the one the turn actually ran at.
56
+ //
57
+ // It costs nothing in any prompt. And it never grants: #3 and #4 still open the ceremony where
58
+ // the human types the project designation, exactly as if they had chosen it themselves.
59
+ const NEEDS = /(necesit|requier|hace falta|no alcanza|insuficiente|permiso|conced|eleva|sub[ei]r|needs?|requires?|not enough|insufficient|permission|grant|raise|escalat)/i;
60
+
61
+ export function modeAsked(text = '', { ran = 1 } = {}) {
62
+ const reply = String(text ?? '');
63
+ if (reply.length > 8000) return null;
64
+ let wanted = null;
65
+ for (const match of reply.matchAll(/#([2-4])\b/g)) {
66
+ const mode = Number(match[1]);
67
+ if (mode <= ran) continue;
68
+ // The word of need has to sit beside the number, not anywhere in a long answer.
69
+ const around = reply.slice(Math.max(0, match.index - 90), match.index + 90);
70
+ if (!NEEDS.test(around)) continue;
71
+ if (wanted === null || mode > wanted) wanted = mode;
72
+ }
73
+ return wanted;
74
+ }