@jossuealcala/madre 0.4.0 → 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 +164 -0
- package/README.md +1 -1
- package/docs/REFERENCE.md +3 -2
- package/docs/SDK.md +19 -5
- package/docs/sdk/hello-module.mjs +8 -0
- package/package.json +1 -1
- package/public/app.js +414 -64
- package/public/es.js +246 -5
- package/public/index.html +4 -2
- package/public/styles.css +122 -14
- package/public/syntax.js +121 -0
- package/public/troubleshooting.js +100 -0
- package/src/adapters/codex.mjs +4 -1
- package/src/adapters/process.mjs +62 -15
- package/src/mcp/image-server.mjs +24 -2
- package/src/modules/image-studio.mjs +3 -2
- package/src/modules/index.mjs +23 -5
- package/src/modules/playwright.mjs +9 -5
- package/src/modules/sdk.mjs +15 -0
- package/src/outbound.mjs +7 -2
- package/src/room.mjs +12 -0
- package/src/runtime-detection.mjs +50 -0
- package/src/sentinel-errors.mjs +19 -1
- package/src/server.mjs +23 -12
- package/src/updates.mjs +9 -1
package/public/es.js
CHANGED
|
@@ -64,6 +64,8 @@ export const ES = {
|
|
|
64
64
|
'NO ADAPTER': 'SIN ADAPTADOR',
|
|
65
65
|
'READY': 'LISTO',
|
|
66
66
|
'SIGNED OUT': 'SIN SESIÓN',
|
|
67
|
+
'ROUTE BLOCKED': 'RUTA BLOQUEADA',
|
|
68
|
+
'route: {destination}': 'ruta: {destination}',
|
|
67
69
|
'Not on this computer.': 'No lo tienes instalado.',
|
|
68
70
|
'Not on this computer · {command}': 'No lo tienes instalado · {command}',
|
|
69
71
|
'version unknown': 'versión desconocida',
|
|
@@ -295,8 +297,9 @@ export const ES = {
|
|
|
295
297
|
'an entry in ~/.pulse/config.json': 'una entrada en ~/.pulse/config.json',
|
|
296
298
|
'an MCP server per turn, started and stopped by the room':
|
|
297
299
|
'un servidor MCP por turno, que la sala levanta y apaga',
|
|
300
|
+
// Bajo NECESITA es un requisito, no una acción: «necesita: se engancha» no concuerda.
|
|
298
301
|
'attached only inside a creation lease with the image scope on':
|
|
299
|
-
'
|
|
302
|
+
'un permiso de creación con el alcance de imagen encendido; solo ahí se engancha',
|
|
300
303
|
'a Gemini API key with credits (the one the Gemini CLI stores, or GEMINI_API_KEY)':
|
|
301
304
|
'una API key de Gemini con créditos (la que guarda el CLI de Gemini, o GEMINI_API_KEY)',
|
|
302
305
|
|
|
@@ -728,6 +731,8 @@ export const ES = {
|
|
|
728
731
|
'Load your module files again without restarting the room': 'Vuelve a cargar tus archivos de módulo sin reiniciar la sala',
|
|
729
732
|
'YOURS · ': 'TUYOS · ',
|
|
730
733
|
'REMOVE': 'QUITAR',
|
|
734
|
+
'UNINSTALL': 'DESINSTALAR',
|
|
735
|
+
'Delete module file {file}': 'Borrar el archivo del módulo {file}',
|
|
731
736
|
'DID NOT LOAD · ': 'NO CARGÓ · ',
|
|
732
737
|
'connections › ': 'conexiones › ',
|
|
733
738
|
'HELP': 'AYUDA',
|
|
@@ -901,7 +906,7 @@ export const ES = {
|
|
|
901
906
|
'loading…': 'cargando…',
|
|
902
907
|
'select & copy': 'selecciona y copia',
|
|
903
908
|
'to ': 'para ',
|
|
904
|
-
'memory ·
|
|
909
|
+
'memory · never writes': 'memoria · nunca escribe',
|
|
905
910
|
'Choose the model for this agent': 'Elige el modelo de este agente',
|
|
906
911
|
'loading models…': 'cargando modelos…',
|
|
907
912
|
'other model name…': 'otro nombre de modelo…',
|
|
@@ -1619,12 +1624,13 @@ export const ES = {
|
|
|
1619
1624
|
// ── EL COMPOSITOR, LOS MODOS Y LA ANULACIÓN ──────────────────────────────
|
|
1620
1625
|
'Arm CREATE for this message: the agent may add new files to the project where they belong.':
|
|
1621
1626
|
'Arma CREATE para este mensaje: el agente puede agregar archivos nuevos donde les toque en el proyecto.',
|
|
1627
|
+
'Build one MADRE module with the guided SDK flow: the agent writes it, then you review and install it.':
|
|
1628
|
+
'Construye un módulo de MADRE con el flujo guiado del SDK: el agente lo escribe y después tú lo revisas e instalas.',
|
|
1622
1629
|
'Image': 'Imagen',
|
|
1623
1630
|
'Ask for an image: arms CREATE with the image scope and routes to an agent that can generate images.':
|
|
1624
1631
|
'Pide una imagen: arma CREATE con el alcance de imagen y la manda a un agente que sepa generarlas.',
|
|
1625
1632
|
'Master brake: halt every plan and turn in flight. Never reaches an agent.':
|
|
1626
1633
|
'Freno maestro: detiene todos los planes y turnos en vuelo. Nunca llega a un agente.',
|
|
1627
|
-
'REVIEW {what} WITH': 'REVISAR {what} CON',
|
|
1628
1634
|
'RIPLEY can render this file. ': 'RIPLEY puede dibujar este archivo. ',
|
|
1629
1635
|
'RIPLEY preview of {path}': 'Vista previa de RIPLEY de {path}',
|
|
1630
1636
|
'Show the file as text': 'Ver el archivo como texto',
|
|
@@ -1633,7 +1639,7 @@ export const ES = {
|
|
|
1633
1639
|
'Permission mode for this message · {hint}': 'Modo de permiso de este mensaje · {hint}',
|
|
1634
1640
|
'default model ▾': 'modelo por defecto ▾',
|
|
1635
1641
|
' · model for this request': ' · modelo para esta petición',
|
|
1636
|
-
' ·
|
|
1642
|
+
' · ceiling #{cap}': ' · techo #{cap}',
|
|
1637
1643
|
'NOW': 'AHORA',
|
|
1638
1644
|
'RAISE TO #{n} ›': 'SUBIR A #{n} ›',
|
|
1639
1645
|
'LOCKED': 'BLOQUEADO',
|
|
@@ -1758,7 +1764,235 @@ export const ES = {
|
|
|
1758
1764
|
'DENIED · NO ANSWER IN TIME': 'NEGADO · NO HUBO RESPUESTA A TIEMPO',
|
|
1759
1765
|
'PLAN STOPPED': 'PLAN DETENIDO',
|
|
1760
1766
|
'DENIED': 'NEGADO',
|
|
1761
|
-
'created · {n} files': 'creados · {n}
|
|
1767
|
+
'created · {n} {files}': 'creados · {n} {files}',
|
|
1768
|
+
'file': 'archivo',
|
|
1769
|
+
'files': 'archivos',
|
|
1770
|
+
// La severidad de una condición de MU/TH/UR. En mayúsculas porque así se lee la ficha, y
|
|
1771
|
+
// porque así no choca con 'warning' en minúsculas, que es el nivel de una cuota.
|
|
1772
|
+
'BLOCKING': 'BLOQUEANTE',
|
|
1773
|
+
'COMMON': 'COMÚN',
|
|
1774
|
+
'DEGRADED': 'DEGRADADA',
|
|
1775
|
+
'ALREADY FIXED': 'RESUELTA',
|
|
1776
|
+
'INFORMATIONAL': 'INFORMATIVA',
|
|
1777
|
+
'TRANSIENT': 'PASAJERA',
|
|
1778
|
+
'TUNABLE': 'AJUSTABLE',
|
|
1779
|
+
'WARNING': 'AVISO',
|
|
1780
|
+
'a note its own sources do not support': 'una nota que sus propias fuentes no sostienen',
|
|
1781
|
+
|
|
1782
|
+
// ── DOS CONDICIONES QUE REPORTÓ QUIEN LA USA ──────────────────────────────
|
|
1783
|
+
'ANTHROPIC_API_KEY takes precedence over the claude.ai plan':
|
|
1784
|
+
'ANTHROPIC_API_KEY gana sobre el plan de claude.ai',
|
|
1785
|
+
'Claude Code found an API key in the environment as well as the claude.ai login, and the key wins. MADRE hands the CLI the environment exactly as this machine has it, so whatever is exported in your shell profile reaches it. The turn is billed to the API account, not to the plan, and your organisation connectors do not load.':
|
|
1786
|
+
'Claude Code encontró en el entorno una llave de API además del inicio de sesión de claude.ai, y gana la llave. MADRE le entrega al CLI el entorno tal como lo tiene esta computadora, así que lo que esté exportado en el perfil de tu shell le llega. El turno se le cobra a la cuenta de API, no al plan, y los conectores de tu organización no cargan.',
|
|
1787
|
+
'Decide which one you mean. To work on the plan, unset the key where your shell exports it and open the room again; to work on the API, this message is only a notice and can be ignored.':
|
|
1788
|
+
'Decide cuál quieres. Para trabajar con el plan, quita la llave de donde tu shell la exporta y vuelve a abrir la sala; para trabajar con la API, este mensaje es solo un aviso y se puede ignorar.',
|
|
1789
|
+
'The agent is pointed at a custom endpoint': 'El agente apunta a un endpoint personalizado',
|
|
1790
|
+
'The installed CLI inherited a base-URL override from this computer, so its request was going to another gateway instead of the official agent service. A demand to join a Telegram channel comes from that gateway, not from MADRE, Anthropic or OpenAI. MADRE now names that route and stops before sending the briefing.':
|
|
1791
|
+
'El CLI instalado heredó de esta computadora una dirección base distinta, así que su solicitud iba a otro gateway y no al servicio oficial del agente. La exigencia de unirse a un canal de Telegram viene de ese gateway, no de MADRE, Anthropic ni OpenAI. MADRE ahora nombra esa ruta y se detiene antes de enviar el briefing.',
|
|
1792
|
+
'Do not subscribe or enter credentials. Remove the base-URL override and reopen MADRE to use the official service. If the gateway is intentional and you have verified who operates it, explicitly allow only that agent.':
|
|
1793
|
+
'No te suscribas ni ingreses credenciales. Quita la dirección base modificada y vuelve a abrir MADRE para usar el servicio oficial. Si el gateway es intencional y verificaste quién lo opera, autoriza explícitamente solo a ese agente.',
|
|
1794
|
+
// La condición que declara el módulo PLAYWRIGHT. Las de los módulos viven en su archivo, no
|
|
1795
|
+
// en troubleshooting.js, y por eso se quedaron fuera del catálogo hasta ahora.
|
|
1796
|
+
'PLAYWRIGHT: the browser server is not installed': 'PLAYWRIGHT: el servidor de navegador no está instalado',
|
|
1797
|
+
'The PLAYWRIGHT module runs @playwright/mcp per turn. Two different things have to be on this computer and only one of them is the package: the server, and the browser build that this version of it expects. A server that starts without its browser answers every tool call with "Browser … is not installed", and one that cannot start at all reaches the agent as CONNECTION_CLOSED.':
|
|
1798
|
+
'El módulo PLAYWRIGHT corre @playwright/mcp en cada turno. Tienen que estar en esta computadora dos cosas distintas y solo una es el paquete: el servidor, y la versión de navegador que esa versión del servidor espera. Un servidor que arranca sin su navegador contesta a cada herramienta con «Browser … is not installed», y uno que no logra arrancar le llega al agente como CONNECTION_CLOSED.',
|
|
1799
|
+
'Install the server once, globally, then its browser — the browser is downloaded by the server itself, not by the playwright CLI — and RECHECK in MODULES.':
|
|
1800
|
+
'Instala el servidor una vez, global, y después su navegador —lo baja el servidor mismo, no el CLI de playwright— y dale RE-REVISAR en MÓDULOS.',
|
|
1801
|
+
// El registro de errores: un código que se dicta por teléfono, y una salida por fila.
|
|
1802
|
+
'SHOW THE {n} DISMISSED': 'VER LOS {n} DESCARTADOS',
|
|
1803
|
+
'DISMISS ALL {n}': 'DESCARTAR LOS {n}',
|
|
1804
|
+
'DOWNLOAD THE LOG': 'DESCARGAR EL REGISTRO',
|
|
1805
|
+
'/module writes a file, so it needs #2 CREATE. Your request is still in the composer.':
|
|
1806
|
+
'/module escribe un archivo, así que necesita #2 CREATE. Tu petición sigue en el compositor.',
|
|
1807
|
+
'ARM #2 CREATE': 'ARMAR #2 CREATE',
|
|
1808
|
+
'review it with': 'revisarlo con',
|
|
1809
|
+
'no session': 'sin sesión',
|
|
1810
|
+
'CLICK A LINE NUMBER TO SELECT · SHIFT FOR A RANGE':
|
|
1811
|
+
'CLIC EN UN NÚMERO DE LÍNEA PARA SELECCIONAR · SHIFT PARA UN RANGO',
|
|
1812
|
+
'{agent} wrote this file in this room': '{agent} escribió este archivo en esta sala',
|
|
1813
|
+
'MU/TH/UR › {name} declares {fields}, which this MADRE does not know. A typo, or a field from a newer version.':
|
|
1814
|
+
'MU/TH/UR › {name} declara {fields}, que esta MADRE no conoce. O es un dedazo, o es un campo de una versión más nueva.',
|
|
1815
|
+
'OR ON MADRE.RUN ↗': 'O EN MADRE.RUN ↗',
|
|
1816
|
+
'✎ REPORT ON MADRE.RUN ↗': '✎ REPORTAR EN MADRE.RUN ↗',
|
|
1817
|
+
'OPEN ⚙ CONNECTIONS · @{agent}': 'ABRIR ⚙ CONEXIONES · @{agent}',
|
|
1818
|
+
'OPEN ⚙ CONNECTIONS': 'ABRIR ⚙ CONEXIONES',
|
|
1819
|
+
// ── LA PROSA DENTRO DE LOS REMEDIOS ──────────────────────────────────────
|
|
1820
|
+
// Un comando no se traduce nunca. Un comentario sí: es prosa que alguien lee, y la
|
|
1821
|
+
// mitad nombra botones que en esta sala se llaman de otra manera.
|
|
1822
|
+
'# remove or comment the line it finds, then:':
|
|
1823
|
+
'# borra o comenta la línea que encuentre, y luego:',
|
|
1824
|
+
'# and start MADRE from a new terminal':
|
|
1825
|
+
'# y arranca MADRE desde una terminal nueva',
|
|
1826
|
+
'# remove that export from ~/.zshrc, ~/.zprofile or ~/.zshenv; then:':
|
|
1827
|
+
'# quita esa exportación de ~/.zshrc, ~/.zprofile o ~/.zshenv; después:',
|
|
1828
|
+
'# remove that export from ~/.bashrc, ~/.profile or ~/.bash_profile; then:':
|
|
1829
|
+
'# quita esa exportación de ~/.bashrc, ~/.profile o ~/.bash_profile; después:',
|
|
1830
|
+
'# open a new room; only for a gateway you verified:':
|
|
1831
|
+
'# abre una sala nueva; solo para un gateway que sí verificaste:',
|
|
1832
|
+
'# inside gemini: /auth → "Use Gemini API key" and paste the key from https://aistudio.google.com/app/apikey':
|
|
1833
|
+
'# dentro de gemini: /auth → "Use Gemini API key" y pega la llave de https://aistudio.google.com/app/apikey',
|
|
1834
|
+
'# or, without the prompt:':
|
|
1835
|
+
'# o, sin el diálogo:',
|
|
1836
|
+
'# persist: echo \'export GEMINI_API_KEY="YOUR_KEY"\' >> ~/.zshrc':
|
|
1837
|
+
'# para que quede: echo \'export GEMINI_API_KEY="TU_LLAVE"\' >> ~/.zshrc',
|
|
1838
|
+
'# inside gemini: /auth → "Use Gemini API key"':
|
|
1839
|
+
'# dentro de gemini: /auth → "Use Gemini API key"',
|
|
1840
|
+
'# persist: echo \'export GEMINI_API_KEY="YOUR_KEY"\' >> ~/.bashrc':
|
|
1841
|
+
'# para que quede: echo \'export GEMINI_API_KEY="TU_LLAVE"\' >> ~/.bashrc',
|
|
1842
|
+
'# billing: https://ai.studio/projects':
|
|
1843
|
+
'# facturación: https://ai.studio/projects',
|
|
1844
|
+
'# check the key still works:':
|
|
1845
|
+
'# comprueba que la llave siga sirviendo:',
|
|
1846
|
+
'# in the room: click the Gemini sphere twice → choose gemini-3-flash-preview':
|
|
1847
|
+
'# en la sala: doble clic en la esfera de Gemini → elige gemini-3-flash-preview',
|
|
1848
|
+
'# check quota: https://aistudio.google.com/app/apikey':
|
|
1849
|
+
'# revisa la cuota: https://aistudio.google.com/app/apikey',
|
|
1850
|
+
'# quota: https://aistudio.google.com/app/apikey':
|
|
1851
|
+
'# cuota: https://aistudio.google.com/app/apikey',
|
|
1852
|
+
'# wait, then resend — or continue with @codex / @claude / @opencode':
|
|
1853
|
+
'# espera y reenvía — o sigue con @codex / @claude / @opencode',
|
|
1854
|
+
'# press [m] and pick a provider/model that has a session, e.g. openai/gpt-5.6-sol':
|
|
1855
|
+
'# presiona [m] y elige un proveedor/modelo con sesión, por ejemplo openai/gpt-5.6-sol',
|
|
1856
|
+
'# one-off alternative:':
|
|
1857
|
+
'# alternativa de una sola vez:',
|
|
1858
|
+
'# or drop the stale key:':
|
|
1859
|
+
'# o tira la llave vencida:',
|
|
1860
|
+
'# press [m] and pick a provider/model that has a session':
|
|
1861
|
+
'# presiona [m] y elige un proveedor/modelo con sesión',
|
|
1862
|
+
'# or directly:':
|
|
1863
|
+
'# o directo:',
|
|
1864
|
+
'# pick the agent you want; see per-agent commands below':
|
|
1865
|
+
'# elige el agente que quieras; abajo están los comandos de cada uno',
|
|
1866
|
+
'# live, no restart: ⚙ CONNECTIONS → DEFAULT TIMEOUT · SECONDS → SAVE':
|
|
1867
|
+
'# en vivo, sin reiniciar: ⚙ CONEXIONES → TIEMPO LÍMITE POR DEFECTO · SEGUNDOS → GUARDAR',
|
|
1868
|
+
'# at launch only (env wins over config.json):':
|
|
1869
|
+
'# solo al arrancar (el entorno gana sobre config.json):',
|
|
1870
|
+
'# or ~/.pulse/config.json → {"timeouts":{"default":300000,"claude":600000}}':
|
|
1871
|
+
'# o ~/.pulse/config.json → {"timeouts":{"default":300000,"claude":600000}}',
|
|
1872
|
+
'# resend the question':
|
|
1873
|
+
'# reenvía la pregunta',
|
|
1874
|
+
'# click the sphere → 5h / 7d windows and reset times':
|
|
1875
|
+
'# clic en la esfera → ventanas de 5 h / 7 d y a qué hora se reinician',
|
|
1876
|
+
'# live: ⚙ CONNECTIONS → LOCAL TOKEN BUDGET PER AGENT → SAVE':
|
|
1877
|
+
'# en vivo: ⚙ CONEXIONES → PRESUPUESTO LOCAL DE TOKENS POR AGENTE → GUARDAR',
|
|
1878
|
+
'# at launch: PULSE_SOFT_TOKEN_BUDGET=1000000 madre start':
|
|
1879
|
+
'# al arrancar: PULSE_SOFT_TOKEN_BUDGET=1000000 madre start',
|
|
1880
|
+
'# or ~/.pulse/config.json → {"room":{"softTokenBudget":1000000}}':
|
|
1881
|
+
'# o ~/.pulse/config.json → {"room":{"softTokenBudget":1000000}}',
|
|
1882
|
+
'# who holds 4317?':
|
|
1883
|
+
'# ¿quién tiene tomado el 4317?',
|
|
1884
|
+
'# in the room: type STOPALL, then resend':
|
|
1885
|
+
'# en la sala: escribe STOPALL y reenvía',
|
|
1886
|
+
'# in the room composer:':
|
|
1887
|
+
'# en el compositor de la sala:',
|
|
1888
|
+
'# or from a terminal:':
|
|
1889
|
+
'# o desde una terminal:',
|
|
1890
|
+
'# MODULES → Image Studio → ENABLE':
|
|
1891
|
+
'# MÓDULOS → Image Studio → ENCENDER',
|
|
1892
|
+
'# ⚙ CONNECTIONS → Gemini → GENERATE IMAGES → SAVE':
|
|
1893
|
+
'# ⚙ CONEXIONES → Gemini → GENERA IMÁGENES → GUARDAR',
|
|
1894
|
+
'# then: CREATE + "generate … as name.png"':
|
|
1895
|
+
'# después: CREATE + "genera … como nombre.png"',
|
|
1896
|
+
'# ⚙ CONNECTIONS → Claude → GENERATE IMAGES → SAVE':
|
|
1897
|
+
'# ⚙ CONEXIONES → Claude → GENERA IMÁGENES → GUARDAR',
|
|
1898
|
+
'# ⚙ CONNECTIONS → OpenCode → GENERATE IMAGES → SAVE':
|
|
1899
|
+
'# ⚙ CONEXIONES → OpenCode → GENERA IMÁGENES → GUARDAR',
|
|
1900
|
+
'# ⚙ CONNECTIONS → agent card → WEB ACCESS → SAVE':
|
|
1901
|
+
'# ⚙ CONEXIONES → ficha del agente → ACCESO WEB → GUARDAR',
|
|
1902
|
+
'# type / or @ in the field box':
|
|
1903
|
+
'# escribe / o @ en el campo',
|
|
1904
|
+
'# chip: TO @codex #1 EXCHANGE ▾ → choose':
|
|
1905
|
+
'# el chip: PARA @codex #1 EXCHANGE ▾ → elige',
|
|
1906
|
+
'# ⚙ CONNECTIONS → agent card → MAX MODE':
|
|
1907
|
+
'# ⚙ CONEXIONES → ficha del agente → MODO MÁXIMO',
|
|
1908
|
+
'# once: composer → CREATE (lock) → send, or /create <request>':
|
|
1909
|
+
'# una vez: compositor → CREATE (candado) → enviar, o /create <petición>',
|
|
1910
|
+
'# always: ⚙ CONNECTIONS → agent card → DEFAULT MODE → #2':
|
|
1911
|
+
'# siempre: ⚙ CONEXIONES → ficha del agente → MODO POR DEFECTO → #2',
|
|
1912
|
+
'# ⚙ CONNECTIONS → agent card → CREATE FILES → SAVE':
|
|
1913
|
+
'# ⚙ CONEXIONES → ficha del agente → CREAR ARCHIVOS → GUARDAR',
|
|
1914
|
+
'# composer → CREATE (lock) → send':
|
|
1915
|
+
'# compositor → CREATE (candado) → enviar',
|
|
1916
|
+
'# or: nvm install --lts':
|
|
1917
|
+
'# o: nvm install --lts',
|
|
1918
|
+
'# or your distro package for Node ≥ 22.5':
|
|
1919
|
+
'# o el paquete de tu distribución para Node ≥ 22.5',
|
|
1920
|
+
'# more recall per turn':
|
|
1921
|
+
'# más recuerdo por turno',
|
|
1922
|
+
'# persist: echo \'export PULSE_RECALL_SHARE="0.45"\' >> ~/.zshrc':
|
|
1923
|
+
'# para que quede: echo \'export PULSE_RECALL_SHARE="0.45"\' >> ~/.zshrc',
|
|
1924
|
+
'# off':
|
|
1925
|
+
'# apagado',
|
|
1926
|
+
'# persist: echo \'export PULSE_DISTILL_AGENT="claude"\' >> ~/.zshrc':
|
|
1927
|
+
'# para que quede: echo \'export PULSE_DISTILL_AGENT="claude"\' >> ~/.zshrc',
|
|
1928
|
+
'# persist: echo \'export PULSE_DISTILL_EVERY="6"\' >> ~/.zshrc':
|
|
1929
|
+
'# para que quede: echo \'export PULSE_DISTILL_EVERY="6"\' >> ~/.zshrc',
|
|
1930
|
+
'# then: MU/TH/UR → ◉ NOSTROMO':
|
|
1931
|
+
'# después: MU/TH/UR → ◉ NOSTROMO',
|
|
1932
|
+
'# MU/TH/UR → ◉ NOSTROMO → designation = project folder name':
|
|
1933
|
+
'# MU/TH/UR → ◉ NOSTROMO → la designación es el nombre de la carpeta del proyecto',
|
|
1934
|
+
'# MODULES → RIPLEY → ENABLE RIPLEY':
|
|
1935
|
+
'# MÓDULOS → RIPLEY → ENCENDER RIPLEY',
|
|
1936
|
+
'# viewer → PREVIEW / SOURCE':
|
|
1937
|
+
'# el visor → PREVIEW / SOURCE',
|
|
1938
|
+
'# MADRE does this for you; these are the alternatives:':
|
|
1939
|
+
'# MADRE hace esto por ti; estas son las alternativas:',
|
|
1940
|
+
'# ⚙ CONNECTIONS → PRIVACY → one term per line → PURGE ROOM':
|
|
1941
|
+
'# ⚙ CONEXIONES → PRIVACIDAD → un término por línea → PURGAR LA SALA',
|
|
1942
|
+
'# room → UNDO under the CONTROL notice':
|
|
1943
|
+
'# la sala → DESHACER debajo del aviso de CONTROL',
|
|
1944
|
+
'# room → the handle under the bar, on the left → NEW CONVERSATION':
|
|
1945
|
+
'# la sala → la manija bajo la barra, a la izquierda → NUEVA CONVERSACIÓN',
|
|
1946
|
+
'# the address of the open room is in the refusal itself':
|
|
1947
|
+
'# la dirección de la sala abierta viene en el propio rechazo',
|
|
1948
|
+
'# room → ◉ NOSTROMO → the dark bodies are aberrations':
|
|
1949
|
+
'# la sala → ◉ NOSTROMO → los cuerpos oscuros son aberraciones',
|
|
1950
|
+
'# ⚙ CONNECTIONS → MEMORY → THE THREE TESTS → CONSISTENCY':
|
|
1951
|
+
'# ⚙ CONEXIONES → MEMORIA → LAS TRES PRUEBAS → CONSISTENCIA',
|
|
1952
|
+
'# ⚙ CONNECTIONS → MEMORY → CARRY WHAT A MEMORY KEEPS ARRIVING WITH':
|
|
1953
|
+
'# ⚙ CONEXIONES → MEMORIA → LLEVAR AQUELLO CON LO QUE UNA MEMORIA SIEMPRE LLEGA',
|
|
1954
|
+
'# room → ◉ NOSTROMO → COLD':
|
|
1955
|
+
'# la sala → ◉ NOSTROMO → FRÍAS',
|
|
1956
|
+
'# room → ◉ NOSTROMO → ASK → PUT IN THE COMPOSER':
|
|
1957
|
+
'# la sala → ◉ NOSTROMO → PREGUNTAR → PONER EN EL COMPOSITOR',
|
|
1958
|
+
'# ⚙ CONNECTIONS → MEMORY → THE THREE TESTS':
|
|
1959
|
+
'# ⚙ CONEXIONES → MEMORIA → LAS TRES PRUEBAS',
|
|
1960
|
+
'# MATCH needs Ollama running with a chat model, and embeddings on':
|
|
1961
|
+
'# COINCIDENCIA necesita Ollama corriendo con un modelo de chat, y los embeddings encendidos',
|
|
1962
|
+
'# or: brew install node # a Homebrew node owns its own prefix':
|
|
1963
|
+
'# o: brew install node # un node de Homebrew es dueño de su propio prefijo',
|
|
1964
|
+
'# or use nvm, which owns the prefix it installs into':
|
|
1965
|
+
'# o usa nvm, que es dueño del prefijo donde instala',
|
|
1966
|
+
'# MODULES → + ADD A MODULE':
|
|
1967
|
+
'# MÓDULOS → + AGREGAR UN MÓDULO',
|
|
1968
|
+
'# docs/SDK.md is the whole contract, and docs/sdk/hello-module.mjs is one that works':
|
|
1969
|
+
'# docs/SDK.md es el contrato entero, y docs/sdk/hello-module.mjs es uno que funciona',
|
|
1970
|
+
'# the line in the room: local · @madre → CHECK IT AGAINST THIS ROOM':
|
|
1971
|
+
'# la línea en la sala: local · @madre → MEDIRLO CONTRA ESTA SALA',
|
|
1972
|
+
'# or: NOSTROMO → THE THREE TESTS → the third one':
|
|
1973
|
+
'# o: NOSTROMO → LAS TRES PRUEBAS → la tercera',
|
|
1974
|
+
'# it needs embeddings on and some turns answered by a CLI agent, which is what it compares against':
|
|
1975
|
+
'# necesita los embeddings encendidos y algunos turnos contestados por un agente de CLI, que es contra lo que compara',
|
|
1976
|
+
'# the seal lifts on its own; MU/TH/UR › NOSTROMO asks for the name again after it does':
|
|
1977
|
+
'# el sello se levanta solo; MU/TH/UR › NOSTROMO vuelve a pedir el nombre cuando pase',
|
|
1978
|
+
'# NOSTROMO → click the core → type HELP':
|
|
1979
|
+
'# NOSTROMO → clic en el núcleo → escribe HELP',
|
|
1980
|
+
'# READ MEMORIES prints the block the next turn would carry':
|
|
1981
|
+
'# LEER MEMORIAS imprime el bloque que llevaría el próximo turno',
|
|
1982
|
+
'# SPECIAL ORDER 937 is answered too':
|
|
1983
|
+
'# la ORDEN ESPECIAL 937 también se contesta',
|
|
1984
|
+
'# NOSTROMO → click the core → WHAT LEFT THIS MACHINE':
|
|
1985
|
+
'# NOSTROMO → clic en el núcleo → LO QUE SALIÓ DE ESTA MÁQUINA',
|
|
1986
|
+
'# embeddings, to keep memories on this computer: MU/TH/UR → MEMORY → EMBEDDINGS → OLLAMA':
|
|
1987
|
+
'# embeddings, para que las memorias se queden en esta computadora: MU/TH/UR → MEMORIA → EMBEDDINGS → OLLAMA',
|
|
1988
|
+
'Dismiss this record · it stays in the ledger': 'Descartar este registro · se queda en el ledger',
|
|
1989
|
+
'Codex says it is reading additional input from stdin':
|
|
1990
|
+
'Codex dice que está leyendo entrada adicional de stdin',
|
|
1991
|
+
'A notice Codex prints, not a failure. MADRE runs it with stdin closed, so the line is harmless and the turn is decided by what Codex returned. If the turn failed, the reason is the line above this one — the exit code, or a clean exit with no answer.':
|
|
1992
|
+
'Un aviso que imprime Codex, no una falla. MADRE lo corre con stdin cerrado, así que la línea es inofensiva y el turno lo decide lo que Codex haya devuelto. Si el turno falló, la razón es la línea de arriba: el código de salida, o una salida limpia sin respuesta.',
|
|
1993
|
+
'Nothing to do about the notice itself. If turns keep failing, check that this Codex is recent enough for the flags MADRE passes: `codex --version`, then update it.':
|
|
1994
|
+
'No hay nada que hacer con el aviso en sí. Si los turnos siguen fallando, revisa que este Codex sea lo bastante reciente para las banderas que MADRE le pasa: `codex --version`, y actualízalo.',
|
|
1995
|
+
'two memories that cannot both be true': 'dos memorias que no pueden ser ciertas a la vez',
|
|
1762
1996
|
'created': 'creado',
|
|
1763
1997
|
'all stop · {plans} plans, {turns} turns halted': 'alto total · {plans} planes, {turns} turnos detenidos',
|
|
1764
1998
|
'all stop · nothing was running': 'alto total · no había nada corriendo',
|
|
@@ -1787,6 +2021,13 @@ export const ES = {
|
|
|
1787
2021
|
'{title} is not available here · see MODULES': '{title} no está disponible aquí · mira MÓDULOS',
|
|
1788
2022
|
'MU/TH/UR › /{name} needs a request after it, e.g. "/{name} a poster for the launch".':
|
|
1789
2023
|
'MU/TH/UR › /{name} necesita una petición después, por ejemplo «/{name} un póster para el lanzamiento».',
|
|
2024
|
+
'MU/TH/UR › /module needs a job, e.g. "/module summarize today’s commits".':
|
|
2025
|
+
'MU/TH/UR › /module necesita una tarea, por ejemplo «/module resume los commits de hoy».',
|
|
2026
|
+
'MU/TH/UR › /module needs #2 CREATE. Choose #2 in the mode chip, then send again.':
|
|
2027
|
+
'MU/TH/UR › /module necesita #2 CREATE. Elige #2 en el chip de modo y vuelve a enviar.',
|
|
2028
|
+
'MU/TH/UR · MODULE · NEEDS #2 ›': 'MU/TH/UR · MODULE · REQUIERE #2 ›',
|
|
2029
|
+
'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.':
|
|
2030
|
+
'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.',
|
|
1790
2031
|
'MU/TH/UR › unknown command /{name}. Type "/" to see what this room offers.':
|
|
1791
2032
|
'MU/TH/UR › comando desconocido /{name}. Escribe «/» para ver lo que ofrece esta sala.',
|
|
1792
2033
|
'{name} · uploading…': '{name} · subiendo…',
|
package/public/index.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<div class="shell">
|
|
11
11
|
<header class="bar">
|
|
12
12
|
<div class="bar-left">
|
|
13
|
-
<a class="brand" href="https://
|
|
13
|
+
<a class="brand" href="https://madre.run" target="_blank" rel="noopener noreferrer" aria-label="MADRE · madre.run" title="MADRE · madre.run">
|
|
14
14
|
<svg class="brand-mark" viewBox="0 0 72 20" aria-hidden="true">
|
|
15
15
|
<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.8" stroke-linecap="round" stroke-linejoin="round" pathLength="100"/>
|
|
16
16
|
<circle class="beat-dot" cx="60" cy="10" r="3" fill="currentColor"/>
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
<button id="nostromo-recenter" class="mother-close" type="button" hidden>RECENTER</button>
|
|
253
253
|
<button id="nostromo-close" class="mother-close" type="button">LEAVE ×</button>
|
|
254
254
|
</header>
|
|
255
|
-
<canvas id="nostromo-canvas" class="nostromo-canvas" aria-label="Memories orbiting MOTHER's core"></canvas>
|
|
255
|
+
<canvas id="nostromo-canvas" class="nostromo-canvas" tabindex="-1" aria-label="Memories orbiting MOTHER's core"></canvas>
|
|
256
256
|
<p class="nostromo-help">DRAG TO MOVE · WHEEL TO ZOOM · CLICK A MEMORY · DO NOT TOUCH MOTHER</p>
|
|
257
257
|
<div id="nostromo-alert" class="nostromo-alert" role="alert" hidden>
|
|
258
258
|
<div class="klaxon"></div>
|
|
@@ -305,6 +305,8 @@
|
|
|
305
305
|
<button id="viewer-reload" class="nav" type="button" title="Reload the page" aria-label="Reload">↻</button>
|
|
306
306
|
</span>
|
|
307
307
|
<span id="viewer-path" class="viewer-path"></span>
|
|
308
|
+
<span id="viewer-lang" class="viewer-lang" hidden></span>
|
|
309
|
+
<span id="viewer-hint-select" class="viewer-lang" hidden>CLICK A LINE NUMBER TO SELECT · SHIFT FOR A RANGE</span>
|
|
308
310
|
<span id="viewer-selection" class="viewer-selection" hidden></span>
|
|
309
311
|
<button id="viewer-mode" class="viewer-review viewer-mode" type="button" hidden>SOURCE</button>
|
|
310
312
|
<button id="viewer-review" class="viewer-review" type="button" hidden>REVIEW WITH ▾</button>
|
package/public/styles.css
CHANGED
|
@@ -40,10 +40,26 @@
|
|
|
40
40
|
--mode-2: #ffb000; --mode-2-ink: #1a1000; /* CREATE · amber phosphor */
|
|
41
41
|
--mode-3: var(--terror); --mode-3-ink: #fff3f1; /* CONTROL · the red screen */
|
|
42
42
|
--mode-4: #8fd3ff; --mode-4-ink: #04131c; /* AIRLOCK · the cold outside */
|
|
43
|
+
--module-electric: #b44cff; --module-electric-ink: #12001d; /* MODULE · MADRE electric purple */
|
|
43
44
|
}
|
|
45
|
+
/* Reading code, in whichever ground the room is standing on. These were picked for phosphor on
|
|
46
|
+
black; on white the same green and yellow disappear, so each one has a light value of its own. */
|
|
47
|
+
:root {
|
|
48
|
+
--syn-keyword: #9bb8ff;
|
|
49
|
+
--syn-string: #9bff66;
|
|
50
|
+
--syn-comment: color-mix(in srgb, var(--text-3) 88%, transparent);
|
|
51
|
+
--syn-number: #ffd166;
|
|
52
|
+
--syn-literal: #ff9ecd;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
@media (prefers-color-scheme: light) {
|
|
45
56
|
:root:not([data-theme="dark"]) {
|
|
46
57
|
color-scheme: light;
|
|
58
|
+
--syn-keyword: #0b57b8;
|
|
59
|
+
--syn-string: #0a6e35;
|
|
60
|
+
--syn-comment: #6a7280;
|
|
61
|
+
--syn-number: #9a5000;
|
|
62
|
+
--syn-literal: #9c1f6b;
|
|
47
63
|
--bg: #f4f5f2;
|
|
48
64
|
--bg-2: #ffffff;
|
|
49
65
|
--panel: #ffffff;
|
|
@@ -71,6 +87,11 @@
|
|
|
71
87
|
}
|
|
72
88
|
:root[data-theme="light"] {
|
|
73
89
|
color-scheme: light;
|
|
90
|
+
--syn-keyword: #0b57b8;
|
|
91
|
+
--syn-string: #0a6e35;
|
|
92
|
+
--syn-comment: #6a7280;
|
|
93
|
+
--syn-number: #9a5000;
|
|
94
|
+
--syn-literal: #9c1f6b;
|
|
74
95
|
--bg: #f4f5f2;
|
|
75
96
|
--bg-2: #ffffff;
|
|
76
97
|
--panel: #ffffff;
|
|
@@ -145,7 +166,11 @@ body {
|
|
|
145
166
|
.brand-mark .beat-dot { animation: none; opacity: 1; }
|
|
146
167
|
.brand-word { animation: none; opacity: 1; transform: none; }
|
|
147
168
|
}
|
|
148
|
-
|
|
169
|
+
/* Two names sit here and only one of them tells you where you are. The project never gives way:
|
|
170
|
+
a room whose project reads `pul…` has stopped saying which project it is. The conversation is
|
|
171
|
+
the one that shrinks — it has a panel of its own where its whole name is written. */
|
|
172
|
+
.project { flex: 0 0 auto; max-width: 24ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-3); }
|
|
173
|
+
.project.chat-here { flex: 0 1 auto; min-width: 3ch; max-width: none; }
|
|
149
174
|
.update-command { display: flex; align-items: center; gap: 10px; margin: 8px 0; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: color-mix(in srgb, var(--text) 4%, transparent); }
|
|
150
175
|
.update-command code { flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; font-family: var(--mono); font-size: 11.5px; color: var(--text); }
|
|
151
176
|
.update-command button { font: inherit; font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; border: 1px solid var(--line); background: transparent; color: var(--text-2); border-radius: 8px; padding: 4px 10px; cursor: pointer; }
|
|
@@ -162,7 +187,7 @@ body {
|
|
|
162
187
|
.train-step-label { font-family: var(--mono); font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-3); }
|
|
163
188
|
.project::before { content: "/ "; }
|
|
164
189
|
.agents { display: flex; gap: 8px; margin-left: 0; flex: none; }
|
|
165
|
-
.connection { display: inline-flex; align-items: center; gap: 6px; color: var(--text-3); text-transform: uppercase; font-size: 10px; }
|
|
190
|
+
.connection { display: inline-flex; flex: 0 0 auto; white-space: nowrap; align-items: center; gap: 6px; color: var(--text-3); text-transform: uppercase; font-size: 10px; }
|
|
166
191
|
.connection-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); }
|
|
167
192
|
.connection[data-state="live"] .connection-dot { background: var(--phosphor); box-shadow: 0 0 10px var(--phosphor); }
|
|
168
193
|
.connection[data-state="reconnecting"] .connection-dot { background: var(--warn); animation: blink 1s infinite; }
|
|
@@ -313,6 +338,10 @@ dialog.nostromo::backdrop { background: #000; }
|
|
|
313
338
|
.nostromo-frame .mother-close { color: var(--ph); border-color: var(--ph-dim); }
|
|
314
339
|
.nostromo-frame .mother-close:hover { background: var(--ph-faint); }
|
|
315
340
|
.nostromo-canvas { display: block; width: 100%; height: 100%; cursor: crosshair; }
|
|
341
|
+
/* The map takes focus when NOSTROMO opens, so that Enter does not land on LEAVE. It is not in
|
|
342
|
+
the tab order (tabindex="-1"), so the ring the browser draws around it points at nothing and
|
|
343
|
+
boxes the constellation in blue. Nothing is hidden by removing it: there is nowhere to tab. */
|
|
344
|
+
.nostromo-canvas:focus, .nostromo-canvas:focus-visible { outline: none; }
|
|
316
345
|
.nostromo-canvas.over { cursor: pointer; }
|
|
317
346
|
.nostromo-canvas.dragging { cursor: grabbing; }
|
|
318
347
|
.nostromo-help { position: absolute; left: 26px; bottom: 16px; margin: 0; font-size: 9px; letter-spacing: .2em; color: var(--ph-dim); pointer-events: none; }
|
|
@@ -566,11 +595,14 @@ pre.core-egress-log { margin: 0; max-height: 34vh; overflow: auto; padding: 10px
|
|
|
566
595
|
/* ================= composer ================= */
|
|
567
596
|
.composer { display: grid; gap: 12px; padding: 14px 0 0; }
|
|
568
597
|
.composer[aria-disabled="true"] { opacity: .45; pointer-events: none; }
|
|
569
|
-
.
|
|
598
|
+
/* One line, always. The spheres and the chips keep their size; the note is the only piece that
|
|
599
|
+
gives way, because its whole sentence is in its tooltip anyway. */
|
|
600
|
+
.picker { display: flex; flex-wrap: nowrap; gap: 8px; align-items: center; padding: 0 4px; }
|
|
570
601
|
.picker .pick { --size: 30px; cursor: pointer; border: 1px solid transparent; background: color-mix(in srgb, var(--agent) 10%, transparent); transition: transform .12s ease, box-shadow .12s ease; }
|
|
571
602
|
.picker .pick:hover { transform: translateY(-1px); }
|
|
572
603
|
.picker .pick[aria-checked="true"] { box-shadow: 0 0 0 2px var(--bg), 0 0 0 3.5px var(--agent); background: color-mix(in srgb, var(--agent) 22%, transparent); }
|
|
573
|
-
.picker .pick-label { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-2); margin-left: 2px; }
|
|
604
|
+
.picker .pick-label { display: flex; align-items: center; gap: 8px; min-width: 0; font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-2); margin-left: 2px; }
|
|
605
|
+
.picker .pick-label > .mode-chip, .picker .pick-label > .model-chip { flex: 0 0 auto; }
|
|
574
606
|
.picker .pick-label b { color: var(--agent, var(--text)); font-weight: 600; }
|
|
575
607
|
.field { position: relative; display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: end; padding: 6px 6px 6px 18px; border: 1px solid var(--line-2); background: var(--panel); border-radius: 24px; }
|
|
576
608
|
.crew-label { align-self: center; font-family: var(--mono); font-size: 10px; letter-spacing: .18em; color: var(--text-3); white-space: nowrap; transition: color .4s ease; }
|
|
@@ -589,7 +621,7 @@ textarea::placeholder { color: var(--text-3); }
|
|
|
589
621
|
.field button[type="submit"] svg { width: 18px; height: 18px; }
|
|
590
622
|
.field button[type="submit"]:hover { filter: brightness(1.06); }
|
|
591
623
|
.field button[type="submit"]:disabled { opacity: .4; cursor: default; box-shadow: none; }
|
|
592
|
-
.pick-label .pick-note { font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-3);
|
|
624
|
+
.pick-label .pick-note { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-3); white-space: nowrap; }
|
|
593
625
|
.safety { margin: 14px auto 18px; color: var(--text-3); font-family: var(--mono); font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; text-align: center; }
|
|
594
626
|
|
|
595
627
|
/* toast */
|
|
@@ -725,11 +757,13 @@ dialog.mother::backdrop { background: rgba(0, 0, 0, .82); backdrop-filter: blur(
|
|
|
725
757
|
.mother-card.hit p.remedy { box-shadow: 0 0 18px rgba(155, 255, 102, .18); animation: remedy-in .6s ease; }
|
|
726
758
|
@keyframes remedy-in { from { background: rgba(155, 255, 102, .35); } to { background: var(--ph-faint); } }
|
|
727
759
|
.mother-cmd { position: relative; margin: 4px 0 0; border: 1px solid var(--ph-faint); background: #000; padding: 10px 12px; }
|
|
728
|
-
.mother-cmd pre { margin: 0; font: inherit; font-size: 12px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ph); }
|
|
760
|
+
.mother-cmd pre { margin: 0; padding-right: 30px; font: inherit; font-size: 12px; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; color: var(--ph); }
|
|
729
761
|
.mother-cmd .c { color: var(--ph-dim); }
|
|
730
|
-
.mother-cmd .copy { position: absolute; top: 6px; right: 6px; border: 1px solid var(--ph-
|
|
762
|
+
.mother-cmd .copy { position: absolute; top: 6px; right: 6px; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: 1px solid var(--ph-faint); border-radius: 3px; background: #000; color: var(--ph-dim); padding: 0; cursor: pointer; }
|
|
763
|
+
.mother-cmd .copy:hover { color: var(--ph); border-color: var(--ph-dim); }
|
|
764
|
+
.mother-cmd .copy.done { color: var(--ph); border-color: var(--ph); }
|
|
731
765
|
.mother-cmd .copy:hover { color: var(--ph); border-color: var(--ph); }
|
|
732
|
-
.mother-record { display: grid; grid-template-columns: 64px 92px 1fr auto; gap:
|
|
766
|
+
.mother-record { display: grid; grid-template-columns: 64px 92px 1fr auto 20px; gap: 14px; align-items: baseline; padding: 10px 0; border-bottom: 1px solid var(--ph-faint); font-size: 12px; }
|
|
733
767
|
.mother-record .t { color: var(--ph-dim); }
|
|
734
768
|
.mother-record .a { color: var(--agent, var(--ph)); text-transform: uppercase; letter-spacing: .1em; }
|
|
735
769
|
.mother-record .e { color: rgba(210, 255, 190, .85); text-shadow: none; overflow-wrap: anywhere; }
|
|
@@ -795,6 +829,8 @@ dialog.mother::backdrop { background: rgba(0, 0, 0, .82); backdrop-filter: blur(
|
|
|
795
829
|
.module-card .actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
|
|
796
830
|
.module-card .actions button { border: 1px solid var(--ph); background: transparent; color: var(--ph); font: inherit; font-size: 10.5px; letter-spacing: .18em; padding: 8px 14px; cursor: pointer; }
|
|
797
831
|
.module-card .actions button.primary { background: var(--ph); color: #041004; text-shadow: none; }
|
|
832
|
+
.module-card .actions button.remove-module { border-color: color-mix(in srgb, var(--danger) 65%, transparent); color: var(--danger); }
|
|
833
|
+
.module-card .actions button.remove-module:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); }
|
|
798
834
|
.module-card .actions button:disabled { opacity: .4; cursor: default; }
|
|
799
835
|
.module-card .actions .note { font-size: 10px; letter-spacing: .12em; color: var(--ph-dim); }
|
|
800
836
|
.module-card .confirm { border: 1px dashed var(--ph); padding: 12px 14px; display: grid; gap: 10px; }
|
|
@@ -909,6 +945,9 @@ dialog.mother::backdrop { background: rgba(0, 0, 0, .82); backdrop-filter: blur(
|
|
|
909
945
|
.picker .mode-chip.m3 { --mode: var(--mode-3); }
|
|
910
946
|
.picker .mode-chip.m4 { --mode: var(--mode-4); }
|
|
911
947
|
.mode-menu { width: min(380px, calc(100vw - 24px)); padding: 12px; }
|
|
948
|
+
/* One line. The header carries two facts — whose mode, and how far it may go — and both have to
|
|
949
|
+
be readable at once; the sentence about this message living only in this message is on the chip
|
|
950
|
+
that opens this menu. Short enough that the ellipsis below should never have anything to do. */
|
|
912
951
|
.mode-menu .model-menu-title { margin: 4px 10px 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
913
952
|
.mode-menu .mode-ladder { display: grid; gap: 2px; }
|
|
914
953
|
.mode-menu .mode-option { --mode: var(--text-2); display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: 14px; align-items: baseline; width: 100%; text-align: left; border: 0; background: transparent; color: var(--text); font: inherit; font-family: var(--mono); padding: 12px 10px; border-radius: 8px; cursor: pointer; transition: background .15s, opacity .15s; }
|
|
@@ -1045,7 +1084,11 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
|
|
|
1045
1084
|
.viewer-review { border: 1px solid var(--phosphor); background: color-mix(in srgb, var(--phosphor) 10%, transparent); color: var(--phosphor); font: inherit; font-family: var(--mono); font-size: 10px; letter-spacing: .14em; padding: 5px 10px; border-radius: 6px; cursor: pointer; white-space: nowrap; }
|
|
1046
1085
|
.viewer-review:hover { background: color-mix(in srgb, var(--phosphor) 20%, transparent); }
|
|
1047
1086
|
.viewer-menu { position: fixed; z-index: 50; min-width: 220px; border: 1px solid var(--line-2); background: var(--panel); border-radius: 12px; box-shadow: 0 14px 40px rgba(0, 0, 0, .35); padding: 6px; display: grid; gap: 2px; }
|
|
1048
|
-
|
|
1087
|
+
/* Two lines: the range being sent, then the question. The reference is a path and can be long,
|
|
1088
|
+
so it wraps instead of pushing the menu wider or being clipped mid-word. */
|
|
1089
|
+
.viewer-menu .hint { display: grid; gap: 2px; padding: 6px 10px 8px; font-family: var(--mono); font-size: 10px; letter-spacing: .12em; color: var(--text-3); }
|
|
1090
|
+
.viewer-menu .hint b { color: var(--text-2); font-weight: 500; overflow-wrap: anywhere; }
|
|
1091
|
+
.viewer-menu .item span { color: var(--text-3); font-size: 11px; }
|
|
1049
1092
|
.viewer-menu .item { display: flex; gap: 10px; align-items: center; padding: 7px 10px; border-radius: 8px; border: 0; background: transparent; color: var(--text); font: inherit; font-size: 13px; cursor: pointer; text-align: left; }
|
|
1050
1093
|
.viewer-menu .item:hover { background: color-mix(in srgb, var(--agent, var(--phosphor)) 14%, transparent); }
|
|
1051
1094
|
.viewer-menu .item b { color: var(--agent, var(--phosphor)); font-family: var(--mono); font-size: 11.5px; letter-spacing: .06em; }
|
|
@@ -1198,6 +1241,36 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
|
|
|
1198
1241
|
.system.escalation.denied { color: var(--text-3); border-color: var(--line-2); background: transparent; }
|
|
1199
1242
|
.composer.creating .field { border-color: var(--mode-2); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mode-2) 18%, transparent); }
|
|
1200
1243
|
.composer.creating .crew-label { color: var(--mode-2); }
|
|
1244
|
+
/* /module temporarily gives CREATE its own electric MADRE signature. The pixel layer crosses
|
|
1245
|
+
the typebox once, then leaves a clean purple field behind while the request is composed. */
|
|
1246
|
+
.composer.module-command { --mode: var(--module-electric); --mode-ink: var(--module-electric-ink); }
|
|
1247
|
+
.composer.creating.module-command .field, .composer.module-command .field {
|
|
1248
|
+
border-color: var(--module-electric);
|
|
1249
|
+
background: linear-gradient(100deg, color-mix(in srgb, var(--module-electric) 8%, var(--panel)), var(--panel) 62%);
|
|
1250
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--module-electric) 18%, transparent), 0 0 28px color-mix(in srgb, var(--module-electric) 18%, transparent);
|
|
1251
|
+
transition: border-color .18s ease, background .22s ease, box-shadow .22s ease;
|
|
1252
|
+
}
|
|
1253
|
+
.composer.module-command .crew-label { color: var(--module-electric); text-shadow: 0 0 9px color-mix(in srgb, var(--module-electric) 58%, transparent); }
|
|
1254
|
+
.composer.module-command .editor textarea { caret-color: var(--module-electric); }
|
|
1255
|
+
.composer.module-command .editor .highlight .chip.cmd { --agent: var(--module-electric); }
|
|
1256
|
+
.composer .field::after {
|
|
1257
|
+
content: ''; position: absolute; inset: 0; z-index: 2; border-radius: inherit; pointer-events: none; opacity: 0;
|
|
1258
|
+
background:
|
|
1259
|
+
linear-gradient(90deg, transparent 0 10%, color-mix(in srgb, var(--module-electric) 72%, transparent) 46% 54%, transparent 90% 100%),
|
|
1260
|
+
repeating-linear-gradient(90deg, color-mix(in srgb, var(--module-electric) 78%, transparent) 0 7px, transparent 7px 12px),
|
|
1261
|
+
repeating-linear-gradient(0deg, color-mix(in srgb, var(--module-electric) 62%, transparent) 0 7px, transparent 7px 12px);
|
|
1262
|
+
background-size: 42% 100%, 100% 12px, 12px 100%;
|
|
1263
|
+
background-position: -55% 0, 0 0, 0 0;
|
|
1264
|
+
mix-blend-mode: normal;
|
|
1265
|
+
}
|
|
1266
|
+
.composer.module-command .field::after { animation: module-pixel-shift .58s steps(9, end) 1; }
|
|
1267
|
+
@keyframes module-pixel-shift {
|
|
1268
|
+
0% { opacity: 0; clip-path: inset(0 100% 0 0); background-position: -55% 0, 0 0, 0 0; }
|
|
1269
|
+
14% { opacity: .82; }
|
|
1270
|
+
58% { opacity: .48; clip-path: inset(0 0 0 0); background-position: 86% 0, 9px 0, 0 7px; }
|
|
1271
|
+
100% { opacity: 0; clip-path: inset(0 0 0 100%); background-position: 155% 0, 18px 0, 0 14px; }
|
|
1272
|
+
}
|
|
1273
|
+
@media (prefers-reduced-motion: reduce) { .composer.module-command .field::after { animation: none; } }
|
|
1201
1274
|
.who .badge.lease { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 50%, transparent); }
|
|
1202
1275
|
.user .stamp .lease { color: var(--warn); }
|
|
1203
1276
|
.system.lease { color: var(--warn); }
|
|
@@ -1238,17 +1311,28 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
|
|
|
1238
1311
|
.composer.creating { width: min(1180px, 100% - 40px); }
|
|
1239
1312
|
.editor textarea::placeholder { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1240
1313
|
.editor { position: relative; display: grid; min-width: 0; }
|
|
1241
|
-
.editor textarea, .editor .highlight { grid-area: 1 / 1; margin: 0; padding: 7px
|
|
1314
|
+
.editor textarea, .editor .highlight { grid-area: 1 / 1; margin: 0 -5px; padding: 7px 5px; line-height: 21px; font-size: 15px; font-family: inherit; letter-spacing: normal; white-space: pre-wrap; overflow-wrap: anywhere; word-break: normal; box-sizing: content-box; min-height: 0; max-height: none; overflow-y: auto; }
|
|
1242
1315
|
.editor textarea { position: relative; z-index: 1; color: transparent; caret-color: var(--text); }
|
|
1243
1316
|
.editor textarea::selection { background: color-mix(in srgb, var(--phosphor) 30%, transparent); }
|
|
1244
1317
|
.composer.stopall .editor textarea { color: var(--terror); }
|
|
1245
1318
|
.composer.stopall .editor .highlight { visibility: hidden; }
|
|
1246
1319
|
.editor .highlight { color: var(--text); pointer-events: none; scrollbar-width: none; }
|
|
1247
1320
|
.editor .highlight::-webkit-scrollbar { display: none; }
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1321
|
+
/* A chip may take any colour it likes and no metric at all. Font family, size, weight and
|
|
1322
|
+
letter-spacing all change how wide a string draws, and the caret under this layer is placed by
|
|
1323
|
+
the textarea's metrics, not by these: change one and the caret drifts into the pill. Colour,
|
|
1324
|
+
background, radius and box-shadow are free — they paint without moving anything. */
|
|
1325
|
+
/* A pill may grow upward and it may not grow sideways. Vertical padding costs nothing: an inline
|
|
1326
|
+
box overflows its line without moving a character. Horizontal padding does move them — and the
|
|
1327
|
+
negative margin that pays for it only gives the room back to the TEXT, while the background
|
|
1328
|
+
still paints those pixels, so the pill ends up covering the space after it and the next word
|
|
1329
|
+
arrives glued to its edge. Its ring is drawn INSET for the same reason: a spread shadow paints
|
|
1330
|
+
outward on every side, so it would swallow that space too, only more quietly. It hugs its
|
|
1331
|
+
characters; the gap after it is the space the human typed, and it stays visible. */
|
|
1332
|
+
.editor .highlight .chip { --chip-bg: color-mix(in srgb, var(--agent, var(--phosphor)) 20%, var(--panel)); border-radius: 5px; padding: 3px 0; margin: 0; background: var(--chip-bg); color: var(--agent, var(--phosphor)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--agent, var(--phosphor)) 50%, transparent); }
|
|
1333
|
+
.editor .highlight .chip.cmd { --agent: var(--phosphor); }
|
|
1334
|
+
.editor .highlight .chip.file { --agent: var(--text-2); }
|
|
1335
|
+
.editor .highlight .chip.unknown { --agent: var(--text-3); text-decoration: underline dotted; }
|
|
1252
1336
|
/* A mention is a word in the sentence you are writing, so it is only ever coloured. A pill drawn
|
|
1253
1337
|
round it turns the line into a form to fill in and breaks the rhythm of reading it back. */
|
|
1254
1338
|
.editor .highlight .chip.agent { background: transparent; box-shadow: none; }
|
|
@@ -1388,6 +1472,7 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
|
|
|
1388
1472
|
:root[data-scheme="light"] .composer.creating .field, :root[data-scheme="light"] .composer.creating.ordering .field { box-shadow: 0 0 0 2px color-mix(in srgb, var(--mode-2) 30%, transparent); }
|
|
1389
1473
|
:root[data-scheme="light"] .composer.ash-on .field { box-shadow: 0 0 0 2px color-mix(in srgb, var(--brew) 22%, transparent); }
|
|
1390
1474
|
:root[data-scheme="light"] .composer.dropping .field { box-shadow: 0 0 0 2px color-mix(in srgb, var(--phosphor) 35%, transparent); }
|
|
1475
|
+
:root[data-scheme="light"] .composer.module-command .field { box-shadow: 0 0 0 2px color-mix(in srgb, var(--module-electric) 34%, transparent); }
|
|
1391
1476
|
:root[data-scheme="light"] .memory-hint .pill { animation: none; box-shadow: none; }
|
|
1392
1477
|
:root[data-scheme="light"] .mode-menu .mode-option .tag .dot { box-shadow: none; }
|
|
1393
1478
|
:root[data-scheme="light"] .picker .mode-chip, :root[data-scheme="light"] .who .badge { text-shadow: none; box-shadow: none; }
|
|
@@ -1626,3 +1711,26 @@ dialog.viewer::backdrop { background: rgba(0,0,0,.7); backdrop-filter: blur(4px)
|
|
|
1626
1711
|
.maturity-row span { font-family: var(--mono); font-size: 9px; letter-spacing: .08em; color: var(--ph-dim); opacity: .8; }
|
|
1627
1712
|
.maturity-next { color: var(--ph); }
|
|
1628
1713
|
@media (max-width: 860px) { .maturity-row { grid-template-columns: 1fr; gap: 2px; } .maturity-row i { display: none; } }
|
|
1714
|
+
|
|
1715
|
+
/* A record you have dealt with: the way out sits at the end of its own row. */
|
|
1716
|
+
.mother-record .drop { justify-self: end; background: none; border: 0; color: var(--ph-faint); cursor: pointer; font: inherit; font-size: 14px; padding: 0; line-height: 1; }
|
|
1717
|
+
.mother-record .drop:hover { color: var(--warn); }
|
|
1718
|
+
.mother-card .tags .code { color: var(--ph); border: 1px solid var(--ph-faint); border-radius: 3px; padding: 0 4px; letter-spacing: .1em; }
|
|
1719
|
+
.mother-clear { display: inline-block; margin: 8px 10px 10px 0; background: none; border: 1px solid var(--ph-faint); border-radius: 4px; color: var(--ph-dim); cursor: pointer; font: inherit; font-size: 9px; letter-spacing: .16em; padding: 4px 10px; }
|
|
1720
|
+
.mother-clear:hover { color: var(--ph); border-color: var(--ph-dim); }
|
|
1721
|
+
|
|
1722
|
+
/* A remedy this room can carry out itself: the button goes above the commands it replaces. */
|
|
1723
|
+
.mother-goto { display: block; margin: 6px 0 0; border: 1px solid var(--ph-dim); border-radius: 4px; background: transparent; color: var(--ph); cursor: pointer; font: inherit; font-size: 10px; letter-spacing: .14em; padding: 6px 12px; text-transform: uppercase; }
|
|
1724
|
+
.mother-goto:hover { background: color-mix(in srgb, var(--ph) 12%, transparent); }
|
|
1725
|
+
|
|
1726
|
+
/* A file an agent wrote in this room, in that agent's own colour. */
|
|
1727
|
+
.tree .node .touched { width: 6px; height: 6px; border-radius: 50%; background: var(--agent, var(--ph)); box-shadow: 0 0 6px var(--agent, var(--ph)); flex: 0 0 auto; margin-left: 2px; }
|
|
1728
|
+
|
|
1729
|
+
/* Read by what the file is. Six roles, the room's own phosphor: enough to find a string or a
|
|
1730
|
+
comment at a glance, and never so many colours that the code stops being the thing you see. */
|
|
1731
|
+
.viewer .code .t-keyword { color: var(--syn-keyword); }
|
|
1732
|
+
.viewer .code .t-string { color: var(--syn-string); }
|
|
1733
|
+
.viewer .code .t-comment { color: var(--syn-comment); font-style: italic; }
|
|
1734
|
+
.viewer .code .t-number { color: var(--syn-number); }
|
|
1735
|
+
.viewer .code .t-literal { color: var(--syn-literal); }
|
|
1736
|
+
.viewer-lang { color: var(--ph-dim); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; }
|