@johpaz/hive-sdk 0.0.12 → 0.0.15

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 (199) hide show
  1. package/.github/CODEOWNERS +9 -0
  2. package/.github/workflows/publish.yml +89 -0
  3. package/.github/workflows/version-bump.yml +102 -0
  4. package/CHANGELOG.md +38 -0
  5. package/README.md +158 -0
  6. package/bun.lock +543 -0
  7. package/bunfig.toml +7 -0
  8. package/docs/API-AGENTS.md +316 -0
  9. package/docs/API-CONTEXT-COMPILER.md +252 -0
  10. package/docs/API-DAG-SCHEDULER.md +273 -0
  11. package/docs/API-TOOLS-SKILLS-CHANNELS.md +293 -0
  12. package/docs/API-WORKERS-EVENTS.md +152 -0
  13. package/docs/INDEX.md +141 -0
  14. package/docs/README.md +68 -0
  15. package/package.json +54 -105
  16. package/packages/cli/package.json +17 -0
  17. package/packages/cli/src/commands/init.ts +56 -0
  18. package/packages/cli/src/commands/run.ts +45 -0
  19. package/packages/cli/src/commands/test.ts +42 -0
  20. package/packages/cli/src/commands/trace.ts +55 -0
  21. package/packages/cli/src/index.ts +43 -0
  22. package/packages/core/package.json +58 -0
  23. package/packages/core/src/ace/Curator.ts +158 -0
  24. package/packages/core/src/ace/Reflector.ts +200 -0
  25. package/packages/core/src/ace/Tracer.ts +100 -0
  26. package/packages/core/src/ace/index.ts +4 -0
  27. package/packages/core/src/agent/AgentRunner.ts +699 -0
  28. package/packages/core/src/agent/Compaction.ts +221 -0
  29. package/packages/core/src/agent/ContextCompiler.ts +567 -0
  30. package/packages/core/src/agent/ContextGuard.ts +91 -0
  31. package/packages/core/src/agent/ConversationStore.ts +244 -0
  32. package/packages/core/src/agent/Hooks.ts +166 -0
  33. package/packages/core/src/agent/NativeTools.ts +31 -0
  34. package/packages/core/src/agent/PromptBuilder.ts +169 -0
  35. package/packages/core/src/agent/Service.ts +267 -0
  36. package/packages/core/src/agent/StuckLoop.ts +133 -0
  37. package/packages/core/src/agent/index.ts +12 -0
  38. package/packages/core/src/agent/providers/LLMClient.ts +149 -0
  39. package/packages/core/src/agent/providers/anthropic.ts +212 -0
  40. package/packages/core/src/agent/providers/gemini.ts +215 -0
  41. package/packages/core/src/agent/providers/index.ts +199 -0
  42. package/packages/core/src/agent/providers/interface.ts +195 -0
  43. package/packages/core/src/agent/providers/ollama.ts +175 -0
  44. package/packages/core/src/agent/providers/openai-compat.ts +231 -0
  45. package/packages/core/src/agent/providers.ts +1 -0
  46. package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
  47. package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
  48. package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
  49. package/packages/core/src/agent/selectors/index.ts +6 -0
  50. package/packages/core/src/api/createAgent.test.ts +48 -0
  51. package/packages/core/src/api/createAgent.ts +122 -0
  52. package/packages/core/src/api/index.ts +2 -0
  53. package/packages/core/src/canvas/CanvasManager.ts +390 -0
  54. package/packages/core/src/canvas/a2ui-tools.ts +255 -0
  55. package/packages/core/src/canvas/canvas-tools.ts +448 -0
  56. package/packages/core/src/canvas/emitter.ts +149 -0
  57. package/packages/core/src/canvas/index.ts +6 -0
  58. package/packages/core/src/config/index.ts +2 -0
  59. package/packages/core/src/config/loader.ts +554 -0
  60. package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
  61. package/packages/core/src/ethics/EthicsGuard.ts +66 -0
  62. package/packages/core/src/ethics/index.ts +2 -0
  63. package/packages/core/src/gateway/channel-notify.test.ts +14 -0
  64. package/packages/core/src/gateway/channel-notify.ts +12 -0
  65. package/packages/core/src/gateway/index.ts +1 -0
  66. package/packages/core/src/index.ts +37 -0
  67. package/packages/core/src/mcp/MCPClient.ts +439 -0
  68. package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
  69. package/packages/core/src/mcp/config.ts +13 -0
  70. package/packages/core/src/mcp/hot-reload.ts +147 -0
  71. package/packages/core/src/mcp/index.ts +11 -0
  72. package/packages/core/src/mcp/logger.ts +42 -0
  73. package/packages/core/src/mcp/singleton.ts +21 -0
  74. package/packages/core/src/mcp/transports/index.ts +67 -0
  75. package/packages/core/src/mcp/transports/sse.ts +241 -0
  76. package/packages/core/src/mcp/transports/websocket.ts +159 -0
  77. package/packages/core/src/memory/Scratchpad.test.ts +47 -0
  78. package/packages/core/src/memory/Scratchpad.ts +37 -0
  79. package/packages/core/src/memory/Storage.ts +6 -0
  80. package/packages/core/src/memory/index.ts +2 -0
  81. package/packages/core/src/multimodal/VisionService.ts +293 -0
  82. package/packages/core/src/multimodal/index.ts +2 -0
  83. package/packages/core/src/multimodal/types.ts +28 -0
  84. package/packages/core/src/security/Pairing.ts +250 -0
  85. package/packages/core/src/security/RateLimit.ts +270 -0
  86. package/packages/core/src/security/index.ts +4 -0
  87. package/packages/core/src/skills/SkillLoader.ts +388 -0
  88. package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
  89. package/packages/core/src/skills/defineSkill.ts +18 -0
  90. package/packages/core/src/skills/index.ts +4 -0
  91. package/packages/core/src/state/index.ts +2 -0
  92. package/packages/core/src/state/store.ts +312 -0
  93. package/packages/core/src/storage/SQLiteStorage.ts +407 -0
  94. package/packages/core/src/storage/crypto.ts +101 -0
  95. package/packages/core/src/storage/index.ts +10 -0
  96. package/packages/core/src/storage/onboarding.ts +1603 -0
  97. package/packages/core/src/storage/schema.ts +689 -0
  98. package/packages/core/src/storage/seed.ts +740 -0
  99. package/packages/core/src/storage/usage.ts +374 -0
  100. package/packages/core/src/swarm/AgentBus.ts +460 -0
  101. package/packages/core/src/swarm/AgentExecutor.ts +53 -0
  102. package/packages/core/src/swarm/Coordinator.ts +251 -0
  103. package/packages/core/src/swarm/EventBridge.ts +122 -0
  104. package/packages/core/src/swarm/EventBus.ts +169 -0
  105. package/packages/core/src/swarm/TaskGraph.ts +192 -0
  106. package/packages/core/src/swarm/TaskNode.ts +97 -0
  107. package/packages/core/src/swarm/TaskResult.ts +22 -0
  108. package/packages/core/src/swarm/WorkerPool.ts +236 -0
  109. package/packages/core/src/swarm/errors.ts +37 -0
  110. package/packages/core/src/swarm/index.ts +30 -0
  111. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
  112. package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
  113. package/packages/core/src/swarm/presets/index.ts +4 -0
  114. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
  115. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
  116. package/packages/core/src/swarm/strategies/index.ts +3 -0
  117. package/packages/core/src/swarm/types.ts +164 -0
  118. package/packages/core/src/tools/ToolExecutor.ts +58 -0
  119. package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
  120. package/packages/core/src/tools/ToolRegistry.ts +61 -0
  121. package/packages/core/src/tools/agents/get-available-models.ts +118 -0
  122. package/packages/core/src/tools/agents/index.ts +715 -0
  123. package/packages/core/src/tools/bridge-events.ts +26 -0
  124. package/packages/core/src/tools/canvas/index.ts +375 -0
  125. package/packages/core/src/tools/cli/index.ts +142 -0
  126. package/packages/core/src/tools/codebridge/index.ts +342 -0
  127. package/packages/core/src/tools/core/index.ts +476 -0
  128. package/packages/core/src/tools/cron/index.ts +626 -0
  129. package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
  130. package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
  131. package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
  132. package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
  133. package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
  134. package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
  135. package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
  136. package/packages/core/src/tools/filesystem/index.ts +34 -0
  137. package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
  138. package/packages/core/src/tools/index.ts +231 -0
  139. package/packages/core/src/tools/meeting/index.ts +363 -0
  140. package/packages/core/src/tools/office/index.ts +47 -0
  141. package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
  142. package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
  143. package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
  144. package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
  145. package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
  146. package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
  147. package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
  148. package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
  149. package/packages/core/src/tools/projects/index.ts +37 -0
  150. package/packages/core/src/tools/projects/project-create.ts +94 -0
  151. package/packages/core/src/tools/projects/project-done.ts +66 -0
  152. package/packages/core/src/tools/projects/project-fail.ts +66 -0
  153. package/packages/core/src/tools/projects/project-list.ts +96 -0
  154. package/packages/core/src/tools/projects/project-update.ts +72 -0
  155. package/packages/core/src/tools/projects/task-create.ts +68 -0
  156. package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
  157. package/packages/core/src/tools/projects/task-update.ts +93 -0
  158. package/packages/core/src/tools/types.ts +39 -0
  159. package/packages/core/src/tools/voice/index.ts +104 -0
  160. package/packages/core/src/tools/web/browser-click.ts +78 -0
  161. package/packages/core/src/tools/web/browser-extract.ts +139 -0
  162. package/packages/core/src/tools/web/browser-navigate.ts +106 -0
  163. package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
  164. package/packages/core/src/tools/web/browser-script.ts +88 -0
  165. package/packages/core/src/tools/web/browser-service.ts +554 -0
  166. package/packages/core/src/tools/web/browser-type.ts +101 -0
  167. package/packages/core/src/tools/web/browser-wait.ts +136 -0
  168. package/packages/core/src/tools/web/index.ts +41 -0
  169. package/packages/core/src/tools/web/web-fetch.ts +78 -0
  170. package/packages/core/src/tools/web/web-search.ts +123 -0
  171. package/packages/core/src/utils/benchmark.ts +80 -0
  172. package/packages/core/src/utils/crypto.ts +73 -0
  173. package/packages/core/src/utils/date.ts +42 -0
  174. package/packages/core/src/utils/index.ts +10 -0
  175. package/packages/core/src/utils/logger.ts +389 -0
  176. package/packages/core/src/utils/retry.ts +70 -0
  177. package/packages/core/src/utils/toon.ts +253 -0
  178. package/packages/core/src/voice/index.ts +656 -0
  179. package/test/setup-db.ts +216 -0
  180. package/tsconfig.json +39 -0
  181. package/src/agents.ts +0 -1
  182. package/src/canvas.ts +0 -1
  183. package/src/channels.ts +0 -1
  184. package/src/config.ts +0 -1
  185. package/src/events.ts +0 -1
  186. package/src/gateway.ts +0 -1
  187. package/src/index.ts +0 -304
  188. package/src/mcp.ts +0 -1
  189. package/src/multimodal.ts +0 -1
  190. package/src/scheduler.ts +0 -1
  191. package/src/security.ts +0 -1
  192. package/src/skills.ts +0 -1
  193. package/src/state.ts +0 -1
  194. package/src/storage.ts +0 -1
  195. package/src/tools.ts +0 -1
  196. package/src/tts.ts +0 -1
  197. package/src/types.ts +0 -82
  198. package/src/utils.ts +0 -1
  199. package/src/voice.ts +0 -1
@@ -0,0 +1,93 @@
1
+ /**
2
+ * office_leer_docx - Leer contenido de un archivo Word (.docx)
3
+ *
4
+ * @category office
5
+ * @seedId office_leer_docx
6
+ * @spanish leer word, abrir docx, extraer texto de word, contenido word
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { logger } from "../../utils/logger.ts";
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+
14
+ const log = logger.child("office-leer-docx");
15
+
16
+ export const officeLeerDocxTool: Tool = {
17
+ name: "office_leer_docx",
18
+ description:
19
+ "Leer un archivo Word (.docx) y retornar el contenido de texto preservando párrafos y tablas. Spanish: leer word, abrir docx, extraer texto de word, contenido word",
20
+ parameters: {
21
+ type: "object",
22
+ properties: {
23
+ ruta: {
24
+ type: "string",
25
+ description: "Ruta absoluta o relativa al archivo .docx",
26
+ },
27
+ incluir_tablas: {
28
+ type: "boolean",
29
+ description: "Incluir contenido de tablas en la extracción (default: true)",
30
+ },
31
+ },
32
+ required: ["ruta"],
33
+ },
34
+ execute: async (params: Record<string, unknown>) => {
35
+ const ruta = params.ruta as string;
36
+ const incluirTablas = (params.incluir_tablas as boolean) ?? true;
37
+
38
+ log.debug(`Leyendo DOCX: ${ruta}`);
39
+
40
+ try {
41
+ const rutaAbsoluta = path.resolve(ruta);
42
+ if (!fs.existsSync(rutaAbsoluta)) {
43
+ return { ok: false, error: `Archivo no encontrado: ${rutaAbsoluta}` };
44
+ }
45
+
46
+ const mammoth = await import("mammoth");
47
+ const buffer = fs.readFileSync(rutaAbsoluta);
48
+
49
+ // Extraer texto plano
50
+ const resultadoTexto = await mammoth.extractRawText({ buffer });
51
+
52
+ // Extraer HTML para información de tablas si se requiere
53
+ let textoTablas: string | undefined;
54
+ if (incluirTablas) {
55
+ const resultadoHtml = await mammoth.convertToHtml({ buffer });
56
+ // Extraer contenido de tablas del HTML
57
+ const tablas = resultadoHtml.value.match(/<table[\s\S]*?<\/table>/gi) ?? [];
58
+ if (tablas.length > 0) {
59
+ textoTablas = tablas
60
+ .map((tabla, i) => {
61
+ // Limpiar tags HTML y extraer texto de celdas
62
+ const celdas = tabla.match(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi) ?? [];
63
+ const textoCeldas = celdas
64
+ .map((celda) => celda.replace(/<[^>]+>/g, "").trim())
65
+ .filter(Boolean);
66
+ return `[Tabla ${i + 1}]\n${textoCeldas.join(" | ")}`;
67
+ })
68
+ .join("\n\n");
69
+ }
70
+ }
71
+
72
+ const advertencias = resultadoTexto.messages
73
+ .filter((m: any) => m.type === "warning")
74
+ .map((m: any) => m.message);
75
+
76
+ log.info(`DOCX leído: ${resultadoTexto.value.length} caracteres`);
77
+
78
+ return {
79
+ ok: true,
80
+ ruta: rutaAbsoluta,
81
+ texto: resultadoTexto.value,
82
+ tablas: textoTablas,
83
+ advertencias: advertencias.length > 0 ? advertencias : undefined,
84
+ };
85
+ } catch (error) {
86
+ log.error(`Error leyendo DOCX: ${(error as Error).message}`);
87
+ return {
88
+ ok: false,
89
+ error: `No se pudo leer el archivo DOCX: ${(error as Error).message}`,
90
+ };
91
+ }
92
+ },
93
+ };
@@ -0,0 +1,114 @@
1
+ /**
2
+ * office_leer_pdf - Leer contenido de un archivo PDF
3
+ *
4
+ * @category office
5
+ * @seedId office_leer_pdf
6
+ * @spanish leer pdf, abrir pdf, extraer texto de pdf, contenido pdf
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { logger } from "../../utils/logger.ts";
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+
14
+ const log = logger.child("office-leer-pdf");
15
+
16
+ export const officeLeerPdfTool: Tool = {
17
+ name: "office_leer_pdf",
18
+ description:
19
+ "Leer contenido de un archivo PDF y retornar texto plano con metadata. Spanish: leer pdf, abrir pdf, extraer texto de pdf, pdf a texto",
20
+ parameters: {
21
+ type: "object",
22
+ properties: {
23
+ ruta: {
24
+ type: "string",
25
+ description: "Ruta absoluta o relativa al archivo PDF",
26
+ },
27
+ pagina_inicio: {
28
+ type: "number",
29
+ description: "Página desde la que empezar (1-indexed, default: 1)",
30
+ },
31
+ pagina_fin: {
32
+ type: "number",
33
+ description: "Última página a leer (default: todas las páginas)",
34
+ },
35
+ },
36
+ required: ["ruta"],
37
+ },
38
+ execute: async (params: Record<string, unknown>) => {
39
+ const ruta = params.ruta as string;
40
+ const paginaInicio = Math.max(1, (params.pagina_inicio as number) ?? 1);
41
+ const paginaFin = params.pagina_fin as number | undefined;
42
+
43
+ log.debug(`Leyendo PDF: ${ruta}`);
44
+
45
+ try {
46
+ const rutaAbsoluta = path.resolve(ruta);
47
+ if (!fs.existsSync(rutaAbsoluta)) {
48
+ return { ok: false, error: `Archivo no encontrado: ${rutaAbsoluta}` };
49
+ }
50
+
51
+ const buffer = fs.readFileSync(rutaAbsoluta);
52
+ const uint8Array = new Uint8Array(buffer);
53
+
54
+ // Importar pdfjs-dist (compatible con Bun, sin worker)
55
+ const pdfjsLib = await import("pdfjs-dist/legacy/build/pdf.mjs" as any).catch(
56
+ () => import("pdfjs-dist" as any)
57
+ );
58
+
59
+ // Desactivar worker para entorno Node/Bun
60
+ const lib = pdfjsLib.default ?? pdfjsLib;
61
+ if (lib.GlobalWorkerOptions) {
62
+ lib.GlobalWorkerOptions.workerSrc = "";
63
+ }
64
+
65
+ const doc = await lib.getDocument({ data: uint8Array, disableWorker: true }).promise;
66
+ const totalPaginas = doc.numPages;
67
+
68
+ // Metadata
69
+ let titulo: string | undefined;
70
+ try {
71
+ const meta = await doc.getMetadata();
72
+ titulo = (meta?.info as any)?.Title ?? undefined;
73
+ } catch {
74
+ // metadata opcional
75
+ }
76
+
77
+ const inicio = paginaInicio;
78
+ const fin = paginaFin ? Math.min(paginaFin, totalPaginas) : totalPaginas;
79
+
80
+ const textosPorPagina: Array<{ pagina: number; texto: string }> = [];
81
+
82
+ for (let i = inicio; i <= fin; i++) {
83
+ const pagina = await doc.getPage(i);
84
+ const contenido = await pagina.getTextContent();
85
+ const texto = (contenido.items as any[])
86
+ .map((item: any) => item.str ?? "")
87
+ .join(" ")
88
+ .replace(/\s+/g, " ")
89
+ .trim();
90
+ textosPorPagina.push({ pagina: i, texto });
91
+ }
92
+
93
+ const textoCompleto = textosPorPagina.map((p) => p.texto).join("\n\n");
94
+
95
+ log.info(`PDF leído: ${totalPaginas} páginas, ${textoCompleto.length} caracteres`);
96
+
97
+ return {
98
+ ok: true,
99
+ ruta: rutaAbsoluta,
100
+ totalPaginas,
101
+ paginasLeidas: fin - inicio + 1,
102
+ titulo,
103
+ texto: textoCompleto,
104
+ paginas: textosPorPagina,
105
+ };
106
+ } catch (error) {
107
+ log.error(`Error leyendo PDF: ${(error as Error).message}`);
108
+ return {
109
+ ok: false,
110
+ error: `No se pudo leer el PDF: ${(error as Error).message}`,
111
+ };
112
+ }
113
+ },
114
+ };
@@ -0,0 +1,136 @@
1
+ /**
2
+ * office_leer_pptx - Leer contenido de un archivo PowerPoint (.pptx)
3
+ *
4
+ * @category office
5
+ * @seedId office_leer_pptx
6
+ * @spanish leer powerpoint, abrir pptx, extraer texto de presentacion, contenido slides
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { logger } from "../../utils/logger.ts";
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+
14
+ const log = logger.child("office-leer-pptx");
15
+
16
+ export const officeLeerPptxTool: Tool = {
17
+ name: "office_leer_pptx",
18
+ description:
19
+ "Leer un archivo PowerPoint (.pptx) y retornar el texto de cada diapositiva como array estructurado. Spanish: leer powerpoint, abrir pptx, extraer texto de presentacion, contenido slides",
20
+ parameters: {
21
+ type: "object",
22
+ properties: {
23
+ ruta: {
24
+ type: "string",
25
+ description: "Ruta absoluta o relativa al archivo .pptx",
26
+ },
27
+ solo_diapositiva: {
28
+ type: "number",
29
+ description:
30
+ "Número de diapositiva específica a leer (1-indexed, default: todas)",
31
+ },
32
+ },
33
+ required: ["ruta"],
34
+ },
35
+ execute: async (params: Record<string, unknown>) => {
36
+ const ruta = params.ruta as string;
37
+ const soloSlide = params.solo_diapositiva as number | undefined;
38
+
39
+ log.debug(`Leyendo PPTX: ${ruta}`);
40
+
41
+ try {
42
+ const rutaAbsoluta = path.resolve(ruta);
43
+ if (!fs.existsSync(rutaAbsoluta)) {
44
+ return { ok: false, error: `Archivo no encontrado: ${rutaAbsoluta}` };
45
+ }
46
+
47
+ const JSZip = (await import("jszip")).default;
48
+ const buffer = fs.readFileSync(rutaAbsoluta);
49
+ const zip = await JSZip.loadAsync(buffer);
50
+
51
+ // Encontrar todos los archivos de slides
52
+ const archivosSlides = Object.keys(zip.files)
53
+ .filter((nombre) => /^ppt\/slides\/slide\d+\.xml$/i.test(nombre))
54
+ .sort((a, b) => {
55
+ const numA = parseInt(a.match(/slide(\d+)/)?.[1] ?? "0");
56
+ const numB = parseInt(b.match(/slide(\d+)/)?.[1] ?? "0");
57
+ return numA - numB;
58
+ });
59
+
60
+ const diapositivas: Array<{
61
+ numero: number;
62
+ titulo?: string;
63
+ texto: string;
64
+ fragmentos: string[];
65
+ }> = [];
66
+
67
+ for (let i = 0; i < archivosSlides.length; i++) {
68
+ const numeroSlide = i + 1;
69
+
70
+ if (soloSlide !== undefined && numeroSlide !== soloSlide) {
71
+ continue;
72
+ }
73
+
74
+ const archivoSlide = archivosSlides[i];
75
+ const xmlContenido = await zip.files[archivoSlide].async("string");
76
+
77
+ // Extraer texto de elementos <a:t> (texto en slides de OOXML)
78
+ const fragmentos: string[] = [];
79
+ const regexTexto = /<a:t[^>]*>([\s\S]*?)<\/a:t>/g;
80
+ let match;
81
+
82
+ while ((match = regexTexto.exec(xmlContenido)) !== null) {
83
+ const texto = match[1]
84
+ .replace(/&amp;/g, "&")
85
+ .replace(/&lt;/g, "<")
86
+ .replace(/&gt;/g, ">")
87
+ .replace(/&quot;/g, '"')
88
+ .replace(/&apos;/g, "'")
89
+ .trim();
90
+
91
+ if (texto) {
92
+ fragmentos.push(texto);
93
+ }
94
+ }
95
+
96
+ // Intentar extraer el título (elemento <p:sp> con tipo "title")
97
+ let titulo: string | undefined;
98
+ const regexTitulo =
99
+ /<p:ph[^>]*type="title"[^>]*\/>[\s\S]*?<a:t[^>]*>([\s\S]*?)<\/a:t>/;
100
+ const matchTitulo = regexTitulo.exec(xmlContenido);
101
+ if (matchTitulo) {
102
+ titulo = matchTitulo[1].trim();
103
+ } else if (fragmentos.length > 0) {
104
+ // Primer fragmento como título tentativo
105
+ titulo = fragmentos[0];
106
+ }
107
+
108
+ const texto = fragmentos.join(" ").replace(/\s+/g, " ").trim();
109
+
110
+ diapositivas.push({
111
+ numero: numeroSlide,
112
+ titulo,
113
+ texto,
114
+ fragmentos,
115
+ });
116
+ }
117
+
118
+ log.info(
119
+ `PPTX leído: ${archivosSlides.length} slides totales, ${diapositivas.length} leídas`
120
+ );
121
+
122
+ return {
123
+ ok: true,
124
+ ruta: rutaAbsoluta,
125
+ totalDiapositivas: archivosSlides.length,
126
+ diapositivas,
127
+ };
128
+ } catch (error) {
129
+ log.error(`Error leyendo PPTX: ${(error as Error).message}`);
130
+ return {
131
+ ok: false,
132
+ error: `No se pudo leer el archivo PowerPoint: ${(error as Error).message}`,
133
+ };
134
+ }
135
+ },
136
+ };
@@ -0,0 +1,124 @@
1
+ /**
2
+ * office_leer_xlsx - Leer un archivo Excel (.xlsx)
3
+ *
4
+ * @category office
5
+ * @seedId office_leer_xlsx
6
+ * @spanish leer excel, abrir xlsx, extraer datos de excel, hojas excel
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { logger } from "../../utils/logger.ts";
11
+ import * as fs from "node:fs";
12
+ import * as path from "node:path";
13
+
14
+ const log = logger.child("office-leer-xlsx");
15
+
16
+ export const officeLeerXlsxTool: Tool = {
17
+ name: "office_leer_xlsx",
18
+ description:
19
+ "Leer un archivo Excel (.xlsx) y retornar las hojas con sus datos como objetos JSON. Spanish: leer excel, abrir xlsx, extraer datos de excel, hojas excel",
20
+ parameters: {
21
+ type: "object",
22
+ properties: {
23
+ ruta: {
24
+ type: "string",
25
+ description: "Ruta absoluta o relativa al archivo .xlsx",
26
+ },
27
+ hoja: {
28
+ type: "string",
29
+ description: "Nombre de hoja específica a leer (default: todas las hojas)",
30
+ },
31
+ incluir_encabezados: {
32
+ type: "boolean",
33
+ description:
34
+ "Usar primera fila como encabezados de columna (default: true)",
35
+ },
36
+ rango: {
37
+ type: "string",
38
+ description:
39
+ "Rango de celdas a leer en notación Excel (ej: 'A1:D10', default: toda la hoja)",
40
+ },
41
+ },
42
+ required: ["ruta"],
43
+ },
44
+ execute: async (params: Record<string, unknown>) => {
45
+ const ruta = params.ruta as string;
46
+ const hojaFiltro = params.hoja as string | undefined;
47
+ const incluirEncabezados = (params.incluir_encabezados as boolean) ?? true;
48
+ const rango = params.rango as string | undefined;
49
+
50
+ log.debug(`Leyendo XLSX: ${ruta}`);
51
+
52
+ try {
53
+ const rutaAbsoluta = path.resolve(ruta);
54
+ if (!fs.existsSync(rutaAbsoluta)) {
55
+ return { ok: false, error: `Archivo no encontrado: ${rutaAbsoluta}` };
56
+ }
57
+
58
+ const XLSX = await import("xlsx");
59
+ const buffer = fs.readFileSync(rutaAbsoluta);
60
+ const workbook = XLSX.read(buffer, { type: "buffer" });
61
+
62
+ const nombresHojas = hojaFiltro
63
+ ? [hojaFiltro]
64
+ : workbook.SheetNames;
65
+
66
+ const hojas: Record<string, any[]> = {};
67
+
68
+ for (const nombreHoja of nombresHojas) {
69
+ const hoja = workbook.Sheets[nombreHoja];
70
+ if (!hoja) {
71
+ log.warn(`Hoja '${nombreHoja}' no encontrada en el archivo`);
72
+ continue;
73
+ }
74
+
75
+ const opciones: any = {
76
+ header: incluirEncabezados ? 1 : 1,
77
+ defval: "",
78
+ };
79
+
80
+ if (rango) {
81
+ opciones.range = rango;
82
+ }
83
+
84
+ if (incluirEncabezados) {
85
+ // La primera fila se usa como encabezados
86
+ hojas[nombreHoja] = XLSX.utils.sheet_to_json(hoja, {
87
+ defval: "",
88
+ range: rango,
89
+ });
90
+ } else {
91
+ // Devolver como array de arrays (sin encabezados)
92
+ hojas[nombreHoja] = XLSX.utils.sheet_to_json(hoja, {
93
+ header: 1,
94
+ defval: "",
95
+ range: rango,
96
+ });
97
+ }
98
+ }
99
+
100
+ const totalFilas = Object.values(hojas).reduce(
101
+ (acc, filas) => acc + filas.length,
102
+ 0
103
+ );
104
+
105
+ log.info(
106
+ `XLSX leído: ${nombresHojas.length} hojas, ${totalFilas} filas totales`
107
+ );
108
+
109
+ return {
110
+ ok: true,
111
+ ruta: rutaAbsoluta,
112
+ hojas: workbook.SheetNames,
113
+ datos: hojas,
114
+ totalFilas,
115
+ };
116
+ } catch (error) {
117
+ log.error(`Error leyendo XLSX: ${(error as Error).message}`);
118
+ return {
119
+ ok: false,
120
+ error: `No se pudo leer el archivo Excel: ${(error as Error).message}`,
121
+ };
122
+ }
123
+ },
124
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Projects Tools - 8 tools
3
+ *
4
+ * @category projects
5
+ */
6
+
7
+ import type { Tool } from "../types.ts";
8
+ import { projectCreateTool } from "./project-create.ts";
9
+ import { projectListTool } from "./project-list.ts";
10
+ import { projectUpdateTool } from "./project-update.ts";
11
+ import { projectDoneTool } from "./project-done.ts";
12
+ import { projectFailTool } from "./project-fail.ts";
13
+ import { taskCreateTool } from "./task-create.ts";
14
+ import { taskUpdateTool } from "./task-update.ts";
15
+ import { taskEvaluateTool } from "./task-evaluate.ts";
16
+
17
+ export function createTools(): Tool[] {
18
+ return [
19
+ projectCreateTool,
20
+ projectListTool,
21
+ projectUpdateTool,
22
+ projectDoneTool,
23
+ projectFailTool,
24
+ taskCreateTool,
25
+ taskUpdateTool,
26
+ taskEvaluateTool,
27
+ ];
28
+ }
29
+
30
+ export * from "./project-create.ts";
31
+ export * from "./project-list.ts";
32
+ export * from "./project-update.ts";
33
+ export * from "./project-done.ts";
34
+ export * from "./project-fail.ts";
35
+ export * from "./task-create.ts";
36
+ export * from "./task-update.ts";
37
+ export * from "./task-evaluate.ts";
@@ -0,0 +1,94 @@
1
+ /**
2
+ * project_create - Create a new project with tasks in the database
3
+ *
4
+ * @category projects
5
+ * @seedId project_create
6
+ * @spanish crear proyecto, nuevo proyecto, iniciar plan
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { getDb } from "../../storage/SQLiteStorage.ts";
11
+ import { logger } from "../../utils/logger.ts";
12
+ import crypto from "crypto";
13
+
14
+ const log = logger.child("project-create");
15
+
16
+ export const projectCreateTool: Tool = {
17
+ name: "project_create",
18
+ description: "Create a new project with tasks in the database. Spanish: crear proyecto, nuevo proyecto, iniciar plan",
19
+ parameters: {
20
+ type: "object",
21
+ properties: {
22
+ name: {
23
+ type: "string",
24
+ description: "Nombre descriptivo del proyecto",
25
+ },
26
+ description: {
27
+ type: "string",
28
+ description: "Descripción detallada del objetivo del proyecto",
29
+ },
30
+ type: {
31
+ type: "string",
32
+ enum: ["general", "code", "research", "content", "data"],
33
+ description: "Tipo de proyecto",
34
+ },
35
+ tasks: {
36
+ type: "array",
37
+ description: "Lista de tareas atómicas que componen el proyecto",
38
+ items: {
39
+ type: "object",
40
+ properties: {
41
+ name: { type: "string", description: "Nombre corto de la tarea" },
42
+ description: { type: "string", description: "Qué debe hacer esta tarea" },
43
+ agent_id: { type: "string", description: "ID del agente asignado (opcional)" },
44
+ },
45
+ required: ["name"],
46
+ },
47
+ },
48
+ },
49
+ required: ["name", "type"],
50
+ },
51
+ execute: async (params: Record<string, unknown>, config?: any) => {
52
+ const db = getDb();
53
+ const name = params.name as string;
54
+ const description = (params.description as string) ?? "";
55
+ const type = (params.type as string) ?? "general";
56
+ const tasks = (params.tasks as any[]) ?? [];
57
+ const userId = config?.configurable?.user_id;
58
+ const agentId = config?.configurable?.agent_id;
59
+
60
+ try {
61
+ const projectId = crypto.randomUUID().replace(/-/g, "").slice(0, 16);
62
+
63
+ log.info(`Creating project: ${name}`);
64
+
65
+ db.query(`
66
+ INSERT INTO projects (id, user_id, agent_id, name, description, type, task, status, created_at, updated_at)
67
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'active', unixepoch(), unixepoch())
68
+ `).run(projectId, userId, agentId, name, description, type, description);
69
+
70
+ const taskIds: number[] = [];
71
+ for (const t of tasks) {
72
+ const result = db.query(`
73
+ INSERT INTO tasks (project_id, agent_id, name, description, status, created_at, updated_at)
74
+ VALUES (?, ?, ?, ?, 'pending', unixepoch(), unixepoch())
75
+ `).run(projectId, t.agent_id ?? agentId, t.name, t.description ?? null);
76
+
77
+ taskIds.push(result.lastInsertRowid as number);
78
+ }
79
+
80
+ return {
81
+ ok: true,
82
+ projectId,
83
+ taskIds,
84
+ message: `Project "${name}" created with ${tasks.length} task(s).`,
85
+ };
86
+ } catch (error) {
87
+ log.error(`Failed to create project: ${(error as Error).message}`);
88
+ return {
89
+ ok: false,
90
+ error: `Failed to create project: ${(error as Error).message}`,
91
+ };
92
+ }
93
+ },
94
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * project_done - Mark project as completed
3
+ *
4
+ * @category projects
5
+ * @seedId project_done
6
+ * @spanish proyecto terminado, cerrar proyecto, completado
7
+ */
8
+
9
+ import type { Tool } from "../types.ts";
10
+ import { getDb } from "../../storage/SQLiteStorage.ts";
11
+ import { logger } from "../../utils/logger.ts";
12
+
13
+ const log = logger.child("project-done");
14
+
15
+ export const projectDoneTool: Tool = {
16
+ name: "project_done",
17
+ description: "Mark project as completed and archive it. Spanish: proyecto terminado, cerrar proyecto, completado",
18
+ parameters: {
19
+ type: "object",
20
+ properties: {
21
+ projectId: {
22
+ type: "string",
23
+ description: "ID del proyecto completado",
24
+ },
25
+ summary: {
26
+ type: "string",
27
+ description: "Resumen final de lo logrado",
28
+ },
29
+ },
30
+ required: ["projectId"],
31
+ },
32
+ execute: async (params: Record<string, unknown>) => {
33
+ const db = getDb();
34
+ const projectId = params.projectId as string;
35
+ const summary = (params.summary as string) ?? "Tarea completada exitosamente.";
36
+
37
+ try {
38
+ log.info(`Completing project ${projectId}`);
39
+
40
+ const result = db.query(`
41
+ UPDATE projects
42
+ SET status = 'done', progress = 100, updated_at = unixepoch(), completed_at = unixepoch(), context = ?
43
+ WHERE id = ?
44
+ `).run(summary, projectId);
45
+
46
+ if (result.changes === 0) {
47
+ return {
48
+ ok: false,
49
+ error: `Project not found: ${projectId}`,
50
+ };
51
+ }
52
+
53
+ return {
54
+ ok: true,
55
+ projectId,
56
+ message: "Project marked as completed.",
57
+ };
58
+ } catch (error) {
59
+ log.error(`Failed to complete project: ${(error as Error).message}`);
60
+ return {
61
+ ok: false,
62
+ error: `Failed to complete project: ${(error as Error).message}`,
63
+ };
64
+ }
65
+ },
66
+ };