@johpaz/hive-sdk 0.1.4 → 0.1.5

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 (272) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +78 -23
  3. package/bunfig.toml +4 -2
  4. package/docs/API-AGENTS.md +78 -27
  5. package/docs/API-CONTEXT-COMPILER.md +31 -34
  6. package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
  7. package/docs/HIVE-HARNESS.md +1 -1
  8. package/docs/INDEX.md +4 -4
  9. package/docs/TEMPLATE-HIVE-APP.md +10 -10
  10. package/package.json +9 -4
  11. package/packages/cli/package.json +2 -2
  12. package/packages/cli/src/commands/create-app.test.ts +36 -7
  13. package/packages/cli/src/commands/init.ts +3 -3
  14. package/packages/cli/src/commands/run.ts +1 -1
  15. package/packages/cli/src/commands/test.ts +37 -25
  16. package/packages/cli/src/commands/trace.ts +30 -28
  17. package/packages/cli/templates/hive-app/.env.example +10 -2
  18. package/packages/cli/templates/hive-app/README.md +103 -0
  19. package/packages/cli/templates/hive-app/hive.config.ts +9 -3
  20. package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
  21. package/packages/cli/templates/hive-app/src/main.ts +12 -19
  22. package/packages/core/package.json +5 -4
  23. package/packages/core/src/agent/acceptance-checks.ts +166 -0
  24. package/packages/core/src/agent/agent-catalog.ts +348 -0
  25. package/packages/core/src/agent/agent-loop.ts +1373 -0
  26. package/packages/core/src/agent/capability-search.ts +186 -0
  27. package/packages/core/src/agent/catalog-selector.ts +103 -0
  28. package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
  29. package/packages/core/src/agent/context-compiler.ts +689 -0
  30. package/packages/core/src/agent/conversation-store.ts +381 -0
  31. package/packages/core/src/agent/curator.ts +276 -0
  32. package/packages/core/src/agent/delegation-runtime.ts +241 -0
  33. package/packages/core/src/agent/goal-runner.ts +323 -0
  34. package/packages/core/src/agent/index.ts +17 -12
  35. package/packages/core/src/agent/llm-client.ts +266 -0
  36. package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
  37. package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
  38. package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
  39. package/packages/core/src/agent/llm-providers/groq.ts +5 -0
  40. package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
  41. package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
  42. package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
  43. package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
  44. package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
  45. package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
  46. package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
  47. package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
  48. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
  49. package/packages/core/src/agent/llm-providers/openai.ts +5 -0
  50. package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
  51. package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
  52. package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
  53. package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
  54. package/packages/core/src/agent/minimal-loadout.ts +47 -0
  55. package/packages/core/src/agent/playbook-selector.ts +119 -0
  56. package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
  57. package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
  58. package/packages/core/src/agent/providers/index.ts +35 -16
  59. package/packages/core/src/agent/reflector.ts +320 -0
  60. package/packages/core/src/agent/routing-intent.ts +22 -0
  61. package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
  62. package/packages/core/src/{harness → agent}/run-store.ts +142 -81
  63. package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
  64. package/packages/core/src/agent/skill-selector.ts +374 -0
  65. package/packages/core/src/agent/stuck-loop.ts +209 -0
  66. package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
  67. package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
  68. package/packages/core/src/api/createAgent.test.ts +139 -27
  69. package/packages/core/src/api/createAgent.ts +232 -44
  70. package/packages/core/src/artifacts/store.ts +162 -0
  71. package/packages/core/src/canvas/canvas-manager.ts +161 -0
  72. package/packages/core/src/canvas/canvas.test.ts +8 -4
  73. package/packages/core/src/canvas/emitter.ts +131 -80
  74. package/packages/core/src/canvas/index.ts +1 -3
  75. package/packages/core/src/channels/base.ts +9 -1
  76. package/packages/core/src/channels/discord.ts +5 -4
  77. package/packages/core/src/channels/manager.ts +122 -30
  78. package/packages/core/src/channels/slack.ts +5 -4
  79. package/packages/core/src/channels/telegram.ts +36 -6
  80. package/packages/core/src/channels/webchat.ts +11 -10
  81. package/packages/core/src/channels/whatsapp.ts +23 -7
  82. package/packages/core/src/config/index.ts +13 -2
  83. package/packages/core/src/config/loader.ts +71 -29
  84. package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
  85. package/packages/core/src/ethics/EthicsGuard.ts +51 -47
  86. package/packages/core/src/events/agent-bus.ts +44 -68
  87. package/packages/core/src/events/channel-narration.ts +150 -0
  88. package/packages/core/src/events/narration.ts +82 -0
  89. package/packages/core/src/events/tool-narration.ts +62 -0
  90. package/packages/core/src/gateway/delegation-groups.ts +258 -0
  91. package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
  92. package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
  93. package/packages/core/src/gateway/lane-queue.ts +173 -0
  94. package/packages/core/src/gateway/notification-inbox.ts +57 -0
  95. package/packages/core/src/gateway/server.ts +1 -1
  96. package/packages/core/src/harness/index.ts +46 -27
  97. package/packages/core/src/index.ts +33 -27
  98. package/packages/core/src/mcp/hot-reload.ts +32 -23
  99. package/packages/core/src/mcp/index.ts +6 -3
  100. package/packages/core/src/mcp/singleton.ts +1 -4
  101. package/packages/core/src/mcp/tool-sync.ts +138 -0
  102. package/packages/core/src/memory/Scratchpad.test.ts +39 -20
  103. package/packages/core/src/memory/Scratchpad.ts +27 -34
  104. package/packages/core/src/multimodal/vision-service.ts +44 -38
  105. package/packages/core/src/resilience/retry.ts +95 -0
  106. package/packages/core/src/scheduler/CronScheduler.ts +334 -287
  107. package/packages/core/src/scheduler/index.ts +9 -7
  108. package/packages/core/src/scheduler/integration.ts +46 -26
  109. package/packages/core/src/scheduler/scheduler.test.ts +9 -13
  110. package/packages/core/src/scheduler/types.ts +7 -2
  111. package/packages/core/src/security/Pairing.ts +1 -1
  112. package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
  113. package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
  114. package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
  115. package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
  116. package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
  117. package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
  118. package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
  119. package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
  120. package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
  121. package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
  122. package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
  123. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
  124. package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
  125. package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
  126. package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
  127. package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
  128. package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
  129. package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
  130. package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
  131. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
  132. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
  133. package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
  134. package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
  135. package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
  136. package/packages/core/src/skills/skills.test.ts +52 -11
  137. package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
  138. package/packages/core/src/storage/bootstrap.ts +151 -0
  139. package/packages/core/src/storage/causal-events.ts +84 -0
  140. package/packages/core/src/storage/collections.ts +680 -0
  141. package/packages/core/src/storage/crypto.ts +205 -74
  142. package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
  143. package/packages/core/src/storage/hivedb.ts +61 -0
  144. package/packages/core/src/storage/index.ts +111 -18
  145. package/packages/core/src/storage/model-id.ts +53 -0
  146. package/packages/core/src/storage/onboarding.ts +540 -972
  147. package/packages/core/src/storage/reconcile.ts +238 -0
  148. package/packages/core/src/storage/seed.ts +572 -406
  149. package/packages/core/src/storage/usage.ts +285 -225
  150. package/packages/core/src/storage/user-email.ts +11 -0
  151. package/packages/core/src/swarm/AgentExecutor.ts +1 -1
  152. package/packages/core/src/swarm/EventBridge.ts +1 -1
  153. package/packages/core/src/swarm/index.ts +12 -9
  154. package/packages/core/src/tool-runtime/index.ts +146 -23
  155. package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
  156. package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
  157. package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
  158. package/packages/core/src/tools/agents/get-available-models.ts +36 -54
  159. package/packages/core/src/tools/agents/index.ts +784 -292
  160. package/packages/core/src/tools/api/api-request.test.ts +164 -0
  161. package/packages/core/src/tools/api/api-request.ts +174 -0
  162. package/packages/core/src/tools/api/index.ts +16 -0
  163. package/packages/core/src/tools/cli/index.ts +4 -0
  164. package/packages/core/src/tools/core/index.ts +281 -112
  165. package/packages/core/src/tools/cron/index.ts +121 -124
  166. package/packages/core/src/tools/index.ts +63 -78
  167. package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
  168. package/packages/core/src/tools/types.ts +3 -1
  169. package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
  170. package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
  171. package/packages/core/src/tools/web/browser-service.ts +5 -0
  172. package/packages/core/src/tools/web/browser-type.ts +3 -8
  173. package/packages/core/src/tools/web/index.ts +4 -4
  174. package/packages/core/src/voice/index.ts +89 -63
  175. package/packages/core/src/workers/agent.worker.ts +2 -2
  176. package/packages/core/src/workers/workers.test.ts +3 -10
  177. package/scripts/bump-version.ts +248 -0
  178. package/scripts/generate-skill-bundle.ts +108 -0
  179. package/test/agent-loop-terminal-synthesis.test.ts +32 -0
  180. package/test/catalog-agents-stay-enabled.test.ts +117 -0
  181. package/test/causal-events.test.ts +117 -0
  182. package/test/compaction.test.ts +105 -0
  183. package/test/context-compiler.test.ts +269 -0
  184. package/test/curator.test.ts +130 -0
  185. package/test/durable-queue.test.ts +114 -0
  186. package/test/harness-barrel.test.ts +64 -0
  187. package/test/hive-helpers.test.ts +130 -0
  188. package/test/hivedb-search.test.ts +189 -0
  189. package/test/internal-turns.test.ts +166 -0
  190. package/test/job-idempotency.test.ts +68 -0
  191. package/test/job-retry-backoff.test.ts +184 -0
  192. package/test/job-store.test.ts +381 -0
  193. package/test/llm-retry.test.ts +97 -0
  194. package/test/memory-perf.test.ts +774 -0
  195. package/test/minimal-loadout.test.ts +78 -0
  196. package/test/model-catalog.test.ts +105 -0
  197. package/test/preload.ts +12 -0
  198. package/test/reflector.test.ts +320 -0
  199. package/test/retention-cap.test.ts +91 -0
  200. package/test/retired-capabilities-pruned.test.ts +192 -0
  201. package/test/run-store.test.ts +355 -0
  202. package/test/scratchpad.test.ts +74 -0
  203. package/test/secrets-durability.test.ts +119 -0
  204. package/test/seed-model-reseed.test.ts +155 -0
  205. package/test/setup-agent-seed.test.ts +264 -0
  206. package/test/tool-inventory.test.ts +65 -0
  207. package/test/tool-runtime.test.ts +258 -0
  208. package/test/toon.test.ts +429 -0
  209. package/tsconfig.json +2 -0
  210. package/packages/core/src/ace/Curator.ts +0 -158
  211. package/packages/core/src/ace/Reflector.ts +0 -200
  212. package/packages/core/src/ace/index.ts +0 -4
  213. package/packages/core/src/agent/AgentRunner.ts +0 -711
  214. package/packages/core/src/agent/ContextCompiler.ts +0 -567
  215. package/packages/core/src/agent/ContextGuard.ts +0 -91
  216. package/packages/core/src/agent/ConversationStore.ts +0 -254
  217. package/packages/core/src/agent/Hooks.ts +0 -166
  218. package/packages/core/src/agent/StuckLoop.ts +0 -133
  219. package/packages/core/src/agent/providers/LLMClient.ts +0 -149
  220. package/packages/core/src/agent/providers/anthropic.ts +0 -212
  221. package/packages/core/src/agent/providers/openai-compat.ts +0 -231
  222. package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
  223. package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
  224. package/packages/core/src/agent/selectors/index.ts +0 -6
  225. package/packages/core/src/auth/auth.ts +0 -121
  226. package/packages/core/src/auth/index.ts +0 -1
  227. package/packages/core/src/canvas/CanvasManager.ts +0 -390
  228. package/packages/core/src/canvas/canvas-tools.ts +0 -448
  229. package/packages/core/src/harness/collections.ts +0 -98
  230. package/packages/core/src/harness/goal-verifier.ts +0 -141
  231. package/packages/core/src/harness/harness.test.ts +0 -236
  232. package/packages/core/src/harness/reconcile.ts +0 -149
  233. package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
  234. package/packages/core/src/multimodal/VisionService.ts +0 -293
  235. package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
  236. package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
  237. package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
  238. package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
  239. package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
  240. package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
  241. package/packages/core/src/scheduler/dag/errors.ts +0 -37
  242. package/packages/core/src/scheduler/dag/index.ts +0 -26
  243. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
  244. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
  245. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
  246. package/packages/core/src/storage/HiveDBStorage.ts +0 -64
  247. package/packages/core/src/storage/SQLiteStorage.ts +0 -414
  248. package/packages/core/src/storage/hiveSeed.ts +0 -308
  249. package/packages/core/src/storage/hiveStorage.test.ts +0 -38
  250. package/packages/core/src/storage/schema.ts +0 -689
  251. package/packages/core/src/storage/storage.test.ts +0 -37
  252. package/packages/core/src/swarm/AgentBus.ts +0 -460
  253. package/packages/core/src/swarm/EventBus.ts +0 -169
  254. package/packages/core/src/swarm/WorkerPool.ts +0 -236
  255. package/packages/core/src/tools/bridge-events.ts +0 -26
  256. package/packages/core/src/tools/canvas/index.ts +0 -375
  257. package/packages/core/src/tools/codebridge/index.ts +0 -342
  258. package/packages/core/src/tools/meeting/index.ts +0 -353
  259. package/packages/core/src/tools/projects/index.ts +0 -37
  260. package/packages/core/src/tools/projects/project-create.ts +0 -94
  261. package/packages/core/src/tools/projects/project-done.ts +0 -66
  262. package/packages/core/src/tools/projects/project-fail.ts +0 -66
  263. package/packages/core/src/tools/projects/project-list.ts +0 -96
  264. package/packages/core/src/tools/projects/project-update.ts +0 -72
  265. package/packages/core/src/tools/projects/task-create.ts +0 -68
  266. package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
  267. package/packages/core/src/tools/projects/task-update.ts +0 -93
  268. package/packages/core/src/tools/voice/index.ts +0 -104
  269. package/packages/core/src/tools/web/api-request.test.ts +0 -170
  270. package/packages/core/src/tools/web/api-request.ts +0 -239
  271. package/test/setup-db.ts +0 -216
  272. /package/packages/core/src/agent/{NativeTools.ts → native-tools.ts} +0 -0
@@ -0,0 +1,23 @@
1
+ import type { Tool } from "../types";
2
+ import { inspectArtifact } from "../../artifacts/store";
3
+
4
+ export const artifactInspectTool: Tool = {
5
+ name: "artifact_inspect",
6
+ description: "Inspect managed artifact metadata, integrity, MIME type and dimensions without returning or modifying its binary content.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: {
10
+ artifactId: {
11
+ type: "string",
12
+ description: "Managed artifact identifier returned by a Hive tool.",
13
+ },
14
+ },
15
+ required: ["artifactId"],
16
+ },
17
+ execute: async (params, config) => {
18
+ const artifactId = String(params.artifactId ?? "").trim();
19
+ if (!artifactId) return { ok: false, error: "artifactId is required" };
20
+ const userId = config?.configurable?.user_id as string | undefined;
21
+ return inspectArtifact(artifactId, { userId });
22
+ },
23
+ };
@@ -9,6 +9,7 @@
9
9
  import type { Tool } from "../types.ts";
10
10
  import { logger } from "../../utils/logger.ts";
11
11
  import { getBrowserService, screenshotElement } from "./browser-service.ts";
12
+ import { createArtifact } from "../../artifacts/store.ts";
12
13
 
13
14
  const log = logger.child("browser-screenshot");
14
15
 
@@ -53,7 +54,7 @@ export const browserScreenshotTool: Tool = {
53
54
  },
54
55
  required: [],
55
56
  },
56
- execute: async (params: Record<string, unknown>) => {
57
+ execute: async (params: Record<string, unknown>, config?: any) => {
57
58
  const url = params.url as string | undefined;
58
59
  const fullPage = (params.fullPage as boolean) ?? false;
59
60
  const selector = params.selector as string | undefined;
@@ -99,14 +100,34 @@ export const browserScreenshotTool: Tool = {
99
100
  }
100
101
 
101
102
  const currentUrl = view.url;
102
- log.info(`Screenshot captured: ${currentUrl} (${screenshot.length} base64 chars, ${format})`);
103
+ const bytes = Buffer.from(screenshot, "base64");
104
+ const effectiveFormat = selector ? "png" : format;
105
+ const mimeType = effectiveFormat === "png" ? "image/png" : "image/jpeg";
106
+ const configurable = config?.configurable ?? {};
107
+ const artifact = await createArtifact({
108
+ bytes,
109
+ mimeType,
110
+ kind: "browser_screenshot",
111
+ userId: String(configurable.user_id ?? ""),
112
+ runId: configurable.run_id ? String(configurable.run_id) : null,
113
+ taskId: configurable.task_id ? String(configurable.task_id) : null,
114
+ rootDir: configurable.artifact_dir ? String(configurable.artifact_dir) : undefined,
115
+ width,
116
+ height,
117
+ });
118
+ log.info(`Screenshot stored as artifact ${artifact.id} (${artifact.size} bytes, ${mimeType})`);
103
119
 
104
120
  return {
105
121
  ok: true,
106
122
  url: currentUrl,
107
- screenshot,
108
- format,
109
- encoding: "base64",
123
+ artifact_id: artifact.id,
124
+ kind: artifact.kind,
125
+ mime_type: artifact.mime_type,
126
+ size: artifact.size,
127
+ sha256: artifact.sha256,
128
+ status: artifact.status,
129
+ expires_at: artifact.expires_at,
130
+ format: effectiveFormat,
110
131
  fullPage,
111
132
  selector,
112
133
  viewport: { width, height },
@@ -178,6 +178,11 @@ export class AgentBrowserView {
178
178
  args.push("--screenshot-quality", String(options.quality));
179
179
  }
180
180
 
181
+ // If clip/selector is provided, agent-browser screenshot accepts a positional selector
182
+ // For element screenshots, we can pass a selector as first positional arg
183
+ // But we don't have selector in options here — the old CDPClient didn't use it either
184
+ // screenshotElement helper handles element-specific screenshots
185
+
181
186
  const res = await this.run(args);
182
187
  if (!res.success) throw new Error(res.error || "screenshot failed");
183
188
 
@@ -68,17 +68,12 @@ export const browserTypeTool: Tool = {
68
68
  await Bun.sleep(500);
69
69
  }
70
70
 
71
- // click(selector) waits for actionability then focuses the element
72
- await view.click(selector, { timeout });
73
-
74
71
  if (clear) {
75
- // Ctrl+A Backspace to clear existing content
76
- await view.press("a", { modifiers: ["Control"] });
77
- await view.press("Backspace");
72
+ await (view as any).fill(selector, text);
73
+ } else {
74
+ await (view as any).typeIn(selector, text);
78
75
  }
79
76
 
80
- await view.type(text);
81
-
82
77
  const currentUrl = view.url;
83
78
  log.info(`Type successful: "${text.substring(0, 50)}${text.length > 50 ? "..." : ""}" into ${selector}`);
84
79
 
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * Web Tools - Browser automation + Web utilities
3
3
  *
4
- * Browser tools use Puppeteer/Chromium (auto-managed).
4
+ * Browser tools use agent-browser (Rust CLI, auto-managed).
5
5
  */
6
6
 
7
7
  import type { Tool } from "../types.ts";
8
8
  import { webSearchTool } from "./web-search.ts";
9
9
  import { webFetchTool } from "./web-fetch.ts";
10
- import { apiRequestTool } from "./api-request.ts";
11
10
  import { browserNavigateTool } from "./browser-navigate.ts";
12
11
  import { browserScreenshotTool } from "./browser-screenshot.ts";
13
12
  import { browserClickTool } from "./browser-click.ts";
@@ -15,12 +14,12 @@ import { browserTypeTool } from "./browser-type.ts";
15
14
  import { browserExtractTool } from "./browser-extract.ts";
16
15
  import { browserScriptTool } from "./browser-script.ts";
17
16
  import { browserWaitTool } from "./browser-wait.ts";
17
+ import { artifactInspectTool } from "./artifact-inspect.ts";
18
18
 
19
19
  export function createTools(): Tool[] {
20
20
  return [
21
21
  webSearchTool,
22
22
  webFetchTool,
23
- apiRequestTool,
24
23
  browserNavigateTool,
25
24
  browserScreenshotTool,
26
25
  browserClickTool,
@@ -28,12 +27,12 @@ export function createTools(): Tool[] {
28
27
  browserExtractTool,
29
28
  browserScriptTool,
30
29
  browserWaitTool,
30
+ artifactInspectTool,
31
31
  ];
32
32
  }
33
33
 
34
34
  export * from "./web-search.ts";
35
35
  export * from "./web-fetch.ts";
36
- export * from "./api-request.ts";
37
36
  export * from "./browser-navigate.ts";
38
37
  export * from "./browser-screenshot.ts";
39
38
  export * from "./browser-click.ts";
@@ -42,3 +41,4 @@ export * from "./browser-extract.ts";
42
41
  export * from "./browser-script.ts";
43
42
  export * from "./browser-wait.ts";
44
43
  export * from "./browser-service.ts";
44
+ export * from "./artifact-inspect.ts";
@@ -1,4 +1,5 @@
1
- import { getDb } from "../storage/SQLiteStorage";
1
+ import { col } from "../storage/hive";
2
+ import type { ChannelDoc, ModelDoc } from "../storage/collections";
2
3
  import { loadProviderApiKey } from "../storage/crypto";
3
4
  import { logger } from "../utils/logger";
4
5
 
@@ -79,20 +80,11 @@ class VoiceService {
79
80
  return VoiceService.instance;
80
81
  }
81
82
 
82
- getChannelVoiceConfig(channelId: string): VoiceConfig {
83
- const db = getDb();
84
- const result = db.query(`
85
- SELECT voice_enabled, tts_enabled, stt_provider, tts_provider, tts_voice_id
86
- FROM channels WHERE id = ?
87
- `).get(channelId) as {
88
- voice_enabled: number;
89
- tts_enabled: number;
90
- stt_provider: string | null;
91
- tts_provider: string | null;
92
- tts_voice_id: string | null;
93
- } | undefined;
94
-
95
- if (!result) {
83
+ async getChannelVoiceConfig(channelId: string): Promise<VoiceConfig> {
84
+ const channelsCol = await col<ChannelDoc>("channels");
85
+ const entry = await channelsCol.get(channelId);
86
+
87
+ if (!entry) {
96
88
  return {
97
89
  voiceEnabled: false,
98
90
  ttsEnabled: false,
@@ -103,26 +95,62 @@ class VoiceService {
103
95
  }
104
96
 
105
97
  return {
106
- voiceEnabled: result.voice_enabled === 1,
107
- ttsEnabled: result.tts_enabled === 1,
108
- sttProvider: result.stt_provider,
109
- ttsProvider: result.tts_provider,
110
- ttsVoiceId: result.tts_voice_id,
98
+ voiceEnabled: entry.doc.voice_enabled,
99
+ ttsEnabled: entry.doc.tts_enabled,
100
+ sttProvider: entry.doc.stt_provider,
101
+ ttsProvider: entry.doc.tts_provider,
102
+ ttsVoiceId: entry.doc.tts_voice_id,
111
103
  };
112
104
  }
113
105
 
106
+ /** Provider de un modelo según la BD; acepta también un id de provider (canales antiguos). */
107
+ private async getModelProvider(modelId: string): Promise<string | null> {
108
+ try {
109
+ const modelsCol = await col<ModelDoc>("models");
110
+ const model = await modelsCol.get(modelId);
111
+ if (model?.doc.provider_id) return model.doc.provider_id;
112
+ const providersCol = await col<import("../storage/collections").ProviderDoc>("providers");
113
+ const provider = await providersCol.get(modelId);
114
+ return provider?.doc.id || null;
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ /** Primer modelo STT/TTS activo de un provider activo, como fallback desde la BD. */
121
+ private async getFirstActiveVoiceModel(type: "stt" | "tts"): Promise<{ id: string; provider: string } | null> {
122
+ try {
123
+ const modelsCol = await col<ModelDoc>("models");
124
+ const providersCol = await col<import("../storage/collections").ProviderDoc>("providers");
125
+ const models = (await modelsCol.findBy("model_type", type)).filter(e => e.doc.active);
126
+ for (const m of models) {
127
+ const provider = await providersCol.get(m.doc.provider_id);
128
+ if (provider?.doc.active) return { id: m.doc.id, provider: m.doc.provider_id };
129
+ }
130
+ return null;
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+
114
136
  async transcribe(audio: AudioInput, modelId: string): Promise<string> {
115
- const isGroq = modelId.startsWith("whisper");
116
- const isOpenAi = modelId === "whisper-1";
117
-
118
- if (isGroq) {
119
- return this.transcribeWithGroq(audio, modelId);
120
- } else if (isOpenAi) {
121
- return this.transcribeWithOpenAIWhisper(audio);
137
+ let provider = await this.getModelProvider(modelId);
138
+ let resolvedModelId = modelId;
139
+
140
+ if (!provider) {
141
+ const fallback = await this.getFirstActiveVoiceModel("stt");
142
+ if (!fallback) throw new Error(`STT model "${modelId}" not found and no active STT models in the database`);
143
+ log.warn(`STT model ${modelId} not found in DB, falling back to ${fallback.provider}/${fallback.id}`);
144
+ provider = fallback.provider;
145
+ resolvedModelId = fallback.id;
146
+ }
147
+
148
+ switch (provider) {
149
+ case "groq": return this.transcribeWithGroq(audio, resolvedModelId);
150
+ case "openai": return this.transcribeWithOpenAIWhisper(audio);
151
+ default:
152
+ throw new Error(`STT not supported for provider "${provider}" (model ${resolvedModelId})`);
122
153
  }
123
-
124
- log.warn(`Unknown STT provider ${modelId}, defaulting to Groq Whisper`);
125
- return this.transcribeWithGroq(audio, "whisper-large-v3-turbo");
126
154
  }
127
155
 
128
156
  private async getProviderApiKey(providerId: string): Promise<string | null> {
@@ -229,26 +257,26 @@ class VoiceService {
229
257
  }
230
258
 
231
259
  async speak(text: string, modelId: string, voiceId?: string): Promise<AudioOutput> {
232
- const isElevenLabs = modelId.startsWith("eleven");
233
- const isOpenAI = modelId.startsWith("tts-") || modelId.startsWith("gpt-");
234
- const isGemini = modelId.startsWith("gemini");
235
- const isQwen = modelId.startsWith("qwen");
236
- const isPiper = modelId === "piper" || modelId === "piper-local";
237
-
238
- if (isPiper) {
239
- return this.speakWithPiper(text, voiceId);
240
- } else if (isElevenLabs) {
241
- return this.speakWithElevenLabs(text, modelId, voiceId);
242
- } else if (isOpenAI) {
243
- return this.speakWithOpenAI(text, modelId, voiceId);
244
- } else if (isGemini) {
245
- return this.speakWithGemini(text, modelId, voiceId);
246
- } else if (isQwen) {
247
- return this.speakWithQwen(text, modelId, voiceId);
248
- }
249
-
250
- log.warn(`Unknown TTS provider ${modelId}, defaulting to ElevenLabs Flash`);
251
- return this.speakWithElevenLabs(text, "eleven_flash_v2_5", voiceId);
260
+ let provider = modelId === "piper-local" ? "piper" : await this.getModelProvider(modelId);
261
+ let resolvedModelId = modelId;
262
+
263
+ if (!provider) {
264
+ const fallback = await this.getFirstActiveVoiceModel("tts");
265
+ if (!fallback) throw new Error(`TTS model "${modelId}" not found and no active TTS models in the database`);
266
+ log.warn(`TTS model ${modelId} not found in DB, falling back to ${fallback.provider}/${fallback.id}`);
267
+ provider = fallback.provider;
268
+ resolvedModelId = fallback.id;
269
+ }
270
+
271
+ switch (provider) {
272
+ case "piper": return this.speakWithPiper(text, voiceId);
273
+ case "elevenlabs": return this.speakWithElevenLabs(text, resolvedModelId, voiceId);
274
+ case "openai": return this.speakWithOpenAI(text, resolvedModelId, voiceId);
275
+ case "gemini": return this.speakWithGemini(text, resolvedModelId, voiceId);
276
+ case "qwen": return this.speakWithQwen(text, resolvedModelId, voiceId);
277
+ default:
278
+ throw new Error(`TTS not supported for provider "${provider}" (model ${resolvedModelId})`);
279
+ }
252
280
  }
253
281
 
254
282
  private async speakWithPiper(text: string, voiceId?: string): Promise<AudioOutput> {
@@ -448,21 +476,19 @@ class VoiceService {
448
476
  };
449
477
  }
450
478
 
451
- getConfiguredVoiceProviders(): { groq: boolean; elevenlabs: boolean; openai: boolean; gemini: boolean; qwen: boolean } {
452
- const db = getDb();
453
- const hasDbKey = (providerId: string): boolean => {
454
- const row = db.query(
455
- `SELECT api_key_encrypted FROM providers WHERE id = ? AND api_key_encrypted IS NOT NULL AND api_key_encrypted != ''`
456
- ).get(providerId) as { api_key_encrypted: string } | undefined;
457
- return !!row;
458
- };
479
+ async getConfiguredVoiceProviders(): Promise<{ groq: boolean; elevenlabs: boolean; openai: boolean; gemini: boolean; qwen: boolean }> {
480
+ const hasDbKey = async (providerId: string): Promise<boolean> => !!(await loadProviderApiKey(providerId));
481
+
482
+ const [groq, elevenlabs, openai, gemini, qwen] = await Promise.all([
483
+ hasDbKey("groq"), hasDbKey("elevenlabs"), hasDbKey("openai"), hasDbKey("gemini"), hasDbKey("qwen"),
484
+ ]);
459
485
 
460
486
  return {
461
- groq: hasDbKey("groq") || !!(process.env.GROQ_API_KEY),
462
- elevenlabs: hasDbKey("elevenlabs") || !!(process.env.ELEVENLABS_API_KEY),
463
- openai: hasDbKey("openai") || !!(process.env.OPENAI_API_KEY),
464
- gemini: hasDbKey("gemini") || !!(process.env.GEMINI_API_KEY),
465
- qwen: hasDbKey("qwen") || !!(process.env.DASHSCOPE_API_KEY),
487
+ groq: groq || !!(process.env.GROQ_API_KEY),
488
+ elevenlabs: elevenlabs || !!(process.env.ELEVENLABS_API_KEY),
489
+ openai: openai || !!(process.env.OPENAI_API_KEY),
490
+ gemini: gemini || !!(process.env.GEMINI_API_KEY),
491
+ qwen: qwen || !!(process.env.DASHSCOPE_API_KEY),
466
492
  };
467
493
  }
468
494
 
@@ -5,8 +5,8 @@
5
5
  * Sends: { type: "AGENT_RESULT", taskId, result } | { type: "AGENT_CHUNK", taskId, chunk }
6
6
  */
7
7
 
8
- import { runAgent } from "../agent/AgentRunner.ts";
9
- import type { StreamChunk } from "../agent/AgentRunner.ts";
8
+ import { runAgent } from "../agent/agent-loop.ts";
9
+ import type { StreamChunk } from "../agent/agent-loop.ts";
10
10
 
11
11
  declare var self: {
12
12
  onmessage: ((event: { data: WorkerMessage }) => void) | null;
@@ -1,16 +1,9 @@
1
- import { describe, expect, it, beforeAll, afterAll } from "bun:test";
1
+ process.env.HIVE_DB_PATH = ":memory:";
2
+
3
+ import { describe, expect, it } from "bun:test";
2
4
  import { createWorker, WorkerPool } from "./index.ts";
3
- import { setupTestDb, teardownTestDb, insertTestAgent, insertTestProvider } from "../../../../test/setup-db.ts";
4
5
 
5
6
  describe("createWorker", () => {
6
- beforeAll(() => {
7
- setupTestDb();
8
- });
9
-
10
- afterAll(() => {
11
- teardownTestDb();
12
- });
13
-
14
7
  it("creates a worker instance with config", () => {
15
8
  const worker = createWorker({
16
9
  name: "test-worker",
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Bump de versión del SDK.
5
+ *
6
+ * Portado de `hive/scripts/bump-version.ts`, adaptado a este repo: acá el
7
+ * artefacto publicado es **sólo el paquete raíz** (`@johpaz/hive-sdk`);
8
+ * `packages/core` y `packages/cli` son workspaces internos que se versionan en
9
+ * paralelo por consistencia, no se publican.
10
+ *
11
+ * El push del tag `vX.Y.Z` es lo que dispara `.github/workflows/publish.yml`.
12
+ */
13
+
14
+ const args = process.argv.slice(2);
15
+ const dryRun = args.includes("--dry-run");
16
+ const shouldPush = args.includes("--push");
17
+ const npmTagArg = args.find((a) => a.startsWith("--npm-tag="));
18
+ const npmTag = npmTagArg ? npmTagArg.split("=")[1] : "latest";
19
+ const positional = args.filter((a) => !a.startsWith("--"));
20
+ const bumpType = positional[0] as "patch" | "minor" | "major" | string;
21
+ const explicitVersion = positional[0]?.match(/^\d+\.\d+\.\d+(-[\w.]+)?$/) ? positional[0] : null;
22
+
23
+ if (!bumpType || (!["patch", "minor", "major"].includes(bumpType) && !explicitVersion)) {
24
+ console.log("Usage:");
25
+ console.log(" bun scripts/bump-version.ts patch|minor|major [--push] [--dry-run] [--npm-tag=<tag>]");
26
+ console.log(" bun scripts/bump-version.ts 0.1.5 [--push] [--dry-run] [--npm-tag=<tag>]");
27
+ console.log("");
28
+ console.log(" (sin flags) Solo actualiza archivos locales (package.json, README, CHANGELOG).");
29
+ console.log(" No toca git. Revisá el diff vos mismo.");
30
+ console.log(" --dry-run Muestra qué cambiaría, sin escribir nada.");
31
+ console.log(" --push Además de bumpear: commitea, crea el tag vX.Y.Z y pushea.");
32
+ console.log(" El tag dispara publish.yml, que publica en npm.");
33
+ console.log(" --npm-tag=X dist-tag de npm (default: latest). Usá `next` o `beta` para");
34
+ console.log(" una preview que no se instale con `bun add @johpaz/hive-sdk`.");
35
+ console.log("");
36
+ console.log("Ejemplos:");
37
+ console.log(" bun scripts/bump-version.ts 0.1.5 # solo archivos");
38
+ console.log(" bun scripts/bump-version.ts 0.1.5 --push # release a latest");
39
+ console.log(" bun scripts/bump-version.ts 0.2.0-rc.1 --push --npm-tag=next");
40
+ process.exit(1);
41
+ }
42
+
43
+ function bumpVersion(current: string, type: "patch" | "minor" | "major"): string {
44
+ const [major, minor, patch] = current.split("-")[0].split(".").map(Number);
45
+ return type === "major"
46
+ ? `${major + 1}.0.0`
47
+ : type === "minor"
48
+ ? `${major}.${minor + 1}.0`
49
+ : `${major}.${minor}.${patch + 1}`;
50
+ }
51
+
52
+ async function confirm(message: string): Promise<boolean> {
53
+ const readline = await import("node:readline/promises");
54
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
55
+ const answer = await rl.question(`${message} (escribe "si" para confirmar): `);
56
+ rl.close();
57
+ return answer.trim().toLowerCase() === "si";
58
+ }
59
+
60
+ /** El raíz es el que se publica; los workspaces van en paralelo por consistencia. */
61
+ const packageFiles = [
62
+ "package.json",
63
+ "packages/core/package.json",
64
+ "packages/cli/package.json",
65
+ ];
66
+
67
+ /** Menciones de versión en prosa que no salen de ningún package.json. */
68
+ function textReplacements(newVersion: string) {
69
+ return [
70
+ {
71
+ path: "README.md",
72
+ pattern: /\*Hive SDK v[\d.]+(?:-[\w.]+)? — MIT\*/g,
73
+ replacement: `*Hive SDK v${newVersion} — MIT*`,
74
+ },
75
+ ];
76
+ }
77
+
78
+ async function main() {
79
+ const rootPkg = JSON.parse(await Bun.file("package.json").text());
80
+ const currentVersion: string = rootPkg.version;
81
+ const newVersion = explicitVersion || bumpVersion(currentVersion, bumpType as "patch" | "minor" | "major");
82
+
83
+ console.log(`\n📦 Bumping version: ${currentVersion} → ${newVersion}`);
84
+ console.log(` npm dist-tag: ${npmTag}\n`);
85
+
86
+ if (newVersion === currentVersion && !explicitVersion) {
87
+ console.log("⚠️ La versión nueva es igual a la actual. Abortando.");
88
+ process.exit(1);
89
+ }
90
+
91
+ // npm rechaza republicar una versión existente: mejor enterarse acá que en CI.
92
+ try {
93
+ const published = await fetch(`https://registry.npmjs.org/${rootPkg.name}`)
94
+ .then((r) => (r.ok ? r.json() : null)) as { versions?: Record<string, unknown> } | null;
95
+ if (published?.versions?.[newVersion]) {
96
+ console.log(`⚠️ ${rootPkg.name}@${newVersion} YA está publicada en npm.`);
97
+ console.log(` Un publish con esta versión falla con 403. Elegí otra.\n`);
98
+ if (!dryRun) process.exit(1);
99
+ }
100
+ } catch {
101
+ console.log(" (no se pudo consultar npm — sigo igual)\n");
102
+ }
103
+
104
+ if (dryRun) {
105
+ console.log("🔎 Dry run — nada se escribe.\n");
106
+ for (const filePath of packageFiles) {
107
+ try {
108
+ const json = JSON.parse(await Bun.file(filePath).text());
109
+ console.log(` ${filePath}: ${json.version} → ${newVersion}`);
110
+ } catch (e) {
111
+ console.log(` ⚠️ ${filePath}: ${(e as Error).message}`);
112
+ }
113
+ }
114
+ for (const file of textReplacements(newVersion)) {
115
+ try {
116
+ const content = await Bun.file(file.path).text();
117
+ const matches = content.match(file.pattern);
118
+ console.log(` ${file.path}: ${matches ? `${matches.length} coincidencia(s)` : "sin coincidencias (revisar patrón)"}`);
119
+ } catch (e) {
120
+ console.log(` ⚠️ ${file.path}: ${(e as Error).message}`);
121
+ }
122
+ }
123
+ if (shouldPush) {
124
+ console.log(`\n Luego: git add -A && git commit -m "chore: release v${newVersion}"`);
125
+ console.log(` git tag v${newVersion} && git push origin main && git push origin v${newVersion}`);
126
+ console.log(` → publish.yml publica con dist-tag "${npmTag}"`);
127
+ } else {
128
+ console.log(`\n Sin --push: no se toca git.`);
129
+ }
130
+ return;
131
+ }
132
+
133
+ for (const filePath of packageFiles) {
134
+ try {
135
+ const json = JSON.parse(await Bun.file(filePath).text());
136
+ const oldVersion = json.version;
137
+ json.version = newVersion;
138
+ await Bun.write(filePath, JSON.stringify(json, null, 2) + "\n");
139
+ console.log(`✅ ${filePath}`);
140
+ console.log(` ${json.name}: ${oldVersion} → ${newVersion}`);
141
+ } catch (e) {
142
+ console.log(`⚠️ ${filePath}: ${(e as Error).message}`);
143
+ }
144
+ }
145
+
146
+ for (const file of textReplacements(newVersion)) {
147
+ try {
148
+ const content = await Bun.file(file.path).text();
149
+ const matched = file.pattern.test(content);
150
+ file.pattern.lastIndex = 0; // test() con /g deja estado — resetear
151
+ const newContent = content.replace(file.pattern, file.replacement);
152
+
153
+ if (!matched) {
154
+ console.log(`⚠️ ${file.path}: el patrón no matcheó nada — revisar manualmente`);
155
+ } else if (newContent !== content) {
156
+ await Bun.write(file.path, newContent);
157
+ console.log(`✅ ${file.path}`);
158
+ } else {
159
+ console.log(`✅ ${file.path} (ya estaba en ${newVersion})`);
160
+ }
161
+ } catch (e) {
162
+ console.log(`⚠️ ${file.path}: ${(e as Error).message}`);
163
+ }
164
+ }
165
+
166
+ // El CHANGELOG lo escribe una persona; acá sólo avisamos si falta la entrada.
167
+ try {
168
+ const changelog = await Bun.file("CHANGELOG.md").text();
169
+ if (!changelog.includes(`## ${newVersion}`)) {
170
+ console.log(`\n⚠️ CHANGELOG.md no tiene una sección "## ${newVersion}". Agregala antes de publicar.`);
171
+ }
172
+ } catch {
173
+ console.log("\n⚠️ No hay CHANGELOG.md.");
174
+ }
175
+
176
+ const { execSync } = await import("child_process");
177
+ const run = (cmd: string) => execSync(cmd, { stdio: "inherit" });
178
+
179
+ console.log(`\n✨ Archivos actualizados. Versión: ${newVersion}\n`);
180
+
181
+ if (!shouldPush) {
182
+ console.log("Sin --push: no se tocó git. Revisá `git diff`, y cuando estés conforme:");
183
+ console.log(` bun scripts/bump-version.ts ${explicitVersion || bumpType} --push${npmTag !== "latest" ? ` --npm-tag=${npmTag}` : ""}\n`);
184
+ return;
185
+ }
186
+
187
+ // ── Git: commit, tag y push — con confirmación antes de publicar ──────────
188
+ console.log("Antes de publicar corro typecheck y tests.\n");
189
+ try {
190
+ run("bun run typecheck");
191
+ run("bun test");
192
+ } catch {
193
+ console.log("\n❌ typecheck o tests fallaron. No se publica.");
194
+ process.exit(1);
195
+ }
196
+
197
+ console.log("\nEsto es lo que se va a commitear (git add -A):\n");
198
+ run("git status --short");
199
+
200
+ const tagExists = (() => {
201
+ try {
202
+ execSync(`git rev-parse v${newVersion}`, { stdio: "ignore" });
203
+ return true;
204
+ } catch {
205
+ return false;
206
+ }
207
+ })();
208
+
209
+ if (tagExists) {
210
+ console.log(`\n⚠️ El tag v${newVersion} ya existe localmente. Suele indicar que esta`);
211
+ console.log(` versión ya se publicó. Abortando — si es intencional, borralo primero`);
212
+ console.log(` (git tag -d v${newVersion}) y volvé a correr con --push.`);
213
+ process.exit(1);
214
+ }
215
+
216
+ const branch = execSync("git branch --show-current").toString().trim();
217
+
218
+ console.log(`\nEsto va a: commitear todo lo de arriba como "chore: release v${newVersion}",`);
219
+ console.log(`crear el tag v${newVersion}, y pushear ${branch} + el tag a origin.`);
220
+ console.log(`El push del tag dispara publish.yml, que publica en npm con dist-tag "${npmTag}".\n`);
221
+
222
+ const ok = await confirm(`¿Publicar v${newVersion} como "${npmTag}"?`);
223
+ if (!ok) {
224
+ console.log("Cancelado. No se tocó git.");
225
+ return;
226
+ }
227
+
228
+ console.log("🔧 Committing changes...");
229
+ run("git add -A");
230
+ try {
231
+ run(`git commit -m "chore: release v${newVersion}"`);
232
+ } catch {
233
+ console.log(" (nothing to commit, skipping)");
234
+ }
235
+
236
+ console.log(`🏷️ Creating tag v${newVersion}...`);
237
+ // El dist-tag viaja en el mensaje del tag: publish.yml lo lee de ahí.
238
+ run(`git tag -a v${newVersion} -m "release v${newVersion} [npm-tag:${npmTag}]"`);
239
+
240
+ console.log("🚀 Pushing commit and tag...");
241
+ run(`git push origin ${branch}`);
242
+ run(`git push origin v${newVersion}`);
243
+
244
+ console.log(`\n🎉 Released v${newVersion} (dist-tag: ${npmTag})\n`);
245
+ console.log(`Verificá en unos minutos: npm view ${rootPkg.name} dist-tags\n`);
246
+ }
247
+
248
+ main().catch(console.error);