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,116 @@
1
+ import { TOOLS, getAllTools } from "../tools/definitions.js";
2
+ import { executeToolCall } from "../tools/runner.js";
3
+ import { truncateOutput } from "../tools/truncator.js";
4
+ import { isReadOnly } from "../tools/safety.js";
5
+ import { MAX_OUTPUT_TOKENS } from "../config/constants.js";
6
+ import { withRetry } from "./retry.js";
7
+ import { createEngineClient } from "../config/engine.js";
8
+ /**
9
+ * Subagentes.
10
+ *
11
+ * Tres arreglos sobre la version anterior:
12
+ *
13
+ * 1. 'explore' y 'plan' recibian TODAS las herramientas, incluidas delete_file,
14
+ * write_file y run_command. Un agente que se presenta como "de solo lectura"
15
+ * y puede borrar archivos es una trampa: ahora se le entregan solo las
16
+ * herramientas de lectura, asi la restriccion es real y no una sugerencia
17
+ * en el prompt.
18
+ *
19
+ * 2. Si agotaba las iteraciones devolvia "Subagente completo la ejecucion", que
20
+ * no dice nada. Todo el trabajo se perdia. Ahora se le pide expresamente un
21
+ * resumen de lo averiguado antes de rendirse.
22
+ *
23
+ * 3. Sin reintentos: un 429 mataba al subagente y con el la tarea del padre.
24
+ */
25
+ const READ_ONLY_TYPES = ["explore", "plan"];
26
+ function toolsFor(type) {
27
+ // Un subagente general hereda tambien las herramientas MCP; uno de solo
28
+ // lectura no, porque no se puede saber si una herramienta MCP escribe.
29
+ if (!READ_ONLY_TYPES.includes(type))
30
+ return getAllTools();
31
+ return TOOLS.filter((t) => isReadOnly(t.function.name));
32
+ }
33
+ export async function runSubagent(type, prompt, apiKey, baseURL, modelName, cwd = process.cwd()) {
34
+ const client = createEngineClient(apiKey, "subagent");
35
+ const roleInstructions = {
36
+ explore: `Eres un SUBAGENTE EXPLORADOR de Chocolatito Code. Investigas archivos y buscas código, y devuelves un informe conciso con rutas y números de línea concretos. Solo tienes herramientas de lectura: no puedes modificar nada.`,
37
+ plan: `Eres un SUBAGENTE ARQUITECTO de Chocolatito Code. Analizas el código existente y devuelves un plan paso a paso con los archivos a crear o modificar y por qué. Solo tienes herramientas de lectura: no implementes, planifica.`,
38
+ general: `Eres un SUBAGENTE DE TRABAJO de Chocolatito Code. Completas la subtarea encomendada con las herramientas necesarias y devuelves el resultado final verificado.`,
39
+ };
40
+ const messages = [
41
+ {
42
+ role: "system",
43
+ content: `${roleInstructions[type]}\n\n` +
44
+ `Directorio de trabajo: ${cwd}\n` +
45
+ `Sistema: ${process.platform}\n\n` +
46
+ `Cuando necesites varias lecturas independientes, pidelas todas en el mismo turno: se ejecutan a la vez.\n` +
47
+ `Responde con hechos que hayas comprobado, citando rutas y lineas. No afirmes nada que no hayas leido.`,
48
+ },
49
+ { role: "user", content: prompt },
50
+ ];
51
+ const tools = toolsFor(type);
52
+ const maxIterations = 14;
53
+ for (let iterations = 0; iterations < maxIterations; iterations++) {
54
+ // Al acercarse al limite se avisa, para que cierre en vez de que le corten.
55
+ if (iterations === maxIterations - 2) {
56
+ messages.push({
57
+ role: "system",
58
+ content: "Aviso: te queda 1 iteración. Devuelve ya tu informe con lo que hayas averiguado.",
59
+ });
60
+ }
61
+ let res;
62
+ try {
63
+ res = await withRetry(() => client.chat.completions.create({
64
+ model: modelName,
65
+ messages,
66
+ tools,
67
+ tool_choice: "auto",
68
+ temperature: 0.1,
69
+ max_tokens: MAX_OUTPUT_TOKENS,
70
+ }));
71
+ }
72
+ catch (err) {
73
+ return `Error en subagente (${type}): ${err?.message || String(err)}`;
74
+ }
75
+ const message = res.choices[0]?.message;
76
+ if (!message)
77
+ break;
78
+ if (message.tool_calls && message.tool_calls.length > 0) {
79
+ messages.push(message);
80
+ // Las llamadas de un subagente explorador son todas de lectura: van a la vez.
81
+ const results = await Promise.all(message.tool_calls.map(async (tc) => {
82
+ let args = {};
83
+ try {
84
+ args = JSON.parse(tc.function.arguments);
85
+ }
86
+ catch { }
87
+ const { result } = await executeToolCall(tc.function.name, args, cwd, apiKey, modelName);
88
+ return { id: tc.id, content: truncateOutput(result, 20_000) };
89
+ }));
90
+ for (const r of results) {
91
+ messages.push({ role: "tool", tool_call_id: r.id, content: r.content });
92
+ }
93
+ continue;
94
+ }
95
+ if (message.content)
96
+ return message.content;
97
+ }
98
+ // Se agotaron las iteraciones: en vez de tirar el trabajo, se pide el resumen.
99
+ try {
100
+ messages.push({
101
+ role: "user",
102
+ content: "Se acabaron las iteraciones. Resume AHORA, sin usar herramientas, todo lo que has averiguado.",
103
+ });
104
+ const final = await withRetry(() => client.chat.completions.create({
105
+ model: modelName,
106
+ messages,
107
+ temperature: 0.1,
108
+ max_tokens: MAX_OUTPUT_TOKENS,
109
+ }));
110
+ const text = final.choices[0]?.message?.content;
111
+ if (text)
112
+ return `[Subagente ${type}: limite de iteraciones alcanzado]\n\n${text}`;
113
+ }
114
+ catch { }
115
+ return `El subagente ${type} agotó sus iteraciones sin llegar a una conclusión. Acota más la subtarea.`;
116
+ }
@@ -0,0 +1,5 @@
1
+ export interface SyntaxCheckResult {
2
+ valid: boolean;
3
+ warning?: string;
4
+ }
5
+ export declare function validateFileSyntax(filePath: string, content: string): SyntaxCheckResult;
@@ -0,0 +1,71 @@
1
+ import path from "node:path";
2
+ export function validateFileSyntax(filePath, content) {
3
+ const ext = path.extname(filePath).toLowerCase();
4
+ // 1. JSON validation
5
+ if (ext === ".json") {
6
+ try {
7
+ JSON.parse(content);
8
+ return { valid: true };
9
+ }
10
+ catch (err) {
11
+ return {
12
+ valid: false,
13
+ warning: `⚠️ Advertencia de sintaxis JSON: ${err?.message || "JSON inválido"}`,
14
+ };
15
+ }
16
+ }
17
+ // 2. Matching brackets & braces check for JS/TS/Python
18
+ if ([".ts", ".js", ".tsx", ".jsx", ".py", ".rs", ".go"].includes(ext)) {
19
+ const stack = [];
20
+ const pairs = { "}": "{", "]": "[", ")": "(" };
21
+ // Ignore comments & strings roughly to avoid false positives
22
+ let inString = null;
23
+ let inComment = false;
24
+ for (let i = 0; i < content.length; i++) {
25
+ const char = content[i];
26
+ const nextChar = content[i + 1];
27
+ // Comments
28
+ if (!inString) {
29
+ if (char === "/" && nextChar === "/") {
30
+ while (i < content.length && content[i] !== "\n")
31
+ i++;
32
+ continue;
33
+ }
34
+ if (char === "#" && ext === ".py") {
35
+ while (i < content.length && content[i] !== "\n")
36
+ i++;
37
+ continue;
38
+ }
39
+ }
40
+ // Strings
41
+ if ((char === '"' || char === "'" || char === "`") && content[i - 1] !== "\\") {
42
+ if (!inString)
43
+ inString = char;
44
+ else if (inString === char)
45
+ inString = null;
46
+ continue;
47
+ }
48
+ if (inString)
49
+ continue;
50
+ if (["{", "[", "("].includes(char)) {
51
+ stack.push(char);
52
+ }
53
+ else if (["}", "]", ")"].includes(char)) {
54
+ const expected = pairs[char];
55
+ if (stack.length === 0 || stack.pop() !== expected) {
56
+ return {
57
+ valid: false,
58
+ warning: `⚠️ Posible desbalance de llaves/paréntesis en "${path.basename(filePath)}" cerca del cierre '${char}'.`,
59
+ };
60
+ }
61
+ }
62
+ }
63
+ if (stack.length > 0 && stack.length < 5) {
64
+ return {
65
+ valid: false,
66
+ warning: `⚠️ Posible llave o paréntesis sin cerrar en "${path.basename(filePath)}" ('${stack.join("', '")}').`,
67
+ };
68
+ }
69
+ }
70
+ return { valid: true };
71
+ }
@@ -0,0 +1,19 @@
1
+ export declare class TokenTracker {
2
+ totalPromptTokens: number;
3
+ totalCompletionTokens: number;
4
+ cachedPromptTokens: number;
5
+ addUsage(usage?: {
6
+ prompt_tokens?: number;
7
+ completion_tokens?: number;
8
+ prompt_tokens_details?: {
9
+ cached_tokens?: number;
10
+ };
11
+ }): void;
12
+ calculateCost(promptTokens?: number, cachedTokens?: number, completionTokens?: number, modelName?: string): {
13
+ inputCost: number;
14
+ outputCost: number;
15
+ totalCost: number;
16
+ formattedCost: string;
17
+ };
18
+ getSummary(modelName?: string): string;
19
+ }
@@ -0,0 +1,38 @@
1
+ import { MODEL_PRICING, PRICING } from "../config/constants.js";
2
+ export class TokenTracker {
3
+ totalPromptTokens = 0;
4
+ totalCompletionTokens = 0;
5
+ cachedPromptTokens = 0;
6
+ addUsage(usage) {
7
+ if (!usage)
8
+ return;
9
+ const prompt = usage.prompt_tokens || 0;
10
+ const completion = usage.completion_tokens || 0;
11
+ const cached = usage.prompt_tokens_details?.cached_tokens || 0;
12
+ this.totalPromptTokens += prompt;
13
+ this.totalCompletionTokens += completion;
14
+ this.cachedPromptTokens += cached;
15
+ }
16
+ calculateCost(promptTokens = this.totalPromptTokens, cachedTokens = this.cachedPromptTokens, completionTokens = this.totalCompletionTokens, modelName = "deepseek-v4-flash") {
17
+ const pricing = MODEL_PRICING[modelName] || PRICING;
18
+ const uncachedPrompt = Math.max(0, promptTokens - cachedTokens);
19
+ const inputCost = (uncachedPrompt / 1_000_000) * pricing.inputCacheMiss +
20
+ (cachedTokens / 1_000_000) * pricing.inputCacheHit;
21
+ const outputCost = (completionTokens / 1_000_000) * pricing.output;
22
+ const totalCost = inputCost + outputCost;
23
+ const formattedCost = totalCost < 0.0001
24
+ ? `$${totalCost.toFixed(5)} USD`
25
+ : `$${totalCost.toFixed(4)} USD`;
26
+ return {
27
+ inputCost,
28
+ outputCost,
29
+ totalCost,
30
+ formattedCost,
31
+ };
32
+ }
33
+ getSummary(modelName = "deepseek-v4-flash") {
34
+ const { formattedCost } = this.calculateCost(undefined, undefined, undefined, modelName);
35
+ const totalTokens = this.totalPromptTokens + this.totalCompletionTokens;
36
+ return `Sesión total: ${totalTokens.toLocaleString()} tokens (Caché: ${this.cachedPromptTokens.toLocaleString()}) | Inversión: ${formattedCost}`;
37
+ }
38
+ }
@@ -0,0 +1,37 @@
1
+ export interface FileSnapshot {
2
+ filePath: string;
3
+ previousContent: string | null;
4
+ }
5
+ export interface Checkpoint {
6
+ id: string;
7
+ timestamp: string;
8
+ description: string;
9
+ snapshots: FileSnapshot[];
10
+ }
11
+ export declare class UndoManager {
12
+ private checkpoints;
13
+ private currentTurnSnapshots;
14
+ /**
15
+ * Captures the state of a file before modifying or deleting it
16
+ */
17
+ snapshotFile(filePath: string, cwd?: string): void;
18
+ /**
19
+ * Finalizes the current turn and saves a rollback checkpoint
20
+ */
21
+ commitTurn(description: string): void;
22
+ /**
23
+ * Undoes the last turn of modifications
24
+ */
25
+ undoLast(): {
26
+ success: boolean;
27
+ message: string;
28
+ restoredFiles: string[];
29
+ };
30
+ getHistory(): {
31
+ id: string;
32
+ description: string;
33
+ time: string;
34
+ fileCount: number;
35
+ }[];
36
+ }
37
+ export declare const globalUndoManager: UndoManager;
@@ -0,0 +1,95 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ export class UndoManager {
4
+ checkpoints = [];
5
+ currentTurnSnapshots = new Map();
6
+ /**
7
+ * Captures the state of a file before modifying or deleting it
8
+ */
9
+ snapshotFile(filePath, cwd = process.cwd()) {
10
+ const resolved = path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);
11
+ if (this.currentTurnSnapshots.has(resolved))
12
+ return; // Already captured for this turn
13
+ if (fs.existsSync(resolved)) {
14
+ try {
15
+ const content = fs.readFileSync(resolved, "utf-8");
16
+ this.currentTurnSnapshots.set(resolved, content);
17
+ }
18
+ catch {
19
+ this.currentTurnSnapshots.set(resolved, null);
20
+ }
21
+ }
22
+ else {
23
+ this.currentTurnSnapshots.set(resolved, null); // New file to be created
24
+ }
25
+ }
26
+ /**
27
+ * Finalizes the current turn and saves a rollback checkpoint
28
+ */
29
+ commitTurn(description) {
30
+ if (this.currentTurnSnapshots.size === 0)
31
+ return;
32
+ const snapshots = [];
33
+ this.currentTurnSnapshots.forEach((content, filePath) => {
34
+ snapshots.push({ filePath, previousContent: content });
35
+ });
36
+ this.checkpoints.push({
37
+ id: `chk_${Date.now()}`,
38
+ timestamp: new Date().toLocaleTimeString(),
39
+ description,
40
+ snapshots,
41
+ });
42
+ this.currentTurnSnapshots.clear();
43
+ // Keep maximum 10 recent checkpoints in memory
44
+ if (this.checkpoints.length > 10) {
45
+ this.checkpoints.shift();
46
+ }
47
+ }
48
+ /**
49
+ * Undoes the last turn of modifications
50
+ */
51
+ undoLast() {
52
+ if (this.checkpoints.length === 0) {
53
+ return {
54
+ success: false,
55
+ message: "No hay acciones previas para deshacer en esta sesión.",
56
+ restoredFiles: [],
57
+ };
58
+ }
59
+ const checkpoint = this.checkpoints.pop();
60
+ const restoredFiles = [];
61
+ for (const snap of checkpoint.snapshots) {
62
+ try {
63
+ if (snap.previousContent === null) {
64
+ // File was newly created during the turn, delete it
65
+ if (fs.existsSync(snap.filePath)) {
66
+ fs.unlinkSync(snap.filePath);
67
+ restoredFiles.push(`(Eliminado archivo creado) ${path.basename(snap.filePath)}`);
68
+ }
69
+ }
70
+ else {
71
+ // File was modified or deleted, restore original content
72
+ fs.writeFileSync(snap.filePath, snap.previousContent, "utf-8");
73
+ restoredFiles.push(`(Restaurado) ${path.basename(snap.filePath)}`);
74
+ }
75
+ }
76
+ catch (err) {
77
+ restoredFiles.push(`(Error restaurando) ${path.basename(snap.filePath)}: ${err?.message}`);
78
+ }
79
+ }
80
+ return {
81
+ success: true,
82
+ message: `✔ Deshecho con éxito: "${checkpoint.description}" (${checkpoint.timestamp})`,
83
+ restoredFiles,
84
+ };
85
+ }
86
+ getHistory() {
87
+ return this.checkpoints.map((c) => ({
88
+ id: c.id,
89
+ description: c.description,
90
+ time: c.timestamp,
91
+ fileCount: c.snapshots.length,
92
+ }));
93
+ }
94
+ }
95
+ export const globalUndoManager = new UndoManager();
@@ -0,0 +1,77 @@
1
+ /** API de DeepSeek directa. La usa quien trae su propia clave. */
2
+ export declare const DIRECT_ENGINE_URL = "https://api.deepseek.com";
3
+ /**
4
+ * Proxy propio para los suscriptores.
5
+ *
6
+ * En modo suscripcion el cliente NO tiene clave de DeepSeek: manda su clave de
7
+ * licencia y el proxy, que si guarda la clave maestra, reenvia la peticion. Por
8
+ * eso la clave maestra nunca viaja dentro del programa que se reparte.
9
+ */
10
+ export declare const MANAGED_ENGINE_URL: string;
11
+ /**
12
+ * A donde se habla.
13
+ *
14
+ * Estaba fijo en el codigo, asi que apuntar al proxy exigia recompilar y
15
+ * republicar. Ahora manda, por orden: la variable de entorno (para pruebas), lo
16
+ * guardado en ~/.chocolatitorc, y si no, el destino que corresponda al modo.
17
+ */
18
+ export declare function getEngineBaseUrl(): string;
19
+ /**
20
+ * Compatibilidad: se conserva el nombre antiguo, pero ya no es una constante
21
+ * congelada al importar. Se resuelve en cada uso.
22
+ */
23
+ export declare const ENGINE_BASE_URL: string;
24
+ /**
25
+ * Modelo multimodal usado como "ojos" del agente.
26
+ * El motor principal es de texto, asi que las capturas se traducen a texto con
27
+ * este modelo antes de llegar al bucle. Se puede sobrescribir con la variable de
28
+ * entorno CHOCOLATITO_VISION_MODEL.
29
+ */
30
+ export declare const VISION_MODEL: string;
31
+ /**
32
+ * Ventana de contexto real de los modelos V4: 1.000.000 de tokens.
33
+ *
34
+ * Antes el proyecto asumia 64.000 y compactaba el historial cada 16 mensajes.
35
+ * Con una ventana 15 veces mayor, eso significaba tirar a la basura casi todo el
36
+ * contexto util cada pocos turnos: el agente se olvidaba de lo que acababa de
37
+ * hacer y repetia trabajo. Era el mayor lastre de calidad del proyecto.
38
+ */
39
+ export declare const CONTEXT_WINDOW = 1000000;
40
+ /** Limite de salida por respuesta. Sin esto el SDK usa un maximo bajo. */
41
+ export declare const MAX_OUTPUT_TOKENS = 16384;
42
+ /**
43
+ * Umbral de auto-compactacion: solo cuando de verdad se acerca el limite.
44
+ * Se deja margen suficiente para una respuesta larga y las herramientas.
45
+ */
46
+ export declare const COMPACT_THRESHOLD_TOKENS: number;
47
+ export interface EspectroModel {
48
+ id: string;
49
+ name: string;
50
+ description: string;
51
+ underlyingModel: string;
52
+ effortLevel: string;
53
+ /** Temperatura del muestreo para este nivel. */
54
+ temperature: number;
55
+ }
56
+ /**
57
+ * Los alias antiguos 'deepseek-chat' y 'deepseek-reasoner' resuelven HOY los dos
58
+ * a deepseek-v4-flash. Es decir: los cuatro niveles de esfuerzo corrian
59
+ * exactamente el mismo modelo y el nivel "MAX" no aportaba nada.
60
+ * Ahora los niveles altos usan deepseek-v4-pro, que si es mas capaz.
61
+ */
62
+ export declare const ESPECTRO_MODELS: Record<string, EspectroModel>;
63
+ export declare const DEFAULT_ESPECTRO: EspectroModel;
64
+ export interface ModelPricing {
65
+ inputCacheMiss: number;
66
+ inputCacheHit: number;
67
+ output: number;
68
+ }
69
+ /**
70
+ * USD por millón de tokens, tarifa estándar (fuera del descuento de horario
71
+ * valle). Los valores anteriores estaban tomados de la generación V3 y
72
+ * subestimaban el gasto real entre 3 y 4 veces.
73
+ */
74
+ export declare const MODEL_PRICING: Record<string, ModelPricing>;
75
+ export declare const PRICING: ModelPricing;
76
+ export declare const CONFIG_FILE_NAME = ".chocolatitorc";
77
+ export declare const RULES_FILE_NAME = "CHOCOLATITO.md";
@@ -0,0 +1,146 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ /** API de DeepSeek directa. La usa quien trae su propia clave. */
5
+ export const DIRECT_ENGINE_URL = "https://api.deepseek.com";
6
+ /**
7
+ * Proxy propio para los suscriptores.
8
+ *
9
+ * En modo suscripcion el cliente NO tiene clave de DeepSeek: manda su clave de
10
+ * licencia y el proxy, que si guarda la clave maestra, reenvia la peticion. Por
11
+ * eso la clave maestra nunca viaja dentro del programa que se reparte.
12
+ */
13
+ export const MANAGED_ENGINE_URL = process.env.CHOCOLATITO_PROXY_URL?.trim() ||
14
+ "https://chocolatito-proxy.chocolatito.workers.dev/v1";
15
+ function rc() {
16
+ try {
17
+ const p = path.join(os.homedir(), ".chocolatitorc");
18
+ if (!fs.existsSync(p))
19
+ return {};
20
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
21
+ }
22
+ catch {
23
+ return {};
24
+ }
25
+ }
26
+ /**
27
+ * A donde se habla.
28
+ *
29
+ * Estaba fijo en el codigo, asi que apuntar al proxy exigia recompilar y
30
+ * republicar. Ahora manda, por orden: la variable de entorno (para pruebas), lo
31
+ * guardado en ~/.chocolatitorc, y si no, el destino que corresponda al modo.
32
+ */
33
+ export function getEngineBaseUrl() {
34
+ const env = process.env.CHOCOLATITO_ENGINE_URL?.trim();
35
+ if (env)
36
+ return env;
37
+ const cfg = rc();
38
+ if (typeof cfg.engineUrl === "string" && cfg.engineUrl.trim())
39
+ return cfg.engineUrl.trim();
40
+ return cfg.managed === true ? MANAGED_ENGINE_URL : DIRECT_ENGINE_URL;
41
+ }
42
+ /**
43
+ * Compatibilidad: se conserva el nombre antiguo, pero ya no es una constante
44
+ * congelada al importar. Se resuelve en cada uso.
45
+ */
46
+ export const ENGINE_BASE_URL = getEngineBaseUrl();
47
+ /**
48
+ * Modelo multimodal usado como "ojos" del agente.
49
+ * El motor principal es de texto, asi que las capturas se traducen a texto con
50
+ * este modelo antes de llegar al bucle. Se puede sobrescribir con la variable de
51
+ * entorno CHOCOLATITO_VISION_MODEL.
52
+ */
53
+ export const VISION_MODEL = process.env.CHOCOLATITO_VISION_MODEL?.trim() || "deepseek-v4-flash-vision-exp";
54
+ /**
55
+ * Ventana de contexto real de los modelos V4: 1.000.000 de tokens.
56
+ *
57
+ * Antes el proyecto asumia 64.000 y compactaba el historial cada 16 mensajes.
58
+ * Con una ventana 15 veces mayor, eso significaba tirar a la basura casi todo el
59
+ * contexto util cada pocos turnos: el agente se olvidaba de lo que acababa de
60
+ * hacer y repetia trabajo. Era el mayor lastre de calidad del proyecto.
61
+ */
62
+ export const CONTEXT_WINDOW = 1_000_000;
63
+ /** Limite de salida por respuesta. Sin esto el SDK usa un maximo bajo. */
64
+ export const MAX_OUTPUT_TOKENS = 16_384;
65
+ /**
66
+ * Umbral de auto-compactacion: solo cuando de verdad se acerca el limite.
67
+ * Se deja margen suficiente para una respuesta larga y las herramientas.
68
+ */
69
+ export const COMPACT_THRESHOLD_TOKENS = Math.floor(CONTEXT_WINDOW * 0.75);
70
+ /**
71
+ * Los alias antiguos 'deepseek-chat' y 'deepseek-reasoner' resuelven HOY los dos
72
+ * a deepseek-v4-flash. Es decir: los cuatro niveles de esfuerzo corrian
73
+ * exactamente el mismo modelo y el nivel "MAX" no aportaba nada.
74
+ * Ahora los niveles altos usan deepseek-v4-pro, que si es mas capaz.
75
+ */
76
+ export const ESPECTRO_MODELS = {
77
+ "1.0": {
78
+ id: "1.0",
79
+ name: "Espectro 1.0 (Ágil)",
80
+ description: "Ultra rápido, ideal para tareas cotidianas y código directo",
81
+ underlyingModel: "deepseek-v4-flash",
82
+ effortLevel: "Normal",
83
+ temperature: 0.1,
84
+ },
85
+ "1.5": {
86
+ id: "1.5",
87
+ name: "Espectro 1.5 (Avanzado)",
88
+ description: "Alta precisión con balance de velocidad para refactorización",
89
+ underlyingModel: "deepseek-v4-flash",
90
+ effortLevel: "Alto",
91
+ temperature: 0.3,
92
+ },
93
+ "2.0": {
94
+ id: "2.0",
95
+ name: "Espectro 2.0 (Razonamiento Pro)",
96
+ description: "Modelo Pro para lógica compleja, bugs difíciles y arquitectura",
97
+ underlyingModel: "deepseek-v4-pro",
98
+ effortLevel: "Extendido",
99
+ temperature: 0.1,
100
+ },
101
+ "2.5": {
102
+ id: "2.5",
103
+ name: "Espectro 2.5 MAX (Máxima Potencia)",
104
+ description: "Modelo Pro con exploración amplia para proyectos enteros",
105
+ underlyingModel: "deepseek-v4-pro",
106
+ effortLevel: "Máximo",
107
+ temperature: 0.35,
108
+ },
109
+ };
110
+ export const DEFAULT_ESPECTRO = ESPECTRO_MODELS["1.0"];
111
+ /**
112
+ * USD por millón de tokens, tarifa estándar (fuera del descuento de horario
113
+ * valle). Los valores anteriores estaban tomados de la generación V3 y
114
+ * subestimaban el gasto real entre 3 y 4 veces.
115
+ */
116
+ export const MODEL_PRICING = {
117
+ "deepseek-v4-flash": {
118
+ inputCacheMiss: 0.44,
119
+ inputCacheHit: 0.014,
120
+ output: 1.32,
121
+ },
122
+ "deepseek-v4-pro": {
123
+ inputCacheMiss: 1.32,
124
+ inputCacheHit: 0.044,
125
+ output: 3.96,
126
+ },
127
+ "deepseek-v4-flash-vision-exp": {
128
+ inputCacheMiss: 0.44,
129
+ inputCacheHit: 0.014,
130
+ output: 1.32,
131
+ },
132
+ // Alias heredados, por si alguna sesión guardada los referencia.
133
+ "deepseek-chat": {
134
+ inputCacheMiss: 0.44,
135
+ inputCacheHit: 0.014,
136
+ output: 1.32,
137
+ },
138
+ "deepseek-reasoner": {
139
+ inputCacheMiss: 0.44,
140
+ inputCacheHit: 0.014,
141
+ output: 1.32,
142
+ },
143
+ };
144
+ export const PRICING = MODEL_PRICING["deepseek-v4-flash"];
145
+ export const CONFIG_FILE_NAME = ".chocolatitorc";
146
+ export const RULES_FILE_NAME = "CHOCOLATITO.md";
@@ -0,0 +1,49 @@
1
+ import OpenAI from "openai";
2
+ /**
3
+ * QUIEN HABLA CON EL MOTOR Y COMO SE IDENTIFICA
4
+ *
5
+ * Habia tres sitios construyendo su propio cliente de OpenAI con la clave y la
6
+ * URL, sin nada mas. Eso dejaba tres agujeros para el modelo de suscripcion:
7
+ *
8
+ * 1. La licencia no viajaba. El CLI mandaba `Authorization: Bearer <clave de
9
+ * DeepSeek>` y punto; la licencia se quedaba en el archivo de configuracion.
10
+ * Un proxy que la esperase habria respondido 401 a todos los suscriptores.
11
+ *
12
+ * 2. El proxy no podia distinguir de que ruta venia el gasto. El bucle, los
13
+ * subagentes, la vision y la compactacion llegaban con cuerpos casi
14
+ * indistinguibles, asi que era imposible decirle al usuario en que se le fue
15
+ * la cuota, ni limitar una ruta concreta.
16
+ *
17
+ * 3. Nada impedia usar el proxy como API generica barata. Es un endpoint
18
+ * compatible con OpenAI: sin una marca propia obligatoria, apuntar ahi
19
+ * cualquier otro cliente da el mismo servicio por el mismo precio.
20
+ */
21
+ export type EngineRoute = "loop" | "subagent" | "vision" | "compact";
22
+ /** Version del paquete instalado, para versionar el contrato con el proxy. */
23
+ export declare function clientVersion(): string;
24
+ /**
25
+ * La credencial que se manda en el Bearer.
26
+ *
27
+ * En suscripcion es la clave de licencia: el cliente no tiene clave de DeepSeek
28
+ * y no debe tenerla, porque la maestra vive en el proxy. Con clave propia se
29
+ * manda la del usuario, como siempre.
30
+ */
31
+ export declare function engineCredential(fallbackApiKey: string): string;
32
+ /**
33
+ * Cabeceras propias en cada peticion.
34
+ *
35
+ * Van en TODAS las rutas para que el proxy pueda atribuir el gasto, rechazar
36
+ * clientes de version incompatible y distinguir a Chocolatito Code de un SDK
37
+ * cualquiera apuntando al mismo endpoint.
38
+ */
39
+ export declare function engineHeaders(route: EngineRoute): Record<string, string>;
40
+ /** Cliente del motor ya configurado. Es el unico sitio donde se construye. */
41
+ export declare function createEngineClient(apiKey: string, route: EngineRoute): OpenAI;
42
+ /**
43
+ * Traduce un error del motor a algo que el usuario entienda.
44
+ *
45
+ * Sin esto, el proxy diciendo "se te acabo la cuota" (402) llega a pantalla como
46
+ * "Error en el motor tras varios reintentos: 402 ...", que ademas miente: un 402
47
+ * no se reintenta nunca.
48
+ */
49
+ export declare function explicarErrorDelMotor(err: any): string | null;