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.
- package/.mcp.json.ejemplo +19 -0
- package/COMPUTER-USE.md +484 -0
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/agent/context.d.ts +9 -0
- package/dist/agent/context.js +123 -0
- package/dist/agent/fileTracker.d.ts +16 -0
- package/dist/agent/fileTracker.js +53 -0
- package/dist/agent/loop.d.ts +25 -0
- package/dist/agent/loop.js +524 -0
- package/dist/agent/mentions.d.ts +11 -0
- package/dist/agent/mentions.js +43 -0
- package/dist/agent/retry.d.ts +17 -0
- package/dist/agent/retry.js +57 -0
- package/dist/agent/subagent.d.ts +2 -0
- package/dist/agent/subagent.js +116 -0
- package/dist/agent/syntaxValidator.d.ts +5 -0
- package/dist/agent/syntaxValidator.js +71 -0
- package/dist/agent/tracker.d.ts +19 -0
- package/dist/agent/tracker.js +38 -0
- package/dist/agent/undoManager.d.ts +37 -0
- package/dist/agent/undoManager.js +95 -0
- package/dist/config/constants.d.ts +77 -0
- package/dist/config/constants.js +146 -0
- package/dist/config/engine.d.ts +49 -0
- package/dist/config/engine.js +86 -0
- package/dist/config/env.d.ts +13 -0
- package/dist/config/env.js +103 -0
- package/dist/config/license.d.ts +39 -0
- package/dist/config/license.js +306 -0
- package/dist/config/permissions.d.ts +38 -0
- package/dist/config/permissions.js +239 -0
- package/dist/config/quota.d.ts +58 -0
- package/dist/config/quota.js +156 -0
- package/dist/hooks/manager.d.ts +60 -0
- package/dist/hooks/manager.js +193 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +470 -0
- package/dist/mcp/client.d.ts +55 -0
- package/dist/mcp/client.js +282 -0
- package/dist/mcp/manager.d.ts +26 -0
- package/dist/mcp/manager.js +167 -0
- package/dist/memory/manager.d.ts +9 -0
- package/dist/memory/manager.js +59 -0
- package/dist/prompts/systemPrompt.d.ts +5 -0
- package/dist/prompts/systemPrompt.js +177 -0
- package/dist/sessions/manager.d.ts +21 -0
- package/dist/sessions/manager.js +54 -0
- package/dist/skills/manager.d.ts +14 -0
- package/dist/skills/manager.js +86 -0
- package/dist/tools/browserCdp.d.ts +26 -0
- package/dist/tools/browserCdp.js +610 -0
- package/dist/tools/browserExtension.d.ts +58 -0
- package/dist/tools/browserExtension.js +479 -0
- package/dist/tools/browserLive.d.ts +12 -0
- package/dist/tools/browserLive.js +265 -0
- package/dist/tools/changeDir.d.ts +5 -0
- package/dist/tools/changeDir.js +63 -0
- package/dist/tools/computerUse.d.ts +58 -0
- package/dist/tools/computerUse.js +567 -0
- package/dist/tools/createImage.d.ts +1 -0
- package/dist/tools/createImage.js +34 -0
- package/dist/tools/definitions.d.ts +8 -0
- package/dist/tools/definitions.js +401 -0
- package/dist/tools/deleteFile.d.ts +1 -0
- package/dist/tools/deleteFile.js +17 -0
- package/dist/tools/editFile.d.ts +5 -0
- package/dist/tools/editFile.js +88 -0
- package/dist/tools/findFiles.d.ts +1 -0
- package/dist/tools/findFiles.js +33 -0
- package/dist/tools/getSystemInfo.d.ts +1 -0
- package/dist/tools/getSystemInfo.js +23 -0
- package/dist/tools/gitTools.d.ts +3 -0
- package/dist/tools/gitTools.js +47 -0
- package/dist/tools/grepSearch.d.ts +1 -0
- package/dist/tools/grepSearch.js +37 -0
- package/dist/tools/listDir.d.ts +1 -0
- package/dist/tools/listDir.js +33 -0
- package/dist/tools/moveCopyFile.d.ts +1 -0
- package/dist/tools/moveCopyFile.js +21 -0
- package/dist/tools/runCommand.d.ts +1 -0
- package/dist/tools/runCommand.js +61 -0
- package/dist/tools/runner.d.ts +5 -0
- package/dist/tools/runner.js +177 -0
- package/dist/tools/safety.d.ts +17 -0
- package/dist/tools/safety.js +33 -0
- package/dist/tools/todoTool.d.ts +8 -0
- package/dist/tools/todoTool.js +27 -0
- package/dist/tools/toolDefsComputer.d.ts +13 -0
- package/dist/tools/toolDefsComputer.js +205 -0
- package/dist/tools/truncator.d.ts +11 -0
- package/dist/tools/truncator.js +24 -0
- package/dist/tools/viewFile.d.ts +1 -0
- package/dist/tools/viewFile.js +45 -0
- package/dist/tools/visionBridge.d.ts +37 -0
- package/dist/tools/visionBridge.js +107 -0
- package/dist/tools/webFetch.d.ts +1 -0
- package/dist/tools/webFetch.js +25 -0
- package/dist/tools/webSearch.d.ts +1 -0
- package/dist/tools/webSearch.js +35 -0
- package/dist/tools/win/hostClient.d.ts +31 -0
- package/dist/tools/win/hostClient.js +158 -0
- package/dist/tools/win/hostScript.d.ts +1 -0
- package/dist/tools/win/hostScript.js +925 -0
- package/dist/tools/writeFile.d.ts +1 -0
- package/dist/tools/writeFile.js +13 -0
- package/dist/ui/banner.d.ts +10 -0
- package/dist/ui/banner.js +165 -0
- package/dist/ui/diffViewer.d.ts +1 -0
- package/dist/ui/diffViewer.js +60 -0
- package/dist/ui/interrupt.d.ts +17 -0
- package/dist/ui/interrupt.js +156 -0
- package/dist/ui/markdownStream.d.ts +23 -0
- package/dist/ui/markdownStream.js +0 -0
- package/dist/ui/modes.d.ts +28 -0
- package/dist/ui/modes.js +57 -0
- package/dist/ui/permissionPrompt.d.ts +35 -0
- package/dist/ui/permissionPrompt.js +271 -0
- package/dist/ui/prompt.d.ts +7 -0
- package/dist/ui/prompt.js +466 -0
- package/dist/ui/reasoningStream.d.ts +6 -0
- package/dist/ui/reasoningStream.js +38 -0
- package/dist/ui/renderer.d.ts +10 -0
- package/dist/ui/renderer.js +142 -0
- package/dist/ui/spinner.d.ts +24 -0
- package/dist/ui/spinner.js +111 -0
- package/dist/ui/theme.d.ts +36 -0
- package/dist/ui/theme.js +37 -0
- package/dist/ui/typeAhead.d.ts +31 -0
- package/dist/ui/typeAhead.js +87 -0
- package/extension/README.md +74 -0
- package/extension/background.js +575 -0
- package/extension/content.js +446 -0
- package/extension/manifest.json +36 -0
- package/extension/popup.html +22 -0
- package/extension/popup.js +12 -0
- package/package.json +66 -0
- package/skills/complex-refactor/SKILL.md +13 -0
- package/skills/deep-debugger/SKILL.md +14 -0
- package/skills/software-architect/SKILL.md +20 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare class DynamicSpinner {
|
|
2
|
+
private timer;
|
|
3
|
+
private glyphIdx;
|
|
4
|
+
private verbIdx;
|
|
5
|
+
private startTime;
|
|
6
|
+
private isRunning;
|
|
7
|
+
private prefix;
|
|
8
|
+
tokenCount: number;
|
|
9
|
+
/** Lineas extra pintadas debajo del spinner en el ultimo tick. */
|
|
10
|
+
private extraRows;
|
|
11
|
+
constructor(prefix?: string);
|
|
12
|
+
start(initialPrefix?: string): void;
|
|
13
|
+
private tick;
|
|
14
|
+
/**
|
|
15
|
+
* Segunda linea con lo que el usuario esta escribiendo mientras se genera.
|
|
16
|
+
*
|
|
17
|
+
* Antes el teclado se tragaba todo sin pintar nada y parecia que el terminal
|
|
18
|
+
* se habia colgado. Se dibuja debajo y el cursor vuelve arriba, para que el
|
|
19
|
+
* siguiente tick sobrescriba las dos lineas sin dejar rastro.
|
|
20
|
+
*/
|
|
21
|
+
private drawTypeAhead;
|
|
22
|
+
private clearExtraRows;
|
|
23
|
+
stop(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { typedText, queuedCount } from "./typeAhead.js";
|
|
4
|
+
import { modeBadge } from "./modes.js";
|
|
5
|
+
const GLYPHS = ["✢", "✳", "∗", "✻", "✽"];
|
|
6
|
+
const VERBS = [
|
|
7
|
+
"Analizando",
|
|
8
|
+
"Rumiando",
|
|
9
|
+
"Tramando",
|
|
10
|
+
"Destilando",
|
|
11
|
+
"Hilvanando",
|
|
12
|
+
"Cavilando",
|
|
13
|
+
"Maquinando",
|
|
14
|
+
"Urdiendo",
|
|
15
|
+
"Tejiendo",
|
|
16
|
+
"Cocinando",
|
|
17
|
+
];
|
|
18
|
+
export class DynamicSpinner {
|
|
19
|
+
timer = null;
|
|
20
|
+
glyphIdx = 0;
|
|
21
|
+
verbIdx = 0;
|
|
22
|
+
startTime = 0;
|
|
23
|
+
isRunning = false;
|
|
24
|
+
prefix = "";
|
|
25
|
+
tokenCount = 0;
|
|
26
|
+
/** Lineas extra pintadas debajo del spinner en el ultimo tick. */
|
|
27
|
+
extraRows = 0;
|
|
28
|
+
constructor(prefix = "") {
|
|
29
|
+
this.prefix = prefix;
|
|
30
|
+
}
|
|
31
|
+
start(initialPrefix) {
|
|
32
|
+
if (this.isRunning)
|
|
33
|
+
return;
|
|
34
|
+
if (initialPrefix)
|
|
35
|
+
this.prefix = initialPrefix;
|
|
36
|
+
this.isRunning = true;
|
|
37
|
+
this.startTime = Date.now();
|
|
38
|
+
this.glyphIdx = 0;
|
|
39
|
+
this.verbIdx = 0;
|
|
40
|
+
this.extraRows = 0;
|
|
41
|
+
this.timer = setInterval(() => {
|
|
42
|
+
this.tick();
|
|
43
|
+
}, 120);
|
|
44
|
+
}
|
|
45
|
+
tick() {
|
|
46
|
+
if (!this.isRunning)
|
|
47
|
+
return;
|
|
48
|
+
this.glyphIdx = (this.glyphIdx + 1) % GLYPHS.length;
|
|
49
|
+
const elapsedSec = Math.floor((Date.now() - this.startTime) / 1000);
|
|
50
|
+
// Rotate verbs every 2.5 seconds
|
|
51
|
+
this.verbIdx = Math.floor(elapsedSec / 2.5) % VERBS.length;
|
|
52
|
+
const glyph = chalk.hex("#D97757")(GLYPHS[this.glyphIdx]);
|
|
53
|
+
const verb = chalk.italic.hex("#D97757")(`${VERBS[this.verbIdx]}…`);
|
|
54
|
+
const timeStr = chalk.gray(`(${elapsedSec}s`);
|
|
55
|
+
const tokenStr = this.tokenCount > 0 ? chalk.gray(` · ↑ ${(this.tokenCount / 1000).toFixed(1)}k tokens`) : "";
|
|
56
|
+
const escStr = chalk.gray(` · esc para pausar)`);
|
|
57
|
+
const badge = modeBadge();
|
|
58
|
+
const modeStr = badge ? ` ${badge}` : "";
|
|
59
|
+
this.clearExtraRows();
|
|
60
|
+
process.stdout.write(`\r\x1b[2K${glyph} ${verb} ${timeStr}${tokenStr}${escStr}${modeStr}`);
|
|
61
|
+
this.drawTypeAhead();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Segunda linea con lo que el usuario esta escribiendo mientras se genera.
|
|
65
|
+
*
|
|
66
|
+
* Antes el teclado se tragaba todo sin pintar nada y parecia que el terminal
|
|
67
|
+
* se habia colgado. Se dibuja debajo y el cursor vuelve arriba, para que el
|
|
68
|
+
* siguiente tick sobrescriba las dos lineas sin dejar rastro.
|
|
69
|
+
*/
|
|
70
|
+
drawTypeAhead() {
|
|
71
|
+
const typing = typedText();
|
|
72
|
+
const pendientes = queuedCount();
|
|
73
|
+
const rows = [];
|
|
74
|
+
if (typing.length > 0) {
|
|
75
|
+
rows.push(`${chalk.hex("#D97757")("❯")} ${chalk.white(typing)}${chalk.gray(" (enter para encolarlo)")}`);
|
|
76
|
+
}
|
|
77
|
+
if (pendientes > 0) {
|
|
78
|
+
const plural = pendientes === 1 ? "mensaje en cola" : "mensajes en cola";
|
|
79
|
+
rows.push(chalk.gray(` ${pendientes} ${plural}; se enviará al terminar este turno`));
|
|
80
|
+
}
|
|
81
|
+
if (rows.length === 0) {
|
|
82
|
+
this.extraRows = 0;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
for (const row of rows) {
|
|
86
|
+
process.stdout.write(`\n\r\x1b[2K${row}`);
|
|
87
|
+
}
|
|
88
|
+
process.stdout.write(`\x1b[${rows.length}A\r`);
|
|
89
|
+
this.extraRows = rows.length;
|
|
90
|
+
}
|
|
91
|
+
clearExtraRows() {
|
|
92
|
+
if (this.extraRows === 0)
|
|
93
|
+
return;
|
|
94
|
+
for (let i = 0; i < this.extraRows; i++) {
|
|
95
|
+
process.stdout.write("\x1b[1B\r\x1b[2K");
|
|
96
|
+
}
|
|
97
|
+
process.stdout.write(`\x1b[${this.extraRows}A\r`);
|
|
98
|
+
this.extraRows = 0;
|
|
99
|
+
}
|
|
100
|
+
stop() {
|
|
101
|
+
if (!this.isRunning)
|
|
102
|
+
return;
|
|
103
|
+
this.isRunning = false;
|
|
104
|
+
if (this.timer) {
|
|
105
|
+
clearInterval(this.timer);
|
|
106
|
+
this.timer = null;
|
|
107
|
+
}
|
|
108
|
+
this.clearExtraRows();
|
|
109
|
+
process.stdout.write("\r\x1b[2K");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare const THEME: {
|
|
2
|
+
colors: {
|
|
3
|
+
terracotta: string;
|
|
4
|
+
terracottaDark: string;
|
|
5
|
+
amber: string;
|
|
6
|
+
purple: string;
|
|
7
|
+
purpleDark: string;
|
|
8
|
+
peach: string;
|
|
9
|
+
green: string;
|
|
10
|
+
red: string;
|
|
11
|
+
cyan: string;
|
|
12
|
+
white: string;
|
|
13
|
+
gray: string;
|
|
14
|
+
grayDark: string;
|
|
15
|
+
bgMuted: string;
|
|
16
|
+
};
|
|
17
|
+
glyphs: {
|
|
18
|
+
bullet: string;
|
|
19
|
+
hook: string;
|
|
20
|
+
chevron: string;
|
|
21
|
+
arrow: string;
|
|
22
|
+
star: string;
|
|
23
|
+
checked: string;
|
|
24
|
+
unchecked: string;
|
|
25
|
+
sparkle: string;
|
|
26
|
+
lightning: string;
|
|
27
|
+
};
|
|
28
|
+
styles: {
|
|
29
|
+
primary: import("chalk").ChalkInstance;
|
|
30
|
+
accent: import("chalk").ChalkInstance;
|
|
31
|
+
success: import("chalk").ChalkInstance;
|
|
32
|
+
warning: import("chalk").ChalkInstance;
|
|
33
|
+
error: import("chalk").ChalkInstance;
|
|
34
|
+
muted: import("chalk").ChalkInstance;
|
|
35
|
+
};
|
|
36
|
+
};
|
package/dist/ui/theme.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
export const THEME = {
|
|
3
|
+
colors: {
|
|
4
|
+
terracotta: "#D97757",
|
|
5
|
+
terracottaDark: "#C06345",
|
|
6
|
+
amber: "#FFA500",
|
|
7
|
+
purple: "#A855F7",
|
|
8
|
+
purpleDark: "#8B5CF6",
|
|
9
|
+
peach: "#F5C7B2",
|
|
10
|
+
green: "#22C55E",
|
|
11
|
+
red: "#EF4444",
|
|
12
|
+
cyan: "#06B6D4",
|
|
13
|
+
white: "#FAF5F0",
|
|
14
|
+
gray: "#71717A",
|
|
15
|
+
grayDark: "#27272A",
|
|
16
|
+
bgMuted: "#252830",
|
|
17
|
+
},
|
|
18
|
+
glyphs: {
|
|
19
|
+
bullet: "●",
|
|
20
|
+
hook: "⎿",
|
|
21
|
+
chevron: "❯",
|
|
22
|
+
arrow: "▸",
|
|
23
|
+
star: "✻",
|
|
24
|
+
checked: "☒",
|
|
25
|
+
unchecked: "☐",
|
|
26
|
+
sparkle: "✨",
|
|
27
|
+
lightning: "⚡",
|
|
28
|
+
},
|
|
29
|
+
styles: {
|
|
30
|
+
primary: chalk.hex("#D97757"),
|
|
31
|
+
accent: chalk.hex("#A855F7"),
|
|
32
|
+
success: chalk.green,
|
|
33
|
+
warning: chalk.hex("#FFA500"),
|
|
34
|
+
error: chalk.red,
|
|
35
|
+
muted: chalk.gray,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESCRIBIR MIENTRAS EL AGENTE TRABAJA
|
|
3
|
+
*
|
|
4
|
+
* Mientras se generaba una respuesta, el vigilante de teclas se quedaba con el
|
|
5
|
+
* teclado en modo crudo y solo miraba Esc y Ctrl+C: todo lo demas que escribiera
|
|
6
|
+
* el usuario se tiraba a la basura sin dejar rastro en pantalla. Daba la
|
|
7
|
+
* sensacion de que el terminal se habia colgado.
|
|
8
|
+
*
|
|
9
|
+
* Ahora lo que se teclea se acumula aqui, se pinta debajo del spinner, y al
|
|
10
|
+
* pulsar Enter queda en cola como siguiente mensaje.
|
|
11
|
+
*
|
|
12
|
+
* CUIDADO CON LO QUE ENTRA. Una flecha del cursor no es texto: el terminal manda
|
|
13
|
+
* "\x1b[A". Al aceptarlo tal cual, el buffer se quedaba con basura invisible que
|
|
14
|
+
* no se limpiaba nunca, y en cuanto el usuario pulsaba Enter en un turno
|
|
15
|
+
* posterior esa basura se encolaba y se enviaba SOLA como si fuera una orden.
|
|
16
|
+
* Desde fuera se veia asi: acabas una respuesta, el agente arranca otra vez por
|
|
17
|
+
* su cuenta y el teclado deja de responder, porque durante la generacion el
|
|
18
|
+
* teclado es del vigilante. De ahi el "a veces despues de una respuesta no se
|
|
19
|
+
* puede escribir".
|
|
20
|
+
*/
|
|
21
|
+
export declare function typedText(): string;
|
|
22
|
+
export declare function pushTyped(text: string): void;
|
|
23
|
+
export declare function backspaceTyped(): void;
|
|
24
|
+
export declare function clearTyped(): void;
|
|
25
|
+
/** Enter durante la generacion: lo escrito pasa a la cola. */
|
|
26
|
+
export declare function commitTyped(): string | null;
|
|
27
|
+
export declare function hasQueued(): boolean;
|
|
28
|
+
export declare function queuedCount(): number;
|
|
29
|
+
/** Recoge todo lo encolado como un unico mensaje y vacia la cola. */
|
|
30
|
+
export declare function takeQueued(): string | null;
|
|
31
|
+
export declare function resetTypeAhead(): void;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESCRIBIR MIENTRAS EL AGENTE TRABAJA
|
|
3
|
+
*
|
|
4
|
+
* Mientras se generaba una respuesta, el vigilante de teclas se quedaba con el
|
|
5
|
+
* teclado en modo crudo y solo miraba Esc y Ctrl+C: todo lo demas que escribiera
|
|
6
|
+
* el usuario se tiraba a la basura sin dejar rastro en pantalla. Daba la
|
|
7
|
+
* sensacion de que el terminal se habia colgado.
|
|
8
|
+
*
|
|
9
|
+
* Ahora lo que se teclea se acumula aqui, se pinta debajo del spinner, y al
|
|
10
|
+
* pulsar Enter queda en cola como siguiente mensaje.
|
|
11
|
+
*
|
|
12
|
+
* CUIDADO CON LO QUE ENTRA. Una flecha del cursor no es texto: el terminal manda
|
|
13
|
+
* "\x1b[A". Al aceptarlo tal cual, el buffer se quedaba con basura invisible que
|
|
14
|
+
* no se limpiaba nunca, y en cuanto el usuario pulsaba Enter en un turno
|
|
15
|
+
* posterior esa basura se encolaba y se enviaba SOLA como si fuera una orden.
|
|
16
|
+
* Desde fuera se veia asi: acabas una respuesta, el agente arranca otra vez por
|
|
17
|
+
* su cuenta y el teclado deja de responder, porque durante la generacion el
|
|
18
|
+
* teclado es del vigilante. De ahi el "a veces despues de una respuesta no se
|
|
19
|
+
* puede escribir".
|
|
20
|
+
*/
|
|
21
|
+
let buffer = "";
|
|
22
|
+
let queued = [];
|
|
23
|
+
/**
|
|
24
|
+
* Deja solo lo que de verdad es texto.
|
|
25
|
+
*
|
|
26
|
+
* Fuera: secuencias de escape (flechas, F1-F12, inicio/fin, shift+tab) y
|
|
27
|
+
* cualquier caracter de control. Si de una pulsacion no queda nada imprimible,
|
|
28
|
+
* es que no era texto.
|
|
29
|
+
*/
|
|
30
|
+
function soloTexto(raw) {
|
|
31
|
+
if (!raw)
|
|
32
|
+
return "";
|
|
33
|
+
// Una secuencia de escape entera se descarta de golpe: sus caracteres
|
|
34
|
+
// sueltos ("[", "A") si son imprimibles y colarian letras falsas.
|
|
35
|
+
if (raw.charCodeAt(0) === 0x1b)
|
|
36
|
+
return "";
|
|
37
|
+
let out = "";
|
|
38
|
+
for (const ch of raw) {
|
|
39
|
+
const c = ch.codePointAt(0);
|
|
40
|
+
// Se descartan los controles C0 y el DEL. Todo lo demas es texto del usuario,
|
|
41
|
+
// incluidas tildes, enies y emoji.
|
|
42
|
+
if (c !== undefined && c >= 0x20 && c !== 0x7f)
|
|
43
|
+
out += ch;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
export function typedText() {
|
|
48
|
+
return buffer;
|
|
49
|
+
}
|
|
50
|
+
export function pushTyped(text) {
|
|
51
|
+
buffer += soloTexto(text);
|
|
52
|
+
}
|
|
53
|
+
export function backspaceTyped() {
|
|
54
|
+
buffer = buffer.slice(0, -1);
|
|
55
|
+
}
|
|
56
|
+
export function clearTyped() {
|
|
57
|
+
buffer = "";
|
|
58
|
+
}
|
|
59
|
+
/** Enter durante la generacion: lo escrito pasa a la cola. */
|
|
60
|
+
export function commitTyped() {
|
|
61
|
+
const text = buffer.trim();
|
|
62
|
+
buffer = "";
|
|
63
|
+
if (!text)
|
|
64
|
+
return null;
|
|
65
|
+
queued.push(text);
|
|
66
|
+
return text;
|
|
67
|
+
}
|
|
68
|
+
export function hasQueued() {
|
|
69
|
+
return queued.length > 0;
|
|
70
|
+
}
|
|
71
|
+
export function queuedCount() {
|
|
72
|
+
return queued.length;
|
|
73
|
+
}
|
|
74
|
+
/** Recoge todo lo encolado como un unico mensaje y vacia la cola. */
|
|
75
|
+
export function takeQueued() {
|
|
76
|
+
if (queued.length === 0)
|
|
77
|
+
return null;
|
|
78
|
+
const text = queued.join("\n").trim();
|
|
79
|
+
queued = [];
|
|
80
|
+
// Una cola que solo tenia ruido no vale como orden: enviarla gasta dinero y
|
|
81
|
+
// se salta el prompt del usuario.
|
|
82
|
+
return text.length > 0 ? text : null;
|
|
83
|
+
}
|
|
84
|
+
export function resetTypeAhead() {
|
|
85
|
+
buffer = "";
|
|
86
|
+
queued = [];
|
|
87
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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.
|