chocolatito-code 1.5.0 → 1.6.1

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/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import { showBanner, animateStartupBanner, showHelp, showEffortMenu } from "./ui
16
16
  import { fijarMotor } from "./ui/motorActual.js";
17
17
  import { elegirDeLista } from "./ui/selector.js";
18
18
  import { entrarEnPantallaFija, pantallaFijaPedida } from "./ui/pantalla.js";
19
+ import { montarArbol } from "./ui/ink/montarApp.js";
19
20
  import { reafirmarModoCrudo } from "./ui/keyboardGuard.js";
20
21
  import { askInteractivePrompt, SLASH_COMMANDS } from "./ui/prompt.js";
21
22
  import { changeDir } from "./tools/changeDir.js";
@@ -239,8 +240,13 @@ ${nodeViejo}
239
240
  // La barra de abajo solo puede quedarse clavada si el programa toma la
240
241
  // pantalla entera. Se pide con CHOCOLATITO_PANTALLA=fija y se paga con el
241
242
  // historial del terminal: ver ui/pantalla.ts.
242
- if (pantallaFijaPedida())
243
+ if (pantallaFijaPedida()) {
243
244
  entrarEnPantallaFija();
245
+ // Entrar y empezar a dibujar son la misma decision: entrar sin montar el
246
+ // arbol deja una consola en blanco de la que solo se sale cerrando la
247
+ // ventana.
248
+ montarArbol();
249
+ }
244
250
  let currentModel = DEFAULT_ESPECTRO;
245
251
  // La barra de estado lo lee de aqui. Fijarlo al arrancar y no solo al
246
252
  // cambiarlo: si no, hasta el primer /effort la barra no dice nada.
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ /**
3
+ * EL ÁRBOL ÚNICO
4
+ *
5
+ * POR QUE EXISTE
6
+ *
7
+ * Antes Ink solo era dueño del prompt: se montaba para pedir una orden y se
8
+ * desmontaba al enviarla. Mientras el agente trabajaba, el terminal volvía a ser
9
+ * de siempre y la barra de abajo la pintaba `pieFijo` borrando y repintando a
10
+ * mano.
11
+ *
12
+ * Eso son DOS dueños del mismo trozo de pantalla turnándose, y de ahí salían
13
+ * casi todas las quejas: la barra que sube con el scroll, el hueco que aparece,
14
+ * el marco que se descuadra. Cada arreglo era coordinar mejor a los dos dueños.
15
+ *
16
+ * Aquí hay uno solo, y vive toda la sesión. Lo que sale del agente entra en el
17
+ * historial (historial.ts) y se pinta arriba; abajo va SIEMPRE la barra, sea la
18
+ * de escribir o la de trabajar. Nadie tiene que ponerse de acuerdo con nadie.
19
+ *
20
+ * Y POR ESO LA BARRA SE QUEDA QUIETA
21
+ *
22
+ * No porque se repinte rápido, sino porque es la última fila de un árbol que
23
+ * ocupa la ventana entera. No hay nada que pueda moverla, ni la rueda del ratón.
24
+ */
25
+ export declare function App(): React.ReactElement;
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import { Box, Text, useStdout } from "ink";
4
+ import { Prompt } from "./Prompt.js";
5
+ import { alEscribir, tope, ventana } from "../historial.js";
6
+ import { cuandoCambieElPie, lineasDelPie } from "../pieFijo.js";
7
+ import { alCambiarElTurno, estadoDelTurno } from "./control.js";
8
+ /**
9
+ * EL ÁRBOL ÚNICO
10
+ *
11
+ * POR QUE EXISTE
12
+ *
13
+ * Antes Ink solo era dueño del prompt: se montaba para pedir una orden y se
14
+ * desmontaba al enviarla. Mientras el agente trabajaba, el terminal volvía a ser
15
+ * de siempre y la barra de abajo la pintaba `pieFijo` borrando y repintando a
16
+ * mano.
17
+ *
18
+ * Eso son DOS dueños del mismo trozo de pantalla turnándose, y de ahí salían
19
+ * casi todas las quejas: la barra que sube con el scroll, el hueco que aparece,
20
+ * el marco que se descuadra. Cada arreglo era coordinar mejor a los dos dueños.
21
+ *
22
+ * Aquí hay uno solo, y vive toda la sesión. Lo que sale del agente entra en el
23
+ * historial (historial.ts) y se pinta arriba; abajo va SIEMPRE la barra, sea la
24
+ * de escribir o la de trabajar. Nadie tiene que ponerse de acuerdo con nadie.
25
+ *
26
+ * Y POR ESO LA BARRA SE QUEDA QUIETA
27
+ *
28
+ * No porque se repinte rápido, sino porque es la última fila de un árbol que
29
+ * ocupa la ventana entera. No hay nada que pueda moverla, ni la rueda del ratón.
30
+ */
31
+ export function App() {
32
+ const { stdout } = useStdout();
33
+ const filas = Math.max(6, stdout?.rows || 24);
34
+ const [, setRedibujar] = useState(0);
35
+ const [subido, setSubido] = useState(0);
36
+ const [turno, setTurno] = useState(estadoDelTurno());
37
+ const repintar = () => setRedibujar((n) => n + 1);
38
+ // Tres fuentes de cambio, todas fuera de React: lo que escribe el agente, lo
39
+ // que publica el spinner, y el paso de "esperando orden" a "trabajando".
40
+ useEffect(() => alEscribir(repintar), []);
41
+ useEffect(() => cuandoCambieElPie(repintar), []);
42
+ useEffect(() => alCambiarElTurno((nuevo) => setTurno(nuevo)), []);
43
+ // Al empezar un turno se vuelve al final: lo interesante es lo que va a salir,
44
+ // no donde estabas mirando.
45
+ useEffect(() => {
46
+ if (turno.esperando)
47
+ return;
48
+ setSubido(0);
49
+ }, [turno.esperando]);
50
+ const barraDeTrabajo = turno.esperando ? [] : lineasDelPie();
51
+ const altoBarra = turno.esperando ? 0 : barraDeTrabajo.length;
52
+ const altoAviso = subido > 0 ? 1 : 0;
53
+ // Cuando espera orden, el hueco de abajo lo ocupa el prompt y su alto lo
54
+ // decide él; se le pasa cuánto sitio hay para lo de arriba.
55
+ const altoDelTexto = Math.max(1, filas - altoBarra - altoAviso - (turno.esperando ? 5 : 0));
56
+ const visible = ventana(altoDelTexto, subido);
57
+ const huecos = Math.max(0, altoDelTexto - visible.length);
58
+ return (_jsxs(Box, { flexDirection: "column", height: filas, children: [Array.from({ length: huecos }, (_, i) => (_jsx(Text, { children: " " }, `hueco-${i}`))), visible.map((linea, i) => (_jsx(Text, { children: linea }, `h-${i}`))), subido > 0 && (_jsx(Text, { dimColor: true, children: ` ↑ ${subido} lineas mas arriba · Av Pag para volver al final` })), turno.esperando ? (_jsx(Prompt, { alEnviar: turno.responder, alCancelar: () => turno.responder("/exit"), cwd: turno.cwd, promptSymbol: turno.promptSymbol, avisos: [], sinHistorial: true, alDesplazar: (cuanto) => setSubido((n) => Math.max(0, Math.min(tope(altoDelTexto), n + cuanto))) })) : (barraDeTrabajo.map((linea, i) => _jsx(Text, { children: linea }, `t-${i}`)))] }));
59
+ }
@@ -38,5 +38,13 @@ export interface PromptProps {
38
38
  promptSymbol: string;
39
39
  /** Mensajes que llegaron tarde y hay que dejar por encima del marco. */
40
40
  avisos: string[];
41
+ /**
42
+ * El historial lo pinta otro (el arbol de App). Aqui solo la barra.
43
+ *
44
+ * Sin esto se pintaria dos veces: una desde App y otra desde aqui.
45
+ */
46
+ sinHistorial?: boolean;
47
+ /** Re Pag / Av Pag cuando quien manda el scroll es el arbol de arriba. */
48
+ alDesplazar?: (cuanto: number) => void;
41
49
  }
42
- export declare function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }: PromptProps): React.ReactElement;
50
+ export declare function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, sinHistorial, alDesplazar, }: PromptProps): React.ReactElement;
@@ -9,7 +9,7 @@ import { alEscribir, tope, ventana } from "../historial.js";
9
9
  import { enPantallaFija } from "../pantalla.js";
10
10
  /** Marca del cursor. Ink esconde el de verdad, así que este se dibuja. */
11
11
  const CARET = "█";
12
- export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
12
+ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, sinHistorial = false, alDesplazar, }) {
13
13
  const { stdout } = useStdout();
14
14
  const { exit } = useApp();
15
15
  const [texto, setTexto] = useState("");
@@ -76,10 +76,18 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
76
76
  //
77
77
  // Solo Re Pag y Av Pag. Las flechas y los caracteres son para escribir:
78
78
  // robarselos aqui dejaria al usuario sin poder teclear.
79
- if (fija && (tecla.pageUp || tecla.pageDown)) {
79
+ if (tecla.pageUp || tecla.pageDown) {
80
80
  const salto = Math.max(1, Math.floor(altoDelTexto / 2));
81
- setSubido((n) => tecla.pageUp ? Math.min(tope(altoDelTexto), n + salto) : Math.max(0, n - salto));
82
- return;
81
+ // Con el arbol de App al mando, el scroll lo lleva el: aqui no se sabe
82
+ // cuanto sitio hay arriba, porque el prompt es solo la parte de abajo.
83
+ if (alDesplazar) {
84
+ alDesplazar(tecla.pageUp ? salto : -salto);
85
+ return;
86
+ }
87
+ if (fija) {
88
+ setSubido((n) => tecla.pageUp ? Math.min(tope(altoDelTexto), n + salto) : Math.max(0, n - salto));
89
+ return;
90
+ }
83
91
  }
84
92
  // ------------------------------------------------------------- salir
85
93
  if (tecla.ctrl && entrada === "c") {
@@ -215,7 +223,7 @@ export function Prompt({ alEnviar, alCancelar, cwd, promptSymbol, avisos, }) {
215
223
  setElegido(0);
216
224
  }
217
225
  });
218
- if (!fija) {
226
+ if (!fija || sinHistorial) {
219
227
  return (_jsxs(Box, { flexDirection: "column", children: [avisos.map((a, i) => (_jsx(Text, { children: a }, `aviso-${i}`))), marco.lines.map((linea, i) => (_jsx(Text, { children: linea }, i)))] }));
220
228
  }
221
229
  // PANTALLA FIJA: el arbol ocupa la ventana entera y la barra va la ultima, asi
@@ -0,0 +1,36 @@
1
+ /**
2
+ * EL PUENTE ENTRE EL BUCLE Y EL ÁRBOL
3
+ *
4
+ * El programa es un `while` que espera: `const orden = await
5
+ * askInteractivePrompt()`. El árbol de Ink, en cambio, vive todo el rato y se
6
+ * limita a dibujar el estado que haya.
7
+ *
8
+ * Aquí se casan las dos formas. `pedirOrden()` marca "esperando", devuelve una
9
+ * promesa y se queda quieto; el componente pinta el prompt, y cuando el usuario
10
+ * envía, resuelve esa promesa y el estado vuelve a "trabajando". El bucle no se
11
+ * entera de nada: sigue teniendo una función que devuelve un texto.
12
+ *
13
+ * POR QUE NO SE MONTA Y DESMONTA EL ÁRBOL EN CADA VUELTA
14
+ *
15
+ * Es lo que se hacía antes, y era la causa de fondo: mientras el agente
16
+ * trabajaba no había árbol, así que la barra la pintaba otro por su cuenta. Dos
17
+ * dueños de la misma pantalla turnándose. Con el árbol siempre vivo hay uno.
18
+ */
19
+ export interface EstadoDelTurno {
20
+ /** ¿Está el programa esperando que el usuario escriba? */
21
+ esperando: boolean;
22
+ cwd: string;
23
+ promptSymbol: string;
24
+ /** Lo llama el prompt al enviar. Fuera de "esperando" no hace nada. */
25
+ responder: (orden: string) => void;
26
+ }
27
+ export declare function estadoDelTurno(): EstadoDelTurno;
28
+ export declare function alCambiarElTurno(cb: (e: EstadoDelTurno) => void): () => void;
29
+ /**
30
+ * Pide una orden. Se resuelve cuando el usuario la envía.
31
+ *
32
+ * El guardián `entregado` no es paranoia: el componente puede llamar a
33
+ * `responder` desde dos caminos —enviar y cancelar— y resolver dos veces una
34
+ * promesa deja el bucle avanzando por su cuenta con una orden que nadie escribió.
35
+ */
36
+ export declare function pedirOrden(promptSymbol: string, cwd: string): Promise<string>;
@@ -0,0 +1,54 @@
1
+ import process from "node:process";
2
+ const TRABAJANDO = {
3
+ esperando: false,
4
+ cwd: process.cwd(),
5
+ promptSymbol: "❯",
6
+ responder: () => { },
7
+ };
8
+ let estado = TRABAJANDO;
9
+ const oyentes = [];
10
+ export function estadoDelTurno() {
11
+ return estado;
12
+ }
13
+ export function alCambiarElTurno(cb) {
14
+ oyentes.push(cb);
15
+ return () => {
16
+ const i = oyentes.indexOf(cb);
17
+ if (i >= 0)
18
+ oyentes.splice(i, 1);
19
+ };
20
+ }
21
+ function avisar() {
22
+ for (const cb of oyentes) {
23
+ try {
24
+ cb(estado);
25
+ }
26
+ catch { }
27
+ }
28
+ }
29
+ /**
30
+ * Pide una orden. Se resuelve cuando el usuario la envía.
31
+ *
32
+ * El guardián `entregado` no es paranoia: el componente puede llamar a
33
+ * `responder` desde dos caminos —enviar y cancelar— y resolver dos veces una
34
+ * promesa deja el bucle avanzando por su cuenta con una orden que nadie escribió.
35
+ */
36
+ export function pedirOrden(promptSymbol, cwd) {
37
+ return new Promise((resolve) => {
38
+ let entregado = false;
39
+ estado = {
40
+ esperando: true,
41
+ cwd,
42
+ promptSymbol,
43
+ responder: (orden) => {
44
+ if (entregado)
45
+ return;
46
+ entregado = true;
47
+ estado = TRABAJANDO;
48
+ avisar();
49
+ resolve(orden);
50
+ },
51
+ };
52
+ avisar();
53
+ });
54
+ }
@@ -0,0 +1,2 @@
1
+ export declare function montarArbol(): void;
2
+ export declare function desmontarArbol(): void;
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import process from "node:process";
3
+ import { render } from "ink";
4
+ import { App } from "./App.js";
5
+ /**
6
+ * MONTA EL ÁRBOL Y LO DEJA VIVO TODA LA SESIÓN
7
+ *
8
+ * Va en su propio archivo por una razón práctica: `pantalla.ts` no puede montar
9
+ * JSX sin arrastrarse a sí mismo. `pantalla` → `App` → `Prompt` → `pantalla` es
10
+ * un ciclo, y los ciclos en ESM funcionan hasta que uno de los módulos necesita
11
+ * un valor del otro antes de tiempo, y entonces fallan de una forma que no se
12
+ * parece a su causa. Con el montaje aparte, `index.ts` llama a los dos y no hay
13
+ * ciclo.
14
+ *
15
+ * `exitOnCtrlC: false` porque Ctrl+C ya lo trata el prompt: dejar que Ink cierre
16
+ * el proceso por su cuenta se salta el guardado de la sesión.
17
+ */
18
+ let arbol = null;
19
+ export function montarArbol() {
20
+ if (arbol)
21
+ return;
22
+ arbol = render(_jsx(App, {}), { exitOnCtrlC: false });
23
+ }
24
+ export function desmontarArbol() {
25
+ if (!arbol)
26
+ return;
27
+ try {
28
+ arbol.unmount();
29
+ }
30
+ catch { }
31
+ arbol = null;
32
+ }
33
+ // Si el proceso muere sin pasar por la salida ordenada, el árbol tiene que
34
+ // soltarse igual: un árbol vivo en un proceso que se cierra deja el terminal a
35
+ // medio restaurar.
36
+ process.on("exit", desmontarArbol);
@@ -7,6 +7,9 @@ import { expandirPegados, limpiarPegados } from "../pegados.js";
7
7
  import { apuntarEnHistorial } from "../entrada.js";
8
8
  import { soltarPie } from "../pieFijo.js";
9
9
  import { clearTyped } from "../typeAhead.js";
10
+ import { enPantallaFija } from "../pantalla.js";
11
+ import { pedirOrden } from "./control.js";
12
+ import { renderUserPrompt } from "../renderer.js";
10
13
  /**
11
14
  * EL PUENTE ENTRE INK Y EL BUCLE DE SIEMPRE
12
15
  *
@@ -64,6 +67,25 @@ export async function preguntarConInk(promptSymbol = "❯", cwd = process.cwd())
64
67
  // pisan, y el que pierde deja filas huérfanas.
65
68
  soltarPie();
66
69
  limpiarRestos();
70
+ // Con el arbol unico montado, aqui no se monta ni se desmonta nada: solo se
71
+ // dice "estoy esperando" y el arbol pinta el prompt. Ver ink/control.ts.
72
+ if (enPantallaFija()) {
73
+ const orden = await pedirOrden(promptSymbol, cwd);
74
+ const entero = expandirPegados(orden);
75
+ if (entero.trim()) {
76
+ apuntarEnHistorial(entero);
77
+ // Y al historial DE LA PANTALLA, que es distinto: el de arriba es el de
78
+ // las flechas y vive en disco.
79
+ //
80
+ // Antes esto no hacia falta porque el marco se quedaba en el historial del
81
+ // terminal al cerrarse el prompt, y ahi quedaba lo escrito. Con el arbol
82
+ // unico el marco es transitorio: si nadie lo apunta, el mensaje del usuario
83
+ // desaparece de la conversacion justo al enviarlo.
84
+ renderUserPrompt(entero);
85
+ }
86
+ limpiarPegados();
87
+ return entero;
88
+ }
67
89
  return new Promise((resolve) => {
68
90
  let entregado = false;
69
91
  let empujarAviso = null;
@@ -1,3 +1,15 @@
1
+ /**
2
+ * Fija POR DEFECTO.
3
+ *
4
+ * Estuvo detras de un interruptor un dia, y fue un error: el usuario pidio
5
+ * cuatro veces que la caja no se moviera y lo que recibio fue una opcion que
6
+ * habia que acordarse de encender. Una funcion que hay que activar a mano es,
7
+ * para quien la pidio, una funcion que no esta.
8
+ *
9
+ * `CHOCOLATITO_PANTALLA=normal` devuelve el comportamiento de siempre: el
10
+ * historial vuelve a ser del terminal y la rueda del raton a servir, a cambio de
11
+ * que la barra suba con el scroll.
12
+ */
1
13
  export declare function pantallaFijaPedida(): boolean;
2
14
  /**
3
15
  * Enciende o apaga el modo a mano, SIN tocar el terminal.
@@ -1,6 +1,7 @@
1
1
  import process from "node:process";
2
2
  import { redirigirDibujo } from "./salida.js";
3
3
  import { apuntar } from "./historial.js";
4
+ import { habilitarPie } from "./pieFijo.js";
4
5
  /**
5
6
  * LA PANTALLA ALTERNATIVA
6
7
  *
@@ -30,8 +31,22 @@ const ENTRAR = "\x1b[?1049h";
30
31
  const SALIR = "\x1b[?1049l";
31
32
  let dentro = false;
32
33
  let logOriginal = null;
34
+ /**
35
+ * Fija POR DEFECTO.
36
+ *
37
+ * Estuvo detras de un interruptor un dia, y fue un error: el usuario pidio
38
+ * cuatro veces que la caja no se moviera y lo que recibio fue una opcion que
39
+ * habia que acordarse de encender. Una funcion que hay que activar a mano es,
40
+ * para quien la pidio, una funcion que no esta.
41
+ *
42
+ * `CHOCOLATITO_PANTALLA=normal` devuelve el comportamiento de siempre: el
43
+ * historial vuelve a ser del terminal y la rueda del raton a servir, a cambio de
44
+ * que la barra suba con el scroll.
45
+ */
33
46
  export function pantallaFijaPedida() {
34
- return process.env.CHOCOLATITO_PANTALLA === "fija";
47
+ if (process.env.CHOCOLATITO_PANTALLA === "normal")
48
+ return false;
49
+ return true;
35
50
  }
36
51
  /** `null` = manda el estado real. Las pruebas lo fuerzan. */
37
52
  let forzado = null;
@@ -55,6 +70,11 @@ export function entrarEnPantallaFija() {
55
70
  process.stdout.write(ENTRAR);
56
71
  // Lo que se dibujaba en el terminal pasa a ser historial nuestro.
57
72
  redirigirDibujo((texto) => apuntar(texto));
73
+ // Y el pie deja de pintar. Sigue guardando sus secciones -el spinner y la
74
+ // linea de razonamiento publican ahi sin enterarse de nada- pero quien las
75
+ // dibuja pasa a ser el arbol. Dos dueños del mismo trozo de pantalla es
76
+ // exactamente el problema que esto viene a quitar.
77
+ habilitarPie(false);
58
78
  logOriginal = console.log;
59
79
  console.log = (...args) => {
60
80
  apuntar(args.map((a) => (typeof a === "string" ? a : String(a))).join(" ") + "\n");
@@ -76,6 +96,7 @@ export function salirDePantallaFija() {
76
96
  logOriginal = null;
77
97
  }
78
98
  redirigirDibujo(null);
99
+ habilitarPie(null);
79
100
  try {
80
101
  process.stdout.write(SALIR);
81
102
  }
@@ -31,6 +31,16 @@ export declare function fijarSeccion(nombre: SeccionDelPie, lineas: string[]): v
31
31
  * para el mismo resultado, y un parpadeo que se nota en un terminal lento.
32
32
  */
33
33
  export declare function fijarSecciones(entradas: Array<[SeccionDelPie, string[]]>): void;
34
+ export declare function cuandoCambieElPie(cb: () => void): () => void;
35
+ /**
36
+ * Las lineas que el pie tiene puestas ahora mismo, en orden.
37
+ *
38
+ * La necesita el arbol de Ink cuando manda el: ahi el pie no pinta nada -pintar
39
+ * seria un segundo dueño del mismo trozo de pantalla- pero el spinner y la
40
+ * linea de razonamiento siguen publicando aqui, que es lo que hace que ese
41
+ * cambio no toque ni al spinner ni al bucle.
42
+ */
43
+ export declare function lineasDelPie(): string[];
34
44
  export declare function quitarSeccion(nombre: SeccionDelPie): void;
35
45
  /**
36
46
  * Escribe texto permanente sin que el pie se lo lleve por delante.
@@ -233,15 +233,51 @@ export function fijarSeccion(nombre, lineas) {
233
233
  * para el mismo resultado, y un parpadeo que se nota en un terminal lento.
234
234
  */
235
235
  export function fijarSecciones(entradas) {
236
- if (!pieUsable())
237
- return;
238
236
  let cambio = false;
239
237
  for (const [nombre, lineas] of entradas) {
240
238
  if (anotar(nombre, lineas))
241
239
  cambio = true;
242
240
  }
243
- if (cambio)
241
+ if (!cambio)
242
+ return;
243
+ // Con el pie apagado -que es lo que pasa cuando manda Ink- las secciones se
244
+ // siguen guardando y se avisa, pero no se pinta nada aqui: pintar seria un
245
+ // segundo dueño del mismo trozo de pantalla.
246
+ if (pieUsable())
244
247
  repintar("");
248
+ for (const cb of alCambiarElPie) {
249
+ try {
250
+ cb();
251
+ }
252
+ catch { }
253
+ }
254
+ }
255
+ /** Quien pinta el pie desde fuera se entera por aqui. */
256
+ const alCambiarElPie = [];
257
+ export function cuandoCambieElPie(cb) {
258
+ alCambiarElPie.push(cb);
259
+ return () => {
260
+ const i = alCambiarElPie.indexOf(cb);
261
+ if (i >= 0)
262
+ alCambiarElPie.splice(i, 1);
263
+ };
264
+ }
265
+ /**
266
+ * Las lineas que el pie tiene puestas ahora mismo, en orden.
267
+ *
268
+ * La necesita el arbol de Ink cuando manda el: ahi el pie no pinta nada -pintar
269
+ * seria un segundo dueño del mismo trozo de pantalla- pero el spinner y la
270
+ * linea de razonamiento siguen publicando aqui, que es lo que hace que ese
271
+ * cambio no toque ni al spinner ni al bucle.
272
+ */
273
+ export function lineasDelPie() {
274
+ const salida = [];
275
+ for (const nombre of ORDEN) {
276
+ const trozo = secciones.get(nombre);
277
+ if (trozo && trozo.length > 0)
278
+ salida.push(...trozo);
279
+ }
280
+ return salida;
245
281
  }
246
282
  export function quitarSeccion(nombre) {
247
283
  fijarSeccion(nombre, []);
@@ -1,3 +1,22 @@
1
+ /**
2
+ * LO QUE ACABAS DE MANDAR, EN EL HISTORIAL
3
+ *
4
+ * Un ">" y el texto sobre un fondo plomo. Sin barras: las barras son el MARCO
5
+ * DE ESCRIBIR, y ese marco vive abajo y no se va nunca. Repetirlo aqui haria que
6
+ * la conversacion se llenara de cajas iguales y costara distinguir cual es la
7
+ * que espera tu orden.
8
+ *
9
+ * POR QUE HACE FALTA AHORA Y ANTES NO
10
+ *
11
+ * Antes el marco lo dejaba el terminal en su historial al cerrarse el prompt, y
12
+ * ahi quedaba lo que habias escrito. Con el arbol unico el marco es transitorio
13
+ * -React lo dibuja y lo borra-, asi que si nadie apunta la orden, tu mensaje
14
+ * desaparece de la conversacion en cuanto se envia.
15
+ *
16
+ * Las lineas se pintan una a una: un fondo de color sobre un texto con saltos
17
+ * dentro deja el color colgando hasta el borde derecho en unas terminales y no
18
+ * en otras.
19
+ */
1
20
  export declare function renderUserPrompt(text: string): void;
2
21
  export declare function renderToolStart(name: string, summary: string): void;
3
22
  export declare function renderToolSuccess(name: string, resultSummary: string): void;
@@ -34,10 +34,32 @@ const marked = new Marked(markedTerminal({
34
34
  },
35
35
  },
36
36
  }));
37
+ /**
38
+ * LO QUE ACABAS DE MANDAR, EN EL HISTORIAL
39
+ *
40
+ * Un ">" y el texto sobre un fondo plomo. Sin barras: las barras son el MARCO
41
+ * DE ESCRIBIR, y ese marco vive abajo y no se va nunca. Repetirlo aqui haria que
42
+ * la conversacion se llenara de cajas iguales y costara distinguir cual es la
43
+ * que espera tu orden.
44
+ *
45
+ * POR QUE HACE FALTA AHORA Y ANTES NO
46
+ *
47
+ * Antes el marco lo dejaba el terminal en su historial al cerrarse el prompt, y
48
+ * ahi quedaba lo que habias escrito. Con el arbol unico el marco es transitorio
49
+ * -React lo dibuja y lo borra-, asi que si nadie apunta la orden, tu mensaje
50
+ * desaparece de la conversacion en cuanto se envia.
51
+ *
52
+ * Las lineas se pintan una a una: un fondo de color sobre un texto con saltos
53
+ * dentro deja el color colgando hasta el borde derecho en unas terminales y no
54
+ * en otras.
55
+ */
37
56
  export function renderUserPrompt(text) {
38
- const symbol = chalk.bold.hex("#D97757")("");
39
- const shaded = chalk.bgHex("#242730").hex("#F4F4F5").bold(` ${text.trim()} `);
40
- salida.linea(`\n${symbol} ${shaded}\n`);
57
+ const lineas = text.trim().split("\n");
58
+ const pintadas = lineas.map((linea, i) => {
59
+ const marca = i === 0 ? chalk.gray(">") : " ";
60
+ return `${marca} ${chalk.bgHex("#2A2D34").hex("#E8E8EA")(` ${linea} `)}`;
61
+ });
62
+ salida.linea(`\n${pintadas.join("\n")}\n`);
41
63
  }
42
64
  // Tool call rendering as specified in §B5
43
65
  export function renderToolStart(name, summary) {
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "minimum_chrome_version": "102",
4
4
  "name": "Chocolatito Code",
5
- "version": "1.5.0",
5
+ "version": "1.6.1",
6
6
  "description": "Deja que Chocolatito Code trabaje dentro de tu Chrome, en segundo plano y con tus sesiones ya iniciadas.",
7
7
  "permissions": [
8
8
  "tabs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chocolatito-code",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "Agente autónomo de programación para la terminal, con control real del ordenador y del navegador. Desarrollado por Chocolatito.",
5
5
  "type": "module",
6
6
  "bin": {