chocolatito-code 1.0.0 → 1.1.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.
Files changed (102) hide show
  1. package/README.md +89 -0
  2. package/dist/agent/compaction.d.ts +65 -0
  3. package/dist/agent/compaction.js +134 -0
  4. package/dist/agent/context.d.ts +3 -0
  5. package/dist/agent/context.js +35 -0
  6. package/dist/agent/loop.d.ts +91 -2
  7. package/dist/agent/loop.js +536 -78
  8. package/dist/agent/loopDetector.d.ts +57 -0
  9. package/dist/agent/loopDetector.js +0 -0
  10. package/dist/agent/mentions.d.ts +13 -0
  11. package/dist/agent/mentions.js +49 -0
  12. package/dist/agent/repoMap.d.ts +117 -0
  13. package/dist/agent/repoMap.js +560 -0
  14. package/dist/agent/result.d.ts +64 -0
  15. package/dist/agent/result.js +48 -0
  16. package/dist/agent/retry.d.ts +35 -0
  17. package/dist/agent/retry.js +123 -4
  18. package/dist/agent/subagent.js +62 -15
  19. package/dist/agent/syntaxValidator.js +288 -52
  20. package/dist/agent/toolGate.d.ts +58 -0
  21. package/dist/agent/toolGate.js +111 -0
  22. package/dist/agent/tracker.js +4 -7
  23. package/dist/agent/undoManager.d.ts +44 -11
  24. package/dist/agent/undoManager.js +95 -24
  25. package/dist/agent/usageMeter.d.ts +56 -0
  26. package/dist/agent/usageMeter.js +51 -0
  27. package/dist/agent/verifier.d.ts +49 -0
  28. package/dist/agent/verifier.js +158 -0
  29. package/dist/config/constants.js +14 -0
  30. package/dist/config/engine.d.ts +19 -0
  31. package/dist/config/engine.js +35 -3
  32. package/dist/config/license.d.ts +5 -0
  33. package/dist/config/license.js +107 -9
  34. package/dist/config/limits.d.ts +28 -0
  35. package/dist/config/limits.js +51 -0
  36. package/dist/config/permissions.d.ts +76 -1
  37. package/dist/config/permissions.js +379 -23
  38. package/dist/config/quota.js +24 -1
  39. package/dist/config/updater.d.ts +68 -0
  40. package/dist/config/updater.js +215 -0
  41. package/dist/hooks/manager.js +159 -14
  42. package/dist/index.js +222 -34
  43. package/dist/mcp/client.d.ts +22 -0
  44. package/dist/mcp/client.js +93 -11
  45. package/dist/prompts/systemPrompt.js +12 -1
  46. package/dist/sessions/manager.d.ts +12 -0
  47. package/dist/sessions/manager.js +33 -5
  48. package/dist/sessions/resume.d.ts +36 -0
  49. package/dist/sessions/resume.js +43 -0
  50. package/dist/skills/manager.d.ts +1 -0
  51. package/dist/skills/manager.js +9 -0
  52. package/dist/tools/binary.d.ts +46 -0
  53. package/dist/tools/binary.js +100 -0
  54. package/dist/tools/browserCdp.js +13 -1
  55. package/dist/tools/browserExtension.d.ts +5 -0
  56. package/dist/tools/browserExtension.js +202 -18
  57. package/dist/tools/browserSession.d.ts +23 -0
  58. package/dist/tools/browserSession.js +28 -0
  59. package/dist/tools/computerUse.js +33 -1
  60. package/dist/tools/createImage.d.ts +11 -0
  61. package/dist/tools/createImage.js +13 -1
  62. package/dist/tools/definitions.js +9 -3
  63. package/dist/tools/editDiagnosis.d.ts +54 -0
  64. package/dist/tools/editDiagnosis.js +142 -0
  65. package/dist/tools/editFile.d.ts +1 -0
  66. package/dist/tools/editFile.js +118 -62
  67. package/dist/tools/findFiles.d.ts +21 -0
  68. package/dist/tools/findFiles.js +75 -6
  69. package/dist/tools/getSystemInfo.js +15 -7
  70. package/dist/tools/gitTools.d.ts +24 -0
  71. package/dist/tools/gitTools.js +87 -26
  72. package/dist/tools/moveCopyFile.d.ts +18 -1
  73. package/dist/tools/moveCopyFile.js +74 -4
  74. package/dist/tools/patchCascade.d.ts +57 -0
  75. package/dist/tools/patchCascade.js +338 -0
  76. package/dist/tools/runCommand.js +213 -25
  77. package/dist/tools/runner.js +57 -4
  78. package/dist/tools/toolDefsComputer.js +12 -2
  79. package/dist/tools/truncator.d.ts +27 -1
  80. package/dist/tools/truncator.js +117 -11
  81. package/dist/tools/viewFile.js +15 -11
  82. package/dist/tools/visionBridge.js +7 -0
  83. package/dist/tools/webSearch.d.ts +21 -0
  84. package/dist/tools/webSearch.js +125 -14
  85. package/dist/tools/writeFile.js +18 -1
  86. package/dist/ui/interrupt.d.ts +4 -1
  87. package/dist/ui/interrupt.js +56 -5
  88. package/dist/ui/keyboardGuard.d.ts +55 -0
  89. package/dist/ui/keyboardGuard.js +65 -0
  90. package/dist/ui/loopPrompt.d.ts +17 -0
  91. package/dist/ui/loopPrompt.js +59 -0
  92. package/dist/ui/permissionPrompt.js +84 -2
  93. package/dist/ui/prompt.d.ts +35 -0
  94. package/dist/ui/prompt.js +345 -125
  95. package/dist/ui/reasoningStream.d.ts +8 -0
  96. package/dist/ui/reasoningStream.js +99 -7
  97. package/extension/README.md +95 -74
  98. package/extension/background.js +598 -178
  99. package/extension/content.js +92 -9
  100. package/extension/manifest.json +2 -1
  101. package/extension/popup.js +28 -12
  102. package/package.json +1 -1
@@ -1,38 +1,130 @@
1
1
  import chalk from "chalk";
2
2
  import process from "node:process";
3
+ /**
4
+ * Lo que se ve mientras el modelo piensa.
5
+ *
6
+ * Antes se volcaba el razonamiento entero, letra a letra:
7
+ *
8
+ * for (let i = 0; i < chunk.length; i++)
9
+ * process.stdout.write(chalk.gray(char));
10
+ *
11
+ * Dos problemas, y el segundo es el grave.
12
+ *
13
+ * **Es ilegible.** Un razonamiento de una tarea mediana son quince mil
14
+ * caracteres de deliberacion en voz alta —"mejor 12x16... no, mejor por
15
+ * partes... cuento: 2+2+6+2=12"— que llenan la pantalla y entierran lo unico
16
+ * que importa: que esta haciendo y si va bien.
17
+ *
18
+ * **Y bloquea el terminal.** Quince mil escrituras sincronas, cada una
19
+ * envuelta por chalk en codigos de color (once bytes para pintar una letra),
20
+ * son quince mil llamadas al sistema. En Windows eso deja el bucle de eventos
21
+ * parado el rato que dura, y las teclas que el usuario pulsa mientras tanto se
22
+ * quedan en la cola del sistema operativo. De ahi el "escribo y no sale nada",
23
+ * que aparecia justo en las tareas largas -las que mas razonan- y nunca al
24
+ * saludar.
25
+ *
26
+ * Ahora se resume: una sola linea que se reescribe sobre si misma diciendo
27
+ * cuanto lleva pensando y en que anda. Cero avance de scroll, una escritura por
28
+ * trozo recibido en vez de una por letra.
29
+ *
30
+ * Quien quiera verlo entero: CHOCOLATITO_RAZONAMIENTO=completo.
31
+ */
32
+ const COMPLETO = process.env.CHOCOLATITO_RAZONAMIENTO === "completo";
33
+ /** Cada cuanto se refresca la linea. Mas a menudo es parpadeo, no informacion. */
34
+ const MS_ENTRE_REFRESCOS = 400;
35
+ /** Se recorta para que quepa siempre en una linea, sin envolver. */
36
+ function unaLinea(texto, ancho) {
37
+ const limpio = texto.replace(/\s+/g, " ").trim();
38
+ if (limpio.length <= ancho)
39
+ return limpio;
40
+ return limpio.slice(0, Math.max(0, ancho - 1)) + "…";
41
+ }
3
42
  export class ReasoningStream {
4
43
  hasStarted = false;
5
44
  atLineStart = true;
45
+ inicio = 0;
46
+ caracteres = 0;
47
+ ultimoRefresco = 0;
48
+ cola = "";
49
+ lineaPintada = false;
6
50
  push(chunk) {
7
51
  if (!chunk)
8
52
  return;
9
53
  if (!this.hasStarted) {
10
54
  this.hasStarted = true;
11
- process.stdout.write(`\n ${chalk.bold.hex("#8B5CF6")("💭 Razonando:")}\n`);
55
+ this.inicio = Date.now();
56
+ this.caracteres = 0;
57
+ this.cola = "";
58
+ if (COMPLETO) {
59
+ process.stdout.write(`\n ${chalk.bold.hex("#8B5CF6")("💭 Razonando:")}\n`);
60
+ }
61
+ }
62
+ if (COMPLETO) {
63
+ this.volcar(chunk);
64
+ return;
12
65
  }
13
- for (let i = 0; i < chunk.length; i++) {
14
- const char = chunk[i];
66
+ this.caracteres += chunk.length;
67
+ // Solo se guarda la cola: es de donde sale el "en que anda ahora".
68
+ this.cola = (this.cola + chunk).slice(-300);
69
+ this.refrescar(false);
70
+ }
71
+ /** El volcado literal, para quien lo pida. Una escritura por trozo, no por letra. */
72
+ volcar(chunk) {
73
+ const prefijo = ` ${chalk.hex("#8B5CF6")("│")} `;
74
+ let salida = "";
75
+ for (const char of chunk) {
15
76
  if (this.atLineStart) {
16
- process.stdout.write(` ${chalk.hex("#8B5CF6")("│")} `);
77
+ salida += prefijo;
17
78
  this.atLineStart = false;
18
79
  }
19
80
  if (char === "\n") {
20
- process.stdout.write("\n");
81
+ salida += "\n";
21
82
  this.atLineStart = true;
22
83
  }
23
84
  else {
24
- process.stdout.write(chalk.gray(char));
85
+ salida += char;
25
86
  }
26
87
  }
88
+ // Un solo write, y el color se aplica una vez al bloque entero en vez de a
89
+ // cada letra: mismo resultado en pantalla, una fraccion de los bytes.
90
+ process.stdout.write(chalk.gray(salida));
91
+ }
92
+ refrescar(forzar) {
93
+ const ahora = Date.now();
94
+ if (!forzar && ahora - this.ultimoRefresco < MS_ENTRE_REFRESCOS)
95
+ return;
96
+ this.ultimoRefresco = ahora;
97
+ if (!process.stdout.isTTY)
98
+ return;
99
+ const segundos = Math.round((ahora - this.inicio) / 1000);
100
+ const ancho = Math.max(20, (process.stdout.columns || 80) - 4);
101
+ const cabeza = ` ${chalk.hex("#8B5CF6")("💭")} ${chalk.gray(`pensando… ${segundos}s`)}`;
102
+ // La ultima frase a medias da una pista de por donde va sin contarlo todo.
103
+ const pista = unaLinea(this.cola, Math.max(0, ancho - 24));
104
+ const linea = pista ? `${cabeza} ${chalk.dim("·")} ${chalk.dim(pista)}` : cabeza;
105
+ process.stdout.write(`\r\x1b[2K${unaLinea(linea, ancho + 40)}`);
106
+ this.lineaPintada = true;
27
107
  }
28
108
  flush() {
29
- if (this.hasStarted) {
109
+ if (!this.hasStarted)
110
+ return;
111
+ if (COMPLETO) {
30
112
  if (!this.atLineStart) {
31
113
  process.stdout.write("\n");
32
114
  this.atLineStart = true;
33
115
  }
34
116
  process.stdout.write("\n");
35
117
  this.hasStarted = false;
118
+ return;
119
+ }
120
+ const segundos = Math.max(1, Math.round((Date.now() - this.inicio) / 1000));
121
+ if (this.lineaPintada) {
122
+ // Se deja una sola linea de resumen donde estaba la que iba cambiando.
123
+ process.stdout.write(`\r\x1b[2K ${chalk.hex("#8B5CF6")("💭")} ${chalk.gray(`pensó ${segundos}s`)}\n`);
36
124
  }
125
+ this.lineaPintada = false;
126
+ this.hasStarted = false;
127
+ this.cola = "";
128
+ this.caracteres = 0;
37
129
  }
38
130
  }
@@ -1,74 +1,95 @@
1
- # Extensión de Chocolatito Code para Chrome
2
-
3
- Es lo que permite que el agente trabaje **dentro de tu Chrome**, con tus cuentas ya
4
- iniciadas y **sin quitarte la pantalla**. Puedes seguir jugando o trabajando mientras
5
- opera en una pestaña que ni siquiera está visible.
6
-
7
- ## Instalación (una sola vez)
8
-
9
- 1. Abre `chrome://extensions`
10
- 2. Activa **Modo de desarrollador** (interruptor arriba a la derecha)
11
- 3. Pulsa **Cargar descomprimida**
12
- 4. Selecciona esta carpeta:
13
- `C:\Users\Ryzen\Documents\tomas\chocolatito-code\extension`
14
-
15
- Listo. El icono mostrará el distintivo `on` cuando la CLI esté abierta.
16
-
17
- > **No uses el flag `--load-extension`.** Chrome 137 lo eliminó por abuso de malware;
18
- > hoy no hace nada. Y si añades `--disable-extensions-except`, Chrome desactiva todas
19
- > las extensiones, incluida esta.
20
-
21
- ## Cómo saber que está funcionando
22
-
23
- - El icono de la extensión muestra `on` cuando hay conexión con la CLI.
24
- - La pestaña en la que trabaja entra en un **grupo naranja "Chocolatito Code"**.
25
- - En esa página aparece un **aviso flotante** abajo a la derecha con lo que está
26
- haciendo en cada momento ("leyendo la pagina", "escribiendo", …).
27
- - Al terminar, `chrome(done)` deshace el grupo y retira el aviso.
28
-
29
- ## Por qué hace falta una extensión
30
-
31
- | Vía | ¿Tus sesiones? | ¿Segundo plano real? |
32
- |---|---|---|
33
- | CDP con puerto de depuración (`browser`) | No — Chrome 136+ lo bloquea en el perfil por defecto | Sí, pero en un perfil vacío |
34
- | UI Automation + ratón y teclado (`computer_use`) | Sí | No — para escribir hay que traer la ventana al frente |
35
- | **Extensión (`chrome`)** | **Sí** | **Sí** |
36
-
37
- Las dos primeras fallan justo en la casilla que importa. La extensión corre dentro del
38
- navegador, así que no necesita foco ni ratón, y hereda tu sesión porque *es* tu Chrome.
39
-
40
- ## Arquitectura
41
-
42
- ```
43
- CLI (chocolatito) Chrome
44
- ┌──────────────────┐ ┌─────────────────────────────┐
45
- │ browserExtension │ WebSocket │ background.js │
46
- servidor local │◄──────────────►│ service worker
47
- 127.0.0.1:8787 │ │ · pestañas y grupos
48
- └──────────────────┘ │ · captura por CDP
49
- └───────────┬─────────────────┘
50
- │ chrome.tabs.sendMessage
51
- ┌───────────▼─────────────────┐
52
- │ content.js (en la página) │
53
- · snapshot con refs
54
- │ · clic y escritura
55
- │ · aviso flotante
56
- └─────────────────────────────┘
57
- ```
58
-
59
- El servidor escucha **solo en 127.0.0.1** y rechaza cualquier conexión cuyo origen no
60
- sea `chrome-extension://`, para que una página web no pueda hablar con él.
61
-
62
- ## Detalles que costó descubrir
63
-
64
- - **Escribir con `el.value = ...` no funciona en React.** El texto se ve pero el estado
65
- interno del framework sigue vacío, así que el botón de enviar queda deshabilitado.
66
- Hay que llamar al *setter nativo* del prototipo y emitir `input`. En campos
67
- `contenteditable`, `document.execCommand("insertText")`.
68
- - **El snapshot atraviesa shadow DOM.** Sin eso, en las apps de Google se ve media
69
- interfaz.
70
- - **Las capturas van por `chrome.debugger`**, no por `chrome.tabs.captureVisibleTab`:
71
- esta última exige que la pestaña esté activa y la ventana enfocada, justo lo que
72
- queremos evitar.
73
- - **El service worker se duerme.** Un ping cada 20 s mantiene viva la conexión y con
74
- ella el índice de referencias del último snapshot.
1
+ # Extensión de Chocolatito Code para Chrome
2
+
3
+ Es lo que permite que el agente trabaje **dentro de tu Chrome**, con tus cuentas ya
4
+ iniciadas y **sin quitarte la pantalla**. Puedes seguir jugando o trabajando mientras
5
+ opera en una pestaña que ni siquiera está visible.
6
+
7
+ ## Instalación (una sola vez)
8
+
9
+ 1. Abre `chrome://extensions`
10
+ 2. Activa **Modo de desarrollador** (interruptor arriba a la derecha)
11
+ 3. Pulsa **Cargar descomprimida**
12
+ 4. Selecciona esta carpeta:
13
+ `C:\Users\Ryzen\Documents\tomas\chocolatito-code\extension`
14
+
15
+ Listo. El icono mostrará el distintivo `on` cuando la CLI esté abierta.
16
+
17
+ > **No uses el flag `--load-extension`.** Chrome 137 lo eliminó por abuso de malware;
18
+ > hoy no hace nada. Y si añades `--disable-extensions-except`, Chrome desactiva todas
19
+ > las extensiones, incluida esta.
20
+
21
+ ## Cómo saber que está funcionando
22
+
23
+ - El icono de la extensión muestra el **número de sesiones** conectadas a la CLI, y al
24
+ pulsarlo el panel lo dice con palabras.
25
+ - La pestaña en la que trabaja entra en un **grupo naranja "Chocolatito Code"**.
26
+ - En esa página aparece un **aviso flotante** abajo a la derecha con lo que está
27
+ haciendo en cada momento ("leyendo la pagina", "escribiendo", …).
28
+ - Al terminar, `chrome(done)` deshace el grupo y retira el aviso.
29
+
30
+ ## Por qué hace falta una extensión
31
+
32
+ | Vía | ¿Tus sesiones? | ¿Segundo plano real? |
33
+ |---|---|---|
34
+ | CDP con puerto de depuración (`browser`) | No — Chrome 136+ lo bloquea en el perfil por defecto | Sí, pero en un perfil vacío |
35
+ | UI Automation + ratón y teclado (`computer_use`) | | No — para escribir hay que traer la ventana al frente |
36
+ | **Extensión (`chrome`)** | **Sí** | **Sí** |
37
+
38
+ Las dos primeras fallan justo en la casilla que importa. La extensión corre dentro del
39
+ navegador, así que no necesita foco ni ratón, y hereda tu sesión porque *es* tu Chrome.
40
+
41
+ ## Arquitectura
42
+
43
+ ```
44
+ CLI (chocolatito) Chrome
45
+ ┌──────────────────┐ ┌─────────────────────────────┐
46
+ browserExtension │ WebSocket │ background.js
47
+ servidor local │◄──────────────►│ service worker
48
+ │ 127.0.0.1:8787 │ │ · pestañas y grupos
49
+ └──────────────────┘ │ · captura por CDP │
50
+ └───────────┬─────────────────┘
51
+ │ chrome.tabs.sendMessage
52
+ ┌───────────▼─────────────────┐
53
+ content.js (en la página)
54
+ │ · snapshot con refs
55
+ │ · clic y escritura
56
+ │ · aviso flotante │
57
+ └─────────────────────────────┘
58
+ ```
59
+
60
+ El servidor escucha **solo en 127.0.0.1** y rechaza cualquier conexión cuyo origen no
61
+ sea `chrome-extension://`, para que una página web no pueda hablar con él.
62
+
63
+ ## Detalles que costó descubrir
64
+
65
+ - **Escribir con `el.value = ...` no funciona en React.** El texto se ve pero el estado
66
+ interno del framework sigue vacío, así que el botón de enviar queda deshabilitado.
67
+ Hay que llamar al *setter nativo* del prototipo y emitir `input`. En campos
68
+ `contenteditable`, `document.execCommand("insertText")`.
69
+ - **El snapshot atraviesa shadow DOM.** Sin eso, en las apps de Google se ve media
70
+ interfaz.
71
+ - **Las capturas van por `chrome.debugger`**, no por `chrome.tabs.captureVisibleTab`:
72
+ esta última exige que la pestaña esté activa y la ventana enfocada, justo lo que
73
+ queremos evitar.
74
+ - **El service worker se duerme.** Un ping cada 20 s mantiene viva la conexión, pero
75
+ Chrome puede apagarlo igual. Cuando eso pasa desaparecen la pestaña de trabajo, el
76
+ grupo y el índice de referencias, y todo empieza a fallar con "el ref 3 no existe"
77
+ aunque en pantalla siga igual. Por eso el estado se apunta en `storage.session` y la
78
+ CLI se identifica con un `sessionId` al conectar: mismo id, se recupera lo suyo; id
79
+ distinto, se empieza limpio (heredar la pestaña de otra sesión es como se acaba
80
+ actuando sobre una pestaña ajena).
81
+ - **Esperar `status === "complete"` no basta.** Justo después de pedir una navegación, la
82
+ pestaña todavía informa del estado de la página *anterior*: hay que ver primero la
83
+ transición (estado `loading` o cambio de URL). Sin eso, `navigate` volvía al instante y
84
+ el snapshot siguiente leía la página que se acababa de abandonar, sin dar ningún error.
85
+ - **`chrome.debugger.attach` es exclusivo por pestaña.** Con varias sesiones hablando por
86
+ el mismo service worker, dos escrituras a la vez se pisaban. Los adjuntos van en cola
87
+ por pestaña, y las coordenadas del elemento se miden **dentro** del turno: medirlas
88
+ antes significa medirlas antes de que la acción anterior mueva la página.
89
+ - **Hay páginas donde ninguna extensión puede entrar** (`chrome://`, la Web Store,
90
+ `view-source:`). Se dice con esas palabras en vez de devolver el "Cannot access
91
+ contents of the page" de Chrome, que no explica ni que es culpa de la URL ni que no
92
+ hay que reintentarlo.
93
+ - **Solo se cierra lo que se abrió.** Cada sesión lleva la lista de las pestañas que
94
+ abrió con `open` o eligió con `select`; mirar una pestaña (`snapshot`, `getText`) nunca
95
+ da derecho a cerrarla.