@johpaz/hive 1.1.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 (156) hide show
  1. package/CONTRIBUTING.md +44 -0
  2. package/README.md +310 -0
  3. package/package.json +96 -0
  4. package/packages/cli/package.json +28 -0
  5. package/packages/cli/src/commands/agent-run.ts +168 -0
  6. package/packages/cli/src/commands/agents.ts +398 -0
  7. package/packages/cli/src/commands/chat.ts +142 -0
  8. package/packages/cli/src/commands/config.ts +50 -0
  9. package/packages/cli/src/commands/cron.ts +161 -0
  10. package/packages/cli/src/commands/dev.ts +95 -0
  11. package/packages/cli/src/commands/doctor.ts +133 -0
  12. package/packages/cli/src/commands/gateway.ts +443 -0
  13. package/packages/cli/src/commands/logs.ts +57 -0
  14. package/packages/cli/src/commands/mcp.ts +175 -0
  15. package/packages/cli/src/commands/message.ts +77 -0
  16. package/packages/cli/src/commands/onboard.ts +1868 -0
  17. package/packages/cli/src/commands/security.ts +144 -0
  18. package/packages/cli/src/commands/service.ts +50 -0
  19. package/packages/cli/src/commands/sessions.ts +116 -0
  20. package/packages/cli/src/commands/skills.ts +187 -0
  21. package/packages/cli/src/commands/update.ts +25 -0
  22. package/packages/cli/src/index.ts +185 -0
  23. package/packages/cli/src/utils/token.ts +6 -0
  24. package/packages/code-bridge/README.md +78 -0
  25. package/packages/code-bridge/package.json +18 -0
  26. package/packages/code-bridge/src/index.ts +95 -0
  27. package/packages/code-bridge/src/process-manager.ts +212 -0
  28. package/packages/code-bridge/src/schemas.ts +133 -0
  29. package/packages/core/package.json +46 -0
  30. package/packages/core/src/agent/agent-loop.ts +369 -0
  31. package/packages/core/src/agent/compaction.ts +140 -0
  32. package/packages/core/src/agent/context-compiler.ts +378 -0
  33. package/packages/core/src/agent/context-guard.ts +91 -0
  34. package/packages/core/src/agent/context.ts +138 -0
  35. package/packages/core/src/agent/conversation-store.ts +198 -0
  36. package/packages/core/src/agent/curator.ts +158 -0
  37. package/packages/core/src/agent/hooks.ts +166 -0
  38. package/packages/core/src/agent/index.ts +116 -0
  39. package/packages/core/src/agent/llm-client.ts +503 -0
  40. package/packages/core/src/agent/native-tools.ts +505 -0
  41. package/packages/core/src/agent/prompt-builder.ts +532 -0
  42. package/packages/core/src/agent/providers/index.ts +167 -0
  43. package/packages/core/src/agent/providers.ts +1 -0
  44. package/packages/core/src/agent/reflector.ts +170 -0
  45. package/packages/core/src/agent/service.ts +64 -0
  46. package/packages/core/src/agent/stuck-loop.ts +133 -0
  47. package/packages/core/src/agent/supervisor.ts +39 -0
  48. package/packages/core/src/agent/tracer.ts +102 -0
  49. package/packages/core/src/agent/workspace.ts +110 -0
  50. package/packages/core/src/canvas/canvas-manager.test.ts +161 -0
  51. package/packages/core/src/canvas/canvas-manager.ts +319 -0
  52. package/packages/core/src/canvas/canvas-tools.ts +420 -0
  53. package/packages/core/src/canvas/emitter.ts +115 -0
  54. package/packages/core/src/canvas/index.ts +2 -0
  55. package/packages/core/src/channels/base.ts +138 -0
  56. package/packages/core/src/channels/discord.ts +260 -0
  57. package/packages/core/src/channels/index.ts +7 -0
  58. package/packages/core/src/channels/manager.ts +383 -0
  59. package/packages/core/src/channels/slack.ts +287 -0
  60. package/packages/core/src/channels/telegram.ts +502 -0
  61. package/packages/core/src/channels/webchat.ts +128 -0
  62. package/packages/core/src/channels/whatsapp.ts +375 -0
  63. package/packages/core/src/config/index.ts +12 -0
  64. package/packages/core/src/config/loader.ts +529 -0
  65. package/packages/core/src/events/event-bus.ts +169 -0
  66. package/packages/core/src/gateway/index.ts +5 -0
  67. package/packages/core/src/gateway/initializer.ts +290 -0
  68. package/packages/core/src/gateway/lane-queue.ts +169 -0
  69. package/packages/core/src/gateway/resolver.ts +108 -0
  70. package/packages/core/src/gateway/router.ts +124 -0
  71. package/packages/core/src/gateway/server.ts +3317 -0
  72. package/packages/core/src/gateway/session.ts +95 -0
  73. package/packages/core/src/gateway/slash-commands.ts +192 -0
  74. package/packages/core/src/heartbeat/index.ts +157 -0
  75. package/packages/core/src/index.ts +19 -0
  76. package/packages/core/src/integrations/catalog.ts +286 -0
  77. package/packages/core/src/integrations/env.ts +64 -0
  78. package/packages/core/src/integrations/index.ts +2 -0
  79. package/packages/core/src/memory/index.ts +1 -0
  80. package/packages/core/src/memory/notes.ts +68 -0
  81. package/packages/core/src/plugins/api.ts +128 -0
  82. package/packages/core/src/plugins/index.ts +2 -0
  83. package/packages/core/src/plugins/loader.ts +365 -0
  84. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  85. package/packages/core/src/security/google-chat.ts +269 -0
  86. package/packages/core/src/security/index.ts +192 -0
  87. package/packages/core/src/security/pairing.ts +250 -0
  88. package/packages/core/src/security/rate-limit.ts +270 -0
  89. package/packages/core/src/security/signal.ts +321 -0
  90. package/packages/core/src/state/store.ts +312 -0
  91. package/packages/core/src/storage/bun-sqlite-store.ts +188 -0
  92. package/packages/core/src/storage/crypto.ts +101 -0
  93. package/packages/core/src/storage/db-context.ts +333 -0
  94. package/packages/core/src/storage/onboarding.ts +1087 -0
  95. package/packages/core/src/storage/schema.ts +541 -0
  96. package/packages/core/src/storage/seed.ts +571 -0
  97. package/packages/core/src/storage/sqlite.ts +387 -0
  98. package/packages/core/src/storage/usage.ts +212 -0
  99. package/packages/core/src/tools/bridge-events.ts +74 -0
  100. package/packages/core/src/tools/browser.ts +275 -0
  101. package/packages/core/src/tools/codebridge.ts +421 -0
  102. package/packages/core/src/tools/coordinator-tools.ts +179 -0
  103. package/packages/core/src/tools/cron.ts +611 -0
  104. package/packages/core/src/tools/exec.ts +140 -0
  105. package/packages/core/src/tools/fs.ts +364 -0
  106. package/packages/core/src/tools/index.ts +12 -0
  107. package/packages/core/src/tools/memory.ts +176 -0
  108. package/packages/core/src/tools/notify.ts +113 -0
  109. package/packages/core/src/tools/project-management.ts +376 -0
  110. package/packages/core/src/tools/project.ts +375 -0
  111. package/packages/core/src/tools/read.ts +158 -0
  112. package/packages/core/src/tools/web.ts +436 -0
  113. package/packages/core/src/tools/workspace.ts +171 -0
  114. package/packages/core/src/utils/benchmark.ts +80 -0
  115. package/packages/core/src/utils/crypto.ts +73 -0
  116. package/packages/core/src/utils/date.ts +42 -0
  117. package/packages/core/src/utils/index.ts +4 -0
  118. package/packages/core/src/utils/logger.ts +388 -0
  119. package/packages/core/src/utils/retry.ts +70 -0
  120. package/packages/core/src/voice/index.ts +583 -0
  121. package/packages/core/tsconfig.json +9 -0
  122. package/packages/mcp/package.json +26 -0
  123. package/packages/mcp/src/config.ts +13 -0
  124. package/packages/mcp/src/index.ts +1 -0
  125. package/packages/mcp/src/logger.ts +42 -0
  126. package/packages/mcp/src/manager.ts +434 -0
  127. package/packages/mcp/src/transports/index.ts +67 -0
  128. package/packages/mcp/src/transports/sse.ts +241 -0
  129. package/packages/mcp/src/transports/websocket.ts +159 -0
  130. package/packages/skills/package.json +21 -0
  131. package/packages/skills/src/bundled/agent_management/SKILL.md +24 -0
  132. package/packages/skills/src/bundled/browser_automation/SKILL.md +30 -0
  133. package/packages/skills/src/bundled/context_compact/SKILL.md +35 -0
  134. package/packages/skills/src/bundled/cron_manager/SKILL.md +52 -0
  135. package/packages/skills/src/bundled/file_manager/SKILL.md +76 -0
  136. package/packages/skills/src/bundled/http_client/SKILL.md +24 -0
  137. package/packages/skills/src/bundled/memory/SKILL.md +42 -0
  138. package/packages/skills/src/bundled/project_management/SKILL.md +26 -0
  139. package/packages/skills/src/bundled/shell/SKILL.md +43 -0
  140. package/packages/skills/src/bundled/system_notify/SKILL.md +52 -0
  141. package/packages/skills/src/bundled/voice/SKILL.md +25 -0
  142. package/packages/skills/src/bundled/web_search/SKILL.md +29 -0
  143. package/packages/skills/src/index.ts +1 -0
  144. package/packages/skills/src/loader.ts +282 -0
  145. package/packages/tools/package.json +43 -0
  146. package/packages/tools/src/browser/browser.test.ts +111 -0
  147. package/packages/tools/src/browser/index.ts +272 -0
  148. package/packages/tools/src/canvas/index.ts +220 -0
  149. package/packages/tools/src/cron/cron.test.ts +164 -0
  150. package/packages/tools/src/cron/index.ts +304 -0
  151. package/packages/tools/src/filesystem/filesystem.test.ts +240 -0
  152. package/packages/tools/src/filesystem/index.ts +379 -0
  153. package/packages/tools/src/git/index.ts +239 -0
  154. package/packages/tools/src/index.ts +4 -0
  155. package/packages/tools/src/shell/detect-env.ts +70 -0
  156. package/packages/tools/tsconfig.json +9 -0
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: memory
3
+ description: "Store and retrieve persistent information in long-term memory"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "🧠"
7
+ category: system
8
+ permissions:
9
+ - memory_read
10
+ - memory_write
11
+ dependencies: []
12
+ tools: [memory, memory_write, memory_read, memory_list, memory_search, memory_delete]
13
+ ---
14
+
15
+ # Memory Skill
16
+
17
+ Esta skill permite al agente mantener una memoria persistente a largo plazo, permitiendo recordar datos entre diferentes sesiones y conversaciones.
18
+
19
+ ## Herramientas Disponibles
20
+
21
+ - `memory_write`: Almacena información importante (hechos, preferencias, contexto).
22
+ - `memory_read`: Recupera una entrada de memoria por su título.
23
+ - `memory_list`: Lista todos los títulos de las entradas guardadas.
24
+ - `memory_search`: Busca en el contenido de la memoria usando una consulta de texto.
25
+ - `memory_delete`: Elimina una entrada de memoria específica.
26
+
27
+ ## Ejemplos de Uso
28
+
29
+ ### Guardar una preferencia del usuario
30
+ ```javascript
31
+ memory_write({ title: "Tecnologías", content: "El usuario prefiere TypeScript y Bun" })
32
+ ```
33
+
34
+ ### Buscar información relevante
35
+ ```javascript
36
+ memory_search({ query: "Preferencias de desarrollo" })
37
+ ```
38
+
39
+ ## Mejores Prácticas
40
+ - **Títulos Descriptivos**: Usa títulos únicos y claros para facilitar la recuperación directa.
41
+ - **Actualización**: Si la información cambia, sobrescribe la entrada con el mismo título.
42
+ - **Privacidad**: Evita guardar información sensible o contraseñas en la memoria persistente.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: project_management
3
+ description: "Track and manage multi-step project tasks and progress"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "📊"
7
+ category: projects
8
+ permissions: []
9
+ dependencies: []
10
+ tools: [project_start, project_update, project_done, project_fail]
11
+ ---
12
+
13
+ # Project Management Skill
14
+
15
+ Esta skill permite al agente realizar un seguimiento detallado de tareas complejas que requieren múltiples pasos, informando sobre el progreso y el estado final.
16
+
17
+ ## Herramientas Disponibles
18
+
19
+ - `project_start`: Inicia el seguimiento de una tarea multi-paso.
20
+ - `project_update`: Actualiza el progreso de una tarea en curso.
21
+ - `project_done`: Marca una tarea como completada exitosamente.
22
+ - `project_fail`: Marca una tarea como fallida por error irrecuperable.
23
+
24
+ ## Mejores Prácticas
25
+ - **Actualizaciones Frecuentes**: Informa sobre hitos importantes durante la ejecución de tareas largas.
26
+ - **Claridad en Errores**: Si una tarea falla, proporciona un motivo claro y detallado en `project_fail`.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: shell
3
+ description: "Execute shell commands safely with allowlist control"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "💻"
7
+ category: system
8
+ permissions:
9
+ - shell_exec
10
+ dependencies: []
11
+ tools: [shell, exec, terminal]
12
+ requirements:
13
+ bins: [bash, sh]
14
+ ---
15
+
16
+ # Shell Skill
17
+
18
+ Esta skill permite al agente ejecutar comandos en la terminal de forma segura y controlada.
19
+
20
+ ## Herramientas Disponibles
21
+
22
+ - `exec`: Ejecuta un comando básico sujeto a listas de permisos (allowlist/denylist). Recomendado para tareas simples.
23
+ - `terminal`: Ejecuta comandos directamente en la shell (bash/zsh/cmd). Útil para operaciones de Git, scripts de npm o comandos complejos que requieren mayor flexibilidad.
24
+
25
+ ## Parámetros de Herramientas
26
+
27
+ ### exec
28
+ - `command` (requerido): El comando a ejecutar.
29
+ - `timeout` (opcional): Tiempo de espera en segundos (por defecto: 30).
30
+
31
+ ### terminal
32
+ - `command` (requerido): El comando a ejecutar.
33
+ - `cwd` (opcional): Directorio de trabajo.
34
+ - `timeoutSeconds` (opcional): Tiempo de espera en segundos (por defecto: 60).
35
+
36
+ ## Seguridad
37
+ - `exec` está limitado por la configuración de seguridad de Hive.
38
+ - `terminal` permite una ejecución más directa pero registra todas las salidas en los puentes de comunicación (`bridge`).
39
+
40
+ ## Mejores Prácticas
41
+ - Prefiere comandos de solo lectura siempre que sea posible.
42
+ - Verifica siempre el código de salida (`exitCode`) y las salidas de error (`stderr`).
43
+ - Usa rutas absolutas para mayor fiabilidad entre diferentes sistemas operativos.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: system_notify
3
+ description: "Send system desktop notifications and interact via Canvas"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "🔔"
7
+ category: system
8
+ permissions:
9
+ - desktop_notification
10
+ - canvas_write
11
+ dependencies: []
12
+ tools: [system_notify, notify, report_progress, canvas_render, canvas_ask, canvas_confirm, canvas_show_card, canvas_show_progress, canvas_show_list, canvas_clear]
13
+ ---
14
+
15
+ # System Notify & Canvas Skill
16
+
17
+ Esta skill permite al agente enviar notificaciones al sistema y renderizar componentes interactivos en el Canvas del usuario (UI).
18
+
19
+ ## Herramientas Disponibles
20
+
21
+ ### Notificaciones del Sistema
22
+ - `notify`: Envía una notificación de escritorio tradicional.
23
+ - `report_progress`: Informa sobre el progreso de tareas de larga duración.
24
+
25
+ ### Herramientas de Canvas (UI)
26
+ - `canvas_render`: Renderiza componentes (botones, tablas, gráficos) en el Canvas.
27
+ - `canvas_ask`: Muestra formularios dinámicos y espera la respuesta del usuario.
28
+ - `canvas_confirm`: Muestra un diálogo de confirmación (Aceptar/Cancelar).
29
+ - `canvas_show_card`: Muestra una tarjeta informativa con ítems etiquetados.
30
+ - `canvas_show_progress`: Muestra barras de progreso múltiples para tareas complejas.
31
+ - `canvas_show_list`: Muestra listas de clave-valor (útil para configuraciones).
32
+ - `canvas_clear`: Limpia el contenido del Canvas para una sesión.
33
+
34
+ ## Uso Dinámico del Canvas
35
+
36
+ El Canvas es ideal para presentar información estructurada que es difícil de leer en texto puro, o para requerir entradas complejas del usuario mediante formularios.
37
+
38
+ ### Ejemplo: Formulario de Registro
39
+ ```javascript
40
+ canvas_ask({
41
+ title: "Datos de Usuario",
42
+ fields: [
43
+ { name: "email", label: "Correo Electrónico", type: "email", required: true },
44
+ { name: "role", label: "Rol", type: "select", options: [{label: "Admin", value: "admin"}] }
45
+ ]
46
+ })
47
+ ```
48
+
49
+ ## Mejores Prácticas
50
+ - **Concisión**: Mantén los mensajes de notificación cortos.
51
+ - **Urgencia**: Usa niveles de urgencia (`low`, `normal`, `critical`) solo para eventos que realmente requieran atención inmediata.
52
+ - **Limpieza**: Usa `canvas_clear` cuando cambies drásticamente de contexto para mantener el espacio de trabajo limpio.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: voice
3
+ description: "Process audio transcriptions and synthesize speech"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "🎙️"
7
+ category: voice
8
+ permissions:
9
+ - internet_access
10
+ dependencies: []
11
+ tools: [voice_transcribe, voice_speak]
12
+ ---
13
+
14
+ # Voice Processing Skill
15
+
16
+ Esta skill permite al agente interactuar mediante voz, transcribiendo audio a texto y convirtiendo texto a voz.
17
+
18
+ ## Herramientas Disponibles
19
+
20
+ - `voice_transcribe`: Transcribe un archivo de audio a texto.
21
+ - `voice_speak`: Convierte texto a audio y lo envía al canal de comunicación activo.
22
+
23
+ ## Mejores Prácticas
24
+ - **Calidad de Audio**: Asegúrate de que los archivos de audio para transcripción sean legibles.
25
+ - **Brevedad**: Para `voice_speak`, prefiere mensajes concisos para una mejor experiencia de usuario.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: web_search
3
+ description: "Search the internet for real-time information"
4
+ version: 1.0.0
5
+ author: Hive Team
6
+ icon: "🔍"
7
+ category: tools
8
+ permissions:
9
+ - internet_access
10
+ dependencies: []
11
+ tools: [web_search]
12
+ ---
13
+
14
+ # Web Search Skill
15
+
16
+ Esta skill permite al agente buscar información actualizada en internet utilizando motores de búsqueda integrados.
17
+
18
+ ## Herramientas Disponibles
19
+
20
+ - `web_search`: Realiza una búsqueda web y devuelve resultados con títulos, URLs y fragmentos de texto.
21
+
22
+ ## Parámetros
23
+
24
+ - `query` (requerido): El término de búsqueda.
25
+ - `numResults` (opcional): Número de resultados a devolver (por defecto: 5).
26
+
27
+ ## Mejores Prácticas
28
+ - **Especificidad**: Usa términos de búsqueda precisos.
29
+ - **Cruzar Datos**: Combina los resultados de búsqueda con la herramienta `web_fetch` (de la skill `http_client`) para obtener el contenido completo de una página si es necesario.
@@ -0,0 +1 @@
1
+ export * from "./loader.ts";
@@ -0,0 +1,282 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as yaml from "js-yaml";
4
+
5
+ export interface SkillsConfig {
6
+ allowBundled?: string[];
7
+ managedDir?: string;
8
+ extraDirs?: string[];
9
+ hotReload?: boolean;
10
+ maxSkillSizeKB?: number;
11
+ }
12
+
13
+ export interface Config {
14
+ skills?: SkillsConfig;
15
+ workspacePath?: string;
16
+ }
17
+
18
+ interface Logger {
19
+ debug: (msg: string, ...args: unknown[]) => void;
20
+ info: (msg: string, ...args: unknown[]) => void;
21
+ warn: (msg: string, ...args: unknown[]) => void;
22
+ error: (msg: string, ...args: unknown[]) => void;
23
+ }
24
+
25
+ function createLogger(): Logger {
26
+ return {
27
+ debug: (msg, ...args) => console.debug(`[skills] ${msg}`, ...args),
28
+ info: (msg, ...args) => console.info(`[skills] ${msg}`, ...args),
29
+ warn: (msg, ...args) => console.warn(`[skills] ${msg}`, ...args),
30
+ error: (msg, ...args) => console.error(`[skills] ${msg}`, ...args),
31
+ };
32
+ }
33
+
34
+ export interface SkillMetadata {
35
+ name: string;
36
+ version?: string;
37
+ author?: string;
38
+ description: string;
39
+ icon?: string;
40
+ category?: string;
41
+ permissions?: string[];
42
+ dependencies?: string[];
43
+ tools?: string[];
44
+ requirements?: {
45
+ os?: string[];
46
+ bins?: string[];
47
+ env?: string[];
48
+ config?: string[];
49
+ };
50
+ // Retrocompatibilidad con el campo metadata.hive previo
51
+ metadata?: {
52
+ hive?: {
53
+ emoji?: string;
54
+ bins?: string[];
55
+ userInvocable?: boolean;
56
+ requires?: {
57
+ config?: string[];
58
+ env?: string[];
59
+ };
60
+ install?: {
61
+ brew?: string;
62
+ apt?: string;
63
+ npm?: string;
64
+ };
65
+ os?: string[];
66
+ };
67
+ };
68
+ }
69
+
70
+ export interface Skill {
71
+ name: string;
72
+ description: string;
73
+ version?: string;
74
+ author?: string;
75
+ icon?: string;
76
+ category?: string;
77
+ content: string;
78
+ raw: string;
79
+ metadata: SkillMetadata;
80
+ source: "bundled" | "managed" | "workspace";
81
+ path: string;
82
+ permissions?: string[];
83
+ dependencies?: string[];
84
+ tools?: string[];
85
+ }
86
+
87
+ function parseFrontmatter(content: string): { frontmatter: Record<string, unknown>; body: string } {
88
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
89
+
90
+ if (!match) {
91
+ return { frontmatter: {}, body: content };
92
+ }
93
+
94
+ try {
95
+ const frontmatter = yaml.load(match[1]!) as Record<string, unknown>;
96
+ const body = match[2]!;
97
+ return { frontmatter, body };
98
+ } catch {
99
+ return { frontmatter: {}, body: content };
100
+ }
101
+ }
102
+
103
+ export class SkillLoader {
104
+ private config: Config;
105
+ private log: Logger;
106
+ private cache: Map<string, Skill> = new Map();
107
+ private bundledDir: string;
108
+
109
+ constructor(config: Config) {
110
+ this.config = config;
111
+ this.log = createLogger();
112
+ this.bundledDir = path.join(__dirname, "bundled");
113
+ }
114
+
115
+ private expandPath(p: string): string {
116
+ if (p.startsWith("~")) {
117
+ return path.join(process.env.HOME ?? "", p.slice(1));
118
+ }
119
+ return p;
120
+ }
121
+
122
+ loadSkill(skillPath: string, source: Skill["source"]): Skill | null {
123
+ try {
124
+ const skillMdPath = path.join(skillPath, "SKILL.md");
125
+
126
+ if (!fs.existsSync(skillMdPath)) {
127
+ return null;
128
+ }
129
+
130
+ const content = fs.readFileSync(skillMdPath, "utf-8");
131
+ const { frontmatter, body } = parseFrontmatter(content);
132
+
133
+ const rawMetadata = (frontmatter.metadata as any) ?? {};
134
+ const hiveMetadata = rawMetadata.hive ?? {};
135
+
136
+ const name = (frontmatter.name as string) ?? path.basename(skillPath);
137
+ const description = (frontmatter.description as string) ?? "";
138
+ const version = (frontmatter.version as string) ?? "0.0.1";
139
+ const author = (frontmatter.author as string) ?? "Anonymous";
140
+ const icon = (frontmatter.icon as string) ?? hiveMetadata.emoji ?? "🧩";
141
+ const category = (frontmatter.category as string) ?? "general";
142
+
143
+ const permissions = (frontmatter.permissions as string[]) ?? [];
144
+ const dependencies = (frontmatter.dependencies as string[]) ?? [];
145
+ const tools = (frontmatter.tools as string[]) ?? [];
146
+
147
+ const metadata: SkillMetadata = {
148
+ ...(frontmatter as any),
149
+ name,
150
+ description,
151
+ version,
152
+ author,
153
+ icon,
154
+ category,
155
+ permissions,
156
+ dependencies,
157
+ tools
158
+ };
159
+
160
+ const skill: Skill = {
161
+ name,
162
+ description,
163
+ version,
164
+ author,
165
+ icon,
166
+ category,
167
+ content: body,
168
+ raw: content,
169
+ metadata,
170
+ source,
171
+ path: skillPath,
172
+ permissions,
173
+ dependencies,
174
+ tools
175
+ };
176
+
177
+ this.cache.set(name, skill);
178
+ return skill;
179
+ } catch (error) {
180
+ this.log.error(`Failed to load skill: ${skillPath}`, { error: (error as Error).message });
181
+ return null;
182
+ }
183
+ }
184
+
185
+ loadBundledSkills(): Skill[] {
186
+ const skills: Map<string, Skill> = new Map();
187
+
188
+ if (!fs.existsSync(this.bundledDir)) {
189
+ this.log.debug(`Bundled skills directory not found: ${this.bundledDir}`);
190
+ return [];
191
+ }
192
+
193
+ for (const entry of fs.readdirSync(this.bundledDir, { withFileTypes: true })) {
194
+ if (entry.isDirectory()) {
195
+ const skill = this.loadSkill(path.join(this.bundledDir, entry.name), "bundled");
196
+ if (skill) {
197
+ skills.set(skill.name, skill);
198
+ }
199
+ }
200
+ }
201
+
202
+ this.log.debug(`Loaded ${skills.size} bundled skills`);
203
+ return Array.from(skills.values());
204
+ }
205
+
206
+ loadAllSkills(): Skill[] {
207
+ const skills: Map<string, Skill> = new Map();
208
+ const allowBundled = this.config.skills?.allowBundled;
209
+
210
+ // 1. Load bundled skills (lowest priority)
211
+ const bundledSkills = this.loadBundledSkills();
212
+ for (const skill of bundledSkills) {
213
+ // If allowBundled is undefined, empty, or contains the skill name, include it
214
+ if (!allowBundled || allowBundled.length === 0 || allowBundled.includes(skill.name)) {
215
+ skills.set(skill.name, skill);
216
+ }
217
+ }
218
+
219
+ // 2. Load managed skills (medium priority)
220
+ const managedDir = this.expandPath(this.config.skills?.managedDir ?? "~/.hive/skills");
221
+ if (fs.existsSync(managedDir)) {
222
+ for (const entry of fs.readdirSync(managedDir, { withFileTypes: true })) {
223
+ if (entry.isDirectory()) {
224
+ const skill = this.loadSkill(path.join(managedDir, entry.name), "managed");
225
+ if (skill) {
226
+ skills.set(skill.name, skill);
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ // 3. Load extra directories
233
+ const extraDirs = this.config.skills?.extraDirs ?? [];
234
+ for (const extraDir of extraDirs) {
235
+ const expandedDir = this.expandPath(extraDir);
236
+ if (fs.existsSync(expandedDir)) {
237
+ for (const entry of fs.readdirSync(expandedDir, { withFileTypes: true })) {
238
+ if (entry.isDirectory()) {
239
+ const skill = this.loadSkill(path.join(expandedDir, entry.name), "managed");
240
+ if (skill) {
241
+ skills.set(skill.name, skill);
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ // 4. Load workspace skills (highest priority)
249
+ const workspacePath = this.config.workspacePath ?? process.cwd();
250
+ const workspaceSkillsDir = path.join(workspacePath, "skills");
251
+ if (fs.existsSync(workspaceSkillsDir)) {
252
+ for (const entry of fs.readdirSync(workspaceSkillsDir, { withFileTypes: true })) {
253
+ if (entry.isDirectory()) {
254
+ const skill = this.loadSkill(path.join(workspaceSkillsDir, entry.name), "workspace");
255
+ if (skill) {
256
+ skills.set(skill.name, skill);
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ this.log.info(`Loaded ${skills.size} total skills`);
263
+ return Array.from(skills.values());
264
+ }
265
+
266
+ getSkill(name: string): Skill | undefined {
267
+ return this.cache.get(name);
268
+ }
269
+
270
+ listSkills(): string[] {
271
+ return Array.from(this.cache.keys());
272
+ }
273
+
274
+ clearCache(): void {
275
+ this.cache.clear();
276
+ }
277
+ }
278
+
279
+ export function createSkillLoader(config: Config): SkillLoader {
280
+ return new SkillLoader(config);
281
+ }
282
+
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@johpaz/hive-tools",
3
+ "version": "1.1.0",
4
+ "private": true,
5
+ "description": "Native tools for Hive AI Gateway - Browser, Cron, FileSystem, Canvas",
6
+ "main": "./src/index.ts",
7
+ "module": "./src/index.ts",
8
+ "types": "./src/index.ts",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/johpaz/hive.git",
13
+ "directory": "packages/tools"
14
+ },
15
+ "keywords": [
16
+ "hive",
17
+ "ai",
18
+ "tools",
19
+ "browser",
20
+ "cron",
21
+ "filesystem",
22
+ "canvas"
23
+ ],
24
+ "files": [
25
+ "src/"
26
+ ],
27
+ "dependencies": {
28
+ "@johpaz/hive-core": "^1.1.0",
29
+ "cron-parser": "^5.5.0",
30
+ "zod": "latest"
31
+ },
32
+ "devDependencies": {
33
+ "typescript": "latest",
34
+ "@types/bun": "latest"
35
+ },
36
+ "exports": {
37
+ ".": "./src/index.ts",
38
+ "./browser": "./src/browser/index.ts",
39
+ "./cron": "./src/cron/index.ts",
40
+ "./filesystem": "./src/filesystem/index.ts",
41
+ "./canvas": "./src/canvas/index.ts"
42
+ }
43
+ }
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect, beforeEach } from "bun:test";
2
+ import {
3
+ createBrowserNavigateTool,
4
+ createBrowserFetchTool,
5
+ createBrowserScreenshotTool,
6
+ createBrowserClickTool,
7
+ createBrowserTypeTool,
8
+ createBrowserTools,
9
+ } from "./index";
10
+
11
+ describe("Browser Tools", () => {
12
+ describe("createBrowserNavigateTool", () => {
13
+ it("creates tool with correct name and description", () => {
14
+ const tool = createBrowserNavigateTool();
15
+ expect(tool.name).toBe("browser_navigate");
16
+ expect(tool.description).toContain("Navigate");
17
+ });
18
+
19
+ it("has required parameters", () => {
20
+ const tool = createBrowserNavigateTool();
21
+ expect(tool.parameters.type).toBe("object");
22
+ expect(tool.parameters.required).toContain("url");
23
+ });
24
+
25
+ it("fetches content from a URL", async () => {
26
+ const tool = createBrowserNavigateTool();
27
+ try {
28
+ const result = await tool.execute({
29
+ url: "https://example.com",
30
+ }) as { success: boolean; content: string };
31
+
32
+ expect(result.success).toBe(true);
33
+ expect(result.content).toBeDefined();
34
+ } catch (error) {
35
+ console.log("Skipping URL fetch test due to network/cert issues");
36
+ }
37
+ }, 30000);
38
+ });
39
+
40
+ describe("createBrowserFetchTool", () => {
41
+ it("creates tool with correct name", () => {
42
+ const tool = createBrowserFetchTool();
43
+ expect(tool.name).toBe("browser_fetch");
44
+ });
45
+
46
+ it("fetches JSON from API", async () => {
47
+ const tool = createBrowserFetchTool();
48
+ try {
49
+ const result = await tool.execute({
50
+ url: "https://jsonplaceholder.typicode.com/posts/1",
51
+ }) as { success: boolean; data: unknown };
52
+
53
+ expect(result.success).toBe(true);
54
+ expect(result.data).toBeDefined();
55
+ } catch (error) {
56
+ console.log("Skipping URL fetch test due to network/cert issues");
57
+ }
58
+ }, 30000);
59
+ });
60
+
61
+ describe("createBrowserScreenshotTool", () => {
62
+ it("creates tool with placeholder response", async () => {
63
+ const tool = createBrowserScreenshotTool();
64
+ const result = await tool.execute({
65
+ url: "https://example.com",
66
+ }) as { success: boolean; error: string };
67
+
68
+ expect(result.success).toBe(false);
69
+ expect(result.error).toContain("puppeteer");
70
+ });
71
+ });
72
+
73
+ describe("createBrowserClickTool", () => {
74
+ it("creates tool with placeholder response", async () => {
75
+ const tool = createBrowserClickTool();
76
+ const result = await tool.execute({
77
+ selector: "#button",
78
+ }) as { success: boolean; error: string };
79
+
80
+ expect(result.success).toBe(false);
81
+ expect(result.error).toContain("puppeteer");
82
+ });
83
+ });
84
+
85
+ describe("createBrowserTypeTool", () => {
86
+ it("creates tool with placeholder response", async () => {
87
+ const tool = createBrowserTypeTool();
88
+ const result = await tool.execute({
89
+ selector: "#input",
90
+ text: "hello",
91
+ }) as { success: boolean; error: string };
92
+
93
+ expect(result.success).toBe(false);
94
+ expect(result.error).toContain("puppeteer");
95
+ });
96
+ });
97
+
98
+ describe("createBrowserTools", () => {
99
+ it("returns all browser tools", () => {
100
+ const tools = createBrowserTools();
101
+ expect(tools.length).toBe(5);
102
+ expect(tools.map((t) => t.name)).toEqual([
103
+ "browser_navigate",
104
+ "browser_fetch",
105
+ "browser_screenshot",
106
+ "browser_click",
107
+ "browser_type",
108
+ ]);
109
+ });
110
+ });
111
+ });