chocolatito-code 1.6.7 → 1.6.9

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 (55) hide show
  1. package/README.md +447 -341
  2. package/dist/agent/context.d.ts +6 -0
  3. package/dist/agent/context.js +69 -2
  4. package/dist/agent/loop.js +8 -0
  5. package/dist/agent/toolGate.js +13 -7
  6. package/dist/agent/verifier.js +2 -1
  7. package/dist/config/permissions.d.ts +17 -0
  8. package/dist/config/permissions.js +47 -7
  9. package/dist/config/plataforma.d.ts +62 -0
  10. package/dist/config/plataforma.js +109 -0
  11. package/dist/config/updater.js +4 -1
  12. package/dist/hooks/manager.js +2 -1
  13. package/dist/index.js +99 -6
  14. package/dist/memory/manager.d.ts +15 -5
  15. package/dist/memory/manager.js +146 -29
  16. package/dist/servidor/captura.d.ts +36 -0
  17. package/dist/servidor/captura.js +74 -0
  18. package/dist/servidor/pagina.d.ts +27 -0
  19. package/dist/servidor/pagina.js +268 -0
  20. package/dist/servidor/puente.d.ts +34 -0
  21. package/dist/servidor/puente.js +115 -0
  22. package/dist/servidor/servidor.d.ts +61 -0
  23. package/dist/servidor/servidor.js +249 -0
  24. package/dist/sessions/manager.d.ts +8 -0
  25. package/dist/sessions/manager.js +44 -0
  26. package/dist/sessions/resume.d.ts +12 -0
  27. package/dist/sessions/resume.js +10 -0
  28. package/dist/tools/backgroundTask.d.ts +64 -0
  29. package/dist/tools/backgroundTask.js +264 -0
  30. package/dist/tools/browserExtension.d.ts +2 -1
  31. package/dist/tools/browserExtension.js +48 -0
  32. package/dist/tools/computerUse.js +51 -9
  33. package/dist/tools/definitions.js +93 -1
  34. package/dist/tools/gitAudit.d.ts +68 -0
  35. package/dist/tools/gitAudit.js +374 -0
  36. package/dist/tools/runCommand.js +5 -2
  37. package/dist/tools/runner.js +36 -2
  38. package/dist/tools/safety.d.ts +1 -0
  39. package/dist/tools/safety.js +3 -0
  40. package/dist/tools/todoTool.d.ts +2 -0
  41. package/dist/tools/todoTool.js +29 -0
  42. package/dist/tools/toolDefsComputer.js +9 -0
  43. package/dist/tools/win/hostScript.js +7 -2
  44. package/dist/ui/comandos.js +2 -0
  45. package/dist/ui/marco.d.ts +1 -0
  46. package/dist/ui/marco.js +4 -2
  47. package/dist/ui/permissionPrompt.d.ts +9 -0
  48. package/dist/ui/permissionPrompt.js +30 -0
  49. package/dist/ui/pieFijo.d.ts +1 -1
  50. package/dist/ui/pieFijo.js +1 -1
  51. package/dist/ui/renderer.js +8 -0
  52. package/extension/background.js +80 -0
  53. package/extension/content.js +106 -0
  54. package/extension/manifest.json +61 -60
  55. package/package.json +3 -2
@@ -4,6 +4,7 @@ import chalk from "chalk";
4
4
  import { cycleMode, describeMode, getMode, modeAnnouncement } from "./modes.js";
5
5
  import { isOutsideProject, isSvgSource } from "../config/permissions.js";
6
6
  import { conElTerminalPrestado } from "./ink/prestamo.js";
7
+ import { pedirPermisoWeb } from "../servidor/puente.js";
7
8
  /**
8
9
  * Aprobacion automatica: se activa con --yes / -y o con la variable de entorno
9
10
  * CHOCOLATITO_AUTO_APPROVE. Pensada para modo no interactivo y CI.
@@ -362,5 +363,34 @@ function details(toolName, args, cwd, width) {
362
363
  * tarea tal cual y no cuesta nada. Ver ui/ink/prestamo.ts.
363
364
  */
364
365
  export function askToolPermission(toolName, args, cwd = process.cwd()) {
366
+ // --yes primero: si ya se aprobo todo a mano, no hay que molestar a nadie ni
367
+ // abrir en el movil un dialogo que se contestaria solo.
368
+ if (autoApprove)
369
+ return Promise.resolve({ approved: true });
370
+ // Con `--servir` y alguien conectado, la pregunta va al navegador. Devuelve
371
+ // null cuando no hay ningun cliente, y entonces esto sigue como siempre: al
372
+ // terminal, que es donde hay un humano. Lo que NO pasa nunca es que se apruebe
373
+ // algo por no tener a quien preguntar.
374
+ const porWeb = pedirPermisoWeb(toolName, detallesEnTextoPlano(toolName, args, cwd), PERMISSION_OPTIONS);
375
+ if (porWeb)
376
+ return porWeb;
365
377
  return conElTerminalPrestado(() => askToolPermissionDirecto(toolName, args, cwd));
366
378
  }
379
+ /**
380
+ * El mismo contenido del dialogo del terminal, sin color y sin marco, para
381
+ * pintarlo en HTML.
382
+ *
383
+ * Se reutiliza `details()` a proposito: dos sitios decidiendo por separado que
384
+ * hay que enseñar antes de aprobar un borrado acaban discrepando, y el que
385
+ * discrepa siempre es el que menos se mira.
386
+ */
387
+ export function detallesEnTextoPlano(toolName, args, cwd = process.cwd()) {
388
+ const sinColor = (t) => t.replace(/\u001b\[[0-9;]*m/g, "");
389
+ const kind = classify(toolName, args);
390
+ return [
391
+ sinColor(kind.title).trim(),
392
+ ...details(toolName, args, cwd, 72)
393
+ .map((d) => sinColor(d.text).trim())
394
+ .filter((t) => t.length > 0),
395
+ ];
396
+ }
@@ -3,7 +3,7 @@
3
3
  * pintara donde le tocara, dos productores independientes -el razonamiento y el
4
4
  * spinner llegan por caminos distintos- se turnarian el sitio y el pie bailaria.
5
5
  */
6
- declare const ORDEN: readonly ["razonamiento", "spinner", "entrada"];
6
+ declare const ORDEN: readonly ["tareas", "razonamiento", "spinner", "entrada"];
7
7
  export type SeccionDelPie = (typeof ORDEN)[number];
8
8
  /**
9
9
  * Enciende o apaga el pie a mano. Con `null` vuelve a mandar el terminal.
@@ -54,7 +54,7 @@ const MOSTRAR_CURSOR = "\x1b[?25h";
54
54
  * pintara donde le tocara, dos productores independientes -el razonamiento y el
55
55
  * spinner llegan por caminos distintos- se turnarian el sitio y el pie bailaria.
56
56
  */
57
- const ORDEN = ["razonamiento", "spinner", "entrada"];
57
+ const ORDEN = ["tareas", "razonamiento", "spinner", "entrada"];
58
58
  const secciones = new Map();
59
59
  /**
60
60
  * Texto permanente que aun no ha recibido su salto de linea.
@@ -179,6 +179,14 @@ export function formatToolName(name) {
179
179
  return "Move";
180
180
  case "run_command":
181
181
  return "Bash";
182
+ case "start_background_task":
183
+ return "BgTask";
184
+ case "read_task_output":
185
+ return "TaskOutput";
186
+ case "list_background_tasks":
187
+ return "ListTasks";
188
+ case "stop_background_task":
189
+ return "StopTask";
182
190
  case "list_dir":
183
191
  return "ListDir";
184
192
  case "grep_search":
@@ -431,6 +431,68 @@ async function setTabOverlay(tabId, activo) {
431
431
  }
432
432
  }
433
433
 
434
+ // Telemetría de red: errores HTTP (>=400) y fallos de conexión por pestaña
435
+ const MAX_NETWORK_ERRORS = 100;
436
+ /** tabId -> Array<{ method: string, url: string, status?: number, error?: string, timestamp: number }> */
437
+ const networkErrorsByTab = new Map();
438
+
439
+ function registrarErrorRed(tabId, info) {
440
+ if (!tabId || tabId < 0) return;
441
+ let lista = networkErrorsByTab.get(tabId);
442
+ if (!lista) {
443
+ lista = [];
444
+ networkErrorsByTab.set(tabId, lista);
445
+ }
446
+ lista.push({
447
+ method: info.method || "GET",
448
+ url: info.url || "",
449
+ status: info.status !== undefined ? info.status : (info.statusCode !== undefined ? info.statusCode : undefined),
450
+ error: info.error || undefined,
451
+ timestamp: info.timestamp || Date.now(),
452
+ });
453
+ if (lista.length > MAX_NETWORK_ERRORS) {
454
+ lista.shift();
455
+ }
456
+ }
457
+
458
+ try {
459
+ if (typeof chrome !== "undefined" && chrome.webRequest && chrome.webRequest.onCompleted && typeof chrome.webRequest.onCompleted.addListener === "function") {
460
+ chrome.webRequest.onCompleted.addListener(
461
+ (details) => {
462
+ if (details && details.tabId > 0 && details.statusCode >= 400) {
463
+ registrarErrorRed(details.tabId, {
464
+ method: details.method,
465
+ url: details.url,
466
+ status: details.statusCode,
467
+ error: `HTTP ${details.statusCode}`,
468
+ timestamp: Math.round(details.timeStamp || Date.now()),
469
+ });
470
+ }
471
+ },
472
+ { urls: ["<all_urls>"] }
473
+ );
474
+ }
475
+ } catch (_) {}
476
+
477
+ try {
478
+ if (typeof chrome !== "undefined" && chrome.webRequest && chrome.webRequest.onErrorOccurred && typeof chrome.webRequest.onErrorOccurred.addListener === "function") {
479
+ chrome.webRequest.onErrorOccurred.addListener(
480
+ (details) => {
481
+ if (details && details.tabId > 0) {
482
+ registrarErrorRed(details.tabId, {
483
+ method: details.method,
484
+ url: details.url,
485
+ status: undefined,
486
+ error: details.error || "net::ERR_FAILED",
487
+ timestamp: Math.round(details.timeStamp || Date.now()),
488
+ });
489
+ }
490
+ },
491
+ { urls: ["<all_urls>"] }
492
+ );
493
+ }
494
+ } catch (_) {}
495
+
434
496
  // D8: Detección y reporte de descargas disparadas por acciones del agente
435
497
  const descargasRecientes = [];
436
498
  try {
@@ -1012,6 +1074,23 @@ async function handle(msg, st) {
1012
1074
  return res;
1013
1075
  }
1014
1076
 
1077
+ if (cmd === "getConsoleLogs") {
1078
+ const { tabId } = await readTab(msg.tabId, st);
1079
+ const res = await tell(tabId, 0, { cmd: "getConsoleLogs", clear: msg.clear === true });
1080
+ if (!res || !res.ok) throw new Error((res && res.error) || "no se pudieron obtener los logs de consola");
1081
+ return { ok: true, tabId, logs: res.logs || [] };
1082
+ }
1083
+
1084
+ if (cmd === "getNetworkErrors") {
1085
+ const { tabId } = await readTab(msg.tabId, st);
1086
+ const lista = networkErrorsByTab.get(tabId) || [];
1087
+ const errors = [...lista];
1088
+ if (msg.clear === true) {
1089
+ networkErrorsByTab.delete(tabId);
1090
+ }
1091
+ return { ok: true, tabId, errors };
1092
+ }
1093
+
1015
1094
  if (cmd === "eval") {
1016
1095
  // eval ejecuta JavaScript arbitrario en la pagina: puede pulsar, enviar
1017
1096
  // formularios y leerlo todo. Es actuacion, no lectura.
@@ -1138,6 +1217,7 @@ async function handle(msg, st) {
1138
1217
  try {
1139
1218
  chrome.tabs.onRemoved.addListener((tabId) => {
1140
1219
  setTabOverlay(tabId, false);
1220
+ networkErrorsByTab.delete(tabId);
1141
1221
  for (const link of links.values()) {
1142
1222
  if (!link.state) continue;
1143
1223
  link.state.propias.delete(tabId);
@@ -17,6 +17,103 @@
17
17
 
18
18
  const IS_TOP = window.top === window;
19
19
 
20
+ // ======================================================== telemetría de consola y errores de página
21
+ const MAX_CONSOLE_LOGS = 100;
22
+ const consoleLogsBuffer = [];
23
+
24
+ function addConsoleLog(level, message, stack, url) {
25
+ const entry = {
26
+ timestamp: Date.now(),
27
+ level: level === "warn" ? "warn" : "error",
28
+ message: String(message || ""),
29
+ };
30
+ if (stack) entry.stack = String(stack);
31
+ if (url) entry.url = String(url);
32
+
33
+ consoleLogsBuffer.push(entry);
34
+ if (consoleLogsBuffer.length > MAX_CONSOLE_LOGS) {
35
+ consoleLogsBuffer.shift();
36
+ }
37
+ }
38
+
39
+ try {
40
+ window.addEventListener("error", (event) => {
41
+ try {
42
+ const msg = event.message || (event.error && event.error.message) || String(event);
43
+ const stack = (event.error && event.error.stack) || undefined;
44
+ const url = event.filename || undefined;
45
+ addConsoleLog("error", msg, stack, url);
46
+ } catch (_) {}
47
+ });
48
+ } catch (_) {}
49
+
50
+ try {
51
+ window.addEventListener("unhandledrejection", (event) => {
52
+ try {
53
+ const reason = event.reason;
54
+ const msg =
55
+ (reason && (reason.message || (typeof reason === "object" ? JSON.stringify(reason) : String(reason)))) ||
56
+ "Unhandled Promise Rejection";
57
+ const stack = (reason && reason.stack) || undefined;
58
+ addConsoleLog("error", `Unhandled rejection: ${msg}`, stack);
59
+ } catch (_) {}
60
+ });
61
+ } catch (_) {}
62
+
63
+ try {
64
+ const originalConsoleError = console.error;
65
+ console.error = function (...args) {
66
+ try {
67
+ const msg = args
68
+ .map((a) => {
69
+ if (a instanceof Error) return a.message || String(a);
70
+ if (typeof a === "object" && a !== null) {
71
+ try {
72
+ return JSON.stringify(a);
73
+ } catch (_) {
74
+ return String(a);
75
+ }
76
+ }
77
+ return String(a);
78
+ })
79
+ .join(" ");
80
+ const errObj = args.find((a) => a instanceof Error);
81
+ const stack = errObj && errObj.stack ? errObj.stack : undefined;
82
+ addConsoleLog("error", msg, stack);
83
+ } catch (_) {}
84
+ if (typeof originalConsoleError === "function") {
85
+ originalConsoleError.apply(console, args);
86
+ }
87
+ };
88
+ } catch (_) {}
89
+
90
+ try {
91
+ const originalConsoleWarn = console.warn;
92
+ console.warn = function (...args) {
93
+ try {
94
+ const msg = args
95
+ .map((a) => {
96
+ if (a instanceof Error) return a.message || String(a);
97
+ if (typeof a === "object" && a !== null) {
98
+ try {
99
+ return JSON.stringify(a);
100
+ } catch (_) {
101
+ return String(a);
102
+ }
103
+ }
104
+ return String(a);
105
+ })
106
+ .join(" ");
107
+ const errObj = args.find((a) => a instanceof Error);
108
+ const stack = errObj && errObj.stack ? errObj.stack : undefined;
109
+ addConsoleLog("warn", msg, stack);
110
+ } catch (_) {}
111
+ if (typeof originalConsoleWarn === "function") {
112
+ originalConsoleWarn.apply(console, args);
113
+ }
114
+ };
115
+ } catch (_) {}
116
+
20
117
  // ======================================================== overlay visual y borde naranja (#D97757)
21
118
 
22
119
  let overlayHost = null;
@@ -916,6 +1013,15 @@
916
1013
  break;
917
1014
  }
918
1015
 
1016
+ case "getConsoleLogs": {
1017
+ const logs = [...consoleLogsBuffer];
1018
+ if (msg.clear === true) {
1019
+ consoleLogsBuffer.length = 0;
1020
+ }
1021
+ sendResponse({ ok: true, logs });
1022
+ break;
1023
+ }
1024
+
919
1025
  default:
920
1026
  sendResponse({ ok: false, error: "comando desconocido: " + (msg.cmd || msg.tipo) });
921
1027
  }
@@ -1,60 +1,61 @@
1
- {
2
- "manifest_version": 3,
3
- "minimum_chrome_version": "102",
4
- "name": "Chocolatito Code",
5
- "version": "1.6.7",
6
- "description": "Deja que Chocolatito Code trabaje dentro de tu Chrome, en segundo plano y con tus sesiones ya iniciadas.",
7
- "permissions": [
8
- "tabs",
9
- "tabGroups",
10
- "scripting",
11
- "debugger",
12
- "webNavigation",
13
- "storage",
14
- "downloads"
15
- ],
16
- "host_permissions": [
17
- "<all_urls>"
18
- ],
19
- "icons": {
20
- "16": "iconos/16.png",
21
- "32": "iconos/32.png",
22
- "48": "iconos/48.png",
23
- "128": "iconos/128.png"
24
- },
25
- "background": {
26
- "service_worker": "background.js"
27
- },
28
- "content_scripts": [
29
- {
30
- "matches": [
31
- "<all_urls>"
32
- ],
33
- "js": [
34
- "content.js"
35
- ],
36
- "run_at": "document_idle",
37
- "all_frames": true
38
- }
39
- ],
40
- "action": {
41
- "default_title": "Chocolatito Code",
42
- "default_popup": "popup.html",
43
- "default_icon": {
44
- "16": "iconos/16.png",
45
- "32": "iconos/32.png",
46
- "48": "iconos/48.png"
47
- }
48
- },
49
- "web_accessible_resources": [
50
- {
51
- "resources": [
52
- "iconos/*",
53
- "fuentes/*"
54
- ],
55
- "matches": [
56
- "<all_urls>"
57
- ]
58
- }
59
- ]
60
- }
1
+ {
2
+ "manifest_version": 3,
3
+ "minimum_chrome_version": "102",
4
+ "name": "Chocolatito Code",
5
+ "version": "1.6.9",
6
+ "description": "Deja que Chocolatito Code trabaje dentro de tu Chrome, en segundo plano y con tus sesiones ya iniciadas.",
7
+ "permissions": [
8
+ "tabs",
9
+ "tabGroups",
10
+ "scripting",
11
+ "debugger",
12
+ "webNavigation",
13
+ "storage",
14
+ "downloads",
15
+ "webRequest"
16
+ ],
17
+ "host_permissions": [
18
+ "<all_urls>"
19
+ ],
20
+ "icons": {
21
+ "16": "iconos/16.png",
22
+ "32": "iconos/32.png",
23
+ "48": "iconos/48.png",
24
+ "128": "iconos/128.png"
25
+ },
26
+ "background": {
27
+ "service_worker": "background.js"
28
+ },
29
+ "content_scripts": [
30
+ {
31
+ "matches": [
32
+ "<all_urls>"
33
+ ],
34
+ "js": [
35
+ "content.js"
36
+ ],
37
+ "run_at": "document_idle",
38
+ "all_frames": true
39
+ }
40
+ ],
41
+ "action": {
42
+ "default_title": "Chocolatito Code",
43
+ "default_popup": "popup.html",
44
+ "default_icon": {
45
+ "16": "iconos/16.png",
46
+ "32": "iconos/32.png",
47
+ "48": "iconos/48.png"
48
+ }
49
+ },
50
+ "web_accessible_resources": [
51
+ {
52
+ "resources": [
53
+ "iconos/*",
54
+ "fuentes/*"
55
+ ],
56
+ "matches": [
57
+ "<all_urls>"
58
+ ]
59
+ }
60
+ ]
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chocolatito-code",
3
- "version": "1.6.7",
3
+ "version": "1.6.9",
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": {
@@ -21,7 +21,8 @@
21
21
  "os": [
22
22
  "win32",
23
23
  "darwin",
24
- "linux"
24
+ "linux",
25
+ "android"
25
26
  ],
26
27
  "scripts": {
27
28
  "build": "tsc",