@johpaz/hive 2.0.2 → 2.0.4

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 (3) hide show
  1. package/README.md +16 -16
  2. package/dist/hive.js +408 -176
  3. package/package.json +1 -1
package/dist/hive.js CHANGED
@@ -16589,6 +16589,7 @@ function ensureSchemaSync() {
16589
16589
  if (_db) {
16590
16590
  _db.query(`UPDATE providers SET base_url = 'https://api.groq.com/openai/v1' WHERE id = 'groq' AND base_url = 'https://api.groq.com/v1'`).run();
16591
16591
  _db.query(`UPDATE providers SET base_url = 'https://api.openai.com/v1' WHERE id = 'openai' AND base_url = 'https://api.openai.com'`).run();
16592
+ _db.query(`UPDATE providers SET base_url = NULL WHERE id = 'gemini' AND base_url = 'https://generativelanguage.googleapis.com/v1beta'`).run();
16592
16593
  }
16593
16594
  }
16594
16595
 
@@ -19741,6 +19742,11 @@ function seedAllData() {
19741
19742
  `).run(provider.id, provider.name, provider.baseUrl || null, provider.category || "llm");
19742
19743
  providerCount++;
19743
19744
  }
19745
+ const ollamaHost = process.env.OLLAMA_HOST;
19746
+ if (ollamaHost) {
19747
+ db.query(`UPDATE providers SET base_url = ? WHERE id = 'ollama'`).run(ollamaHost);
19748
+ log.info(`[seed] \u2705 Ollama base_url set to ${ollamaHost} (from OLLAMA_HOST env)`);
19749
+ }
19744
19750
  log.info(`[seed] \u2705 ${providerCount} providers procesados`);
19745
19751
  let modelCount = 0;
19746
19752
  for (const model of SEED_DATA.models) {
@@ -19899,7 +19905,7 @@ var init_seed = __esm(() => {
19899
19905
  providers: [
19900
19906
  { id: "anthropic", name: "Anthropic", baseUrl: "https://api.anthropic.com" },
19901
19907
  { id: "openai", name: "OpenAI", baseUrl: "https://api.openai.com/v1" },
19902
- { id: "gemini", name: "Google Gemini", baseUrl: "https://generativelanguage.googleapis.com/v1beta" },
19908
+ { id: "gemini", name: "Google Gemini" },
19903
19909
  { id: "mistral", name: "Mistral AI", baseUrl: "https://api.mistral.ai/v1" },
19904
19910
  { id: "deepseek", name: "DeepSeek", baseUrl: "https://api.deepseek.com/v1" },
19905
19911
  { id: "kimi", name: "Kimi (Moonshot)", baseUrl: "https://api.moonshot.ai/v1" },
@@ -20711,7 +20717,7 @@ Las 52 herramientas nativas se cargan din\xE1micamente desde la base de datos.
20711
20717
  | \u23F0 CRON | 4 | cron_add, cron_list, cron_edit, cron_remove |
20712
20718
  | \uD83D\uDCBB CLI | 1 | cli_exec |
20713
20719
  | \uD83E\uDDE0 AGENTS | 14 | memory_*, agent_*, task_delegate, bus_*, project_updates |
20714
- | \uD83C\uDFA8 CANVAS | 7 | canvas_show_card, canvas_show_progress, canvas_ask, canvas_confirm |
20720
+ | \uD83C\uDFA8 CANVAS | 7 | canvas_render(chart/table/form/button/alert-dialog/markdown/...), canvas_ask, canvas_confirm, canvas_show_card, canvas_show_progress |
20715
20721
  | \uD83C\uDF09 CODEBRIDGE | 3 | codebridge_launch, codebridge_status, codebridge_cancel |
20716
20722
  | \uD83C\uDF99\uFE0F VOICE | 2 | voice_transcribe, voice_speak |
20717
20723
  | \uD83D\uDD14 CORE | 4 | search_knowledge, notify, save_note, report_progress |
@@ -22417,7 +22423,7 @@ function emitCanvas(type2, data) {
22417
22423
  }
22418
22424
  function getCanvasSnapshot() {
22419
22425
  const db = getDb();
22420
- const agentNodes = db.query("SELECT id, name, description, status FROM agents").all().map((a) => {
22426
+ const agentNodes = db.query("SELECT id, name, description, role, status FROM agents").all().map((a) => {
22421
22427
  const live = agentLiveState.get(a.id);
22422
22428
  return {
22423
22429
  id: a.id,
@@ -22425,7 +22431,7 @@ function getCanvasSnapshot() {
22425
22431
  description: a.description,
22426
22432
  status: live?.status ?? a.status,
22427
22433
  type: "agent",
22428
- data: { currentTool: live?.currentTool ?? null }
22434
+ data: { role: a.role, currentTool: live?.currentTool ?? null }
22429
22435
  };
22430
22436
  });
22431
22437
  const mcpNodes = db.query("SELECT id, name, status FROM mcp_servers WHERE enabled = 1").all().map((m) => ({
@@ -55275,7 +55281,7 @@ class OllamaProvider {
55275
55281
  async call(options2) {
55276
55282
  const { Ollama: Ollama3 } = await Promise.resolve().then(() => (init_dist3(), exports_dist2));
55277
55283
  const modelName = options2.model.replace(/^ollama\//, "");
55278
- const host = options2.baseUrl?.trim() || "http://localhost:11434";
55284
+ const host = options2.baseUrl?.trim() || process.env.OLLAMA_HOST || "http://localhost:11434";
55279
55285
  try {
55280
55286
  const isCloud = host.includes("ollama.com");
55281
55287
  const headers = {};
@@ -317925,12 +317931,12 @@ var init_canvas = __esm(() => {
317925
317931
  log57 = logger.child("canvas");
317926
317932
  canvasRenderTool = {
317927
317933
  name: "canvas_render",
317928
- description: "Render a component or visualization on the canvas. Spanish: renderizar, visualizar, gr\xE1fico, diagrama",
317934
+ description: "Render a component or visualization on the canvas. Use specific types instead of always using card+markdown. Key types: chart (bar/line/area/pie graphs), table (tabular data), markdown (rich text), form (interactive form - waits for submit), button (interactive button), alert-dialog (confirm/cancel dialog), progress (progress bars), accordion, tabs, badge, card, bee-loader. Spanish: renderizar, visualizar, gr\xE1fico, diagrama, tabla, formulario",
317929
317935
  parameters: {
317930
317936
  type: "object",
317931
317937
  properties: {
317932
- component: { type: "string", description: "Component type to render. Available: alert, alert-dialog, accordion, avatar, badge, breadcrumb, button, calendar, card, carousel, chart, checkbox, collapsible, command, context-menu, dialog, drawer, dropdown-menu, form, input, input-otp, label, markdown, menubar, navigation-menu, pagination, popover, progress, radio-group, resizable, scroll-area, select, separator, sheet, skeleton, slider, switch, table, tabs, textarea, toggle, toggle-group, tooltip, aspect-ratio, hover-card, bee-loader, custom" },
317933
- data: { type: "object", description: "Data to pass to the component" }
317938
+ component: { type: "string", description: "Component type. Visualization: chart, table, markdown, card, progress, accordion, tabs, badge, separator, bee-loader. Interactive: form, button, alert-dialog. Layout: carousel, collapsible, resizable, scroll-area, tabs. Other: alert, avatar, breadcrumb, calendar, checkbox, dialog, drawer, dropdown-menu, hover-card, input, input-otp, label, menubar, navigation-menu, pagination, popover, radio-group, select, sheet, skeleton, slider, switch, textarea, toggle, toggle-group, tooltip, aspect-ratio, command, context-menu, custom" },
317939
+ data: { type: "object", description: "Props for the component. chart: {type:'bar'|'line'|'area'|'pie', data:[{name,...}], xKey:'name', keys:['value'], title}. table: {title, columns:[{header,key}], data:[{}]}. form: {title, fields:[{name,label,type:'text'|'email'|'number'|'textarea'|'select'|'checkbox',placeholder,options:[{value,label}]}], submitLabel}. alert-dialog: {title, description, confirmLabel, cancelLabel}. button: {label, variant:'default'|'outline'|'secondary'|'destructive'}. markdown: {content}. progress: {value:0-100}." }
317934
317940
  },
317935
317941
  required: ["component", "data"]
317936
317942
  },
@@ -318950,11 +318956,68 @@ ${scratchpadContent}
318950
318956
  ` + `- Playbook (buenas pr\xE1cticas): type="playbook"
318951
318957
  ` + `- Herramientas nativas espec\xEDficas: type="tools"
318952
318958
  ` + `Las herramientas MCP ya est\xE1n disponibles - no necesitas buscarlas.
318959
+ ` + `
318960
+ ## REGLA CR\xCDTICA \u2014 Delegaci\xF3n a workers
318961
+ ` + `Los workers arrancan con herramientas m\xEDnimas (save_note, notify, report_progress, search_knowledge).
318962
+ ` + `**ANTES de crear o delegar a un worker**, SIEMPRE debes:
318963
+ ` + `1. Usar \`search_knowledge(type="tools", query="<tarea del worker>")\` para identificar qu\xE9 herramientas necesita.
318964
+ ` + `2. Incluir esas herramientas en el campo \`tools\` al crear el agente con \`create_agent\`, o
318965
+ ` + ` en el campo \`task_description\` de \`task_delegate\` como instrucci\xF3n expl\xEDcita:
318966
+ ` + ` "Usa las herramientas: web_search, fs_read, ... para completar esta tarea."
318967
+ ` + `3. El worker con esa instrucci\xF3n usar\xE1 \`search_knowledge\` para activar las tools por nombre.
318968
+ ` + `Ejemplo: si el worker debe investigar en internet \u2192 busca "web search herramienta internet" \u2192 obtienes "web_search" \u2192 dile al worker que use web_search.
318969
+ `;
318970
+ systemPrompt += `
318971
+
318972
+ # \uD83C\uDFA8 CANVAS A2UI \u2014 Componentes disponibles para \`canvas_render\`
318973
+ ` + `**REGLA**: Us\xE1 \`canvas_render\` con el tipo espec\xEDfico en vez de siempre usar \`canvas_show_card\` + markdown.
318974
+
318975
+ ` + `## Tipos de visualizaci\xF3n:
318976
+ ` + `- **chart** \u2014 Gr\xE1ficos. Props: \`{type:"bar"|"line"|"area"|"pie", data:[{name,...}], xKey:"name", keys:["valor"], colors:[], title}\`
318977
+ ` + `- **table** \u2014 Tablas de datos. Props: \`{title, columns:[{header,key}], data:[{...}]}\`
318978
+ ` + `- **progress** \u2014 Barras de progreso. Props: \`{bars:[{label,value:0-100}]}\`
318979
+ ` + `- **markdown** \u2014 Texto rich. Props: \`{content:"## t\xEDtulo\\n..."}\`
318980
+ ` + `- **card** \u2014 Tarjeta con items. Props: \`{title, description, items:[{label,value}], footer}\`
318981
+ ` + `- **accordion** \u2014 Secciones colapsables. Props: \`{items:[{value,title,content}]}\`
318982
+ ` + `- **tabs** \u2014 Pesta\xF1as. Props: \`{tabs:[{value,label,content}]}\`
318983
+ ` + `- **badge** \u2014 Etiqueta. Props: \`{label, variant:"default"|"secondary"|"destructive"|"outline"}\`
318984
+ ` + `- **separator** \u2014 L\xEDnea divisora
318985
+ ` + `- **bee-loader** \u2014 Animaci\xF3n de carga. Props: \`{message}\`
318986
+
318987
+ ` + `## Tipos interactivos (bloquean hasta respuesta del usuario):
318988
+ ` + `- **form** \u2014 Formulario. Props: \`{title, fields:[{name,label,type,placeholder,options}], submitLabel}\`
318989
+ ` + ` \u2192 Tipos de campo: \`text\`, \`email\`, \`number\`, \`textarea\`, \`select\`, \`checkbox\`
318990
+ ` + ` \u2192 Al Submit recibir\xE1s: \`{data:{campo:valor,...}}\`
318991
+ ` + `- **button** \u2014 Bot\xF3n clickeable. Props: \`{label, variant:"default"|"outline"|"secondary"|"destructive"}\`
318992
+ ` + ` \u2192 Al click recibir\xE1s: \`{action:"click", data:{label}}\`
318993
+ ` + `- **alert-dialog** \u2014 Confirmaci\xF3n. Props: \`{title, description, confirmLabel, cancelLabel}\`
318994
+ ` + ` \u2192 Al confirmar recibir\xE1s: \`{data:{confirmed:true|false}}\`
318995
+
318996
+ ` + `## Cu\xE1ndo usar cada uno:
318997
+ ` + `- Estad\xEDsticas/datos num\xE9ricos \u2192 **chart** (bar/line/pie)
318998
+ ` + `- Listas de filas/columnas \u2192 **table**
318999
+ ` + `- Texto largo / an\xE1lisis \u2192 **markdown**
319000
+ ` + `- Pedir datos al usuario \u2192 **canvas_ask** o **canvas_render con form**
319001
+ ` + `- Confirmar acci\xF3n peligrosa \u2192 **canvas_confirm** o **canvas_render con alert-dialog**
319002
+ ` + `- Mostrar progreso de tarea \u2192 **canvas_show_progress**
319003
+
319004
+ ` + `## Ejemplos:
319005
+ ` + `\`\`\`
319006
+ ` + `canvas_render(component:"chart", data:{type:"bar", data:[{mes:"Ene",ventas:1200},{mes:"Feb",ventas:1800}], xKey:"mes", keys:["ventas"], title:"Ventas por mes"})
319007
+ ` + `canvas_render(component:"table", data:{title:"Archivos", columns:[{header:"Nombre",key:"name"},{header:"Tama\xF1o",key:"size"}], data:[{name:"app.ts",size:"12KB"}]})
319008
+ ` + `canvas_render(component:"form", data:{title:"Configuraci\xF3n", fields:[{name:"nombre",label:"Nombre",type:"text"},{name:"tipo",label:"Tipo",type:"select",options:[{value:"a",label:"A"},{value:"b",label:"B"}]}], submitLabel:"Guardar"})
319009
+ ` + `\`\`\`
318953
319010
  `;
318954
319011
  }
318955
319012
  if (isWorker && opts.taskContext) {
318956
319013
  systemPrompt += `
318957
319014
 
319015
+ # HERRAMIENTAS DISPONIBLES
319016
+ ` + `Arrancas con herramientas b\xE1sicas. Si tu tarea requiere herramientas adicionales (web_search, fs_read, browser_navigate, etc.):
319017
+ ` + `1. Us\xE1 \`search_knowledge(type="tools", query="<herramienta o tarea>")\` para encontrarlas.
319018
+ ` + `2. Las herramientas que encuentres estar\xE1n disponibles para usar inmediatamente.
319019
+ ` + `Si el coordinador te indic\xF3 herramientas espec\xEDficas, buscalas primero con search_knowledge antes de ejecutar tu tarea.
319020
+ ` + `
318958
319021
  # CURRENT TASK
318959
319022
  ${opts.taskContext}
318960
319023
 
@@ -555680,18 +555743,19 @@ async function handleVerifyProvider(req) {
555680
555743
  let headers = {};
555681
555744
  const testMessages = [{ role: "user", content: "Say 'ok' if you can read this." }];
555682
555745
  if (provider === "ollama") {
555746
+ const ollamaUrl = process.env.OLLAMA_HOST || "http://localhost:11434";
555683
555747
  try {
555684
- const response2 = await fetch("http://localhost:11434/api/tags", {
555748
+ const response2 = await fetch(`${ollamaUrl}/api/tags`, {
555685
555749
  signal: AbortSignal.timeout(5000)
555686
555750
  });
555687
555751
  return Response.json({
555688
555752
  success: response2.ok,
555689
- error: response2.ok ? null : "Could not connect to Ollama"
555753
+ error: response2.ok ? null : `Could not connect to Ollama at ${ollamaUrl}`
555690
555754
  });
555691
555755
  } catch {
555692
555756
  return Response.json({
555693
555757
  success: false,
555694
- error: "Could not connect to Ollama at http://localhost:11434"
555758
+ error: `Could not connect to Ollama at ${ollamaUrl}`
555695
555759
  });
555696
555760
  }
555697
555761
  }
@@ -556171,7 +556235,7 @@ async function handleSyncProviderModels(req, addCorsHeaders, providerId) {
556171
556235
  if (!providerRow) {
556172
556236
  return addCorsHeaders(new Response("Provider not found", { status: 404 }), req);
556173
556237
  }
556174
- const baseUrl = (providerRow.base_url || "http://localhost:11434").replace(/\/(v1|api)\/?$/, "");
556238
+ const baseUrl = (providerRow.base_url || process.env.OLLAMA_HOST || "http://localhost:11434").replace(/\/(v1|api)\/?$/, "");
556175
556239
  try {
556176
556240
  const res = await fetch(`${baseUrl}/api/tags`);
556177
556241
  if (!res.ok) {
@@ -557333,6 +557397,96 @@ var init_voice3 = __esm(() => {
557333
557397
  init_crypto();
557334
557398
  });
557335
557399
 
557400
+ // packages/core/package.json
557401
+ var package_default;
557402
+ var init_package = __esm(() => {
557403
+ package_default = {
557404
+ name: "@johpaz/hive-core",
557405
+ version: "2.0.4",
557406
+ private: true,
557407
+ description: "Hive Gateway \u2014 Personal AI agent runtime",
557408
+ main: "./src/index.ts",
557409
+ module: "./src/index.ts",
557410
+ types: "./src/index.ts",
557411
+ license: "MIT",
557412
+ files: [
557413
+ "src/"
557414
+ ],
557415
+ scripts: {
557416
+ test: "bun test",
557417
+ typecheck: "tsc --noEmit"
557418
+ },
557419
+ dependencies: {
557420
+ "@ag-ui/core": "^0.0.46",
557421
+ "@johpaz/hive-code-bridge": "^2.0.4",
557422
+ "@johpaz/hive-mcp": "^2.0.4",
557423
+ "@johpaz/hive-skills": "^2.0.4",
557424
+ "@modelcontextprotocol/sdk": "latest",
557425
+ "@sapphire/snowflake": "latest",
557426
+ "@slack/bolt": "latest",
557427
+ "@whiskeysockets/baileys": "latest",
557428
+ croner: "^10.0.1",
557429
+ "discord.js": "latest",
557430
+ grammy: "latest",
557431
+ "js-yaml": "latest",
557432
+ puppeteer: "^24.39.1",
557433
+ "qrcode-terminal": "latest",
557434
+ "toon-format-parser": "1.1.4",
557435
+ zod: "latest"
557436
+ },
557437
+ devDependencies: {
557438
+ typescript: "6.0.1-rc",
557439
+ "@types/bun": "latest"
557440
+ },
557441
+ exports: {
557442
+ ".": "./src/index.ts",
557443
+ "./gateway": "./src/gateway/index.ts",
557444
+ "./agent": "./src/agent/index.ts",
557445
+ "./agent/service": "./src/agent/service.ts",
557446
+ "./agent/agent-loop": "./src/agent/agent-loop.ts",
557447
+ "./agent/context-compiler": "./src/agent/context-compiler.ts",
557448
+ "./agent/prompt-builder": "./src/agent/prompt-builder.ts",
557449
+ "./agent/conversation-store": "./src/agent/conversation-store.ts",
557450
+ "./agent/tool-selector": "./src/agent/tool-selector.ts",
557451
+ "./agent/skill-selector": "./src/agent/skill-selector.ts",
557452
+ "./agent/playbook-selector": "./src/agent/playbook-selector.ts",
557453
+ "./agent/llm-client": "./src/agent/llm-client.ts",
557454
+ "./channels": "./src/channels/index.ts",
557455
+ "./channels/base": "./src/channels/base.ts",
557456
+ "./channels/manager": "./src/channels/manager.ts",
557457
+ "./channels/telegram": "./src/channels/telegram.ts",
557458
+ "./channels/discord": "./src/channels/discord.ts",
557459
+ "./channels/whatsapp": "./src/channels/whatsapp.ts",
557460
+ "./channels/slack": "./src/channels/slack.ts",
557461
+ "./channels/webchat": "./src/channels/webchat.ts",
557462
+ "./config": "./src/config/loader.ts",
557463
+ "./config/loader": "./src/config/loader.ts",
557464
+ "./utils": "./src/utils/logger.ts",
557465
+ "./utils/logger": "./src/utils/logger.ts",
557466
+ "./storage/sqlite": "./src/storage/sqlite.ts",
557467
+ "./storage/onboarding": "./src/storage/onboarding.ts",
557468
+ "./storage/crypto": "./src/storage/crypto.ts",
557469
+ "./storage/schema": "./src/storage/schema.ts",
557470
+ "./storage/seed": "./src/storage/seed.ts",
557471
+ "./tools": "./src/tools/index.ts",
557472
+ "./tools/agents": "./src/tools/agents/index.ts",
557473
+ "./tools/canvas": "./src/tools/canvas/index.ts",
557474
+ "./tools/cli": "./src/tools/cli/index.ts",
557475
+ "./tools/codebridge": "./src/tools/codebridge/index.ts",
557476
+ "./tools/core": "./src/tools/core/index.ts",
557477
+ "./tools/cron": "./src/tools/cron/index.ts",
557478
+ "./tools/filesystem": "./src/tools/filesystem/index.ts",
557479
+ "./tools/projects": "./src/tools/projects/index.ts",
557480
+ "./tools/voice": "./src/tools/voice/index.ts",
557481
+ "./tools/web": "./src/tools/web/index.ts",
557482
+ "./integrations": "./src/integrations/index.ts",
557483
+ "./integrations/catalog": "./src/integrations/catalog.ts",
557484
+ "./integrations/env": "./src/integrations/env.ts",
557485
+ "./voice": "./src/voice/index.ts"
557486
+ }
557487
+ };
557488
+ });
557489
+
557336
557490
  // packages/core/src/gateway/routes/system.ts
557337
557491
  import { cpus } from "os";
557338
557492
  function detectInstallationType() {
@@ -557676,10 +557830,12 @@ async function handleApiReload(req, addCorsHeaders, agent) {
557676
557830
  return addCorsHeaders(Response.json({ success: false, error: error50.message }, { status: 500 }), req);
557677
557831
  }
557678
557832
  }
557679
- var CURRENT_VERSION = "1.7.15";
557833
+ var CURRENT_VERSION;
557680
557834
  var init_system = __esm(() => {
557681
557835
  init_sqlite();
557682
557836
  init_loader();
557837
+ init_package();
557838
+ CURRENT_VERSION = package_default.version;
557683
557839
  });
557684
557840
 
557685
557841
  // packages/core/src/agent/providers.ts
@@ -558141,32 +558297,56 @@ var init_helpers2 = __esm(() => {
558141
558297
  init_cors();
558142
558298
  });
558143
558299
 
558300
+ // packages/core/src/tools/cron/index.ts
558301
+ function resolveBestChannel(userId, notifyChannelId) {
558302
+ if (notifyChannelId)
558303
+ return notifyChannelId;
558304
+ try {
558305
+ const db = getDb();
558306
+ const identities = db.query("SELECT channel FROM user_identities WHERE user_id = ? ORDER BY channel ASC LIMIT 5").all(userId);
558307
+ const preferred = ["telegram", "discord", "slack", "whatsapp"];
558308
+ for (const p2 of preferred) {
558309
+ if (identities.some((i2) => i2.channel === p2))
558310
+ return p2;
558311
+ }
558312
+ } catch {}
558313
+ return "webchat";
558314
+ }
558315
+ var log67, activeJobs;
558316
+ var init_cron2 = __esm(() => {
558317
+ init_sqlite();
558318
+ init_logger();
558319
+ init_croner();
558320
+ log67 = logger.child("cron");
558321
+ activeJobs = new Map;
558322
+ });
558323
+
558144
558324
  // packages/core/src/scheduler/integration.ts
558145
558325
  function setSchedulerForCleanup(scheduler) {
558146
558326
  _scheduler2 = scheduler;
558147
558327
  }
558148
558328
  async function executeScheduledTask(task) {
558149
- log67.info(`[execute] Processing task "${task.name}" (${task.id})`);
558329
+ log68.info(`[execute] Processing task "${task.name}" (${task.id})`);
558150
558330
  try {
558151
558331
  let payload;
558152
558332
  try {
558153
558333
  payload = JSON.parse(task.payload);
558154
558334
  } catch (err) {
558155
- log67.error(`[execute] Invalid payload JSON for task "${task.id}": ${err.message}`);
558335
+ log68.error(`[execute] Invalid payload JSON for task "${task.id}": ${err.message}`);
558156
558336
  return { success: false, error: "Invalid payload JSON" };
558157
558337
  }
558158
558338
  const prompt = payload.prompt || payload.message;
558159
558339
  if (!prompt && !payload._internal) {
558160
- log67.error(`[execute] Task "${task.id}" has no prompt or message in payload`);
558340
+ log68.error(`[execute] Task "${task.id}" has no prompt or message in payload`);
558161
558341
  return { success: false, error: "Missing prompt or message in payload" };
558162
558342
  }
558163
558343
  if (payload._internal === true && payload.action === "cleanup") {
558164
558344
  if (_scheduler2) {
558165
558345
  _scheduler2.runCleanup();
558166
558346
  } else {
558167
- log67.warn("[execute] Cleanup task fired but scheduler instance not available");
558347
+ log68.warn("[execute] Cleanup task fired but scheduler instance not available");
558168
558348
  }
558169
- log67.info("[execute] Cleanup task executed");
558349
+ log68.info("[execute] Cleanup task executed");
558170
558350
  return { success: true, response: "Cleanup completed" };
558171
558351
  }
558172
558352
  const metadata = {
@@ -558180,7 +558360,7 @@ async function executeScheduledTask(task) {
558180
558360
  let targetAgentId = task.agent_id || null;
558181
558361
  if (!targetAgentId) {
558182
558362
  targetAgentId = resolveAgentId(null);
558183
- log67.debug(`[execute] No agent specified, routing to Coordinator: ${targetAgentId}`);
558363
+ log68.debug(`[execute] No agent specified, routing to Coordinator: ${targetAgentId}`);
558184
558364
  }
558185
558365
  const db = getDb();
558186
558366
  const user = db.query("SELECT id, timezone, language FROM users LIMIT 1").get();
@@ -558209,16 +558389,17 @@ Type: ${task.task_type}
558209
558389
  Triggered at: ${hora_usuario} on ${fecha_usuario} (${userTimezone})
558210
558390
 
558211
558391
  ${prompt || `Execute tool: ${task.tool_name}`}`;
558212
- log67.debug(`[execute] Sending to agent ${targetAgentId}: "${contextPrompt.slice(0, 100)}..."`);
558392
+ log68.debug(`[execute] Sending to agent ${targetAgentId}: "${contextPrompt.slice(0, 100)}..."`);
558213
558393
  try {
558214
558394
  const agentLoop = buildAgentLoop({ mcpManager: undefined });
558215
558395
  const sessionId = `sched_${task.id}_${Date.now()}`;
558396
+ const agentChannel = task.channel && task.channel !== "system" ? task.channel : resolveBestChannel(user?.id || "");
558216
558397
  const messages2 = [{ role: "user", content: contextPrompt }];
558217
558398
  const stream = agentLoop.stream({ messages: messages2 }, {
558218
558399
  configurable: {
558219
558400
  thread_id: sessionId,
558220
558401
  agent_id: targetAgentId || undefined,
558221
- channel: task.channel,
558402
+ channel: agentChannel,
558222
558403
  user_id: user?.id || "",
558223
558404
  system_prompt: undefined,
558224
558405
  raw_user_message: contextPrompt
@@ -558245,20 +558426,20 @@ ${prompt || `Execute tool: ${task.tool_name}`}`;
558245
558426
  if (hasError && !response) {
558246
558427
  throw new Error("Agent execution returned errors");
558247
558428
  }
558248
- log67.info(`[execute] Agent response received for task "${task.name}"`);
558429
+ log68.info(`[execute] Agent response received for task "${task.name}"`);
558249
558430
  return {
558250
558431
  success: true,
558251
558432
  response: response || "Task executed successfully"
558252
558433
  };
558253
558434
  } catch (agentErr) {
558254
- log67.error(`[execute] Agent execution failed: ${agentErr.message}`);
558435
+ log68.error(`[execute] Agent execution failed: ${agentErr.message}`);
558255
558436
  return {
558256
558437
  success: false,
558257
558438
  error: `Agent execution failed: ${agentErr.message}`
558258
558439
  };
558259
558440
  }
558260
558441
  } catch (err) {
558261
- log67.error(`[execute] Task execution failed: ${err.message}`);
558442
+ log68.error(`[execute] Task execution failed: ${err.message}`);
558262
558443
  return {
558263
558444
  success: false,
558264
558445
  error: err.message
@@ -558269,19 +558450,20 @@ async function notifyTaskCompletion(taskId, taskName, success2, response, error5
558269
558450
  const db = getDb();
558270
558451
  const task = db.query("SELECT channel, agent_id FROM scheduled_tasks WHERE id = ?").get(taskId);
558271
558452
  if (!task) {
558272
- log67.warn(`[notify] Task "${taskId}" not found`);
558273
- return;
558274
- }
558275
- if (task.channel === "system") {
558276
- log67.debug(`[notify] Skipping notification for system channel`);
558453
+ log68.warn(`[notify] Task "${taskId}" not found`);
558277
558454
  return;
558278
558455
  }
558279
558456
  const userRow = db.query("SELECT id FROM users LIMIT 1").get();
558280
558457
  const userId = userRow?.id || "";
558281
- const identities = db.query("SELECT channel FROM user_identities WHERE user_id = ? ORDER BY channel").all(userId);
558282
- let notifyChannel = task.channel;
558283
- if (!identities.some((i2) => i2.channel === notifyChannel)) {
558284
- const preferred = ["telegram", "discord", "slack", "whatsapp", "webchat"];
558458
+ const activeChannels = db.query(`
558459
+ SELECT ui.channel FROM user_identities ui
558460
+ JOIN channels c ON c.id = ui.channel
558461
+ WHERE ui.user_id = ? AND c.active = 1 AND c.status = 'connected'
558462
+ `).all(userId);
558463
+ const identities = activeChannels.length > 0 ? activeChannels : db.query("SELECT channel FROM user_identities WHERE user_id = ?").all(userId);
558464
+ const preferred = ["telegram", "discord", "slack", "whatsapp", "webchat"];
558465
+ let notifyChannel = task.channel && task.channel !== "system" ? task.channel : "";
558466
+ if (!notifyChannel || !identities.some((i2) => i2.channel === notifyChannel)) {
558285
558467
  for (const p2 of preferred) {
558286
558468
  if (identities.some((i2) => i2.channel === p2)) {
558287
558469
  notifyChannel = p2;
@@ -558289,25 +558471,34 @@ async function notifyTaskCompletion(taskId, taskName, success2, response, error5
558289
558471
  }
558290
558472
  }
558291
558473
  }
558474
+ if (!notifyChannel || notifyChannel === "system")
558475
+ notifyChannel = "webchat";
558292
558476
  const status = success2 ? "\u2705" : "\u274C";
558293
558477
  const message = success2 ? `${status} Scheduled task "${taskName}" completed
558294
558478
  ${response || ""}` : `${status} Scheduled task "${taskName}" failed
558295
558479
  ${error50 || ""}`;
558296
- log67.info(`[notify] Sending notification to ${notifyChannel}: "${message.slice(0, 50)}..."`);
558480
+ log68.info(`[notify] Sending notification to ${notifyChannel}: "${message.slice(0, 50)}..."`);
558481
+ try {
558482
+ addMessage(userId, "assistant", message, { channel: notifyChannel });
558483
+ } catch (e) {
558484
+ log68.warn(`[notify] Failed to persist notification to DB: ${e.message}`);
558485
+ }
558297
558486
  await sendToUserChannel(notifyChannel, userId, message);
558298
- log67.info(`[notify] Notification sent to ${notifyChannel}`);
558487
+ log68.info(`[notify] Notification sent to ${notifyChannel}`);
558299
558488
  }
558300
558489
  function createTaskHandler() {
558301
558490
  return executeScheduledTask;
558302
558491
  }
558303
- var log67, _scheduler2 = null;
558492
+ var log68, _scheduler2 = null;
558304
558493
  var init_integration = __esm(() => {
558305
558494
  init_logger();
558306
558495
  init_sqlite();
558307
558496
  init_agent_loop();
558308
558497
  init_onboarding();
558309
558498
  init_channel_notify();
558310
- log67 = logger.child("SchedulerIntegration");
558499
+ init_conversation_store();
558500
+ init_cron2();
558501
+ log68 = logger.child("SchedulerIntegration");
558311
558502
  });
558312
558503
 
558313
558504
  // packages/core/src/scheduler/CronScheduler.ts
@@ -558327,7 +558518,7 @@ class CronScheduler {
558327
558518
  for (const task of tasks) {
558328
558519
  this.activate(task);
558329
558520
  }
558330
- log68.info(`[boot] Loaded ${tasks.length} active task(s)`);
558521
+ log69.info(`[boot] Loaded ${tasks.length} active task(s)`);
558331
558522
  this.ensureCleanupTask();
558332
558523
  }
558333
558524
  activate(task) {
@@ -558335,23 +558526,23 @@ class CronScheduler {
558335
558526
  if (existingJob) {
558336
558527
  existingJob.stop();
558337
558528
  this.jobs.delete(task.id);
558338
- log68.debug(`[activate] Stopped existing job for task "${task.name}" (${task.id})`);
558529
+ log69.debug(`[activate] Stopped existing job for task "${task.name}" (${task.id})`);
558339
558530
  }
558340
558531
  if (task.status === "paused" || task.status === "completed" || task.status === "cancelled") {
558341
- log68.debug(`[activate] Skipping task "${task.name}" (${task.id}) - status: ${task.status}`);
558532
+ log69.debug(`[activate] Skipping task "${task.name}" (${task.id}) - status: ${task.status}`);
558342
558533
  return;
558343
558534
  }
558344
558535
  try {
558345
558536
  let pattern;
558346
558537
  if (task.task_type === "recurring") {
558347
558538
  if (!task.cron_expression) {
558348
- log68.error(`[activate] Task "${task.name}" (${task.id}) is recurring but has no cron_expression`);
558539
+ log69.error(`[activate] Task "${task.name}" (${task.id}) is recurring but has no cron_expression`);
558349
558540
  return;
558350
558541
  }
558351
558542
  pattern = task.cron_expression;
558352
558543
  } else {
558353
558544
  if (!task.fire_at) {
558354
- log68.error(`[activate] Task "${task.name}" (${task.id}) is one_shot but has no fire_at`);
558545
+ log69.error(`[activate] Task "${task.name}" (${task.id}) is one_shot but has no fire_at`);
558355
558546
  return;
558356
558547
  }
558357
558548
  pattern = task.fire_at;
@@ -558359,7 +558550,7 @@ class CronScheduler {
558359
558550
  try {
558360
558551
  new E(pattern);
558361
558552
  } catch (err) {
558362
- log68.error(`[activate] Invalid cron pattern "${pattern}" for task "${task.name}": ${err.message}`);
558553
+ log69.error(`[activate] Invalid cron pattern "${pattern}" for task "${task.name}": ${err.message}`);
558363
558554
  return;
558364
558555
  }
558365
558556
  const options2 = {
@@ -558380,26 +558571,26 @@ class CronScheduler {
558380
558571
  if (nextRun) {
558381
558572
  const nextRunIso = nextRun.toISOString();
558382
558573
  this.db.query("UPDATE scheduled_tasks SET next_run_at = ? WHERE id = ?").run(nextRunIso, task.id);
558383
- log68.info(`[activate] Task "${task.name}" (${task.id}) scheduled - next: ${nextRunIso}`);
558574
+ log69.info(`[activate] Task "${task.name}" (${task.id}) scheduled - next: ${nextRunIso}`);
558384
558575
  } else {
558385
- log68.warn(`[activate] Task "${task.name}" (${task.id}) has no next run date`);
558576
+ log69.warn(`[activate] Task "${task.name}" (${task.id}) has no next run date`);
558386
558577
  }
558387
558578
  } catch (err) {
558388
- log68.error(`[activate] Failed to activate task "${task.name}" (${task.id}): ${err.message}`);
558579
+ log69.error(`[activate] Failed to activate task "${task.name}" (${task.id}): ${err.message}`);
558389
558580
  }
558390
558581
  }
558391
558582
  async execute(task) {
558392
558583
  const runId = crypto.randomUUID().replace(/-/g, "").slice(0, 16);
558393
558584
  const startedAt = new Date().toISOString();
558394
558585
  const startTime2 = performance.now();
558395
- log68.info(`[execute] Starting task "${task.name}" (${task.id}) run #${runId}`);
558586
+ log69.info(`[execute] Starting task "${task.name}" (${task.id}) run #${runId}`);
558396
558587
  try {
558397
558588
  this.db.query(`
558398
558589
  INSERT INTO task_runs (id, task_id, status, started_at, payload_snapshot)
558399
558590
  VALUES (?, ?, 'running', ?, ?)
558400
558591
  `).run(runId, task.id, startedAt, task.payload);
558401
558592
  } catch (err) {
558402
- log68.error(`[execute] Failed to create task_run record: ${err.message}`);
558593
+ log69.error(`[execute] Failed to create task_run record: ${err.message}`);
558403
558594
  }
558404
558595
  try {
558405
558596
  const result2 = await this.handler(task);
@@ -558431,9 +558622,9 @@ class CronScheduler {
558431
558622
  WHERE id = ?
558432
558623
  `).run(finishedAt, task.id);
558433
558624
  this.deactivate(task.id);
558434
- log68.info(`[execute] One-shot task "${task.name}" (${task.id}) completed`);
558625
+ log69.info(`[execute] One-shot task "${task.name}" (${task.id}) completed`);
558435
558626
  } else {
558436
- log68.info(`[execute] Task "${task.name}" (${task.id}) completed in ${Math.round(duration3)}ms`);
558627
+ log69.info(`[execute] Task "${task.name}" (${task.id}) completed in ${Math.round(duration3)}ms`);
558437
558628
  }
558438
558629
  } else {
558439
558630
  throw new Error(result2.error || "Handler reported failure");
@@ -558452,12 +558643,12 @@ class CronScheduler {
558452
558643
  SET error_count = error_count + 1, last_error = ?
558453
558644
  WHERE id = ?
558454
558645
  `).run(errorMessage, task.id);
558455
- log68.error(`[execute] Task "${task.name}" (${task.id}) failed: ${errorMessage}`);
558646
+ log69.error(`[execute] Task "${task.name}" (${task.id}) failed: ${errorMessage}`);
558456
558647
  await notifyTaskCompletion(task.id, task.name, false, undefined, errorMessage);
558457
558648
  }
558458
558649
  }
558459
558650
  handleError(task, error50) {
558460
- log68.error(`[error] Task "${task.name}" (${task.id}) error: ${error50.message}`);
558651
+ log69.error(`[error] Task "${task.name}" (${task.id}) error: ${error50.message}`);
558461
558652
  this.db.query(`
558462
558653
  UPDATE scheduled_tasks
558463
558654
  SET error_count = error_count + 1, last_error = ?
@@ -558471,21 +558662,21 @@ class CronScheduler {
558471
558662
  }
558472
558663
  const result2 = this.db.query("UPDATE scheduled_tasks SET status = 'paused' WHERE id = ?").run(taskId);
558473
558664
  if (result2.changes > 0) {
558474
- log68.info(`[pause] Task "${taskId}" paused`);
558665
+ log69.info(`[pause] Task "${taskId}" paused`);
558475
558666
  return true;
558476
558667
  }
558477
- log68.warn(`[pause] Task "${taskId}" not found`);
558668
+ log69.warn(`[pause] Task "${taskId}" not found`);
558478
558669
  return false;
558479
558670
  }
558480
558671
  resume(taskId) {
558481
558672
  const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
558482
558673
  if (!task) {
558483
- log68.warn(`[resume] Task "${taskId}" not found`);
558674
+ log69.warn(`[resume] Task "${taskId}" not found`);
558484
558675
  return false;
558485
558676
  }
558486
558677
  this.db.query("UPDATE scheduled_tasks SET status = 'active' WHERE id = ?").run(taskId);
558487
558678
  this.activate(task);
558488
- log68.info(`[resume] Task "${taskId}" resumed`);
558679
+ log69.info(`[resume] Task "${taskId}" resumed`);
558489
558680
  return true;
558490
558681
  }
558491
558682
  deactivate(taskId) {
@@ -558493,17 +558684,17 @@ class CronScheduler {
558493
558684
  if (job) {
558494
558685
  job.stop();
558495
558686
  this.jobs.delete(taskId);
558496
- log68.debug(`[deactivate] Task "${taskId}" deactivated`);
558687
+ log69.debug(`[deactivate] Task "${taskId}" deactivated`);
558497
558688
  }
558498
558689
  }
558499
558690
  delete(taskId) {
558500
558691
  this.deactivate(taskId);
558501
558692
  const result2 = this.db.query("DELETE FROM scheduled_tasks WHERE id = ?").run(taskId);
558502
558693
  if (result2.changes > 0) {
558503
- log68.info(`[delete] Task "${taskId}" deleted`);
558694
+ log69.info(`[delete] Task "${taskId}" deleted`);
558504
558695
  return true;
558505
558696
  }
558506
- log68.warn(`[delete] Task "${taskId}" not found`);
558697
+ log69.warn(`[delete] Task "${taskId}" not found`);
558507
558698
  return false;
558508
558699
  }
558509
558700
  create(input2) {
@@ -558550,13 +558741,13 @@ class CronScheduler {
558550
558741
  this.activate(task);
558551
558742
  const job = this.jobs.get(id);
558552
558743
  const nextRun = job?.nextRun()?.toISOString();
558553
- log68.info(`[create] Task "${input2.name}" (${id}) created`);
558744
+ log69.info(`[create] Task "${input2.name}" (${id}) created`);
558554
558745
  return { id, nextRun };
558555
558746
  }
558556
558747
  update(taskId, changes) {
558557
558748
  const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
558558
558749
  if (!task) {
558559
- log68.warn(`[update] Task "${taskId}" not found`);
558750
+ log69.warn(`[update] Task "${taskId}" not found`);
558560
558751
  return false;
558561
558752
  }
558562
558753
  const fields = [];
@@ -558624,7 +558815,7 @@ class CronScheduler {
558624
558815
  this.db.query(`UPDATE scheduled_tasks SET ${fields.join(", ")} WHERE id = ?`).run(...values2);
558625
558816
  const updatedTask = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
558626
558817
  this.activate(updatedTask);
558627
- log68.info(`[update] Task "${taskId}" updated`);
558818
+ log69.info(`[update] Task "${taskId}" updated`);
558628
558819
  return true;
558629
558820
  }
558630
558821
  getStatus() {
@@ -558643,16 +558834,16 @@ class CronScheduler {
558643
558834
  trigger(taskId) {
558644
558835
  const task = this.db.query("SELECT * FROM scheduled_tasks WHERE id = ?").get(taskId);
558645
558836
  if (!task) {
558646
- log68.warn(`[trigger] Task "${taskId}" not found`);
558837
+ log69.warn(`[trigger] Task "${taskId}" not found`);
558647
558838
  return false;
558648
558839
  }
558649
558840
  const job = this.jobs.get(taskId);
558650
558841
  if (!job) {
558651
- log68.warn(`[trigger] Task "${taskId}" has no active job`);
558842
+ log69.warn(`[trigger] Task "${taskId}" has no active job`);
558652
558843
  return false;
558653
558844
  }
558654
558845
  job.trigger();
558655
- log68.info(`[trigger] Task "${taskId}" manually triggered`);
558846
+ log69.info(`[trigger] Task "${taskId}" manually triggered`);
558656
558847
  return true;
558657
558848
  }
558658
558849
  shutdown() {
@@ -558660,13 +558851,13 @@ class CronScheduler {
558660
558851
  job.stop();
558661
558852
  }
558662
558853
  this.jobs.clear();
558663
- log68.info("[shutdown] All jobs stopped");
558854
+ log69.info("[shutdown] All jobs stopped");
558664
558855
  }
558665
558856
  ensureCleanupTask() {
558666
558857
  const existing = this.db.query("SELECT id FROM scheduled_tasks WHERE name = '_hive_cleanup_runs'").get();
558667
558858
  if (existing) {
558668
558859
  this.cleanupTaskId = existing.id;
558669
- log68.debug("[ensureCleanupTask] Cleanup task already exists");
558860
+ log69.debug("[ensureCleanupTask] Cleanup task already exists");
558670
558861
  return;
558671
558862
  }
558672
558863
  try {
@@ -558680,9 +558871,9 @@ class CronScheduler {
558680
558871
  protect: true
558681
558872
  });
558682
558873
  this.cleanupTaskId = result2.id;
558683
- log68.info("[ensureCleanupTask] Cleanup task created");
558874
+ log69.info("[ensureCleanupTask] Cleanup task created");
558684
558875
  } catch (err) {
558685
- log68.error(`[ensureCleanupTask] Failed to create cleanup task: ${err.message}`);
558876
+ log69.error(`[ensureCleanupTask] Failed to create cleanup task: ${err.message}`);
558686
558877
  }
558687
558878
  }
558688
558879
  runCleanup() {
@@ -558712,7 +558903,7 @@ class CronScheduler {
558712
558903
  )
558713
558904
  `).run(task_id, task_id);
558714
558905
  }
558715
- log68.info("[runCleanup] Cleanup completed");
558906
+ log69.info("[runCleanup] Cleanup completed");
558716
558907
  }
558717
558908
  getHistory(taskId, limit2 = 50) {
558718
558909
  return this.db.query(`
@@ -558732,12 +558923,12 @@ class CronScheduler {
558732
558923
  return this.db.query("SELECT * FROM scheduled_tasks ORDER BY next_run_at").all();
558733
558924
  }
558734
558925
  }
558735
- var log68;
558926
+ var log69;
558736
558927
  var init_CronScheduler = __esm(() => {
558737
558928
  init_croner();
558738
558929
  init_logger();
558739
558930
  init_integration();
558740
- log68 = logger.child("CronScheduler");
558931
+ log69 = logger.child("CronScheduler");
558741
558932
  });
558742
558933
 
558743
558934
  // packages/core/src/gateway/routes/scheduled-tasks.ts
@@ -559037,24 +559228,24 @@ async function startGateway(config3) {
559037
559228
  const numCores = osCpus().length || 1;
559038
559229
  let lastCpuSample = process.cpuUsage();
559039
559230
  let lastCpuSampleTime = Date.now();
559040
- const log69 = logger.child("gateway");
559231
+ const log70 = logger.child("gateway");
559041
559232
  const mcpLog2 = logger.child("mcp:api");
559042
- log69.info(`Starting gateway on ${host}:${port}`);
559233
+ log70.info(`Starting gateway on ${host}:${port}`);
559043
559234
  const tokenFile = path30.join(getHiveDir(), ".auth_token");
559044
559235
  if (!process.env.HIVE_AUTH_TOKEN) {
559045
559236
  if (existsSync18(tokenFile)) {
559046
559237
  process.env.HIVE_AUTH_TOKEN = readFileSync9(tokenFile, "utf-8").trim();
559047
- log69.info("\uD83D\uDD11 Auth token loaded from persistent storage");
559238
+ log70.info("\uD83D\uDD11 Auth token loaded from persistent storage");
559048
559239
  } else {
559049
559240
  const generated = randomUUID2().replace(/-/g, "");
559050
559241
  process.env.HIVE_AUTH_TOKEN = generated;
559051
559242
  mkdirSync11(path30.dirname(tokenFile), { recursive: true });
559052
559243
  writeFileSync5(tokenFile, generated, { mode: 384 });
559053
- log69.info("\uD83D\uDD11 Auth token auto-generated and persisted");
559244
+ log70.info("\uD83D\uDD11 Auth token auto-generated and persisted");
559054
559245
  }
559055
559246
  } else {
559056
559247
  writeFileSync5(tokenFile, process.env.HIVE_AUTH_TOKEN, { mode: 384 });
559057
- log69.info("\uD83D\uDD11 Auth token loaded from environment variable");
559248
+ log70.info("\uD83D\uDD11 Auth token loaded from environment variable");
559058
559249
  }
559059
559250
  let agent;
559060
559251
  let runner;
@@ -559084,7 +559275,7 @@ async function startGateway(config3) {
559084
559275
  },
559085
559276
  websocket: { open() {}, message() {}, close() {} }
559086
559277
  });
559087
- log69.info(`Port ${port} bound (initializing gateway...)`);
559278
+ log70.info(`Port ${port} bound (initializing gateway...)`);
559088
559279
  try {
559089
559280
  initializeDatabase();
559090
559281
  seedAllData();
@@ -559107,9 +559298,9 @@ async function startGateway(config3) {
559107
559298
  await channelManager.send(channel, sessionId, { content, type: "progress" });
559108
559299
  });
559109
559300
  if (gatewaySetupMode) {
559110
- log69.info("\uD83C\uDF89 Setup mode: gateway running \u2014 open http://localhost:" + port + "/setup to configure");
559301
+ log70.info("\uD83C\uDF89 Setup mode: gateway running \u2014 open http://localhost:" + port + "/setup to configure");
559111
559302
  } else {
559112
- log69.info("\u2705 Gateway initialization completed successfully");
559303
+ log70.info("\u2705 Gateway initialization completed successfully");
559113
559304
  try {
559114
559305
  const db = getDb();
559115
559306
  db.query(`
@@ -559123,18 +559314,18 @@ async function startGateway(config3) {
559123
559314
  setSchedulerInstance(scheduler);
559124
559315
  setSchedulerInstance2(scheduler);
559125
559316
  setSchedulerForCleanup(scheduler);
559126
- log69.info(`\uD83D\uDCC5 CronScheduler initialized with ${scheduler.getStatus().length} task(s)`);
559317
+ log70.info(`\uD83D\uDCC5 CronScheduler initialized with ${scheduler.getStatus().length} task(s)`);
559127
559318
  } catch (err) {
559128
- log69.error(`\u274C CronScheduler initialization failed: ${err.message}`);
559319
+ log70.error(`\u274C CronScheduler initialization failed: ${err.message}`);
559129
559320
  }
559130
559321
  }
559131
559322
  } catch (error50) {
559132
- log69.error(`\u274C Gateway initialization failed: ${error50.message}`);
559133
- log69.error("Stack trace:", error50.stack);
559323
+ log70.error(`\u274C Gateway initialization failed: ${error50.message}`);
559324
+ log70.error("Stack trace:", error50.stack);
559134
559325
  process.exit(1);
559135
559326
  }
559136
559327
  if (host === "0.0.0.0" && config3.security?.warnOnInsecureConfig !== false) {
559137
- log69.warn("Gateway binding to 0.0.0.0 exposes server to all network interfaces!");
559328
+ log70.warn("Gateway binding to 0.0.0.0 exposes server to all network interfaces!");
559138
559329
  }
559139
559330
  function prepareTools(agentInstance, sessionId) {
559140
559331
  return;
@@ -559142,17 +559333,17 @@ async function startGateway(config3) {
559142
559333
  const watchers = [];
559143
559334
  if (!gatewaySetupMode)
559144
559335
  channelManager.onMessage(async (message) => {
559145
- log69.info(`\uD83D\uDCE5 Message from ${message.channel}:${message.accountId}`);
559146
- log69.info(` Session: ${message.sessionId}`);
559336
+ log70.info(`\uD83D\uDCE5 Message from ${message.channel}:${message.accountId}`);
559337
+ log70.info(` Session: ${message.sessionId}`);
559147
559338
  const voiceConfig = voiceService.getChannelVoiceConfig(message.channel);
559148
559339
  let messageContent = message.content;
559149
559340
  let preferAudioResponse = false;
559150
559341
  let inputType = "text";
559151
559342
  let sttProviderUsed = null;
559152
559343
  if (voiceConfig.voiceEnabled && message.audio) {
559153
- log69.info(`\uD83C\uDF99\uFE0F Voice enabled, processing audio...`);
559344
+ log70.info(`\uD83C\uDF99\uFE0F Voice enabled, processing audio...`);
559154
559345
  if (!voiceConfig.sttProvider) {
559155
- log69.warn(`\u26A0\uFE0F STT provider not configured for channel ${message.channel}`);
559346
+ log70.warn(`\u26A0\uFE0F STT provider not configured for channel ${message.channel}`);
559156
559347
  await channelManager.send(message.channel, message.sessionId, {
559157
559348
  content: `\uD83C\uDF99\uFE0F Para usar notas de voz, necesitas configurar el proveedor STT en la configuraci\xF3n del canal. Ve a Configuraci\xF3n > Canales > [Tu canal] y configura "Prov. STT" (ej: groq-whisper o openai)`
559158
559349
  });
@@ -559162,7 +559353,7 @@ async function startGateway(config3) {
559162
559353
  const audioInput = voiceService.normalizeAudioFromChannel(message.channel, message.audio);
559163
559354
  sttProviderUsed = voiceConfig.sttProvider || "groq-whisper";
559164
559355
  messageContent = await voiceService.transcribe(audioInput, sttProviderUsed);
559165
- log69.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
559356
+ log70.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
559166
559357
  inputType = "audio_transcribed";
559167
559358
  preferAudioResponse = !!voiceConfig.ttsProvider;
559168
559359
  await channelManager.send(message.channel, message.sessionId, {
@@ -559170,14 +559361,14 @@ async function startGateway(config3) {
559170
559361
  type: "message"
559171
559362
  });
559172
559363
  } catch (error50) {
559173
- log69.error(`\u274C Transcription failed: ${error50.message}`);
559364
+ log70.error(`\u274C Transcription failed: ${error50.message}`);
559174
559365
  await channelManager.send(message.channel, message.sessionId, {
559175
559366
  content: `Error al transcribir audio: ${error50.message}`
559176
559367
  });
559177
559368
  return;
559178
559369
  }
559179
559370
  }
559180
- log69.info(` Content: ${messageContent.substring(0, 150)}${messageContent.length > 150 ? "..." : ""}`);
559371
+ log70.info(` Content: ${messageContent.substring(0, 150)}${messageContent.length > 150 ? "..." : ""}`);
559181
559372
  const { userId } = resolveContext({
559182
559373
  channel: message.channel,
559183
559374
  channelUserId: message.sessionId
@@ -559208,7 +559399,7 @@ async function startGateway(config3) {
559208
559399
  ${messageContent}`;
559209
559400
  const messages2 = [{ role: "user", content: messageContentWithTime }];
559210
559401
  try {
559211
- log69.info(`\uD83E\uDD16 Routing to agent loop...`);
559402
+ log70.info(`\uD83E\uDD16 Routing to agent loop...`);
559212
559403
  const response = await runner.generate({
559213
559404
  provider: dbProvider,
559214
559405
  messages: messages2,
@@ -559223,7 +559414,7 @@ ${messageContent}`;
559223
559414
  if (step.type === "text" && step.message) {
559224
559415
  const trimmedMessage = (typeof step.message === "string" ? step.message : "").trim();
559225
559416
  if (trimmedMessage) {
559226
- log69.debug(`[NARRATION] ${trimmedMessage.substring(0, 100)}`);
559417
+ log70.debug(`[NARRATION] ${trimmedMessage.substring(0, 100)}`);
559227
559418
  await channelManager.send(message.channel, routingSessionId, {
559228
559419
  content: trimmedMessage,
559229
559420
  type: "progress"
@@ -559233,7 +559424,7 @@ ${messageContent}`;
559233
559424
  }
559234
559425
  if (step.type === "tool_call" && step.toolName) {
559235
559426
  const narration = getNarration(step.toolName);
559236
- log69.debug(`[TOOL] ${step.toolName} \u2192 "${narration}"`);
559427
+ log70.debug(`[TOOL] ${step.toolName} \u2192 "${narration}"`);
559237
559428
  await channelManager.send(message.channel, routingSessionId, {
559238
559429
  content: narration,
559239
559430
  type: "progress"
@@ -559257,10 +559448,10 @@ ${messageContent}`;
559257
559448
  });
559258
559449
  const responseContent = response.content?.trim() || "";
559259
559450
  if (!responseContent) {
559260
- log69.warn(`\uD83D\uDCE4 LLM response: empty \u2014 skipping send`);
559451
+ log70.warn(`\uD83D\uDCE4 LLM response: empty \u2014 skipping send`);
559261
559452
  return;
559262
559453
  }
559263
- log69.info(`\uD83D\uDCE4 LLM response: ${responseContent.substring(0, 100)}${responseContent.length > 100 ? "..." : ""}`);
559454
+ log70.info(`\uD83D\uDCE4 LLM response: ${responseContent.substring(0, 100)}${responseContent.length > 100 ? "..." : ""}`);
559264
559455
  const shouldSpeak = preferAudioResponse;
559265
559456
  let responseType = "text";
559266
559457
  let ttsProviderUsed = null;
@@ -559268,7 +559459,7 @@ ${messageContent}`;
559268
559459
  if (responseContent) {
559269
559460
  if (shouldSpeak) {
559270
559461
  if (!voiceConfig.ttsProvider) {
559271
- log69.warn(`\u26A0\uFE0F TTS provider not configured, user requested audio`);
559462
+ log70.warn(`\u26A0\uFE0F TTS provider not configured, user requested audio`);
559272
559463
  await channelManager.send(message.channel, routingSessionId, {
559273
559464
  content: `${responseContent}
559274
559465
 
@@ -559276,7 +559467,7 @@ ${messageContent}`;
559276
559467
  });
559277
559468
  } else {
559278
559469
  try {
559279
- log69.info(`\uD83D\uDD0A TTS enabled, synthesizing audio...`);
559470
+ log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio...`);
559280
559471
  const audioOutput = await voiceService.speak(responseContent, voiceConfig.ttsProvider, voiceConfig.ttsVoiceId || undefined);
559281
559472
  ttsProviderUsed = voiceConfig.ttsProvider;
559282
559473
  ttsMimeType = audioOutput.mimeType;
@@ -559285,17 +559476,17 @@ ${messageContent}`;
559285
559476
  const channel = channelManager.getChannel(message.channel);
559286
559477
  if (channel?.sendAudio) {
559287
559478
  await channel.sendAudio(routingSessionId, audioOutput.data, audioOutput.mimeType);
559288
- log69.info(`\u2705 Audio sent to ${routingSessionId}`);
559479
+ log70.info(`\u2705 Audio sent to ${routingSessionId}`);
559289
559480
  } else {
559290
- log69.warn(`Channel ${message.channel} does not support audio, sending text`);
559481
+ log70.warn(`Channel ${message.channel} does not support audio, sending text`);
559291
559482
  await channelManager.send(message.channel, routingSessionId, { content: responseContent });
559292
559483
  }
559293
559484
  } catch (audioError) {
559294
- log69.error(`\u274C Audio send failed: ${audioError.message}, sending text instead`);
559485
+ log70.error(`\u274C Audio send failed: ${audioError.message}, sending text instead`);
559295
559486
  await channelManager.send(message.channel, routingSessionId, { content: responseContent });
559296
559487
  }
559297
559488
  } catch (ttsError) {
559298
- log69.error(`\u274C TTS failed: ${ttsError.message}, sending text instead`);
559489
+ log70.error(`\u274C TTS failed: ${ttsError.message}, sending text instead`);
559299
559490
  await channelManager.send(message.channel, routingSessionId, { content: responseContent });
559300
559491
  }
559301
559492
  }
@@ -559310,10 +559501,10 @@ ${messageContent}`;
559310
559501
  channel: message.channel
559311
559502
  };
559312
559503
  await channelManager.stopTyping(message.channel, routingSessionId);
559313
- log69.info(`\u2705 Response sent to ${routingSessionId} via ${message.channel}`);
559504
+ log70.info(`\u2705 Response sent to ${routingSessionId} via ${message.channel}`);
559314
559505
  } catch (error50) {
559315
559506
  await channelManager.stopTyping(message.channel, routingSessionId);
559316
- log69.error(`\u274C Error: ${error50.message} `);
559507
+ log70.error(`\u274C Error: ${error50.message} `);
559317
559508
  await channelManager.send(message.channel, routingSessionId, {
559318
559509
  content: `Error: ${error50.message} `
559319
559510
  });
@@ -559323,6 +559514,8 @@ ${messageContent}`;
559323
559514
  function checkAuth(req, url3) {
559324
559515
  if (isDev)
559325
559516
  return true;
559517
+ if (gatewaySetupMode)
559518
+ return true;
559326
559519
  if (url3.pathname.startsWith("/api/setup/"))
559327
559520
  return true;
559328
559521
  const activeToken = process.env.HIVE_AUTH_TOKEN;
@@ -559339,9 +559532,9 @@ ${messageContent}`;
559339
559532
  const method = req.method;
559340
559533
  const logRequest = (status, duration3) => {
559341
559534
  if (url3.pathname === "/health" || url3.pathname === "/health/") {
559342
- log69.debug(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
559535
+ log70.debug(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
559343
559536
  } else {
559344
- log69.info(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
559537
+ log70.info(`${method} ${url3.pathname} - ${status} (${duration3}ms)`);
559345
559538
  }
559346
559539
  };
559347
559540
  const handleRequest = async () => {
@@ -559362,8 +559555,15 @@ ${messageContent}`;
559362
559555
  return new Response(null, { status: 204 });
559363
559556
  }
559364
559557
  if (url3.pathname === "/ws" || url3.pathname === "/ws/") {
559365
- const sessionId = url3.searchParams.get("session") || resolveUserId({}) || "default";
559366
- if (!isDev) {
559558
+ let sessionId = url3.searchParams.get("session") || resolveUserId({}) || "default";
559559
+ if (!isDev && !gatewaySetupMode) {
559560
+ const tokenParam = url3.searchParams.get("token");
559561
+ const activeToken = process.env.HIVE_AUTH_TOKEN;
559562
+ if (tokenParam && activeToken && tokenParam === activeToken) {
559563
+ const user = getDb().query("SELECT id FROM users LIMIT 1").get();
559564
+ if (user)
559565
+ sessionId = user.id;
559566
+ }
559367
559567
  try {
559368
559568
  const userExists = getDb().query("SELECT 1 FROM users WHERE id = ? LIMIT 1").get(sessionId);
559369
559569
  if (!userExists) {
@@ -559408,7 +559608,7 @@ ${messageContent}`;
559408
559608
  }
559409
559609
  if (url3.pathname === "/health" || url3.pathname === "/health/") {
559410
559610
  const uptime = Math.floor((Date.now() - startTime2) / 1000);
559411
- return addCorsHeaders(Response.json({ status: "ok", version: "1.7.18", uptime }), req);
559611
+ return addCorsHeaders(Response.json({ status: "ok", version: _pkgVersion, uptime }), req);
559412
559612
  }
559413
559613
  const isApiRequest = url3.pathname.startsWith("/api");
559414
559614
  const isWsRequest = url3.pathname.startsWith("/ws");
@@ -559427,7 +559627,8 @@ ${messageContent}`;
559427
559627
  const uiDir = uiDirFromEnv || (existsSync18(path30.join(uiDirFromHive, "index.html")) ? uiDirFromHive : uiDirFromCwd);
559428
559628
  let subPath = url3.pathname;
559429
559629
  if (gatewaySetupMode && (subPath === "/" || subPath === "/ui" || subPath === "/ui/")) {
559430
- return Response.redirect(`http://${host}:${port}/setup`, 302);
559630
+ const _publicBase = process.env.HIVE_PUBLIC_URL?.replace(/\/$/, "") ?? `http://${host === "0.0.0.0" ? "localhost" : host}:${port}`;
559631
+ return Response.redirect(`${_publicBase}/setup`, 302);
559431
559632
  }
559432
559633
  if (subPath === "/ui" || subPath === "/ui/") {
559433
559634
  subPath = "/index.html";
@@ -559450,6 +559651,12 @@ ${messageContent}`;
559450
559651
  if (await uiFile.exists()) {
559451
559652
  return new Response(uiFile);
559452
559653
  }
559654
+ if (!path30.extname(subPath)) {
559655
+ const indexFile = Bun.file(path30.join(uiDir, "index.html"));
559656
+ if (await indexFile.exists()) {
559657
+ return new Response(indexFile);
559658
+ }
559659
+ }
559453
559660
  if (isUiRequest || isSetupRequest) {
559454
559661
  return new Response(`UI not found.
559455
559662
 
@@ -559465,7 +559672,7 @@ ${messageContent}`;
559465
559672
  return Response.redirect(`/ ui${tokenParam} `, 301);
559466
559673
  }
559467
559674
  if (!checkAuth(req, url3)) {
559468
- log69.warn(`[AUTH] Unauthorized request to ${url3.pathname} from ${req.headers.get("origin")} `);
559675
+ log70.warn(`[AUTH] Unauthorized request to ${url3.pathname} from ${req.headers.get("origin")} `);
559469
559676
  return addCorsHeaders(new Response("Unauthorized", { status: 401 }), req);
559470
559677
  }
559471
559678
  if (url3.pathname === "/api/setup/status" || url3.pathname === "/api/setup/status/") {
@@ -559664,7 +559871,7 @@ ${messageContent}`;
559664
559871
  return await handleApiReload(req, addCorsHeaders, agent);
559665
559872
  }
559666
559873
  if (url3.pathname === "/api/user/channels" && req.method === "POST") {
559667
- return await handleLinkUserChannel(req, addCorsHeaders, config3, log69);
559874
+ return await handleLinkUserChannel(req, addCorsHeaders, config3, log70);
559668
559875
  }
559669
559876
  if (url3.pathname === "/api/user/channels" && req.method === "GET") {
559670
559877
  return await handleGetUserChannels(req, addCorsHeaders, config3);
@@ -559794,16 +560001,16 @@ ${messageContent}`;
559794
560001
  if (active === undefined) {
559795
560002
  return addCorsHeaders(Response.json({ success: false, error: "Missing active field" }, { status: 400 }), req);
559796
560003
  }
559797
- log69.info(`[MCP] Toggle connection for ${mcpName}, active=${active}`);
560004
+ log70.info(`[MCP] Toggle connection for ${mcpName}, active=${active}`);
559798
560005
  getDb().query(`UPDATE mcp_servers SET active = ?, enabled = ? WHERE id = ? OR name = ?`).run(active ? 1 : 0, active ? 1 : 0, mcpName, mcpName);
559799
560006
  try {
559800
560007
  const mcp = agent?.getMCPManager() ?? null;
559801
560008
  if (mcp) {
559802
- log69.info(`[MCP] Manager found, connecting ${mcpName}...`);
560009
+ log70.info(`[MCP] Manager found, connecting ${mcpName}...`);
559803
560010
  if (active) {
559804
560011
  const server4 = getDb().query(`SELECT * FROM mcp_servers WHERE id = ? OR name = ?`).get(mcpName, mcpName);
559805
560012
  if (server4) {
559806
- log69.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
560013
+ log70.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
559807
560014
  const mcpServerConfig = {
559808
560015
  transport: server4.transport,
559809
560016
  command: server4.command,
@@ -559815,7 +560022,7 @@ ${messageContent}`;
559815
560022
  try {
559816
560023
  mcpServerConfig.headers = decryptConfig(server4.headers_encrypted, server4.headers_iv);
559817
560024
  } catch (e) {
559818
- log69.warn(`Failed to decrypt headers for ${mcpName}`);
560025
+ log70.warn(`Failed to decrypt headers for ${mcpName}`);
559819
560026
  }
559820
560027
  }
559821
560028
  const currentConfig = mcp.config || { servers: {} };
@@ -559825,22 +560032,22 @@ ${messageContent}`;
559825
560032
  ...currentConfig,
559826
560033
  servers: newServersConfig
559827
560034
  });
559828
- log69.info(`[MCP] Server registered in MCP Manager`);
560035
+ log70.info(`[MCP] Server registered in MCP Manager`);
559829
560036
  const tools = mcp.getServerTools(mcpName) || [];
559830
- log69.info(`[MCP] Connected! Tools: ${tools.length}`);
560037
+ log70.info(`[MCP] Connected! Tools: ${tools.length}`);
559831
560038
  getDb().query(`UPDATE mcp_servers SET status = ?, tools_count = ? WHERE id = ? OR name = ?`).run("connected", tools.length, mcpName, mcpName);
559832
560039
  } else {
559833
- log69.error(`[MCP] Server not found in DB: ${mcpName}`);
560040
+ log70.error(`[MCP] Server not found in DB: ${mcpName}`);
559834
560041
  }
559835
560042
  } else {
559836
560043
  await mcp.disconnectServer(mcpName);
559837
560044
  getDb().query(`UPDATE mcp_servers SET status = ? WHERE id = ? OR name = ?`).run("disconnected", mcpName, mcpName);
559838
560045
  }
559839
560046
  } else {
559840
- log69.error(`[MCP] No MCP Manager found`);
560047
+ log70.error(`[MCP] No MCP Manager found`);
559841
560048
  }
559842
560049
  } catch (error50) {
559843
- log69.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
560050
+ log70.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
559844
560051
  }
559845
560052
  return addCorsHeaders(Response.json({ success: true, active, message: active ? "Servidor MCP conectado" : "Servidor MCP desconectado" }), req);
559846
560053
  }
@@ -559867,7 +560074,7 @@ ${messageContent}`;
559867
560074
  if (active) {
559868
560075
  const server4 = getDb().query(`SELECT * FROM mcp_servers WHERE id = ? OR name = ?`).get(mcpName, mcpName);
559869
560076
  if (server4) {
559870
- log69.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
560077
+ log70.info(`[MCP] Server config: transport=${server4.transport}, url=${server4.url}`);
559871
560078
  const mcpServerConfig = {
559872
560079
  transport: server4.transport,
559873
560080
  command: server4.command,
@@ -559879,7 +560086,7 @@ ${messageContent}`;
559879
560086
  try {
559880
560087
  mcpServerConfig.headers = decryptConfig(server4.headers_encrypted, server4.headers_iv);
559881
560088
  } catch (e) {
559882
- log69.warn(`Failed to decrypt headers for ${mcpName}`);
560089
+ log70.warn(`Failed to decrypt headers for ${mcpName}`);
559883
560090
  }
559884
560091
  }
559885
560092
  const currentConfig = mcp.config || { servers: {} };
@@ -559889,12 +560096,12 @@ ${messageContent}`;
559889
560096
  ...currentConfig,
559890
560097
  servers: newServersConfig
559891
560098
  });
559892
- log69.info(`[MCP] Server registered in MCP Manager`);
560099
+ log70.info(`[MCP] Server registered in MCP Manager`);
559893
560100
  const tools = mcp.getServerTools(mcpName) || [];
559894
- log69.info(`[MCP] Connected! Tools: ${tools.length}`);
560101
+ log70.info(`[MCP] Connected! Tools: ${tools.length}`);
559895
560102
  getDb().query(`UPDATE mcp_servers SET status = ?, tools_count = ? WHERE id = ? OR name = ?`).run("connected", tools.length, mcpName, mcpName);
559896
560103
  } else {
559897
- log69.error(`[MCP] Server not found in DB: ${mcpName}`);
560104
+ log70.error(`[MCP] Server not found in DB: ${mcpName}`);
559898
560105
  }
559899
560106
  } else {
559900
560107
  await mcp.disconnectServer(mcpName);
@@ -559902,7 +560109,7 @@ ${messageContent}`;
559902
560109
  }
559903
560110
  }
559904
560111
  } catch (error50) {
559905
- log69.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
560112
+ log70.error(`[MCP] Failed to connect ${mcpName}: ${error50.message}`);
559906
560113
  }
559907
560114
  return addCorsHeaders(Response.json({ success: true, active, message: active ? "Servidor MCP conectado" : "Servidor MCP desconectado" }), req);
559908
560115
  }
@@ -560022,12 +560229,12 @@ ${messageContent}`;
560022
560229
  if (response) {
560023
560230
  logRequest(response.status, duration3);
560024
560231
  } else {
560025
- log69.info(`${method} ${url3.pathname} - 101 Switching Protocols(${duration3}ms)`);
560232
+ log70.info(`${method} ${url3.pathname} - 101 Switching Protocols(${duration3}ms)`);
560026
560233
  }
560027
560234
  return response;
560028
560235
  } catch (error50) {
560029
560236
  const duration3 = Date.now() - start;
560030
- log69.error(`${method} ${url3.pathname} - Internal Error(${duration3}ms): ${error50.message} `);
560237
+ log70.error(`${method} ${url3.pathname} - Internal Error(${duration3}ms): ${error50.message} `);
560031
560238
  return addCorsHeaders(Response.json({ success: false, error: error50.message, message: "Error interno del servidor" }, { status: 500 }), req);
560032
560239
  }
560033
560240
  },
@@ -560037,20 +560244,20 @@ ${messageContent}`;
560037
560244
  const isCanvas = data.sessionId.startsWith("canvas:");
560038
560245
  const isBridge = data.sessionId.startsWith("bridge:");
560039
560246
  if (isBridge) {
560040
- log69.info(`Bridge events client connected: ${data.sessionId}`);
560247
+ log70.info(`Bridge events client connected: ${data.sessionId}`);
560041
560248
  subscribeBridge(ws);
560042
560249
  ws.send(JSON.stringify({ type: "bridge:connected", sessionId: data.sessionId }));
560043
560250
  return;
560044
560251
  }
560045
560252
  if (isCanvas) {
560046
- log69.info(`Canvas session connected: ${data.sessionId} `);
560253
+ log70.info(`Canvas session connected: ${data.sessionId} `);
560047
560254
  canvasManager.registerSession(data.sessionId, ws);
560048
560255
  subscribeCanvas(ws);
560049
560256
  ws.send(JSON.stringify({ type: "canvas:connected", sessionId: data.sessionId }));
560050
560257
  ws.send(JSON.stringify({ type: "canvas:snapshot", data: getCanvasSnapshot() }));
560051
560258
  return;
560052
560259
  }
560053
- log69.debug(`WebSocket connected: ${data.sessionId} `);
560260
+ log70.debug(`WebSocket connected: ${data.sessionId} `);
560054
560261
  sessionManager.create(data.sessionId, ws);
560055
560262
  const channel = channelManager?.getChannel("webchat");
560056
560263
  if (channel?.registerConnection)
@@ -560081,13 +560288,19 @@ ${messageContent}`;
560081
560288
  codeBridge: codeBridge.map((cb) => cb.id)
560082
560289
  }));
560083
560290
  } catch (err) {
560084
- log69.error("Error sending welcome message:", err);
560291
+ log70.error("Error sending welcome message:", err);
560085
560292
  }
560086
560293
  },
560087
560294
  async message(ws, message) {
560088
560295
  const data = ws.data;
560089
- if (data.sessionId.startsWith("bridge:"))
560296
+ if (data.sessionId.startsWith("bridge:")) {
560297
+ try {
560298
+ const m2 = JSON.parse(message.toString());
560299
+ if (m2?.type === "ping")
560300
+ ws.send(JSON.stringify({ type: "pong" }));
560301
+ } catch {}
560090
560302
  return;
560303
+ }
560091
560304
  let msg;
560092
560305
  try {
560093
560306
  msg = JSON.parse(message.toString());
@@ -560130,17 +560343,17 @@ ${messageContent}`;
560130
560343
  }
560131
560344
  if (msg.type === "logs_subscribe") {
560132
560345
  logSubscribers.add(data.sessionId);
560133
- log69.debug(`Session ${data.sessionId} subscribed to logs`);
560346
+ log70.debug(`Session ${data.sessionId} subscribed to logs`);
560134
560347
  return;
560135
560348
  }
560136
560349
  if (msg.type === "logs_unsubscribe") {
560137
560350
  logSubscribers.delete(data.sessionId);
560138
- log69.debug(`Session ${data.sessionId} unsubscribed from logs`);
560351
+ log70.debug(`Session ${data.sessionId} unsubscribed from logs`);
560139
560352
  return;
560140
560353
  }
560141
560354
  let webchatPreferAudio = false;
560142
560355
  if (msg.type === "audio" && msg.audio) {
560143
- log69.info(`WebChat audio from session ${msg.sessionId}`);
560356
+ log70.info(`WebChat audio from session ${msg.sessionId}`);
560144
560357
  const voiceConfig = voiceService.getChannelVoiceConfig("webchat");
560145
560358
  if (!voiceConfig.voiceEnabled) {
560146
560359
  ws.send(JSON.stringify({
@@ -560167,7 +560380,7 @@ ${messageContent}`;
560167
560380
  const audioInput = { type: "base64", data: msg.audio, mimeType: "audio/webm" };
560168
560381
  const sttProvider = voiceConfig.sttProvider || "groq-whisper";
560169
560382
  const messageContent = await voiceService.transcribe(audioInput, sttProvider);
560170
- log69.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
560383
+ log70.info(`\uD83D\uDCDD Transcribed: ${messageContent.substring(0, 100)}...`);
560171
560384
  webchatPreferAudio = true;
560172
560385
  ws.send(JSON.stringify({
560173
560386
  type: "message",
@@ -560188,7 +560401,7 @@ ${messageContent}`;
560188
560401
  try {
560189
560402
  const unifiedSessionId = msg.sessionId;
560190
560403
  const messages2 = [{ role: "user", content: messageContent }];
560191
- log69.info(`Generating response for session ${unifiedSessionId}...`);
560404
+ log70.info(`Generating response for session ${unifiedSessionId}...`);
560192
560405
  const { userId } = resolveContext({
560193
560406
  channel: "webchat",
560194
560407
  channelUserId: msg.sessionId
@@ -560234,11 +560447,11 @@ ${messageContent}`;
560234
560447
  }
560235
560448
  } catch {}
560236
560449
  }
560237
- log69.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
560450
+ log70.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
560238
560451
  }
560239
560452
  });
560240
560453
  const content = streamedContent || response.content?.trim() || "";
560241
- log69.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
560454
+ log70.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
560242
560455
  const voiceCfg = voiceService.getChannelVoiceConfig("webchat");
560243
560456
  const shouldSpeak = webchatPreferAudio;
560244
560457
  let responseType = "text";
@@ -560259,7 +560472,7 @@ ${messageContent}`;
560259
560472
  }));
560260
560473
  } else {
560261
560474
  try {
560262
- log69.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
560475
+ log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
560263
560476
  const audioOutput = await voiceService.speak(content, voiceCfg.ttsProvider, voiceCfg.ttsVoiceId || undefined);
560264
560477
  ttsProviderUsed = voiceCfg.ttsProvider;
560265
560478
  ttsMimeType = audioOutput.mimeType;
@@ -560273,7 +560486,7 @@ ${messageContent}`;
560273
560486
  mimeType: audioOutput.mimeType
560274
560487
  }));
560275
560488
  } catch (ttsError) {
560276
- log69.error(`TTS failed: ${ttsError.message}), sending text instead`);
560489
+ log70.error(`TTS failed: ${ttsError.message}), sending text instead`);
560277
560490
  ws.send(JSON.stringify({ type: "message", sessionId: unifiedSessionId, content, isStep: false }));
560278
560491
  }
560279
560492
  }
@@ -560288,7 +560501,7 @@ ${messageContent}`;
560288
560501
  sessionId: msg.sessionId,
560289
560502
  error: error50.message
560290
560503
  }));
560291
- log69.error(`Error for session ${msg.sessionId}: ${error50.message}`);
560504
+ log70.error(`Error for session ${msg.sessionId}: ${error50.message}`);
560292
560505
  }
560293
560506
  });
560294
560507
  } catch (error50) {
@@ -560306,7 +560519,7 @@ ${messageContent}`;
560306
560519
  return;
560307
560520
  }
560308
560521
  if (msg.type === "message" && msg.content) {
560309
- log69.info(`WebChat message from session ${msg.sessionId}: ${msg.content.substring(0, 100)}`);
560522
+ log70.info(`WebChat message from session ${msg.sessionId}: ${msg.content.substring(0, 100)}`);
560310
560523
  ws.send(JSON.stringify({
560311
560524
  type: "typing",
560312
560525
  isTyping: true,
@@ -560321,7 +560534,7 @@ ${messageContent}`;
560321
560534
  try {
560322
560535
  const unifiedSessionId = msg.sessionId;
560323
560536
  const messages2 = [{ role: "user", content: msg.content }];
560324
- log69.info(`Generating response for session ${unifiedSessionId}...`);
560537
+ log70.info(`Generating response for session ${unifiedSessionId}...`);
560325
560538
  const { userId } = resolveContext({
560326
560539
  channel: "webchat",
560327
560540
  channelUserId: msg.sessionId
@@ -560367,11 +560580,11 @@ ${messageContent}`;
560367
560580
  }
560368
560581
  } catch {}
560369
560582
  }
560370
- log69.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
560583
+ log70.debug(`[TOOL] ${step.type}: ${step.toolName || ""}`);
560371
560584
  }
560372
560585
  });
560373
560586
  const content = streamedContent || response.content?.trim() || "";
560374
- log69.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
560587
+ log70.info(`Response sent to session ${unifiedSessionId} (${content.length} chars)`);
560375
560588
  const voiceConfig = voiceService.getChannelVoiceConfig("webchat");
560376
560589
  const shouldSpeak = webchatPreferAudio;
560377
560590
  let responseType = "text";
@@ -560392,7 +560605,7 @@ ${messageContent}`;
560392
560605
  }));
560393
560606
  } else {
560394
560607
  try {
560395
- log69.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
560608
+ log70.info(`\uD83D\uDD0A TTS enabled, synthesizing audio for WebChat...`);
560396
560609
  const audioOutput = await voiceService.speak(content, voiceConfig.ttsProvider, voiceConfig.ttsVoiceId || undefined);
560397
560610
  ttsProviderUsed = voiceConfig.ttsProvider;
560398
560611
  ttsMimeType = audioOutput.mimeType;
@@ -560406,7 +560619,7 @@ ${messageContent}`;
560406
560619
  mimeType: audioOutput.mimeType
560407
560620
  }));
560408
560621
  } catch (ttsError) {
560409
- log69.error(`TTS failed: ${ttsError.message}), sending text instead`);
560622
+ log70.error(`TTS failed: ${ttsError.message}), sending text instead`);
560410
560623
  ws.send(JSON.stringify({ type: "message", sessionId: unifiedSessionId, content, isStep: false }));
560411
560624
  }
560412
560625
  }
@@ -560422,7 +560635,7 @@ ${messageContent}`;
560422
560635
  sessionId: unifiedSessionId,
560423
560636
  error: error50.message
560424
560637
  }));
560425
- log69.error(`Error for session ${unifiedSessionId}: ${error50.message}`);
560638
+ log70.error(`Error for session ${unifiedSessionId}: ${error50.message}`);
560426
560639
  }
560427
560640
  });
560428
560641
  return;
@@ -560446,7 +560659,7 @@ ${messageContent}`;
560446
560659
  unsubscribeCanvas(ws);
560447
560660
  return;
560448
560661
  }
560449
- log69.debug(`WebSocket disconnected: ${data.sessionId}`);
560662
+ log70.debug(`WebSocket disconnected: ${data.sessionId}`);
560450
560663
  logSubscribers.delete(data.sessionId);
560451
560664
  sessionManager.delete(data.sessionId);
560452
560665
  laneQueue.cancel(data.sessionId);
@@ -560477,25 +560690,25 @@ ${messageContent}`;
560477
560690
  }
560478
560691
  }
560479
560692
  });
560480
- log69.info(`Gateway started successfully`);
560693
+ log70.info(`Gateway started successfully`);
560481
560694
  const isGatewayChild = process.env.HIVE_GATEWAY_CHILD === "1";
560482
560695
  if (isDev) {
560483
- log69.info(`[gateway] API: http://${host}:${port}`);
560484
- log69.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
560485
- log69.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
560486
- log69.info(`[gateway] Modo: desarrollo`);
560696
+ log70.info(`[gateway] API: http://${host}:${port}`);
560697
+ log70.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
560698
+ log70.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
560699
+ log70.info(`[gateway] Modo: desarrollo`);
560487
560700
  if (!isGatewayChild) {
560488
- log69.info(`\uD83D\uDC1D Administra tu Hive aqu\xED: http://localhost:5173`);
560701
+ log70.info(`\uD83D\uDC1D Administra tu Hive aqu\xED: http://localhost:5173`);
560489
560702
  }
560490
560703
  } else {
560491
560704
  const isSetupMode2 = gatewaySetupMode;
560492
- const baseUrl = `http://${host}:${port}`;
560705
+ const baseUrl = process.env.HIVE_PUBLIC_URL?.replace(/\/$/, "") ?? `http://${host}:${port}`;
560493
560706
  const uiUrl = isSetupMode2 ? `${baseUrl}/setup` : `${baseUrl}/ui`;
560494
- log69.info(`[gateway] UI: ${uiUrl}`);
560495
- log69.info(`[gateway] API: http://${host}:${port}`);
560496
- log69.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
560497
- log69.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
560498
- log69.info(isSetupMode2 ? `\uD83C\uDF89 Primer arranque \u2014 abriendo wizard de configuraci\xF3n...` : `\uD83D\uDC1D Administra tu Hive aqu\xED: ${uiUrl}`);
560707
+ log70.info(`[gateway] UI: ${uiUrl}`);
560708
+ log70.info(`[gateway] API: http://${host}:${port}`);
560709
+ log70.info(`[gateway] WebSocket: ws://${host}:${port}/ws`);
560710
+ log70.info(`[gateway] Canvas: ws://${host}:${port}/canvas`);
560711
+ log70.info(isSetupMode2 ? `\uD83C\uDF89 Primer arranque \u2014 abriendo wizard de configuraci\xF3n...` : `\uD83D\uDC1D Administra tu Hive aqu\xED: ${uiUrl}`);
560499
560712
  if (!process.env.NO_BROWSER) {
560500
560713
  try {
560501
560714
  const platform2 = process.platform;
@@ -560516,18 +560729,18 @@ ${messageContent}`;
560516
560729
  });
560517
560730
  proc.unref();
560518
560731
  } catch (err) {
560519
- log69.warn(`Could not open browser: ${err.message}`);
560732
+ log70.warn(`Could not open browser: ${err.message}`);
560520
560733
  }
560521
560734
  }
560522
560735
  }
560523
560736
  if (!gatewaySetupMode)
560524
- log69.info(`Channels: ${channelManager.listChannels().map((c3) => c3.name).join(", ") || "none"}`);
560737
+ log70.info(`Channels: ${channelManager.listChannels().map((c3) => c3.name).join(", ") || "none"}`);
560525
560738
  process.on("SIGTERM", async () => {
560526
- log69.info("Received SIGTERM, shutting down gracefully...");
560739
+ log70.info("Received SIGTERM, shutting down gracefully...");
560527
560740
  watchers.forEach((close) => close());
560528
560741
  const mcp = agent?.getMCPManager();
560529
560742
  if (mcp) {
560530
- log69.info("Disconnecting MCP servers...");
560743
+ log70.info("Disconnecting MCP servers...");
560531
560744
  await mcp.disconnectAll().catch(() => {});
560532
560745
  }
560533
560746
  if (channelManager)
@@ -560539,18 +560752,18 @@ ${messageContent}`;
560539
560752
  process.exit(0);
560540
560753
  });
560541
560754
  process.on("SIGHUP", async () => {
560542
- log69.info("Received SIGHUP, reloading configuration...");
560755
+ log70.info("Received SIGHUP, reloading configuration...");
560543
560756
  try {
560544
560757
  const newConfig = await loadConfig();
560545
560758
  await agent.updateConfig(newConfig);
560546
560759
  await agent.reload();
560547
- log69.info("Configuration reloaded successfully");
560760
+ log70.info("Configuration reloaded successfully");
560548
560761
  } catch (error50) {
560549
- log69.error(`Failed to reload configuration: ${error50.message}`);
560762
+ log70.error(`Failed to reload configuration: ${error50.message}`);
560550
560763
  }
560551
560764
  });
560552
560765
  }
560553
- var logSubscribers;
560766
+ var _pkgVersion, logSubscribers;
560554
560767
  var init_server = __esm(() => {
560555
560768
  init_loader();
560556
560769
  init_logger();
@@ -560593,6 +560806,14 @@ var init_server = __esm(() => {
560593
560806
  init_schedule();
560594
560807
  init_scheduled_tasks();
560595
560808
  init_scheduled_tasks();
560809
+ _pkgVersion = (() => {
560810
+ try {
560811
+ const pkgPath = path30.join(import.meta.dir, "../../../package.json");
560812
+ return JSON.parse(readFileSync9(pkgPath, "utf-8")).version;
560813
+ } catch {
560814
+ return "2.0.3";
560815
+ }
560816
+ })();
560596
560817
  logSubscribers = new Set;
560597
560818
  });
560598
560819
 
@@ -562644,7 +562865,8 @@ var init_schemas4 = __esm(() => {
562644
562865
  prompt: exports_external.string()
562645
562866
  }),
562646
562867
  exports_external.object({ cmd: exports_external.literal("cancel"), taskId: exports_external.string() }),
562647
- exports_external.object({ cmd: exports_external.literal("status") })
562868
+ exports_external.object({ cmd: exports_external.literal("status") }),
562869
+ exports_external.object({ cmd: exports_external.literal("ping") })
562648
562870
  ]);
562649
562871
  });
562650
562872
 
@@ -562716,6 +562938,10 @@ var init_src4 = __esm(() => {
562716
562938
  ws.send(JSON.stringify(manager4.status()));
562717
562939
  break;
562718
562940
  }
562941
+ case "ping": {
562942
+ ws.send(JSON.stringify({ type: "pong" }));
562943
+ break;
562944
+ }
562719
562945
  }
562720
562946
  },
562721
562947
  close(ws) {
@@ -562880,7 +563106,7 @@ async function start(flags) {
562880
563106
  \u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2551
562881
563107
  \u2551 \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u2551
562882
563108
  \u2551 \u2551
562883
- \u2551 Personal Swarm AI Gateway \u2014 v2.0.2 \u2551
563109
+ \u2551 Personal Swarm AI Gateway \u2014 v2.0.4 \u2551
562884
563110
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
562885
563111
  `);
562886
563112
  }
@@ -563006,6 +563232,12 @@ async function start(flags) {
563006
563232
  }
563007
563233
  return;
563008
563234
  }
563235
+ try {
563236
+ await Promise.resolve().then(() => (init_src4(), exports_src));
563237
+ console.log("\uD83C\uDF09 Code Bridge iniciado en puerto 18791");
563238
+ } catch (error50) {
563239
+ console.warn(`\u26A0\uFE0F No se pudo iniciar el Code Bridge: ${error50.message}`);
563240
+ }
563009
563241
  if (!daemon && !isGatewayChild) {
563010
563242
  const port = config4.gateway?.port || 18790;
563011
563243
  waitForPort(port, 30000).then(() => {
@@ -565090,7 +565322,7 @@ async function executeAsync(gatewayUrl, payload, spinner) {
565090
565322
  }
565091
565323
 
565092
565324
  // packages/cli/src/index.ts
565093
- var VERSION4 = "2.0.2";
565325
+ var VERSION4 = "2.0.4";
565094
565326
  var HELP = `
565095
565327
  \uD83D\uDC1D Hive \u2014 Personal Swarm AI Gateway v${VERSION4}
565096
565328