chocolatito-code 1.0.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 (140) hide show
  1. package/.mcp.json.ejemplo +19 -0
  2. package/COMPUTER-USE.md +484 -0
  3. package/LICENSE +21 -0
  4. package/README.md +186 -0
  5. package/dist/agent/context.d.ts +9 -0
  6. package/dist/agent/context.js +123 -0
  7. package/dist/agent/fileTracker.d.ts +16 -0
  8. package/dist/agent/fileTracker.js +53 -0
  9. package/dist/agent/loop.d.ts +25 -0
  10. package/dist/agent/loop.js +524 -0
  11. package/dist/agent/mentions.d.ts +11 -0
  12. package/dist/agent/mentions.js +43 -0
  13. package/dist/agent/retry.d.ts +17 -0
  14. package/dist/agent/retry.js +57 -0
  15. package/dist/agent/subagent.d.ts +2 -0
  16. package/dist/agent/subagent.js +116 -0
  17. package/dist/agent/syntaxValidator.d.ts +5 -0
  18. package/dist/agent/syntaxValidator.js +71 -0
  19. package/dist/agent/tracker.d.ts +19 -0
  20. package/dist/agent/tracker.js +38 -0
  21. package/dist/agent/undoManager.d.ts +37 -0
  22. package/dist/agent/undoManager.js +95 -0
  23. package/dist/config/constants.d.ts +77 -0
  24. package/dist/config/constants.js +146 -0
  25. package/dist/config/engine.d.ts +49 -0
  26. package/dist/config/engine.js +86 -0
  27. package/dist/config/env.d.ts +13 -0
  28. package/dist/config/env.js +103 -0
  29. package/dist/config/license.d.ts +39 -0
  30. package/dist/config/license.js +306 -0
  31. package/dist/config/permissions.d.ts +38 -0
  32. package/dist/config/permissions.js +239 -0
  33. package/dist/config/quota.d.ts +58 -0
  34. package/dist/config/quota.js +156 -0
  35. package/dist/hooks/manager.d.ts +60 -0
  36. package/dist/hooks/manager.js +193 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +470 -0
  39. package/dist/mcp/client.d.ts +55 -0
  40. package/dist/mcp/client.js +282 -0
  41. package/dist/mcp/manager.d.ts +26 -0
  42. package/dist/mcp/manager.js +167 -0
  43. package/dist/memory/manager.d.ts +9 -0
  44. package/dist/memory/manager.js +59 -0
  45. package/dist/prompts/systemPrompt.d.ts +5 -0
  46. package/dist/prompts/systemPrompt.js +177 -0
  47. package/dist/sessions/manager.d.ts +21 -0
  48. package/dist/sessions/manager.js +54 -0
  49. package/dist/skills/manager.d.ts +14 -0
  50. package/dist/skills/manager.js +86 -0
  51. package/dist/tools/browserCdp.d.ts +26 -0
  52. package/dist/tools/browserCdp.js +610 -0
  53. package/dist/tools/browserExtension.d.ts +58 -0
  54. package/dist/tools/browserExtension.js +479 -0
  55. package/dist/tools/browserLive.d.ts +12 -0
  56. package/dist/tools/browserLive.js +265 -0
  57. package/dist/tools/changeDir.d.ts +5 -0
  58. package/dist/tools/changeDir.js +63 -0
  59. package/dist/tools/computerUse.d.ts +58 -0
  60. package/dist/tools/computerUse.js +567 -0
  61. package/dist/tools/createImage.d.ts +1 -0
  62. package/dist/tools/createImage.js +34 -0
  63. package/dist/tools/definitions.d.ts +8 -0
  64. package/dist/tools/definitions.js +401 -0
  65. package/dist/tools/deleteFile.d.ts +1 -0
  66. package/dist/tools/deleteFile.js +17 -0
  67. package/dist/tools/editFile.d.ts +5 -0
  68. package/dist/tools/editFile.js +88 -0
  69. package/dist/tools/findFiles.d.ts +1 -0
  70. package/dist/tools/findFiles.js +33 -0
  71. package/dist/tools/getSystemInfo.d.ts +1 -0
  72. package/dist/tools/getSystemInfo.js +23 -0
  73. package/dist/tools/gitTools.d.ts +3 -0
  74. package/dist/tools/gitTools.js +47 -0
  75. package/dist/tools/grepSearch.d.ts +1 -0
  76. package/dist/tools/grepSearch.js +37 -0
  77. package/dist/tools/listDir.d.ts +1 -0
  78. package/dist/tools/listDir.js +33 -0
  79. package/dist/tools/moveCopyFile.d.ts +1 -0
  80. package/dist/tools/moveCopyFile.js +21 -0
  81. package/dist/tools/runCommand.d.ts +1 -0
  82. package/dist/tools/runCommand.js +61 -0
  83. package/dist/tools/runner.d.ts +5 -0
  84. package/dist/tools/runner.js +177 -0
  85. package/dist/tools/safety.d.ts +17 -0
  86. package/dist/tools/safety.js +33 -0
  87. package/dist/tools/todoTool.d.ts +8 -0
  88. package/dist/tools/todoTool.js +27 -0
  89. package/dist/tools/toolDefsComputer.d.ts +13 -0
  90. package/dist/tools/toolDefsComputer.js +205 -0
  91. package/dist/tools/truncator.d.ts +11 -0
  92. package/dist/tools/truncator.js +24 -0
  93. package/dist/tools/viewFile.d.ts +1 -0
  94. package/dist/tools/viewFile.js +45 -0
  95. package/dist/tools/visionBridge.d.ts +37 -0
  96. package/dist/tools/visionBridge.js +107 -0
  97. package/dist/tools/webFetch.d.ts +1 -0
  98. package/dist/tools/webFetch.js +25 -0
  99. package/dist/tools/webSearch.d.ts +1 -0
  100. package/dist/tools/webSearch.js +35 -0
  101. package/dist/tools/win/hostClient.d.ts +31 -0
  102. package/dist/tools/win/hostClient.js +158 -0
  103. package/dist/tools/win/hostScript.d.ts +1 -0
  104. package/dist/tools/win/hostScript.js +925 -0
  105. package/dist/tools/writeFile.d.ts +1 -0
  106. package/dist/tools/writeFile.js +13 -0
  107. package/dist/ui/banner.d.ts +10 -0
  108. package/dist/ui/banner.js +165 -0
  109. package/dist/ui/diffViewer.d.ts +1 -0
  110. package/dist/ui/diffViewer.js +60 -0
  111. package/dist/ui/interrupt.d.ts +17 -0
  112. package/dist/ui/interrupt.js +156 -0
  113. package/dist/ui/markdownStream.d.ts +23 -0
  114. package/dist/ui/markdownStream.js +0 -0
  115. package/dist/ui/modes.d.ts +28 -0
  116. package/dist/ui/modes.js +57 -0
  117. package/dist/ui/permissionPrompt.d.ts +35 -0
  118. package/dist/ui/permissionPrompt.js +271 -0
  119. package/dist/ui/prompt.d.ts +7 -0
  120. package/dist/ui/prompt.js +466 -0
  121. package/dist/ui/reasoningStream.d.ts +6 -0
  122. package/dist/ui/reasoningStream.js +38 -0
  123. package/dist/ui/renderer.d.ts +10 -0
  124. package/dist/ui/renderer.js +142 -0
  125. package/dist/ui/spinner.d.ts +24 -0
  126. package/dist/ui/spinner.js +111 -0
  127. package/dist/ui/theme.d.ts +36 -0
  128. package/dist/ui/theme.js +37 -0
  129. package/dist/ui/typeAhead.d.ts +31 -0
  130. package/dist/ui/typeAhead.js +87 -0
  131. package/extension/README.md +74 -0
  132. package/extension/background.js +575 -0
  133. package/extension/content.js +446 -0
  134. package/extension/manifest.json +36 -0
  135. package/extension/popup.html +22 -0
  136. package/extension/popup.js +12 -0
  137. package/package.json +66 -0
  138. package/skills/complex-refactor/SKILL.md +13 -0
  139. package/skills/deep-debugger/SKILL.md +14 -0
  140. package/skills/software-architect/SKILL.md +20 -0
@@ -0,0 +1,19 @@
1
+ {
2
+ "_comentario": "Renombra este archivo a .mcp.json para activarlo. Se conecta al arrancar.",
3
+ "mcpServers": {
4
+ "filesystem": {
5
+ "command": "npx",
6
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
7
+ },
8
+ "github": {
9
+ "command": "npx",
10
+ "args": ["-y", "@modelcontextprotocol/server-github"],
11
+ "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
12
+ },
13
+ "servidor-remoto": {
14
+ "type": "http",
15
+ "url": "https://ejemplo.com/mcp",
16
+ "headers": { "Authorization": "Bearer ${MI_TOKEN}" }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,484 @@
1
+ # Computer Use en Chocolatito Code
2
+
3
+ Documento de diseño del control de ordenador y navegador. Explica **por qué fallaba**,
4
+ **qué dicen las implementaciones oficiales**, y **cómo está construido ahora**.
5
+
6
+ ---
7
+
8
+ ## 1. Diagnóstico: por qué abría lo que no era y se quedaba trabado
9
+
10
+ Los cuatro fallos eran independientes y se acumulaban. Cualquiera de ellos por sí solo
11
+ bastaba para que el agente hiciera clic en el sitio equivocado.
12
+
13
+ ### 1.1 El agente estaba ciego (causa principal)
14
+
15
+ `computer_use(screenshot)` guardaba un PNG y devolvía al modelo un texto como:
16
+
17
+ ```
18
+ ✔ Captura de pantalla tomada (312.4 KB) -> "screenshot_latest.png" [Ventana: "Chrome"].
19
+ ```
20
+
21
+ El motor (`deepseek-chat`) es de texto: nunca vio la imagen. Recibía una confirmación de
22
+ que existía un archivo, y nada más.
23
+
24
+ Como el modelo no podía ver, el system prompt le daba coordenadas fijas escritas a mano:
25
+
26
+ ```
27
+ * Paso 4: haz clic en "New Project" con (action: "click", x: 180, y: 140)
28
+ * Paso 6: haz clic en la barra de prompt con (action: "click", x: 960, y: 920)
29
+ ```
30
+
31
+ Esas coordenadas eran válidas, como mucho, para una resolución concreta, con la ventana
32
+ maximizada, sin barra de marcadores y con esa versión exacta de la interfaz de Flow.
33
+ En cualquier otra situación el clic caía en un sitio arbitrario. **Esto es lo que hacía
34
+ que "siempre abra lo que no es".**
35
+
36
+ El propio `screenshot` reforzaba el error inventando una guía falsa:
37
+
38
+ ```ts
39
+ if (winTitle.includes("flow") || winTitle.includes("chrome")) {
40
+ flowGuide = `\n📍 [Guía de Interfaz Detectada]:
41
+ - Botón "New Project": (X: 180, Y: 140)...`;
42
+ }
43
+ ```
44
+
45
+ No detectaba nada: imprimía constantes fijas siempre que el título contuviera "chrome".
46
+
47
+ ### 1.2 Todas las coordenadas estaban desviadas un 25%
48
+
49
+ Verificado en esta máquina:
50
+
51
+ | Medición | Valor |
52
+ |---|---|
53
+ | `Screen.PrimaryScreen.Bounds` (proceso sin DPI awareness) | **2048 × 1152** |
54
+ | `GetSystemMetrics` con DPI awareness | **2560 × 1440** |
55
+ | Escala de Windows | 125% |
56
+
57
+ El proceso de PowerShell no declaraba DPI awareness, así que Windows le mentía sobre el
58
+ tamaño de la pantalla. La captura se tomaba en el espacio virtualizado de 2048×1152
59
+ mientras que las coordenadas de UI Automation y del escritorio real son de 2560×1440.
60
+
61
+ Resultado: **un desfase sistemático de 1,25×**. Un clic destinado a (2000, 1100) aterrizaba
62
+ en (1600, 880). Cuanto más a la derecha y más abajo estuviera el objetivo, mayor el error.
63
+
64
+ ### 1.3 Cada acción tardaba ~1 segundo
65
+
66
+ Cada clic lanzaba un `powershell.exe` nuevo que compilaba tipos C# con `Add-Type` desde
67
+ cero. Medido: 700–1500 ms por acción, sin contar el trabajo real. Una secuencia de 15
68
+ pasos gastaba unos 20 segundos solo en arrancar procesos. De ahí la sensación de que
69
+ "se queda trabado".
70
+
71
+ ### 1.4 Peleaba con el usuario por la pantalla
72
+
73
+ Todo pasaba por el primer plano: `SetForegroundWindow`, `SetCursorPos`, `SendKeys`.
74
+ Además cada clic dibujaba un formulario `TopMost` de Windows Forms como puntero láser,
75
+ que consumía 250 ms y podía robar la activación de la ventana justo antes de pulsar.
76
+
77
+ Y `SendKeys` era frágil por partida doble. El escape estaba mal construido:
78
+
79
+ ```ts
80
+ const escaped = text.replace(/[{}+^%~()\[\\]]/g, "{$&}");
81
+ ```
82
+
83
+ Esa clase de caracteres no es la que se pretendía, y `SendKeys` además pierde caracteres
84
+ en textos largos y no maneja bien acentos ni emoji.
85
+
86
+ ---
87
+
88
+ ## 2. Referencias oficiales consultadas
89
+
90
+ ### 2.1 Anthropic — Computer Use Tool
91
+
92
+ `platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool`
93
+
94
+ Lo que se ha adoptado de la especificación:
95
+
96
+ - **El ciclo es observar → actuar → verificar.** La guía oficial insiste en cerrar cada
97
+ lote de acciones con una captura para que el modelo compruebe el resultado, y en
98
+ pedirle explícitamente que evalúe si el paso salió bien antes de continuar.
99
+ - **Escalado de imagen con factor guardado.** Se captura a resolución nativa, se reduce
100
+ para el envío, y al ejecutar se vuelven a escalar las coordenadas al espacio físico.
101
+ El límite clásico de lado largo es 1568 px; es el que se usa aquí.
102
+ - **Resoluciones recomendadas** de 1024×768 a 1366×768; evitar por encima de 1920×1080.
103
+ - **Diagnóstico de precisión de clic:** un desfase constante indica desajuste de escala
104
+ entre la captura y la pantalla. Es exactamente el fallo 1.2 de este proyecto.
105
+ - **Nomenclatura de teclas:** `Return`, `Escape`, `ctrl+s`, `alt+Tab`.
106
+ - La implementación de referencia (`anthropic-quickstarts/computer-use-demo`,
107
+ `tools/computer.py`) escribe en trozos con retardo por carácter y espera ~2 s tras
108
+ cada acción para que la interfaz se asiente antes de capturar.
109
+
110
+ ### 2.2 Microsoft — Playwright MCP
111
+
112
+ `github.com/microsoft/playwright-mcp`
113
+
114
+ De aquí sale la decisión de diseño más importante:
115
+
116
+ > Opera sobre datos estructurados en vez de píxeles. `browser_snapshot` devuelve el árbol
117
+ > de accesibilidad y cada elemento lleva una referencia; se actúa sobre esa referencia.
118
+ > El modo por coordenadas (`browser_mouse_click_xy`) es opcional (`--caps=vision`) y se
119
+ > reserva para lienzos.
120
+
121
+ Es decir: **el enfoque por defecto de la herramienta oficial no es hacer clic en píxeles,
122
+ sino en elementos identificados**. Eso elimina de raíz la ambigüedad que hacía que se
123
+ pulsara el botón equivocado. Este proyecto aplica la misma idea en dos frentes: el árbol
124
+ de UI Automation para el escritorio y el DOM para las páginas web.
125
+
126
+ ### 2.3 Chrome DevTools Protocol
127
+
128
+ `Input.dispatchMouseEvent` entrega el evento directamente a la pestaña. No mueve el ratón
129
+ del sistema y no exige que la ventana esté delante. Es la base técnica del modo en
130
+ segundo plano para navegador.
131
+
132
+ ---
133
+
134
+ ## 3. Arquitectura actual
135
+
136
+ ```
137
+ ┌──────────────────────────────┐
138
+ │ bucle del agente │
139
+ └──────┬───────────────┬───────┘
140
+ │ │
141
+ computer_use browser
142
+ (escritorio) (páginas web)
143
+ │ │
144
+ ┌─────────┴────────┐ │
145
+ │ host persistente │ │ puppeteer.connect
146
+ │ PowerShell + C# │ │ (CDP, puerto 9222)
147
+ │ · DPI-aware │ │
148
+ │ · UI Automation │ ▼
149
+ │ · SendInput │ Chrome real
150
+ │ · PrintWindow │ (perfil con sesión)
151
+ └──────────────────┘
152
+
153
+ visionBridge → deepseek-v4-flash-vision-exp
154
+ ```
155
+
156
+ ### 3.1 Host persistente de Windows
157
+
158
+ `src/tools/win/hostScript.ts` + `src/tools/win/hostClient.ts`
159
+
160
+ Un único `powershell.exe` por sesión que compila los tipos nativos al arrancar y después
161
+ atiende comandos JSON por stdin, respondiendo `CHOCO#<id>#<json>`.
162
+
163
+ **Medido:** arranque 606 ms, y después **12–246 ms por acción** (frente a 700–1500 ms antes).
164
+
165
+ Lo primero que hace, antes de medir nada:
166
+
167
+ ```csharp
168
+ SetProcessDpiAwarenessContext(new IntPtr(-4)); // PER_MONITOR_AWARE_V2
169
+ ```
170
+
171
+ Con eso hay un único sistema de coordenadas en píxeles físicos y desaparece el desfase
172
+ del 25%.
173
+
174
+ ### 3.2 Árbol de accesibilidad: el camino por defecto
175
+
176
+ `ui_snapshot` recorre en anchura el árbol de UI Automation de una ventana y devuelve sus
177
+ controles reales:
178
+
179
+ ```
180
+ SNAPSHOT DE "*.env.local: Bloc de notas" (ventana 1800x941 en 280,280)
181
+
182
+ [1] Document "Editor de texto" = "NEXT_PUBLIC_SUPABASE_URL=https://..." @(1180, 773)
183
+ [11] MenuItem "Archivo" @(335, 352)
184
+ [12] MenuItem "Editar" @(422, 352)
185
+ ```
186
+
187
+ Después `ui_click(ref: 11)` activa ese elemento mediante `InvokePattern`, que **no mueve
188
+ el ratón, no roba el foco y no depende de ninguna coordenada**. Si no hay `InvokePattern`
189
+ se prueban `SelectionItem`, `Toggle` y `ExpandCollapse` en ese orden.
190
+
191
+ Ventaja añadida: al ser texto, funciona con un motor sin visión y cuesta muy pocos tokens.
192
+
193
+ ### 3.3 Captura de una ventana tapada
194
+
195
+ `PrintWindow(hwnd, hdc, PW_RENDERFULLCONTENT)` pide a la ventana que se redibuje en
196
+ nuestro contexto gráfico. Funciona con la ventana detrás de otras o sin foco. Si el
197
+ resultado sale casi negro (le pasa a Chrome y a apps Electron por composición en GPU),
198
+ se recurre automáticamente a copiar esa región de la pantalla.
199
+
200
+ Verificado: captura completa y legible de Chrome sin traerlo al frente ni una sola vez.
201
+
202
+ ### 3.4 Entrada en segundo plano
203
+
204
+ | Modo | Mecanismo | Mueve el ratón | Roba el foco |
205
+ |---|---|---|---|
206
+ | `ui_click` / `ui_type` | Patrones de UI Automation | No | No |
207
+ | `mode: "background"` | `PostMessage` a la ventana | No | No |
208
+ | `mode: "foreground"` | `SendInput` absoluto | Sí | Sí |
209
+
210
+ `SendInput` sustituye a `SendKeys`: con `KEYEVENTF_UNICODE` escribe cualquier carácter
211
+ —acentos, eñes, emoji— sin escapes y sin perder caracteres.
212
+
213
+ ### 3.5 Navegador por CDP
214
+
215
+ `src/tools/browserCdp.ts`
216
+
217
+ `browser(snapshot)` recorre el DOM de todos los frames **y atraviesa shadow roots**
218
+ (imprescindible en apps modernas de Google), marca cada elemento con `data-choco-ref` y
219
+ devuelve una lista con su nombre accesible:
220
+
221
+ ```
222
+ PAGINA: "DuckDuckGo - Protección. Privacidad. Tranquilidad."
223
+
224
+ [1] textbox "Buscar con DuckDuckGo"
225
+ [3] button "Buscar"
226
+ [12] button "Búsqueda Privada" [hay que hacer scroll]
227
+ ```
228
+
229
+ `browser(type, ref: 1, text: "...", submit: true)` escribe y envía por CDP. Verificado de
230
+ extremo a extremo: la búsqueda se ejecutó y el snapshot siguiente confirmó la página de
231
+ resultados, con Chrome en segundo plano en todo momento.
232
+
233
+ **Sesión de Google — límite importante.** Desde **Chrome 136** Google bloquea
234
+ `--remote-debugging-port` cuando se usa el directorio de perfil por defecto. Es una
235
+ medida de seguridad deliberada, no un fallo de configuración. Consecuencia práctica:
236
+
237
+ > **`browser` NO puede engancharse al Chrome del usuario ni a sus cuentas ya iniciadas.**
238
+
239
+ Por eso hay dos caminos, y elegir bien es lo que decide si la tarea funciona:
240
+
241
+ | Situación | Herramienta |
242
+ |---|---|
243
+ | Hace falta la sesión del usuario (Flow, su Gmail, su panel) | `computer_use` sobre su Chrome |
244
+ | Web pública, cuenta del propio agente, `localhost`, scraping | `browser` (CDP) |
245
+
246
+ `browser` usa un perfil propio en `~/.chocolatito/chrome-profile`. Si necesita una cuenta,
247
+ **la inicia el usuario a mano una vez**. El agente nunca pide ni escribe credenciales.
248
+
249
+ La opción `useSystemProfile: true` sigue existiendo pero solo sirve en Chrome anterior
250
+ a 136; en versiones actuales la propia Chrome rechaza el puerto.
251
+
252
+ Se lanza con `--disable-background-timer-throttling`,
253
+ `--disable-backgrounding-occluded-windows` y `--disable-renderer-backgrounding`: sin
254
+ esas banderas Chrome congela temporizadores y renderizado cuando la ventana no está
255
+ delante, que es justo como se va a usar.
256
+
257
+ ### 3.7 Conducir el Chrome del usuario (con su sesión)
258
+
259
+ Este es el camino para todo lo que dependa de una cuenta ya iniciada. Verificado de
260
+ extremo a extremo contra Google Flow.
261
+
262
+ **UI Automation sí expone el contenido de las páginas de Chrome.** No solo la barra de
263
+ direcciones y las pestañas: también botones, enlaces y menús del propio sitio, con su
264
+ texto real y coordenadas físicas correctas.
265
+
266
+ ```
267
+ computer_use(open_app, appName: "https://labs.google/fx/tools/flow")
268
+ → abre en el navegador por defecto, con el perfil y la sesión del usuario
269
+
270
+ computer_use(ui_snapshot, window: "Flow")
271
+ → [34] Button "add_2 Proyecto nuevo" @(1280, 1231)
272
+ [8] Button "Tomas Diego" ← confirma que la sesión está iniciada
273
+
274
+ computer_use(ui_click, ref: 34)
275
+ → Activado (via invoke, sin mover el ratón)
276
+ ```
277
+
278
+ #### Escribir en una web: por qué `ValuePattern` no vale
279
+
280
+ Es la trampa más importante de todo el sistema, y costó descubrirla en vivo.
281
+
282
+ `ValuePattern.SetValue` escribe en el DOM, y el texto **se ve** en pantalla. Pero React
283
+ —y cualquier framework con estado controlado— no recibe los eventos de teclado, así que
284
+ su estado interno sigue vacío. Resultado observado en Flow: el prompt aparecía escrito
285
+ en el campo, y al pulsar Crear la aplicación respondía **"Se debe proporcionar una
286
+ instrucción"**. El botón de enviar seguía marcado como deshabilitado.
287
+
288
+ Por eso `ui_type` ahora detecta si la ventana es un navegador y, en ese caso, hace clic
289
+ real sobre el elemento y teclea de verdad, verificando después leyendo el valor del
290
+ control. Solo en aplicaciones nativas de escritorio usa `ValuePattern`.
291
+
292
+ Aviso relacionado: **no limpies un campo web con `ctrl+a` + `Delete` antes de escribir.**
293
+ Al vaciarse, React vuelve a montar el composer, el foco se pierde y las pulsaciones
294
+ siguientes caen sobre la página, donde pueden disparar atajos de teclado. Observado: se
295
+ activó solo el modo "Agente" de Flow. Haz clic y escribe directamente.
296
+
297
+ #### Búsqueda tolerante
298
+
299
+ Dos correcciones sobre `find_element`, ambas surgidas de fallos reales:
300
+
301
+ - **Consulta en lenguaje natural.** El filtro del árbol es coincidencia de subcadena, así
302
+ que `"el botón Imagen del menú inferior"` no encontraba nada y caía a la visión, que
303
+ devolvió (872, 950) cuando el control estaba en (1352, 894). Ahora se prueba la frase
304
+ completa y después palabra por palabra, descartando palabras vacías.
305
+ - **Tildes.** Buscar `"Imagenes"` no encontraba `"Imágenes"`. Toda comparación pasa ahora
306
+ por una normalización que quita diacríticos.
307
+
308
+ La lección general: **la visión estima coordenadas mal.** Sirve para *entender* una
309
+ pantalla, no para apuntar. Para apuntar, el árbol de accesibilidad.
310
+
311
+ ### 3.6 Puente de visión
312
+
313
+ `src/tools/visionBridge.ts`
314
+
315
+ La cuenta tiene `deepseek-v4-flash-vision-exp`, multimodal. La captura se le manda y
316
+ vuelve como texto que el motor principal sí entiende:
317
+
318
+ ```
319
+ LO QUE SE VE:
320
+ Aplicación: DuckDuckGo. Pantalla: página de inicio en español.
321
+ El campo de búsqueda está vacío, con el placeholder "Busca de manera privada".
322
+ Elementos accionables: Campo de texto..., Botón "Buscar", Botón "Duck.ai"...
323
+ ```
324
+
325
+ Coste medido: ~500 tokens de entrada por captura de 1568 px de lado largo.
326
+
327
+ Detalle importante: es un modelo que razona antes de responder. Si se agota el
328
+ presupuesto de tokens razonando, `content` llega vacío. Por eso hay margen amplio
329
+ (1600 tokens) y, si aun así llega vacío, se aprovecha `reasoning_content`.
330
+
331
+ `find_element` combina ambos mundos: primero busca en el árbol de accesibilidad (exacto y
332
+ gratis) y solo si no encuentra nada recurre a la visión, validando que el punto devuelto
333
+ caiga dentro de la imagen antes de darlo por bueno.
334
+
335
+ ---
336
+
337
+ ## 4. Cómo se usa
338
+
339
+ ### Página web (Google Flow, paneles, formularios)
340
+
341
+ ```
342
+ browser(attach)
343
+ browser(tabs) → ver qué hay abierto
344
+ browser(select_tab, match: "flow")
345
+ browser(snapshot) → [7] button "New project"
346
+ browser(click, ref: 7)
347
+ browser(wait_for, text: "Prompt")
348
+ browser(snapshot, filter: "prompt") → [3] textbox "Escribe tu idea"
349
+ browser(type, ref: 3, text: "...", submit: true)
350
+ browser(snapshot) → verificar
351
+ ```
352
+
353
+ ### Aplicación de escritorio
354
+
355
+ ```
356
+ computer_use(list_windows)
357
+ computer_use(ui_snapshot, window: "Blender") → [14] Button "Render"
358
+ computer_use(ui_click, ref: 14)
359
+ computer_use(ui_snapshot, window: "Blender") → verificar
360
+ ```
361
+
362
+ ### Cuando no hay árbol accesible (lienzos, vídeo, juegos)
363
+
364
+ ```
365
+ computer_use(screenshot, window: "Flow", question: "¿Terminó de generar el vídeo?")
366
+ computer_use(find_element, window: "Flow", query: "botón de descarga")
367
+ computer_use(click, window: "Flow", coordinate: [x, y]) ← solo con las coords que dio find_element
368
+ ```
369
+
370
+ ---
371
+
372
+ ## 5. Reglas de seguridad incorporadas
373
+
374
+ - **`ui_type` nunca arrasa un documento.** `ValuePattern.SetValue` sustituye *todo* el
375
+ contenido de un control. En un campo de una línea es lo deseable; en un editor de texto
376
+ completo borra el documento entero. Los controles de tipo `Document` se escriben
377
+ enfocando y tecleando (inserta en el cursor) salvo que se pase `replace: true`
378
+ explícitamente.
379
+ - **`open_app` espera a que la ventana exista** antes de devolver el control. Devolver
380
+ antes era lo que hacía que la acción siguiente cayera en la ventana anterior.
381
+ - **`focus_window` verifica el resultado real** con `GetForegroundWindow` en vez de fiarse
382
+ del valor de retorno de `SetForegroundWindow`, que miente cuando Windows bloquea el
383
+ cambio de primer plano.
384
+ - **`browser(close)` no cierra el Chrome del usuario**: si la conexión era a un Chrome
385
+ existente, solo se desconecta.
386
+ - **La visión valida sus propias coordenadas**: un punto fuera de los límites de la imagen
387
+ se trata como alucinación, no como acierto.
388
+
389
+ ---
390
+
391
+ ## 6. Antes y después
392
+
393
+ | | Antes | Ahora |
394
+ |---|---|---|
395
+ | Coordenadas | Fijas en el prompt, desviadas 25% por DPI | Del árbol de accesibilidad o del DOM, en píxeles físicos |
396
+ | Qué ve el modelo | "Captura guardada, 312 KB" | Lista de controles con texto exacto, o descripción de la imagen |
397
+ | Latencia por acción | 700–1500 ms | 12–246 ms |
398
+ | Pantalla del usuario | Ocupada, con overlay que se pegaba | Libre: se actúa en segundo plano |
399
+ | Escritura | `SendKeys` con escapes rotos | `SendInput` Unicode / `ValuePattern` / CDP |
400
+ | Sesión de Google | Sandbox aislado sin cookies | Perfil persistente con sesión real |
401
+ | Verificación | Ninguna | Snapshot obligatorio después de cada acción |
402
+
403
+ ---
404
+
405
+ ## 7. Archivos
406
+
407
+ | Archivo | Contenido |
408
+ |---|---|
409
+ | `src/tools/win/hostScript.ts` | Host PowerShell + C#: DPI, ventanas, UIA, captura, entrada |
410
+ | `src/tools/win/hostClient.ts` | Gestión del proceso persistente y protocolo JSON |
411
+ | `src/tools/computerUse.ts` | Herramienta de escritorio |
412
+ | `src/tools/browserCdp.ts` | Herramienta de navegador por CDP |
413
+ | `src/tools/visionBridge.ts` | Traducción de imagen a texto |
414
+ | `src/tools/toolDefsComputer.ts` | Esquemas de ambas herramientas |
415
+ | `src/prompts/systemPrompt.ts` | Bloque 5: reglas de observar → actuar → verificar |
416
+
417
+ `src/tools/browserLive.ts` queda como código muerto: el nombre `browser_live` sigue
418
+ aceptándose por compatibilidad, pero se redirige a `browserCdp`. Se puede borrar.
419
+
420
+ ---
421
+
422
+ ## 8. La extensión de Chrome: trabajo real en segundo plano
423
+
424
+ Las dos vías anteriores fallan justo donde importa:
425
+
426
+ | Vía | ¿Usa tus sesiones? | ¿Segundo plano real? |
427
+ |---|---|---|
428
+ | CDP con puerto de depuración (`browser`) | No — Chrome 136+ lo bloquea en el perfil por defecto | Sí, pero en un perfil vacío |
429
+ | UI Automation + ratón y teclado (`computer_use`) | Sí | **No** — para escribir hay que traer la ventana al frente |
430
+ | **Extensión (`chrome`)** | **Sí** | **Sí** |
431
+
432
+ `computer_use` sirve para leer y pulsar en segundo plano, pero escribir en una web exige
433
+ foco real. Si el usuario está jugando, eso le saca del juego. La extensión resuelve el
434
+ problema por construcción: corre *dentro* del navegador, así que no necesita foco ni
435
+ ratón, y hereda la sesión porque **es** el Chrome del usuario.
436
+
437
+ ### Cómo se ve mientras trabaja
438
+
439
+ - La pestaña entra en un **grupo naranja "Chocolatito Code"** en la barra de pestañas.
440
+ - En la página aparece un **aviso flotante** abajo a la derecha, en shadow DOM para que
441
+ ni la página lo rompa ni él ensucie la página, con lo que está haciendo en cada
442
+ momento.
443
+ - `chrome(done)` deshace el grupo y retira el aviso.
444
+
445
+ ### Verificado
446
+
447
+ Abrió el proyecto de Flow en una pestaña de fondo, con la sesión del usuario, y leyó su
448
+ contenido. La ventana en primer plano fue la misma antes y después:
449
+
450
+ ```
451
+ ANTES: Ventana activa: "Extensiones - Google Chrome"
452
+ → chrome(open, url) + chrome(snapshot) sobre el proyecto de Flow
453
+ DESPUES: Ventana activa: "Extensiones - Google Chrome"
454
+ ```
455
+
456
+ ### Trampas encontradas al construirla
457
+
458
+ - **Chrome 137 eliminó `--load-extension`.** Hay que cargarla por la UI. Y si se pasa
459
+ `--disable-extensions-except`, Chrome desactiva *todas* las extensiones, incluida la
460
+ que se acaba de cargar: eso costó varios intentos de depuración.
461
+ - **Un `.click()` desde JS no abre diálogos de archivo.** Chrome exige un gesto de
462
+ usuario de confianza; hay que usar entrada CDP o un clic real.
463
+ - **Los diálogos nativos no se rellenan con `ValuePattern`.** Ponen el texto pero el
464
+ diálogo no lo resuelve como ruta. Hay que enfocar y teclear de verdad.
465
+ - **El título del diálogo cambia entre versiones de Chrome** ("Seleccionar el directorio
466
+ de extensión." frente a "Selecciona el directorio de la extensión."). Nunca dependas
467
+ de un título literal: usa `list_windows` y quédate con el `hwnd`.
468
+
469
+ ### Regla de seguridad que salió de un accidente real
470
+
471
+ Buscar la ventana `"Google Chrome"` coincide con **todas** las ventanas de Chrome. El
472
+ desempate era por área, así que eligió la principal del usuario y un `alt+F4` la cerró
473
+ con todas sus pestañas.
474
+
475
+ Ahora `focus_window` **se niega a actuar si la consulta es ambigua**:
476
+
477
+ ```
478
+ Error en computer_use (focus_window): "Google Chrome" coincide con 2 ventanas
479
+ (CSP - 1er Ciclo 26-2 - Presentación - Google Chrome | Nueva pestaña - Google Chrome).
480
+ Es ambiguo y no voy a elegir por ti: usa list_windows y pasa un titulo mas concreto.
481
+ ```
482
+
483
+ Elegir a ciegas entre candidatos empatados no es una comodidad: es cómo se acaba
484
+ mandando una pulsación destructiva a la ventana equivocada.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chocolatito
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.