@johpaz/hive-sdk 0.1.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/README.md +21 -3
  3. package/package.json +27 -5
  4. package/packages/core/src/agent/acceptance-checks.ts +9 -9
  5. package/packages/core/src/agent/agent-catalog.ts +82 -25
  6. package/packages/core/src/agent/agent-loop.ts +115 -26
  7. package/packages/core/src/agent/capability-search.ts +2 -2
  8. package/packages/core/src/agent/catalog-selector.ts +4 -4
  9. package/packages/core/src/agent/compaction.ts +30 -10
  10. package/packages/core/src/agent/context-compiler.ts +63 -36
  11. package/packages/core/src/agent/conversation-store.ts +167 -9
  12. package/packages/core/src/agent/curator.ts +16 -7
  13. package/packages/core/src/agent/delegation-runtime.ts +5 -5
  14. package/packages/core/src/agent/goal-runner.ts +9 -9
  15. package/packages/core/src/agent/index.ts +1 -0
  16. package/packages/core/src/agent/llm-client.ts +98 -37
  17. package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
  18. package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
  19. package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
  20. package/packages/core/src/agent/llm-providers/groq.ts +1 -1
  21. package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
  22. package/packages/core/src/agent/llm-providers/interface.ts +2 -2
  23. package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
  24. package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
  25. package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
  26. package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
  27. package/packages/core/src/agent/llm-providers/nvidia.ts +40 -1
  28. package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
  29. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +47 -7
  30. package/packages/core/src/agent/llm-providers/openai.ts +1 -1
  31. package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
  32. package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
  33. package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
  34. package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
  35. package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
  36. package/packages/core/src/agent/playbook-selector.ts +22 -7
  37. package/packages/core/src/agent/prompt-builder.ts +5 -5
  38. package/packages/core/src/agent/proof-packet.ts +5 -5
  39. package/packages/core/src/agent/providers/index.ts +39 -4
  40. package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
  41. package/packages/core/src/agent/realtime-providers/index.ts +29 -0
  42. package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
  43. package/packages/core/src/agent/reflector.ts +38 -15
  44. package/packages/core/src/agent/run-store.ts +8 -8
  45. package/packages/core/src/agent/service.ts +10 -10
  46. package/packages/core/src/agent/skill-selector.ts +6 -6
  47. package/packages/core/src/agent/thread-id.ts +71 -0
  48. package/packages/core/src/agent/thread-store.ts +293 -0
  49. package/packages/core/src/agent/tool-selector.ts +9 -5
  50. package/packages/core/src/agent/tracer.ts +5 -5
  51. package/packages/core/src/api/createAgent.ts +67 -2
  52. package/packages/core/src/artifacts/index.ts +15 -0
  53. package/packages/core/src/artifacts/store.ts +161 -5
  54. package/packages/core/src/canvas/emitter.ts +2 -2
  55. package/packages/core/src/canvas/index.ts +9 -0
  56. package/packages/core/src/channels/telegram.ts +1 -1
  57. package/packages/core/src/channels/webchat.ts +1 -1
  58. package/packages/core/src/config/loader.ts +14 -5
  59. package/packages/core/src/ethics/EthicsGuard.ts +7 -1
  60. package/packages/core/src/events/agent-bus.ts +3 -3
  61. package/packages/core/src/events/channel-narration.ts +3 -3
  62. package/packages/core/src/events/event-bus.ts +1 -1
  63. package/packages/core/src/events/index.ts +18 -0
  64. package/packages/core/src/events/narration.ts +3 -3
  65. package/packages/core/src/events/tool-narration.ts +4 -0
  66. package/packages/core/src/gateway/channel-notify.ts +103 -6
  67. package/packages/core/src/gateway/delegation-groups.ts +4 -4
  68. package/packages/core/src/gateway/durable-queue.ts +18 -6
  69. package/packages/core/src/gateway/index.ts +3 -0
  70. package/packages/core/src/gateway/job-store.ts +11 -5
  71. package/packages/core/src/gateway/notification-inbox.ts +2 -2
  72. package/packages/core/src/gateway/server.ts +2 -2
  73. package/packages/core/src/harness/executors.ts +493 -0
  74. package/packages/core/src/harness/index.ts +12 -2
  75. package/packages/core/src/hooks/index.ts +203 -0
  76. package/packages/core/src/images/index.ts +161 -0
  77. package/packages/core/src/index.ts +1 -0
  78. package/packages/core/src/mcp/MCPClient.ts +3 -3
  79. package/packages/core/src/mcp/hot-reload.ts +5 -5
  80. package/packages/core/src/mcp/tool-sync.ts +5 -5
  81. package/packages/core/src/mcp/transports/index.ts +2 -2
  82. package/packages/core/src/mcp/transports/sse.ts +1 -1
  83. package/packages/core/src/models/index.ts +36 -0
  84. package/packages/core/src/multimodal/index.ts +2 -2
  85. package/packages/core/src/multimodal/vision-service.ts +51 -19
  86. package/packages/core/src/plugins/loader.ts +4 -1
  87. package/packages/core/src/resilience/circuit-breaker.ts +16 -5
  88. package/packages/core/src/resilience/index.ts +13 -0
  89. package/packages/core/src/resilience/retry.ts +1 -1
  90. package/packages/core/src/scheduler/CronScheduler.ts +54 -27
  91. package/packages/core/src/scheduler/cron/expression.ts +165 -0
  92. package/packages/core/src/scheduler/cron/index.ts +10 -0
  93. package/packages/core/src/scheduler/cron/job.ts +339 -0
  94. package/packages/core/src/scheduler/cron/next-run.ts +121 -0
  95. package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
  96. package/packages/core/src/scheduler/index.ts +21 -3
  97. package/packages/core/src/scheduler/integration.ts +25 -14
  98. package/packages/core/src/scheduler/types.ts +3 -18
  99. package/packages/core/src/services/agents.ts +268 -0
  100. package/packages/core/src/services/cron.ts +257 -0
  101. package/packages/core/src/services/endpoints.ts +289 -0
  102. package/packages/core/src/services/ethics.ts +107 -0
  103. package/packages/core/src/services/images.ts +212 -0
  104. package/packages/core/src/services/index.ts +112 -0
  105. package/packages/core/src/services/mcp.ts +201 -0
  106. package/packages/core/src/services/memory.ts +133 -0
  107. package/packages/core/src/services/models.ts +179 -0
  108. package/packages/core/src/services/providers.ts +152 -0
  109. package/packages/core/src/services/setup.ts +222 -0
  110. package/packages/core/src/services/skills.ts +241 -0
  111. package/packages/core/src/services/swarms.ts +307 -0
  112. package/packages/core/src/services/tools.ts +106 -0
  113. package/packages/core/src/sessions/index.ts +268 -0
  114. package/packages/core/src/sessions/resolve.ts +108 -0
  115. package/packages/core/src/skills/SkillLoader.ts +8 -1
  116. package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
  117. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
  118. package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
  119. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
  120. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
  121. package/packages/core/src/skills/bundled-data.generated.ts +110 -12
  122. package/packages/core/src/storage/bootstrap.ts +107 -12
  123. package/packages/core/src/storage/causal-events.ts +1 -1
  124. package/packages/core/src/storage/collections.ts +138 -2
  125. package/packages/core/src/storage/crypto.ts +35 -4
  126. package/packages/core/src/storage/hive.ts +1 -1
  127. package/packages/core/src/storage/hivedb.ts +10 -1
  128. package/packages/core/src/storage/index.ts +2 -1
  129. package/packages/core/src/storage/onboarding.ts +61 -45
  130. package/packages/core/src/storage/reconcile.ts +11 -6
  131. package/packages/core/src/storage/seed.ts +191 -23
  132. package/packages/core/src/storage/usage.ts +3 -3
  133. package/packages/core/src/swarm/AgentExecutor.ts +2 -2
  134. package/packages/core/src/swarm/Coordinator.ts +8 -8
  135. package/packages/core/src/swarm/EventBridge.ts +2 -2
  136. package/packages/core/src/swarm/RoleSwarm.ts +234 -0
  137. package/packages/core/src/swarm/TaskGraph.ts +2 -2
  138. package/packages/core/src/swarm/index.ts +7 -0
  139. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
  140. package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
  141. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
  142. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
  143. package/packages/core/src/swarm/types.ts +3 -18
  144. package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
  145. package/packages/core/src/tool-runtime/index.ts +129 -14
  146. package/packages/core/src/tools/ToolExecutor.ts +7 -3
  147. package/packages/core/src/tools/agents/index.ts +18 -60
  148. package/packages/core/src/tools/cli/index.ts +55 -0
  149. package/packages/core/src/tools/core/index.ts +52 -4
  150. package/packages/core/src/tools/cron/index.ts +8 -8
  151. package/packages/core/src/tools/images/index.ts +130 -0
  152. package/packages/core/src/tools/index.ts +14 -1
  153. package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
  154. package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
  155. package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
  156. package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
  157. package/packages/core/src/tools/web/artifact-read.ts +162 -0
  158. package/packages/core/src/tools/web/browser-backend.ts +141 -44
  159. package/packages/core/src/tools/web/browser-click.ts +2 -2
  160. package/packages/core/src/tools/web/browser-extract.ts +2 -2
  161. package/packages/core/src/tools/web/browser-navigate.ts +2 -2
  162. package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
  163. package/packages/core/src/tools/web/browser-script.ts +2 -2
  164. package/packages/core/src/tools/web/browser-service.ts +63 -384
  165. package/packages/core/src/tools/web/browser-session.ts +125 -0
  166. package/packages/core/src/tools/web/browser-type.ts +2 -2
  167. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  168. package/packages/core/src/tools/web/computer-use.ts +553 -0
  169. package/packages/core/src/tools/web/index.ts +8 -1
  170. package/packages/core/src/tools/web/webview-backend.ts +460 -21
  171. package/packages/core/src/utils/index.ts +1 -0
  172. package/packages/core/src/utils/logger.ts +12 -4
  173. package/packages/core/src/utils/redact-binary.ts +17 -0
  174. package/packages/core/src/utils/toon.ts +1 -1
  175. package/packages/core/src/voice/index.ts +6 -6
  176. package/bun.lock +0 -859
  177. package/bunfig.toml +0 -9
  178. package/docs/API-AGENTS.md +0 -367
  179. package/docs/API-CONTEXT-COMPILER.md +0 -249
  180. package/docs/API-DAG-SCHEDULER.md +0 -273
  181. package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
  182. package/docs/API-WORKERS-EVENTS.md +0 -299
  183. package/docs/HIVE-HARNESS.md +0 -113
  184. package/docs/INDEX.md +0 -190
  185. package/docs/TEMPLATE-HIVE-APP.md +0 -360
  186. package/packages/cli/package.json +0 -17
  187. package/packages/cli/src/commands/create-app.test.ts +0 -180
  188. package/packages/core/package.json +0 -70
  189. package/packages/core/src/api/createAgent.test.ts +0 -160
  190. package/packages/core/src/canvas/canvas.test.ts +0 -36
  191. package/packages/core/src/channels/channels.test.ts +0 -18
  192. package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
  193. package/packages/core/src/gateway/gateway.test.ts +0 -38
  194. package/packages/core/src/memory/Scratchpad.test.ts +0 -68
  195. package/packages/core/src/scheduler/scheduler.test.ts +0 -15
  196. package/packages/core/src/skills/skills.test.ts +0 -62
  197. package/packages/core/src/swarm/swarm.test.ts +0 -24
  198. package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
  199. package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
  200. package/packages/core/src/tools/api/api-request.test.ts +0 -164
  201. package/packages/core/src/tools/web/browser-service.test.ts +0 -83
  202. package/packages/core/src/workers/workers.test.ts +0 -41
  203. package/scripts/bump-version.ts +0 -248
  204. package/scripts/generate-skill-bundle.ts +0 -108
  205. package/test/acceptance-checks.test.ts +0 -403
  206. package/test/agent-loop-terminal-synthesis.test.ts +0 -32
  207. package/test/browser-backend.test.ts +0 -308
  208. package/test/catalog-agents-stay-enabled.test.ts +0 -117
  209. package/test/causal-events.test.ts +0 -117
  210. package/test/compaction.test.ts +0 -105
  211. package/test/context-compiler.test.ts +0 -269
  212. package/test/curator.test.ts +0 -130
  213. package/test/durable-queue.test.ts +0 -114
  214. package/test/harness-barrel.test.ts +0 -64
  215. package/test/hive-helpers.test.ts +0 -130
  216. package/test/hivedb-search.test.ts +0 -189
  217. package/test/internal-turns.test.ts +0 -166
  218. package/test/job-idempotency.test.ts +0 -68
  219. package/test/job-retry-backoff.test.ts +0 -184
  220. package/test/job-store.test.ts +0 -381
  221. package/test/llm-retry.test.ts +0 -97
  222. package/test/memory-perf.test.ts +0 -774
  223. package/test/minimal-loadout.test.ts +0 -78
  224. package/test/model-catalog.test.ts +0 -105
  225. package/test/preload.ts +0 -12
  226. package/test/reflector.test.ts +0 -320
  227. package/test/retention-cap.test.ts +0 -91
  228. package/test/retired-capabilities-pruned.test.ts +0 -192
  229. package/test/run-store.test.ts +0 -355
  230. package/test/scratchpad.test.ts +0 -74
  231. package/test/secrets-durability.test.ts +0 -119
  232. package/test/seed-model-reseed.test.ts +0 -155
  233. package/test/setup-agent-seed.test.ts +0 -264
  234. package/test/tool-inventory.test.ts +0 -65
  235. package/test/tool-runtime.test.ts +0 -258
  236. package/test/tool-selector-runtime-tools.test.ts +0 -117
  237. package/test/toon.test.ts +0 -429
  238. package/tsconfig.json +0 -42
@@ -1,98 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { ToolRegistry, defineTool } from "./ToolRegistry.ts";
3
- import { ToolExecutor } from "./ToolExecutor.ts";
4
-
5
- describe("defineTool", () => {
6
- it("creates a tool definition", () => {
7
- const tool = defineTool({
8
- name: "hello",
9
- description: "Say hello",
10
- execute: async (args: { name?: string }) => ({ greeting: `Hello, ${args.name ?? "world"}!` }),
11
- });
12
- expect(tool.name).toBe("hello");
13
- expect(tool.description).toBe("Say hello");
14
- });
15
- });
16
-
17
- describe("ToolRegistry", () => {
18
- it("register, get, has", () => {
19
- const reg = new ToolRegistry();
20
- const tool = defineTool({
21
- name: "test",
22
- description: "a test tool",
23
- execute: async () => ({ ok: true }),
24
- });
25
- reg.register(tool);
26
- expect(reg.has("test")).toBe(true);
27
- expect(reg.get("test")).toBe(tool);
28
- expect(reg.get("nope")).toBeUndefined();
29
- });
30
-
31
- it("throws on duplicate registration", () => {
32
- const reg = new ToolRegistry();
33
- reg.register(defineTool({ name: "dup", description: "", execute: async () => ({}) }));
34
- expect(() =>
35
- reg.register(defineTool({ name: "dup", description: "", execute: async () => ({}) }))
36
- ).toThrow("already registered");
37
- });
38
-
39
- it("lists and categorizes", () => {
40
- const reg = new ToolRegistry();
41
- reg.register(defineTool({ name: "a", description: "", category: "web", execute: async () => ({}) }));
42
- reg.register(defineTool({ name: "b", description: "", category: "fs", execute: async () => ({}) }));
43
- reg.register(defineTool({ name: "c", description: "", category: "web", execute: async () => ({}) }));
44
- expect(reg.size()).toBe(3);
45
- expect(reg.list()).toHaveLength(3);
46
- expect(reg.getByCategory("web")).toHaveLength(2);
47
- expect(reg.getNames()).toEqual(["a", "b", "c"]);
48
- });
49
-
50
- it("merge and clear", () => {
51
- const a = new ToolRegistry();
52
- const b = new ToolRegistry();
53
- a.register(defineTool({ name: "x", description: "", execute: async () => ({}) }));
54
- b.register(defineTool({ name: "y", description: "", execute: async () => ({}) }));
55
- a.merge(b);
56
- expect(a.size()).toBe(2);
57
- a.clear();
58
- expect(a.size()).toBe(0);
59
- });
60
- });
61
-
62
- describe("ToolExecutor", () => {
63
- it("executes a registered tool", async () => {
64
- const reg = new ToolRegistry();
65
- reg.register(
66
- defineTool({
67
- name: "echo",
68
- description: "echo args",
69
- execute: async (args) => args,
70
- })
71
- );
72
- const exec = new ToolExecutor(reg);
73
- const result = await exec.execute("echo", { msg: "hi" });
74
- expect(result.toolName).toBe("echo");
75
- expect(result.result).toEqual({ msg: "hi" });
76
- expect(result.error).toBeUndefined();
77
- expect(result.durationMs).toBeGreaterThanOrEqual(0);
78
- });
79
-
80
- it("returns error for unknown tool", async () => {
81
- const exec = new ToolExecutor(new ToolRegistry());
82
- const result = await exec.execute("ghost", {});
83
- expect(result.error).toBeString();
84
- expect(result.error).toContain("not found");
85
- });
86
-
87
- it("executes batch", async () => {
88
- const reg = new ToolRegistry();
89
- reg.register(defineTool({ name: "t1", description: "", execute: async () => 1 }));
90
- reg.register(defineTool({ name: "t2", description: "", execute: async () => 2 }));
91
- const exec = new ToolExecutor(reg);
92
- const results = await exec.executeBatch([{ name: "t1", args: {} }, { name: "t2", args: {} }, { name: "nope", args: {} }]);
93
- expect(results).toHaveLength(3);
94
- expect(results[0].result).toBe(1);
95
- expect(results[1].result).toBe(2);
96
- expect(results[2].error).toBeString();
97
- });
98
- });
@@ -1,164 +0,0 @@
1
- /**
2
- * `api_request` cambió de contrato en 0.1.5.
3
- *
4
- * El tool anterior (`tools/web/api-request.ts`) tenía helpers de autenticación
5
- * (`auth: { type: "bearer" | "basic" | "api_key" }`), aceptaba `body` como
6
- * objeto y devolvía `{ ok, status, data }`. El de hive es más chato: la
7
- * autenticación va como un header más, `body` es string, y la respuesta expone
8
- * `body` + `contentType` en vez de `data`.
9
- */
10
-
11
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
12
- import { apiRequestTool } from "./api-request.ts";
13
-
14
- describe("apiRequestTool", () => {
15
- let originalFetch: typeof fetch;
16
-
17
- beforeEach(() => {
18
- originalFetch = globalThis.fetch;
19
- });
20
-
21
- afterEach(() => {
22
- globalThis.fetch = originalFetch;
23
- });
24
-
25
- function stubFetch(handler: (url: string, init: RequestInit) => Response) {
26
- globalThis.fetch = Object.assign(
27
- async (url: any, init?: any) => handler(url.toString(), init ?? {}),
28
- { preconnect: async () => undefined }
29
- ) as typeof fetch;
30
- }
31
-
32
- function jsonResponse(body: unknown, init: ResponseInit = {}) {
33
- return new Response(JSON.stringify(body), {
34
- status: init.status ?? 200,
35
- statusText: init.statusText ?? "OK",
36
- headers: { "content-type": "application/json" },
37
- });
38
- }
39
-
40
- it("ejecuta un GET simple y parsea el JSON", async () => {
41
- let capturedUrl = "";
42
- let capturedInit: RequestInit = {};
43
- stubFetch((url, init) => {
44
- capturedUrl = url;
45
- capturedInit = init;
46
- return jsonResponse({ hello: "world" });
47
- });
48
-
49
- const result = await apiRequestTool.execute({
50
- method: "GET",
51
- url: "https://api.example.com/data",
52
- }) as any;
53
-
54
- expect(capturedUrl).toBe("https://api.example.com/data");
55
- expect(capturedInit.method).toBe("GET");
56
- expect(result.ok).toBe(true);
57
- expect(result.status).toBe(200);
58
- expect(result.body).toEqual({ hello: "world" });
59
- });
60
-
61
- it("manda POST con el body tal cual y los headers dados", async () => {
62
- let capturedInit: RequestInit = {};
63
- stubFetch((_url, init) => {
64
- capturedInit = init;
65
- return jsonResponse({ id: 1 }, { status: 201, statusText: "Created" });
66
- });
67
-
68
- const result = await apiRequestTool.execute({
69
- method: "POST",
70
- url: "https://api.example.com/items",
71
- body: JSON.stringify({ name: "test" }),
72
- headers: { "Content-Type": "application/json", Authorization: "Bearer tok" },
73
- }) as any;
74
-
75
- expect(capturedInit.method).toBe("POST");
76
- expect(capturedInit.body).toBe('{"name":"test"}');
77
- expect((capturedInit.headers as Record<string, string>).Authorization).toBe("Bearer tok");
78
- expect(result.status).toBe(201);
79
- expect(result.body).toEqual({ id: 1 });
80
- });
81
-
82
- it("codifica query_params en la URL", async () => {
83
- let capturedUrl = "";
84
- stubFetch((url) => {
85
- capturedUrl = url;
86
- return jsonResponse({});
87
- });
88
-
89
- await apiRequestTool.execute({
90
- method: "GET",
91
- url: "https://api.example.com/search",
92
- query_params: { q: "hola mundo", limit: "10" },
93
- });
94
-
95
- expect(capturedUrl).toContain("q=hola+mundo");
96
- expect(capturedUrl).toContain("limit=10");
97
- });
98
-
99
- it("devuelve texto plano sin intentar parsearlo", async () => {
100
- stubFetch(() => new Response("hello world", {
101
- status: 200,
102
- statusText: "OK",
103
- headers: { "content-type": "text/plain" },
104
- }));
105
-
106
- const result = await apiRequestTool.execute({
107
- method: "GET",
108
- url: "https://api.example.com/text",
109
- }) as any;
110
-
111
- expect(result.ok).toBe(true);
112
- expect(result.body).toBe("hello world");
113
- expect(result.contentType).toContain("text/plain");
114
- });
115
-
116
- it("marca ok:false en un HTTP no exitoso sin lanzar", async () => {
117
- stubFetch(() => jsonResponse({ error: "not found" }, { status: 404, statusText: "Not Found" }));
118
-
119
- const result = await apiRequestTool.execute({
120
- method: "GET",
121
- url: "https://api.example.com/missing",
122
- }) as any;
123
-
124
- expect(result.ok).toBe(false);
125
- expect(result.status).toBe(404);
126
- expect(result.statusText).toBe("Not Found");
127
- });
128
-
129
- it("rechaza un método no permitido antes de tocar la red", async () => {
130
- let called = false;
131
- stubFetch(() => { called = true; return jsonResponse({}); });
132
-
133
- const result = await apiRequestTool.execute({
134
- method: "TRACE",
135
- url: "https://api.example.com/data",
136
- }) as any;
137
-
138
- expect(called).toBe(false);
139
- expect(result.ok).toBe(false);
140
- expect(result.error).toContain("Invalid HTTP method");
141
- });
142
-
143
- it("exige url", async () => {
144
- const result = await apiRequestTool.execute({ method: "GET" }) as any;
145
-
146
- expect(result.ok).toBe(false);
147
- expect(result.error).toContain("url");
148
- });
149
-
150
- it("devuelve el error de red como resultado, no como excepción", async () => {
151
- globalThis.fetch = Object.assign(
152
- async () => { throw new Error("ECONNREFUSED"); },
153
- { preconnect: async () => undefined }
154
- ) as typeof fetch;
155
-
156
- const result = await apiRequestTool.execute({
157
- method: "GET",
158
- url: "https://api.example.com/down",
159
- }) as any;
160
-
161
- expect(result.ok).toBe(false);
162
- expect(result.error).toContain("ECONNREFUSED");
163
- });
164
- });
@@ -1,83 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import {
3
- AgentBrowserView,
4
- BrowserService,
5
- initializeBrowserService,
6
- getBrowserService,
7
- waitForSelector,
8
- waitForCondition,
9
- } from "./browser-service.ts";
10
- import type { Config } from "../../config/loader.ts";
11
-
12
- describe("AgentBrowserView", () => {
13
- it("has the expected API surface", () => {
14
- const view = new AgentBrowserView("test-session");
15
- expect(view.url).toBe("");
16
- expect(typeof view.navigate).toBe("function");
17
- expect(typeof view.evaluate).toBe("function");
18
- expect(typeof view.click).toBe("function");
19
- expect(typeof view.type).toBe("function");
20
- expect(typeof view.typeIn).toBe("function");
21
- expect(typeof view.fill).toBe("function");
22
- expect(typeof view.press).toBe("function");
23
- expect(typeof view.scroll).toBe("function");
24
- expect(typeof view.scrollTo).toBe("function");
25
- expect(typeof view.back).toBe("function");
26
- expect(typeof view.forward).toBe("function");
27
- expect(typeof view.reload).toBe("function");
28
- expect(typeof view.resize).toBe("function");
29
- expect(typeof view.screenshot).toBe("function");
30
- expect(typeof view.snapshot).toBe("function");
31
- expect(typeof view.cdp).toBe("function");
32
- expect(typeof view.close).toBe("function");
33
- });
34
- });
35
-
36
- describe("BrowserService singleton", () => {
37
- it("initializes and returns the same instance", () => {
38
- const config = { tools: { browser: { enabled: true, sessionName: "test" } } } as Config;
39
- const service = initializeBrowserService(config);
40
- expect(service).toBeInstanceOf(BrowserService);
41
- expect(getBrowserService()).toBe(service);
42
- });
43
-
44
- it("exposes expected service methods", () => {
45
- const config = { tools: { browser: { enabled: true, sessionName: "test" } } } as Config;
46
- const service = BrowserService.getInstance(config);
47
- expect(typeof service.start).toBe("function");
48
- expect(typeof service.getView).toBe("function");
49
- expect(typeof service.isAvailable).toBe("function");
50
- expect(typeof service.stop).toBe("function");
51
- });
52
- });
53
-
54
- describe("wait helpers", () => {
55
- it("waitForSelector resolves when element appears", async () => {
56
- let found = false;
57
- const view = {
58
- evaluate: async (script: string) => {
59
- if (script.includes("document.querySelector")) {
60
- found = true;
61
- return true;
62
- }
63
- return false;
64
- },
65
- } as unknown as AgentBrowserView;
66
-
67
- await waitForSelector(view, "#test", 1000);
68
- expect(found).toBe(true);
69
- });
70
-
71
- it("waitForCondition resolves when expression is truthy", async () => {
72
- let calls = 0;
73
- const view = {
74
- evaluate: async () => {
75
- calls++;
76
- return calls >= 2;
77
- },
78
- } as unknown as AgentBrowserView;
79
-
80
- await waitForCondition(view, "window.ready", 1000);
81
- expect(calls).toBeGreaterThanOrEqual(2);
82
- });
83
- });
@@ -1,41 +0,0 @@
1
- process.env.HIVE_DB_PATH = ":memory:";
2
-
3
- import { describe, expect, it } from "bun:test";
4
- import { createWorker, WorkerPool } from "./index.ts";
5
-
6
- describe("createWorker", () => {
7
- it("creates a worker instance with config", () => {
8
- const worker = createWorker({
9
- name: "test-worker",
10
- systemPrompt: "You are a test worker.",
11
- });
12
-
13
- expect(worker.name).toBe("test-worker");
14
- expect(worker.id).toContain("test-worker-");
15
- worker.terminate();
16
- });
17
-
18
- it("WorkerPool creates and manages workers", () => {
19
- const pool = new WorkerPool({ maxWorkers: 2 });
20
- expect(pool.stats.total).toBe(0);
21
- expect(pool.stats.idle).toBe(0);
22
- expect(pool.stats.busy).toBe(0);
23
- pool.shutdown();
24
- });
25
-
26
- it("WorkerPool executes tasks with limited concurrency", async () => {
27
- const pool = new WorkerPool({
28
- maxWorkers: 2,
29
- workerConfig: { name: "pool-test" },
30
- });
31
-
32
- const tasks = Array.from({ length: 4 }, (_, i) => ({
33
- id: `task-${i}`,
34
- message: `Test message ${i}`,
35
- }));
36
-
37
- // Since we don't have a real LLM in tests, we just verify the pool structure
38
- expect(tasks).toHaveLength(4);
39
- pool.shutdown();
40
- });
41
- });
@@ -1,248 +0,0 @@
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);