@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.
- package/.github/CODEOWNERS +9 -0
- package/.github/workflows/publish.yml +89 -0
- package/.github/workflows/version-bump.yml +102 -0
- package/CHANGELOG.md +38 -0
- package/README.md +158 -0
- package/bun.lock +543 -0
- package/bunfig.toml +7 -0
- package/docs/API-AGENTS.md +316 -0
- package/docs/API-CONTEXT-COMPILER.md +252 -0
- package/docs/API-DAG-SCHEDULER.md +273 -0
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +293 -0
- package/docs/API-WORKERS-EVENTS.md +152 -0
- package/docs/INDEX.md +141 -0
- package/docs/README.md +68 -0
- package/package.json +54 -105
- package/packages/cli/package.json +17 -0
- package/packages/cli/src/commands/init.ts +56 -0
- package/packages/cli/src/commands/run.ts +45 -0
- package/packages/cli/src/commands/test.ts +42 -0
- package/packages/cli/src/commands/trace.ts +55 -0
- package/packages/cli/src/index.ts +43 -0
- package/packages/core/package.json +58 -0
- package/packages/core/src/ace/Curator.ts +158 -0
- package/packages/core/src/ace/Reflector.ts +200 -0
- package/packages/core/src/ace/Tracer.ts +100 -0
- package/packages/core/src/ace/index.ts +4 -0
- package/packages/core/src/agent/AgentRunner.ts +699 -0
- package/packages/core/src/agent/Compaction.ts +221 -0
- package/packages/core/src/agent/ContextCompiler.ts +567 -0
- package/packages/core/src/agent/ContextGuard.ts +91 -0
- package/packages/core/src/agent/ConversationStore.ts +244 -0
- package/packages/core/src/agent/Hooks.ts +166 -0
- package/packages/core/src/agent/NativeTools.ts +31 -0
- package/packages/core/src/agent/PromptBuilder.ts +169 -0
- package/packages/core/src/agent/Service.ts +267 -0
- package/packages/core/src/agent/StuckLoop.ts +133 -0
- package/packages/core/src/agent/index.ts +12 -0
- package/packages/core/src/agent/providers/LLMClient.ts +149 -0
- package/packages/core/src/agent/providers/anthropic.ts +212 -0
- package/packages/core/src/agent/providers/gemini.ts +215 -0
- package/packages/core/src/agent/providers/index.ts +199 -0
- package/packages/core/src/agent/providers/interface.ts +195 -0
- package/packages/core/src/agent/providers/ollama.ts +175 -0
- package/packages/core/src/agent/providers/openai-compat.ts +231 -0
- package/packages/core/src/agent/providers.ts +1 -0
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
- package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
- package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
- package/packages/core/src/agent/selectors/index.ts +6 -0
- package/packages/core/src/api/createAgent.test.ts +48 -0
- package/packages/core/src/api/createAgent.ts +122 -0
- package/packages/core/src/api/index.ts +2 -0
- package/packages/core/src/canvas/CanvasManager.ts +390 -0
- package/packages/core/src/canvas/a2ui-tools.ts +255 -0
- package/packages/core/src/canvas/canvas-tools.ts +448 -0
- package/packages/core/src/canvas/emitter.ts +149 -0
- package/packages/core/src/canvas/index.ts +6 -0
- package/packages/core/src/config/index.ts +2 -0
- package/packages/core/src/config/loader.ts +554 -0
- package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
- package/packages/core/src/ethics/EthicsGuard.ts +66 -0
- package/packages/core/src/ethics/index.ts +2 -0
- package/packages/core/src/gateway/channel-notify.test.ts +14 -0
- package/packages/core/src/gateway/channel-notify.ts +12 -0
- package/packages/core/src/gateway/index.ts +1 -0
- package/packages/core/src/index.ts +37 -0
- package/packages/core/src/mcp/MCPClient.ts +439 -0
- package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
- package/packages/core/src/mcp/config.ts +13 -0
- package/packages/core/src/mcp/hot-reload.ts +147 -0
- package/packages/core/src/mcp/index.ts +11 -0
- package/packages/core/src/mcp/logger.ts +42 -0
- package/packages/core/src/mcp/singleton.ts +21 -0
- package/packages/core/src/mcp/transports/index.ts +67 -0
- package/packages/core/src/mcp/transports/sse.ts +241 -0
- package/packages/core/src/mcp/transports/websocket.ts +159 -0
- package/packages/core/src/memory/Scratchpad.test.ts +47 -0
- package/packages/core/src/memory/Scratchpad.ts +37 -0
- package/packages/core/src/memory/Storage.ts +6 -0
- package/packages/core/src/memory/index.ts +2 -0
- package/packages/core/src/multimodal/VisionService.ts +293 -0
- package/packages/core/src/multimodal/index.ts +2 -0
- package/packages/core/src/multimodal/types.ts +28 -0
- package/packages/core/src/security/Pairing.ts +250 -0
- package/packages/core/src/security/RateLimit.ts +270 -0
- package/packages/core/src/security/index.ts +4 -0
- package/packages/core/src/skills/SkillLoader.ts +388 -0
- package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
- package/packages/core/src/skills/defineSkill.ts +18 -0
- package/packages/core/src/skills/index.ts +4 -0
- package/packages/core/src/state/index.ts +2 -0
- package/packages/core/src/state/store.ts +312 -0
- package/packages/core/src/storage/SQLiteStorage.ts +407 -0
- package/packages/core/src/storage/crypto.ts +101 -0
- package/packages/core/src/storage/index.ts +10 -0
- package/packages/core/src/storage/onboarding.ts +1603 -0
- package/packages/core/src/storage/schema.ts +689 -0
- package/packages/core/src/storage/seed.ts +740 -0
- package/packages/core/src/storage/usage.ts +374 -0
- package/packages/core/src/swarm/AgentBus.ts +460 -0
- package/packages/core/src/swarm/AgentExecutor.ts +53 -0
- package/packages/core/src/swarm/Coordinator.ts +251 -0
- package/packages/core/src/swarm/EventBridge.ts +122 -0
- package/packages/core/src/swarm/EventBus.ts +169 -0
- package/packages/core/src/swarm/TaskGraph.ts +192 -0
- package/packages/core/src/swarm/TaskNode.ts +97 -0
- package/packages/core/src/swarm/TaskResult.ts +22 -0
- package/packages/core/src/swarm/WorkerPool.ts +236 -0
- package/packages/core/src/swarm/errors.ts +37 -0
- package/packages/core/src/swarm/index.ts +30 -0
- package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
- package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
- package/packages/core/src/swarm/presets/index.ts +4 -0
- package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
- package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
- package/packages/core/src/swarm/strategies/index.ts +3 -0
- package/packages/core/src/swarm/types.ts +164 -0
- package/packages/core/src/tools/ToolExecutor.ts +58 -0
- package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
- package/packages/core/src/tools/ToolRegistry.ts +61 -0
- package/packages/core/src/tools/agents/get-available-models.ts +118 -0
- package/packages/core/src/tools/agents/index.ts +715 -0
- package/packages/core/src/tools/bridge-events.ts +26 -0
- package/packages/core/src/tools/canvas/index.ts +375 -0
- package/packages/core/src/tools/cli/index.ts +142 -0
- package/packages/core/src/tools/codebridge/index.ts +342 -0
- package/packages/core/src/tools/core/index.ts +476 -0
- package/packages/core/src/tools/cron/index.ts +626 -0
- package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
- package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
- package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
- package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
- package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
- package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
- package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
- package/packages/core/src/tools/filesystem/index.ts +34 -0
- package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
- package/packages/core/src/tools/index.ts +231 -0
- package/packages/core/src/tools/meeting/index.ts +363 -0
- package/packages/core/src/tools/office/index.ts +47 -0
- package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
- package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
- package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
- package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
- package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
- package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
- package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
- package/packages/core/src/tools/projects/index.ts +37 -0
- package/packages/core/src/tools/projects/project-create.ts +94 -0
- package/packages/core/src/tools/projects/project-done.ts +66 -0
- package/packages/core/src/tools/projects/project-fail.ts +66 -0
- package/packages/core/src/tools/projects/project-list.ts +96 -0
- package/packages/core/src/tools/projects/project-update.ts +72 -0
- package/packages/core/src/tools/projects/task-create.ts +68 -0
- package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
- package/packages/core/src/tools/projects/task-update.ts +93 -0
- package/packages/core/src/tools/types.ts +39 -0
- package/packages/core/src/tools/voice/index.ts +104 -0
- package/packages/core/src/tools/web/browser-click.ts +78 -0
- package/packages/core/src/tools/web/browser-extract.ts +139 -0
- package/packages/core/src/tools/web/browser-navigate.ts +106 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
- package/packages/core/src/tools/web/browser-script.ts +88 -0
- package/packages/core/src/tools/web/browser-service.ts +554 -0
- package/packages/core/src/tools/web/browser-type.ts +101 -0
- package/packages/core/src/tools/web/browser-wait.ts +136 -0
- package/packages/core/src/tools/web/index.ts +41 -0
- package/packages/core/src/tools/web/web-fetch.ts +78 -0
- package/packages/core/src/tools/web/web-search.ts +123 -0
- package/packages/core/src/utils/benchmark.ts +80 -0
- package/packages/core/src/utils/crypto.ts +73 -0
- package/packages/core/src/utils/date.ts +42 -0
- package/packages/core/src/utils/index.ts +10 -0
- package/packages/core/src/utils/logger.ts +389 -0
- package/packages/core/src/utils/retry.ts +70 -0
- package/packages/core/src/utils/toon.ts +253 -0
- package/packages/core/src/voice/index.ts +656 -0
- package/test/setup-db.ts +216 -0
- package/tsconfig.json +39 -0
- package/src/agents.ts +0 -1
- package/src/canvas.ts +0 -1
- package/src/channels.ts +0 -1
- package/src/config.ts +0 -1
- package/src/events.ts +0 -1
- package/src/gateway.ts +0 -1
- package/src/index.ts +0 -304
- package/src/mcp.ts +0 -1
- package/src/multimodal.ts +0 -1
- package/src/scheduler.ts +0 -1
- package/src/security.ts +0 -1
- package/src/skills.ts +0 -1
- package/src/state.ts +0 -1
- package/src/storage.ts +0 -1
- package/src/tools.ts +0 -1
- package/src/tts.ts +0 -1
- package/src/types.ts +0 -82
- package/src/utils.ts +0 -1
- package/src/voice.ts +0 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* office_escribir_docx - Generar un archivo Word (.docx)
|
|
3
|
+
*
|
|
4
|
+
* @category office
|
|
5
|
+
* @seedId office_escribir_docx
|
|
6
|
+
* @spanish crear word, generar docx, escribir documento word, exportar a docx
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
|
|
14
|
+
const log = logger.child("office-escribir-docx");
|
|
15
|
+
|
|
16
|
+
interface ParrafoInput {
|
|
17
|
+
texto: string;
|
|
18
|
+
tipo?: "titulo1" | "titulo2" | "titulo3" | "parrafo" | "lista";
|
|
19
|
+
negrita?: boolean;
|
|
20
|
+
cursiva?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface TablaInput {
|
|
24
|
+
filas: Array<{ celdas: string[] }>;
|
|
25
|
+
encabezado?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const officeEscribirDocxTool: Tool = {
|
|
29
|
+
name: "office_escribir_docx",
|
|
30
|
+
description:
|
|
31
|
+
"Generar un archivo Word (.docx) con párrafos, títulos y tablas. Spanish: crear word, generar docx, escribir documento word, exportar a docx",
|
|
32
|
+
parameters: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
ruta: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Ruta donde guardar el archivo .docx generado",
|
|
38
|
+
},
|
|
39
|
+
titulo: {
|
|
40
|
+
type: "string",
|
|
41
|
+
description: "Título del documento (opcional)",
|
|
42
|
+
},
|
|
43
|
+
parrafos: {
|
|
44
|
+
type: "array",
|
|
45
|
+
description:
|
|
46
|
+
"Array de párrafos a incluir. Cada párrafo tiene: texto (string), tipo ('titulo1'|'titulo2'|'titulo3'|'parrafo'|'lista'), negrita (bool), cursiva (bool)",
|
|
47
|
+
items: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
texto: { type: "string" },
|
|
51
|
+
tipo: { type: "string" },
|
|
52
|
+
negrita: { type: "boolean" },
|
|
53
|
+
cursiva: { type: "boolean" },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
tablas: {
|
|
58
|
+
type: "array",
|
|
59
|
+
description:
|
|
60
|
+
"Array de tablas a incluir. Cada tabla tiene: filas (array de {celdas: string[]}), encabezado (bool, primera fila como encabezado)",
|
|
61
|
+
items: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
filas: { type: "array", items: { type: "object" } },
|
|
65
|
+
encabezado: { type: "boolean" },
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
required: ["ruta"],
|
|
71
|
+
},
|
|
72
|
+
execute: async (params: Record<string, unknown>) => {
|
|
73
|
+
const ruta = params.ruta as string;
|
|
74
|
+
const titulo = params.titulo as string | undefined;
|
|
75
|
+
const parrafosInput = (params.parrafos as ParrafoInput[]) ?? [];
|
|
76
|
+
const tablasInput = (params.tablas as TablaInput[]) ?? [];
|
|
77
|
+
|
|
78
|
+
log.debug(`Generando DOCX: ${ruta}`);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const {
|
|
82
|
+
Document,
|
|
83
|
+
Packer,
|
|
84
|
+
Paragraph,
|
|
85
|
+
TextRun,
|
|
86
|
+
HeadingLevel,
|
|
87
|
+
Table,
|
|
88
|
+
TableRow,
|
|
89
|
+
TableCell,
|
|
90
|
+
WidthType,
|
|
91
|
+
BorderStyle,
|
|
92
|
+
} = await import("docx");
|
|
93
|
+
|
|
94
|
+
const seccionChildren: any[] = [];
|
|
95
|
+
|
|
96
|
+
// Título del documento
|
|
97
|
+
if (titulo) {
|
|
98
|
+
seccionChildren.push(
|
|
99
|
+
new Paragraph({
|
|
100
|
+
text: titulo,
|
|
101
|
+
heading: HeadingLevel.TITLE,
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Párrafos
|
|
107
|
+
for (const p of parrafosInput) {
|
|
108
|
+
const run = new TextRun({
|
|
109
|
+
text: p.texto,
|
|
110
|
+
bold: p.negrita ?? false,
|
|
111
|
+
italics: p.cursiva ?? false,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
let heading: any = undefined;
|
|
115
|
+
if (p.tipo === "titulo1") heading = HeadingLevel.HEADING_1;
|
|
116
|
+
else if (p.tipo === "titulo2") heading = HeadingLevel.HEADING_2;
|
|
117
|
+
else if (p.tipo === "titulo3") heading = HeadingLevel.HEADING_3;
|
|
118
|
+
|
|
119
|
+
const opciones: any = { children: [run] };
|
|
120
|
+
if (heading) opciones.heading = heading;
|
|
121
|
+
if (p.tipo === "lista") opciones.bullet = { level: 0 };
|
|
122
|
+
|
|
123
|
+
seccionChildren.push(new Paragraph(opciones));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Tablas
|
|
127
|
+
for (const tablaInput of tablasInput) {
|
|
128
|
+
const filas = tablaInput.filas.map((fila, filaIdx) => {
|
|
129
|
+
const celdas = fila.celdas.map((textoCelda) => {
|
|
130
|
+
const esEncabezado = tablaInput.encabezado && filaIdx === 0;
|
|
131
|
+
return new TableCell({
|
|
132
|
+
children: [
|
|
133
|
+
new Paragraph({
|
|
134
|
+
children: [
|
|
135
|
+
new TextRun({
|
|
136
|
+
text: textoCelda,
|
|
137
|
+
bold: esEncabezado,
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
}),
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
return new TableRow({ children: celdas });
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
seccionChildren.push(
|
|
148
|
+
new Table({
|
|
149
|
+
rows: filas,
|
|
150
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
// Línea en blanco después de la tabla
|
|
155
|
+
seccionChildren.push(new Paragraph({ text: "" }));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const doc = new Document({
|
|
159
|
+
sections: [
|
|
160
|
+
{
|
|
161
|
+
children: seccionChildren,
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const rutaAbsoluta = path.resolve(ruta);
|
|
167
|
+
const dirDestino = path.dirname(rutaAbsoluta);
|
|
168
|
+
if (!fs.existsSync(dirDestino)) {
|
|
169
|
+
fs.mkdirSync(dirDestino, { recursive: true });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const buffer = await Packer.toBuffer(doc);
|
|
173
|
+
fs.writeFileSync(rutaAbsoluta, buffer);
|
|
174
|
+
|
|
175
|
+
log.info(`DOCX generado: ${rutaAbsoluta} (${buffer.length} bytes)`);
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
ok: true,
|
|
179
|
+
ruta: rutaAbsoluta,
|
|
180
|
+
bytesEscritos: buffer.length,
|
|
181
|
+
parrafos: parrafosInput.length,
|
|
182
|
+
tablas: tablasInput.length,
|
|
183
|
+
};
|
|
184
|
+
} catch (error) {
|
|
185
|
+
log.error(`Error generando DOCX: ${(error as Error).message}`);
|
|
186
|
+
return {
|
|
187
|
+
ok: false,
|
|
188
|
+
error: `No se pudo generar el archivo DOCX: ${(error as Error).message}`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* office_escribir_pdf - Generar un archivo PDF desde texto
|
|
3
|
+
*
|
|
4
|
+
* @category office
|
|
5
|
+
* @seedId office_escribir_pdf
|
|
6
|
+
* @spanish crear pdf, generar pdf, escribir pdf, exportar a pdf
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
|
|
14
|
+
const log = logger.child("office-escribir-pdf");
|
|
15
|
+
|
|
16
|
+
export const officeEscribirPdfTool: Tool = {
|
|
17
|
+
name: "office_escribir_pdf",
|
|
18
|
+
description:
|
|
19
|
+
"Generar un archivo PDF desde texto con configuración de márgenes y tamaño de página. Spanish: crear pdf, generar pdf, escribir pdf, exportar a pdf",
|
|
20
|
+
parameters: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
ruta: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Ruta donde guardar el archivo PDF generado",
|
|
26
|
+
},
|
|
27
|
+
contenido: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Texto o contenido a escribir en el PDF",
|
|
30
|
+
},
|
|
31
|
+
titulo: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Título del documento (opcional)",
|
|
34
|
+
},
|
|
35
|
+
tamaño_pagina: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Tamaño de página: 'A4' o 'Letter' (default: 'A4')",
|
|
38
|
+
enum: ["A4", "Letter"],
|
|
39
|
+
},
|
|
40
|
+
margen: {
|
|
41
|
+
type: "number",
|
|
42
|
+
description: "Margen en puntos (default: 50)",
|
|
43
|
+
},
|
|
44
|
+
tamaño_fuente: {
|
|
45
|
+
type: "number",
|
|
46
|
+
description: "Tamaño de fuente en puntos (default: 12)",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
required: ["ruta", "contenido"],
|
|
50
|
+
},
|
|
51
|
+
execute: async (params: Record<string, unknown>) => {
|
|
52
|
+
const ruta = params.ruta as string;
|
|
53
|
+
const contenido = params.contenido as string;
|
|
54
|
+
const titulo = params.titulo as string | undefined;
|
|
55
|
+
const tamañoPagina = (params.tamaño_pagina as string) ?? "A4";
|
|
56
|
+
const margen = (params.margen as number) ?? 50;
|
|
57
|
+
const tamañoFuente = (params.tamaño_fuente as number) ?? 12;
|
|
58
|
+
|
|
59
|
+
log.debug(`Generando PDF: ${ruta}`);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const { PDFDocument, StandardFonts, rgb, PageSizes } = await import("pdf-lib");
|
|
63
|
+
|
|
64
|
+
const pdfDoc = await PDFDocument.create();
|
|
65
|
+
|
|
66
|
+
if (titulo) {
|
|
67
|
+
pdfDoc.setTitle(titulo);
|
|
68
|
+
}
|
|
69
|
+
pdfDoc.setCreator("Hive Agent");
|
|
70
|
+
pdfDoc.setCreationDate(new Date());
|
|
71
|
+
|
|
72
|
+
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
|
|
73
|
+
const pageSize = tamañoPagina === "Letter" ? PageSizes.Letter : PageSizes.A4;
|
|
74
|
+
|
|
75
|
+
const anchoPagina = pageSize[0];
|
|
76
|
+
const altoPagina = pageSize[1];
|
|
77
|
+
const anchoUtil = anchoPagina - margen * 2;
|
|
78
|
+
const lineHeight = tamañoFuente * 1.4;
|
|
79
|
+
|
|
80
|
+
// Si hay título, agregarlo primero
|
|
81
|
+
const lineasTodas: string[] = [];
|
|
82
|
+
if (titulo) {
|
|
83
|
+
lineasTodas.push(titulo);
|
|
84
|
+
lineasTodas.push(""); // línea en blanco
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Dividir el contenido en líneas respetando saltos de línea
|
|
88
|
+
const lineasContenido = contenido.split("\n");
|
|
89
|
+
|
|
90
|
+
// Para cada línea, dividir en sublíneas si es demasiado larga
|
|
91
|
+
for (const linea of lineasContenido) {
|
|
92
|
+
if (linea.trim() === "") {
|
|
93
|
+
lineasTodas.push("");
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const palabras = linea.split(" ");
|
|
98
|
+
let lineaActual = "";
|
|
99
|
+
|
|
100
|
+
for (const palabra of palabras) {
|
|
101
|
+
const prueba = lineaActual ? `${lineaActual} ${palabra}` : palabra;
|
|
102
|
+
const ancho = font.widthOfTextAtSize(prueba, tamañoFuente);
|
|
103
|
+
|
|
104
|
+
if (ancho > anchoUtil && lineaActual) {
|
|
105
|
+
lineasTodas.push(lineaActual);
|
|
106
|
+
lineaActual = palabra;
|
|
107
|
+
} else {
|
|
108
|
+
lineaActual = prueba;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (lineaActual) {
|
|
113
|
+
lineasTodas.push(lineaActual);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Distribuir líneas en páginas
|
|
118
|
+
const lineasPorPagina = Math.floor((altoPagina - margen * 2) / lineHeight);
|
|
119
|
+
let paginaActual = pdfDoc.addPage(pageSize);
|
|
120
|
+
let yActual = altoPagina - margen;
|
|
121
|
+
let lineasEnPagina = 0;
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < lineasTodas.length; i++) {
|
|
124
|
+
if (lineasEnPagina >= lineasPorPagina) {
|
|
125
|
+
paginaActual = pdfDoc.addPage(pageSize);
|
|
126
|
+
yActual = altoPagina - margen;
|
|
127
|
+
lineasEnPagina = 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const esEncabezado = titulo && i === 0;
|
|
131
|
+
const fuenteActual = esEncabezado ? tamañoFuente + 4 : tamañoFuente;
|
|
132
|
+
|
|
133
|
+
if (lineasTodas[i] !== "") {
|
|
134
|
+
paginaActual.drawText(lineasTodas[i], {
|
|
135
|
+
x: margen,
|
|
136
|
+
y: yActual,
|
|
137
|
+
size: fuenteActual,
|
|
138
|
+
font,
|
|
139
|
+
color: rgb(0, 0, 0),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
yActual -= lineHeight;
|
|
144
|
+
lineasEnPagina++;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const rutaAbsoluta = path.resolve(ruta);
|
|
148
|
+
const dirDestino = path.dirname(rutaAbsoluta);
|
|
149
|
+
if (!fs.existsSync(dirDestino)) {
|
|
150
|
+
fs.mkdirSync(dirDestino, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const pdfBytes = await pdfDoc.save();
|
|
154
|
+
fs.writeFileSync(rutaAbsoluta, pdfBytes);
|
|
155
|
+
|
|
156
|
+
log.info(`PDF generado: ${rutaAbsoluta} (${pdfDoc.getPageCount()} páginas)`);
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
ruta: rutaAbsoluta,
|
|
161
|
+
paginas: pdfDoc.getPageCount(),
|
|
162
|
+
bytesEscritos: pdfBytes.length,
|
|
163
|
+
};
|
|
164
|
+
} catch (error) {
|
|
165
|
+
log.error(`Error generando PDF: ${(error as Error).message}`);
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
error: `No se pudo generar el PDF: ${(error as Error).message}`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* office_escribir_pptx - Generar un archivo PowerPoint (.pptx)
|
|
3
|
+
*
|
|
4
|
+
* @category office
|
|
5
|
+
* @seedId office_escribir_pptx
|
|
6
|
+
* @spanish crear powerpoint, generar pptx, escribir presentacion, exportar a pptx
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
|
|
14
|
+
const log = logger.child("office-escribir-pptx");
|
|
15
|
+
|
|
16
|
+
interface DiapositivaInput {
|
|
17
|
+
titulo?: string;
|
|
18
|
+
contenido?: string;
|
|
19
|
+
puntos?: string[];
|
|
20
|
+
notas?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const officeEscribirPptxTool: Tool = {
|
|
24
|
+
name: "office_escribir_pptx",
|
|
25
|
+
description:
|
|
26
|
+
"Generar un archivo PowerPoint (.pptx) desde un array de diapositivas con título y contenido. Spanish: crear powerpoint, generar pptx, escribir presentacion, exportar a pptx",
|
|
27
|
+
parameters: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
ruta: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Ruta donde guardar el archivo .pptx generado",
|
|
33
|
+
},
|
|
34
|
+
titulo_presentacion: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Título de la presentación (aparece en la primera diapositiva)",
|
|
37
|
+
},
|
|
38
|
+
diapositivas: {
|
|
39
|
+
type: "array",
|
|
40
|
+
description:
|
|
41
|
+
"Array de diapositivas. Cada una tiene: titulo (string), contenido (string, texto libre), puntos (string[], lista de viñetas), notas (string, notas del presentador)",
|
|
42
|
+
items: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
titulo: { type: "string" },
|
|
46
|
+
contenido: { type: "string" },
|
|
47
|
+
puntos: { type: "array", items: { type: "string" } },
|
|
48
|
+
notas: { type: "string" },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ["ruta", "diapositivas"],
|
|
54
|
+
},
|
|
55
|
+
execute: async (params: Record<string, unknown>) => {
|
|
56
|
+
const ruta = params.ruta as string;
|
|
57
|
+
const tituloPresentacion = params.titulo_presentacion as string | undefined;
|
|
58
|
+
const diapositivasInput = params.diapositivas as DiapositivaInput[];
|
|
59
|
+
|
|
60
|
+
log.debug(`Generando PPTX: ${ruta}`);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const pptxgen = (await import("pptxgenjs")).default;
|
|
64
|
+
const pres = new pptxgen();
|
|
65
|
+
|
|
66
|
+
// Configuración básica
|
|
67
|
+
pres.layout = "LAYOUT_16x9";
|
|
68
|
+
|
|
69
|
+
// Diapositiva de título (si se proporciona título de presentación)
|
|
70
|
+
if (tituloPresentacion) {
|
|
71
|
+
const slidePortada = pres.addSlide();
|
|
72
|
+
slidePortada.addText(tituloPresentacion, {
|
|
73
|
+
x: "10%",
|
|
74
|
+
y: "35%",
|
|
75
|
+
w: "80%",
|
|
76
|
+
h: "30%",
|
|
77
|
+
fontSize: 36,
|
|
78
|
+
bold: true,
|
|
79
|
+
align: "center",
|
|
80
|
+
color: "363636",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Diapositivas de contenido
|
|
85
|
+
for (const diapoInput of diapositivasInput) {
|
|
86
|
+
const slide = pres.addSlide();
|
|
87
|
+
|
|
88
|
+
// Título de la diapositiva
|
|
89
|
+
if (diapoInput.titulo) {
|
|
90
|
+
slide.addText(diapoInput.titulo, {
|
|
91
|
+
x: "5%",
|
|
92
|
+
y: "5%",
|
|
93
|
+
w: "90%",
|
|
94
|
+
h: "15%",
|
|
95
|
+
fontSize: 24,
|
|
96
|
+
bold: true,
|
|
97
|
+
color: "363636",
|
|
98
|
+
valign: "middle",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const yContenido = diapoInput.titulo ? "22%" : "10%";
|
|
103
|
+
const hContenido = diapoInput.titulo ? "70%" : "82%";
|
|
104
|
+
|
|
105
|
+
// Puntos de viñeta (tienen prioridad sobre contenido libre)
|
|
106
|
+
if (diapoInput.puntos && diapoInput.puntos.length > 0) {
|
|
107
|
+
const textoPuntos = diapoInput.puntos.map((punto) => ({
|
|
108
|
+
text: punto,
|
|
109
|
+
options: {
|
|
110
|
+
bullet: true,
|
|
111
|
+
fontSize: 18,
|
|
112
|
+
color: "595959",
|
|
113
|
+
breakLine: true,
|
|
114
|
+
} as any,
|
|
115
|
+
}));
|
|
116
|
+
|
|
117
|
+
slide.addText(textoPuntos, {
|
|
118
|
+
x: "5%",
|
|
119
|
+
y: yContenido,
|
|
120
|
+
w: "90%",
|
|
121
|
+
h: hContenido,
|
|
122
|
+
valign: "top",
|
|
123
|
+
});
|
|
124
|
+
} else if (diapoInput.contenido) {
|
|
125
|
+
// Texto libre
|
|
126
|
+
slide.addText(diapoInput.contenido, {
|
|
127
|
+
x: "5%",
|
|
128
|
+
y: yContenido,
|
|
129
|
+
w: "90%",
|
|
130
|
+
h: hContenido,
|
|
131
|
+
fontSize: 16,
|
|
132
|
+
color: "595959",
|
|
133
|
+
valign: "top",
|
|
134
|
+
wrap: true,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Notas del presentador
|
|
139
|
+
if (diapoInput.notas) {
|
|
140
|
+
slide.addNotes(diapoInput.notas);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const rutaAbsoluta = path.resolve(ruta);
|
|
145
|
+
const dirDestino = path.dirname(rutaAbsoluta);
|
|
146
|
+
if (!fs.existsSync(dirDestino)) {
|
|
147
|
+
fs.mkdirSync(dirDestino, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Escribir el archivo
|
|
151
|
+
await pres.writeFile({ fileName: rutaAbsoluta });
|
|
152
|
+
|
|
153
|
+
const stats = fs.statSync(rutaAbsoluta);
|
|
154
|
+
|
|
155
|
+
log.info(
|
|
156
|
+
`PPTX generado: ${rutaAbsoluta} (${diapositivasInput.length} diapositivas)`
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
ok: true,
|
|
161
|
+
ruta: rutaAbsoluta,
|
|
162
|
+
totalDiapositivas:
|
|
163
|
+
diapositivasInput.length + (tituloPresentacion ? 1 : 0),
|
|
164
|
+
bytesEscritos: stats.size,
|
|
165
|
+
};
|
|
166
|
+
} catch (error) {
|
|
167
|
+
log.error(`Error generando PPTX: ${(error as Error).message}`);
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
error: `No se pudo generar el archivo PowerPoint: ${(error as Error).message}`,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* office_escribir_xlsx - Generar un archivo Excel (.xlsx)
|
|
3
|
+
*
|
|
4
|
+
* @category office
|
|
5
|
+
* @seedId office_escribir_xlsx
|
|
6
|
+
* @spanish crear excel, generar xlsx, escribir excel, exportar a xlsx
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Tool } from "../types.ts";
|
|
10
|
+
import { logger } from "../../utils/logger.ts";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
|
|
14
|
+
const log = logger.child("office-escribir-xlsx");
|
|
15
|
+
|
|
16
|
+
interface HojaInput {
|
|
17
|
+
nombre: string;
|
|
18
|
+
datos: Record<string, any>[] | any[][];
|
|
19
|
+
encabezados?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const officeEscribirXlsxTool: Tool = {
|
|
23
|
+
name: "office_escribir_xlsx",
|
|
24
|
+
description:
|
|
25
|
+
"Generar un archivo Excel (.xlsx) desde un objeto JSON con hojas, filas y columnas. Spanish: crear excel, generar xlsx, escribir excel, exportar a xlsx",
|
|
26
|
+
parameters: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
ruta: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Ruta donde guardar el archivo .xlsx generado",
|
|
32
|
+
},
|
|
33
|
+
hojas: {
|
|
34
|
+
type: "array",
|
|
35
|
+
description:
|
|
36
|
+
"Array de hojas a crear. Cada hoja tiene: nombre (string), datos (array de objetos o array de arrays), encabezados (string[], opcional para forzar orden de columnas)",
|
|
37
|
+
items: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
nombre: { type: "string" },
|
|
41
|
+
datos: { type: "array" },
|
|
42
|
+
encabezados: { type: "array", items: { type: "string" } },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ["ruta", "hojas"],
|
|
48
|
+
},
|
|
49
|
+
execute: async (params: Record<string, unknown>) => {
|
|
50
|
+
const ruta = params.ruta as string;
|
|
51
|
+
const hojasInput = params.hojas as HojaInput[];
|
|
52
|
+
|
|
53
|
+
log.debug(`Generando XLSX: ${ruta}`);
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const XLSX = await import("xlsx");
|
|
57
|
+
|
|
58
|
+
const workbook = XLSX.utils.book_new();
|
|
59
|
+
|
|
60
|
+
for (const hojaInput of hojasInput) {
|
|
61
|
+
let worksheet: any;
|
|
62
|
+
|
|
63
|
+
if (
|
|
64
|
+
hojasInput.length > 0 &&
|
|
65
|
+
Array.isArray(hojaInput.datos) &&
|
|
66
|
+
hojaInput.datos.length > 0 &&
|
|
67
|
+
Array.isArray(hojaInput.datos[0])
|
|
68
|
+
) {
|
|
69
|
+
// Si los datos son array de arrays
|
|
70
|
+
worksheet = XLSX.utils.aoa_to_sheet(hojaInput.datos as any[][]);
|
|
71
|
+
} else {
|
|
72
|
+
// Si los datos son array de objetos
|
|
73
|
+
worksheet = XLSX.utils.json_to_sheet(
|
|
74
|
+
hojaInput.datos as Record<string, any>[],
|
|
75
|
+
hojaInput.encabezados ? { header: hojaInput.encabezados } : undefined
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, hojaInput.nombre);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const rutaAbsoluta = path.resolve(ruta);
|
|
83
|
+
const dirDestino = path.dirname(rutaAbsoluta);
|
|
84
|
+
if (!fs.existsSync(dirDestino)) {
|
|
85
|
+
fs.mkdirSync(dirDestino, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const buffer = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" });
|
|
89
|
+
fs.writeFileSync(rutaAbsoluta, buffer);
|
|
90
|
+
|
|
91
|
+
const totalFilas = hojasInput.reduce(
|
|
92
|
+
(acc, h) => acc + h.datos.length,
|
|
93
|
+
0
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
log.info(
|
|
97
|
+
`XLSX generado: ${rutaAbsoluta} (${hojasInput.length} hojas, ${totalFilas} filas)`
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
ok: true,
|
|
102
|
+
ruta: rutaAbsoluta,
|
|
103
|
+
hojas: hojasInput.map((h) => h.nombre),
|
|
104
|
+
totalHojas: hojasInput.length,
|
|
105
|
+
totalFilas,
|
|
106
|
+
bytesEscritos: buffer.length,
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
log.error(`Error generando XLSX: ${(error as Error).message}`);
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
error: `No se pudo generar el archivo Excel: ${(error as Error).message}`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|