@johpaz/hive-sdk 0.0.17 → 0.1.3

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 (63) hide show
  1. package/README.md +83 -203
  2. package/bun.lock +833 -0
  3. package/bunfig.toml +7 -0
  4. package/docs/API-TOOLS-SKILLS-CHANNELS.md +60 -0
  5. package/docs/HIVE-HARNESS.md +113 -0
  6. package/package.json +36 -2
  7. package/packages/cli/package.json +1 -1
  8. package/packages/core/package.json +13 -2
  9. package/packages/core/src/ace/Tracer.ts +1 -1
  10. package/packages/core/src/agent/AgentRunner.ts +12 -0
  11. package/packages/core/src/agent/ContextCompiler.ts +4 -4
  12. package/packages/core/src/agent/ConversationStore.ts +30 -20
  13. package/packages/core/src/agent/selectors/PlaybookSelector.ts +50 -76
  14. package/packages/core/src/agent/selectors/SkillSelector.ts +106 -262
  15. package/packages/core/src/agent/selectors/ToolSelector.ts +54 -89
  16. package/packages/core/src/api/createAgent.ts +10 -0
  17. package/packages/core/src/auth/auth.ts +36 -23
  18. package/packages/core/src/config/loader.ts +2 -2
  19. package/packages/core/src/harness/boot-id.ts +20 -0
  20. package/packages/core/src/harness/collections.ts +98 -0
  21. package/packages/core/src/harness/db-helpers.ts +87 -0
  22. package/packages/core/src/harness/durable-queue.ts +337 -0
  23. package/packages/core/src/harness/goal-verifier.ts +141 -0
  24. package/packages/core/src/harness/harness.test.ts +236 -0
  25. package/packages/core/src/harness/index.ts +34 -0
  26. package/packages/core/src/harness/job-store.ts +399 -0
  27. package/packages/core/src/harness/proof-packet.ts +69 -0
  28. package/packages/core/src/harness/reconcile.ts +149 -0
  29. package/packages/core/src/harness/run-epoch.ts +32 -0
  30. package/packages/core/src/harness/run-store.ts +334 -0
  31. package/packages/core/src/index.ts +19 -0
  32. package/packages/core/src/memory/Scratchpad.test.ts +23 -21
  33. package/packages/core/src/memory/Scratchpad.ts +41 -24
  34. package/packages/core/src/skills/bundled-data.generated.ts +50 -0
  35. package/packages/core/src/skills/skills.test.ts +21 -0
  36. package/packages/core/src/storage/HiveDBStorage.ts +64 -0
  37. package/packages/core/src/storage/SQLiteStorage.ts +7 -0
  38. package/packages/core/src/storage/hiveSeed.ts +308 -0
  39. package/packages/core/src/storage/hiveStorage.test.ts +38 -0
  40. package/packages/core/src/storage/index.ts +10 -0
  41. package/packages/core/src/storage/seed.ts +5 -1
  42. package/packages/core/src/storage/usage.ts +106 -167
  43. package/packages/core/src/tool-runtime/tool-runtime.test.ts +11 -3
  44. package/packages/core/src/tools/agents/get-available-models.ts +52 -56
  45. package/packages/core/src/tools/agents/index.ts +77 -60
  46. package/packages/core/src/tools/core/index.ts +106 -291
  47. package/packages/core/src/tools/index.ts +1 -0
  48. package/packages/core/src/tools/meeting/index.ts +83 -93
  49. package/packages/core/src/tools/web/api-request.test.ts +170 -0
  50. package/packages/core/src/tools/web/api-request.ts +239 -0
  51. package/packages/core/src/tools/web/browser-click.ts +2 -2
  52. package/packages/core/src/tools/web/browser-extract.ts +22 -6
  53. package/packages/core/src/tools/web/browser-navigate.ts +34 -18
  54. package/packages/core/src/tools/web/browser-screenshot.ts +40 -8
  55. package/packages/core/src/tools/web/browser-script.ts +2 -2
  56. package/packages/core/src/tools/web/browser-service.test.ts +83 -0
  57. package/packages/core/src/tools/web/browser-service.ts +290 -341
  58. package/packages/core/src/tools/web/browser-type.ts +2 -2
  59. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  60. package/packages/core/src/tools/web/index.ts +3 -0
  61. package/packages/core/src/utils/toon.ts +4 -4
  62. package/CHANGELOG.md +0 -72
  63. package/docs/README.md +0 -161
@@ -1,37 +1,54 @@
1
- import type { Database } from "bun:sqlite";
1
+ import { getHiveDB } from "../storage/HiveDBStorage.ts";
2
+
3
+ interface ScratchpadDoc {
4
+ threadId: string;
5
+ key: string;
6
+ value: string;
7
+ updatedAt: number;
8
+ }
2
9
 
3
10
  export class Scratchpad {
4
- constructor(private db: Database) {}
11
+ async write(threadId: string, key: string, value: string): Promise<void> {
12
+ const db = await getHiveDB();
13
+ const col = db.collection<ScratchpadDoc>("scratchpad");
14
+ await col.put(this.docId(threadId, key), { threadId, key, value, updatedAt: Date.now() });
15
+ }
5
16
 
6
- write(threadId: string, key: string, value: string): void {
7
- this.db.run(
8
- `INSERT OR REPLACE INTO scratchpad (thread_id, key, value, updated_at) VALUES (?, ?, ?, datetime('now'))`,
9
- [threadId, key, value]
10
- );
17
+ async read(threadId: string, key: string): Promise<string | undefined> {
18
+ const db = await getHiveDB();
19
+ const col = db.collection<ScratchpadDoc>("scratchpad");
20
+ const entry = await col.get(this.docId(threadId, key));
21
+ return entry?.doc.value;
11
22
  }
12
23
 
13
- read(threadId: string, key: string): string | null {
14
- const row = this.db
15
- .query(`SELECT value FROM scratchpad WHERE thread_id = ? AND key = ?`)
16
- .get(threadId, key) as any;
17
- return row?.value ?? null;
24
+ async list(threadId: string): Promise<Record<string, string>> {
25
+ const db = await getHiveDB();
26
+ const col = db.collection<ScratchpadDoc>("scratchpad");
27
+ const entries = await col.scan();
28
+ const result: Record<string, string> = {};
29
+ for (const e of entries) {
30
+ if (e.doc.threadId === threadId) {
31
+ result[e.doc.key] = e.doc.value;
32
+ }
33
+ }
34
+ return result;
18
35
  }
19
36
 
20
- list(threadId: string): Record<string, string> {
21
- const rows = this.db
22
- .query(`SELECT key, value FROM scratchpad WHERE thread_id = ?`)
23
- .all(threadId) as any[];
24
- return Object.fromEntries(rows.map(r => [r.key, r.value]));
37
+ async delete(threadId: string, key: string): Promise<void> {
38
+ const db = await getHiveDB();
39
+ const col = db.collection<ScratchpadDoc>("scratchpad");
40
+ await col.delete(this.docId(threadId, key));
25
41
  }
26
42
 
27
- delete(threadId: string, key: string): void {
28
- this.db.run(
29
- `DELETE FROM scratchpad WHERE thread_id = ? AND key = ?`,
30
- [threadId, key]
31
- );
43
+ async clear(threadId: string): Promise<void> {
44
+ const db = await getHiveDB();
45
+ const col = db.collection<ScratchpadDoc>("scratchpad");
46
+ const entries = await col.scan();
47
+ const ids = entries.filter(e => e.doc.threadId === threadId).map(e => e.id);
48
+ await db.batch(ids.map(id => ({ op: "delete" as const, collection: "scratchpad", id })));
32
49
  }
33
50
 
34
- clear(threadId: string): void {
35
- this.db.run(`DELETE FROM scratchpad WHERE thread_id = ?`, [threadId]);
51
+ private docId(threadId: string, key: string): string {
52
+ return `${threadId}:${key}`;
36
53
  }
37
54
  }
@@ -338,6 +338,56 @@ Esta skill se activa para automatizar flujos de interacción con aplicaciones we
338
338
  - ❌ No esperar carga de página
339
339
  - ❌ Ignorar errores de elementos
340
340
  - ❌ No verificar estado después de acciones
341
+ `,
342
+ },
343
+ {
344
+ name: "web_browser_research",
345
+ description: `Search the web and navigate results with a real browser to extract content from dynamic or JavaScript-heavy sites`,
346
+ category: "web",
347
+ version: "1.0.0",
348
+ tools: ["web_search","browser_navigate","browser_extract","web_fetch"],
349
+ triggers: ["investigá en web con navegador","web browser research","buscá y navegá","search and browse","research with browser","navegá los resultados","browse search results","contenido dinámico","dynamic content research","sitios con javascript","javascript sites research"],
350
+ body: `
351
+ # Web Browser Research Skill
352
+
353
+ ## Cuándo se Activa
354
+
355
+ Esta skill se activa cuando el usuario necesita investigación web profunda, especialmente cuando:
356
+ - Los resultados de búsqueda pueden requerir navegación real por sitios dinámicos.
357
+ - El contenido objetivo está renderizado con JavaScript (SPAs, dashboards, etc.).
358
+ - Se necesita extraer datos estructurados de páginas web.
359
+
360
+ ## Herramientas Disponibles
361
+
362
+ | Tool | Qué hace | Cuándo usarla |
363
+ |------|----------|---------------|
364
+ | \`web_search\` | Busca en internet y devuelve resultados | Encontrar URLs relevantes |
365
+ | \`browser_navigate\` | Navega y renderiza la página completa | Sitios dinámicos con JavaScript |
366
+ | \`browser_extract\` | Extrae datos con selectores CSS/XPath | Obtener contenido estructurado |
367
+ | \`web_fetch\` | Descarga contenido estático | Páginas simples o respaldo |
368
+
369
+ ## Workflow
370
+
371
+ 1. **Buscar** → \`web_search({ query, numResults: 5 })\`
372
+ 2. **Seleccionar fuentes** → Elegir 2-3 URLs relevantes y confiables.
373
+ 3. **Navegar** → \`browser_navigate({ url })\` para cada fuente dinámica.
374
+ 4. **Extraer** → \`browser_extract({ selector: "article, .content, main" })\` o similar.
375
+ 5. **Respaldo estático** → Si el browser falla, usar \`web_fetch({ url })\`.
376
+ 6. **Sintetizar** → Responder con puntos clave y citas con URLs completas.
377
+
378
+ ## Mejores Prácticas
379
+
380
+ - Priorizar sitios oficiales, documentación y fuentes primarias.
381
+ - Usar selectores estables (etiquetas semánticas como \`article\`, \`main\`).
382
+ - Si el contenido es largo, extraer por secciones.
383
+ - Siempre incluir URLs de fuentes en la respuesta final.
384
+
385
+ ## Errores a Evitar
386
+
387
+ - ❌ Usar solo \`web_fetch\` para SPAs sin probar el browser primero.
388
+ - ❌ Seleccionar selectores frágiles basados en clases aleatorias.
389
+ - ❌ No citar las fuentes usadas.
390
+ - ❌ Confundir snippets de búsqueda con contenido completo verificado.
341
391
  `,
342
392
  },
343
393
  {
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { BUNDLED_SKILLS_DATA } from "./bundled-data.generated.ts";
3
+
4
+ describe("Bundled skills", () => {
5
+ it("includes web_browser_research skill", () => {
6
+ const skill = BUNDLED_SKILLS_DATA.find((s) => s.name === "web_browser_research");
7
+ expect(skill).toBeDefined();
8
+ expect(skill?.category).toBe("web");
9
+ expect(skill?.tools).toContain("web_search");
10
+ expect(skill?.tools).toContain("browser_navigate");
11
+ expect(skill?.tools).toContain("browser_extract");
12
+ expect(skill?.triggers.length).toBeGreaterThan(0);
13
+ });
14
+
15
+ it("includes existing web and browser skills", () => {
16
+ const names = BUNDLED_SKILLS_DATA.map((s) => s.name);
17
+ expect(names).toContain("web_research");
18
+ expect(names).toContain("browser_scrape");
19
+ expect(names).toContain("browser_automate");
20
+ });
21
+ });
@@ -0,0 +1,64 @@
1
+ import { HiveDB, type Collection, type EventInput, type Event } from "@johpaz/hive-db";
2
+ import * as path from "node:path";
3
+ import { existsSync, mkdirSync } from "node:fs";
4
+ import { getHiveDir } from "../config/loader.ts";
5
+ import { logger } from "../utils/logger.ts";
6
+
7
+ const log = logger.child("hivedb-storage");
8
+
9
+ let _db: HiveDB | null = null;
10
+ let _opening: Promise<HiveDB> | null = null;
11
+
12
+ export function getHiveDbPath(): string {
13
+ return path.join(getHiveDir(), "data", "hive");
14
+ }
15
+
16
+ export function openHiveDB(): Promise<HiveDB> {
17
+ if (_db) return Promise.resolve(_db);
18
+ if (_opening) return _opening;
19
+
20
+ const hiveDir = getHiveDir();
21
+ const dir = path.join(hiveDir, "data");
22
+ if (!existsSync(dir)) {
23
+ mkdirSync(dir, { recursive: true });
24
+ }
25
+
26
+ const dbPath = getHiveDbPath();
27
+ log.info(`[hivedb] Opening HiveDB at ${dbPath}`);
28
+ _opening = HiveDB.open(dbPath, { vector: { dimension: 384, spaceId: "hive-sdk-v1" } }).then((db) => {
29
+ _db = db;
30
+ _opening = null;
31
+ return db;
32
+ });
33
+ return _opening;
34
+ }
35
+
36
+ export async function getHiveDB(): Promise<HiveDB> {
37
+ if (_db) return _db;
38
+ if (_opening) return _opening;
39
+ return openHiveDB();
40
+ }
41
+
42
+ export async function closeHiveDB(): Promise<void> {
43
+ if (_db) {
44
+ _db.close();
45
+ _db = null;
46
+ }
47
+ _opening = null;
48
+ }
49
+
50
+ export async function hiveCollection<T = unknown>(name: string): Promise<Collection<T>> {
51
+ return (await getHiveDB()).collection<T>(name);
52
+ }
53
+
54
+ export async function hiveAppend(input: EventInput): Promise<number> {
55
+ return (await getHiveDB()).append(input);
56
+ }
57
+
58
+ export async function hiveRead(seq: number): Promise<Event> {
59
+ return (await getHiveDB()).read(seq);
60
+ }
61
+
62
+ export function isHiveDBInitialized(): boolean {
63
+ return _db !== null;
64
+ }
@@ -4,6 +4,7 @@ import * as path from "node:path";
4
4
  import { existsSync, mkdirSync } from "node:fs";
5
5
  import { getHiveDir } from "../config/loader.ts";
6
6
  import { SCHEMA, PROJECTS_SCHEMA, CONTEXT_ENGINE_SCHEMA, MEETING_SCHEMA } from "./schema.ts";
7
+ import { openHiveDB, closeHiveDB } from "./HiveDBStorage.ts";
7
8
 
8
9
  function getDbPath(): string {
9
10
  return path.join(getHiveDir(), "data", "hive.db");
@@ -84,6 +85,12 @@ export function initializeDatabase(): Database {
84
85
 
85
86
  ensureSchemaSync();
86
87
 
88
+ // Open HiveDB as the new source-of-truth engine alongside SQLite
89
+ // during the migration; SQLite will be removed once all tables are migrated.
90
+ openHiveDB().catch((err) => {
91
+ logger.error("❌ Failed to initialize HiveDB:", err);
92
+ });
93
+
87
94
  return _db;
88
95
  }
89
96
 
@@ -0,0 +1,308 @@
1
+ import { getHiveDB, hiveCollection } from "./HiveDBStorage.ts";
2
+ import { logger } from "../utils/logger.ts";
3
+ import { SEED_DATA, INITIAL_PLAYBOOK_RULES } from "./seed.ts";
4
+ import { SkillLoader } from "../skills/index.ts";
5
+ import { enrichToolDescription } from "../agent/selectors/ToolSelector.ts";
6
+ import type { ToolDescriptor } from "../agent/selectors/ToolSelector.ts";
7
+ import type { IndexDoc, HiveDB } from "@johpaz/hive-db";
8
+
9
+ const log = logger.child("hive-seed");
10
+
11
+ export interface HiveToolDoc {
12
+ name: string;
13
+ description: string;
14
+ category: string;
15
+ enabled: boolean;
16
+ active: boolean;
17
+ }
18
+
19
+ export interface HiveProviderDoc {
20
+ id: string;
21
+ name: string;
22
+ baseUrl?: string;
23
+ category: string;
24
+ enabled: boolean;
25
+ active: boolean;
26
+ }
27
+
28
+ export interface HiveModelDoc {
29
+ id: string;
30
+ providerId: string;
31
+ name: string;
32
+ modelType: string;
33
+ contextWindow?: number;
34
+ capabilities?: string[];
35
+ enabled: boolean;
36
+ active: boolean;
37
+ }
38
+
39
+ export interface HiveSkillDoc {
40
+ id: string;
41
+ name: string;
42
+ description: string;
43
+ version: string;
44
+ author: string;
45
+ icon: string;
46
+ category: string;
47
+ permissions: string[];
48
+ dependencies: string[];
49
+ tools: string[];
50
+ triggers: string[];
51
+ preferredAgents: string[];
52
+ body: string;
53
+ versionNum: number;
54
+ active: boolean;
55
+ }
56
+
57
+ export interface HiveAgentDoc {
58
+ id: string;
59
+ userId?: string;
60
+ name: string;
61
+ description: string;
62
+ systemPrompt: string;
63
+ toolsJson?: string;
64
+ role: string;
65
+ status: string;
66
+ parentId?: string;
67
+ providerId: string;
68
+ modelId: string;
69
+ tone?: string;
70
+ maxIterations: number;
71
+ workspace?: string;
72
+ enabled: boolean;
73
+ active: boolean;
74
+ createdAt: number;
75
+ updatedAt: number;
76
+ }
77
+
78
+ export interface HiveChannelDoc {
79
+ id: string;
80
+ type: string;
81
+ enabled: boolean;
82
+ active: boolean;
83
+ status: string;
84
+ }
85
+
86
+ export interface HiveEthicsDoc {
87
+ id: string;
88
+ name: string;
89
+ description: string;
90
+ content: string;
91
+ isDefault: boolean;
92
+ enabled: boolean;
93
+ active: boolean;
94
+ }
95
+
96
+ export interface HiveCodeBridgeDoc {
97
+ id: string;
98
+ name: string;
99
+ cliCommand: string;
100
+ port: number;
101
+ enabled: boolean;
102
+ active: boolean;
103
+ }
104
+
105
+ export interface HiveCodeBridgeConfigDoc {
106
+ id: string;
107
+ key: string;
108
+ value: string;
109
+ }
110
+
111
+ export interface HivePlaybookDoc {
112
+ rule: string;
113
+ category: string;
114
+ applicableTo?: string[];
115
+ helpfulCount: number;
116
+ harmfulCount: number;
117
+ active: boolean;
118
+ }
119
+
120
+ export async function seedHiveDB(db?: HiveDB): Promise<void> {
121
+ db ??= await getHiveDB();
122
+
123
+ log.info("[hive-seed] 🌱 Iniciando seed de HiveDB");
124
+
125
+ // 1️⃣ Tools
126
+ const toolsCol = db.collection<HiveToolDoc>("tools");
127
+ await toolsCol.createIndex("name", { unique: true });
128
+ for (const tool of SEED_DATA.tools) {
129
+ await toolsCol.put(tool.id, {
130
+ name: tool.name,
131
+ description: tool.description,
132
+ category: tool.category,
133
+ enabled: tool.enabled ?? true,
134
+ active: true,
135
+ });
136
+ }
137
+ log.info(`[hive-seed] ✅ ${SEED_DATA.tools.length} tools seeded`);
138
+
139
+ // 2️⃣ Index tools for hybrid search
140
+ const toolDocs: IndexDoc[] = SEED_DATA.tools.map(tool => ({
141
+ id: tool.name,
142
+ name: tool.name,
143
+ body: enrichToolDescription({ name: tool.name, description: tool.description, category: tool.category } as ToolDescriptor),
144
+ tags: tool.category,
145
+ filters: [{ field: "type", value: "tool" }],
146
+ }));
147
+ await db.upsertBatch(toolDocs);
148
+ log.info(`[hive-seed] ✅ ${toolDocs.length} tools indexed`);
149
+
150
+ // 3️⃣ Providers
151
+ const providersCol = db.collection<HiveProviderDoc>("providers");
152
+ await providersCol.createIndex("id", { unique: true });
153
+ for (const provider of SEED_DATA.providers) {
154
+ await providersCol.put(provider.id, {
155
+ id: provider.id,
156
+ name: provider.name,
157
+ baseUrl: provider.baseUrl,
158
+ category: provider.category ?? "llm",
159
+ enabled: true,
160
+ active: false,
161
+ });
162
+ }
163
+ const ollamaHost = process.env.OLLAMA_HOST;
164
+ if (ollamaHost) {
165
+ const entry = await providersCol.get("ollama");
166
+ if (entry) {
167
+ await providersCol.put("ollama", { ...entry.doc, baseUrl: ollamaHost });
168
+ }
169
+ }
170
+ log.info(`[hive-seed] ✅ ${SEED_DATA.providers.length} providers seeded`);
171
+
172
+ // 4️⃣ Models
173
+ const modelsCol = db.collection<HiveModelDoc>("models");
174
+ await modelsCol.createIndex("id", { unique: true });
175
+ await modelsCol.createIndex("providerId");
176
+ for (const model of SEED_DATA.models) {
177
+ await modelsCol.put(model.id, {
178
+ id: model.id,
179
+ providerId: model.providerId,
180
+ name: model.name,
181
+ modelType: model.modelType,
182
+ contextWindow: model.contextWindow,
183
+ capabilities: model.capabilities ? JSON.parse(model.capabilities) : undefined,
184
+ enabled: true,
185
+ active: false,
186
+ });
187
+ }
188
+ log.info(`[hive-seed] ✅ ${SEED_DATA.models.length} models seeded`);
189
+
190
+ // 5️⃣ MCP servers
191
+ const mcpCol = db.collection("mcp_servers");
192
+ await mcpCol.createIndex("id", { unique: true });
193
+ for (const mcp of SEED_DATA.mcpServers) {
194
+ await mcpCol.put(mcp.id, { ...mcp, enabled: true, active: false, builtin: mcp.builtin, toolsCount: 0 });
195
+ }
196
+ log.info(`[hive-seed] ✅ ${SEED_DATA.mcpServers.length} MCP servers seeded`);
197
+
198
+ // 6️⃣ Channels
199
+ const channelsCol = db.collection<HiveChannelDoc>("channels");
200
+ await channelsCol.createIndex("id", { unique: true });
201
+ for (const channel of SEED_DATA.channels) {
202
+ const isWebChat = channel.id === "webchat";
203
+ await channelsCol.put(channel.id, {
204
+ id: channel.id,
205
+ type: channel.type,
206
+ enabled: true,
207
+ active: isWebChat,
208
+ status: isWebChat ? "connected" : "disconnected",
209
+ });
210
+ }
211
+ log.info(`[hive-seed] ✅ ${SEED_DATA.channels.length} channels seeded`);
212
+
213
+ // 7️⃣ Ethics
214
+ const ethicsCol = db.collection<HiveEthicsDoc>("ethics");
215
+ await ethicsCol.createIndex("id", { unique: true });
216
+ for (const ethics of SEED_DATA.ethics) {
217
+ await ethicsCol.put(ethics.id, {
218
+ id: ethics.id,
219
+ name: ethics.name,
220
+ description: ethics.description,
221
+ content: ethics.content,
222
+ isDefault: ethics.isDefault,
223
+ enabled: true,
224
+ active: ethics.isDefault,
225
+ });
226
+ }
227
+ log.info(`[hive-seed] ✅ ${SEED_DATA.ethics.length} ethics templates seeded`);
228
+
229
+ // 8️⃣ Code Bridge
230
+ const cbCol = db.collection<HiveCodeBridgeDoc>("code_bridge");
231
+ await cbCol.createIndex("id", { unique: true });
232
+ for (const cb of SEED_DATA.codeBridge) {
233
+ await cbCol.put(cb.id, { ...cb, enabled: false, active: false });
234
+ }
235
+ log.info(`[hive-seed] ✅ ${SEED_DATA.codeBridge.length} Code Bridge entries seeded`);
236
+
237
+ // 9️⃣ Code Bridge Config
238
+ const cbConfigCol = db.collection<HiveCodeBridgeConfigDoc>("code_bridge_config");
239
+ await cbConfigCol.createIndex("id", { unique: true });
240
+ for (const config of SEED_DATA.codeBridgeConfig) {
241
+ await cbConfigCol.put(config.id, config);
242
+ }
243
+ log.info(`[hive-seed] ✅ ${SEED_DATA.codeBridgeConfig.length} Code Bridge Config entries seeded`);
244
+
245
+ // 🔟 Skills
246
+ const skillLoader = new SkillLoader({ workspacePath: process.env.HIVE_HOME || process.cwd() });
247
+ const realSkills = skillLoader.loadBundledSkills();
248
+ const skillsCol = db.collection("skills");
249
+ await skillsCol.createIndex("id", { unique: true });
250
+ const skillDocs: IndexDoc[] = [];
251
+ for (const s of realSkills) {
252
+ const doc = {
253
+ id: s.name,
254
+ name: s.name,
255
+ description: s.description || "",
256
+ version: typeof s.version === "string" ? s.version : String(s.version || "0.0.1"),
257
+ author: s.author || "Anonymous",
258
+ icon: s.icon || "🧩",
259
+ category: s.category || "general",
260
+ permissions: s.permissions || [],
261
+ dependencies: s.dependencies || [],
262
+ tools: s.tools || [],
263
+ triggers: s.triggers || [],
264
+ preferredAgents: s.preferred_agents || [],
265
+ body: s.content || "",
266
+ versionNum: parseInt(String(s.version || "0.0.1").split(".")[0]) || 1,
267
+ active: true,
268
+ };
269
+ await skillsCol.put(s.name, doc);
270
+ skillDocs.push({
271
+ id: s.name,
272
+ name: s.name,
273
+ body: `${s.description || ""} ${s.content || ""}`,
274
+ tags: [s.category || "general", ...(s.tools || []), ...(s.triggers || [])].join(" "),
275
+ filters: [{ field: "type", value: "skill" }],
276
+ });
277
+ }
278
+ await db.upsertBatch(skillDocs);
279
+ log.info(`[hive-seed] ✅ ${realSkills.length} skills seeded and indexed`);
280
+
281
+ // 11. ACE Playbook
282
+ const playbookCol = db.collection<HivePlaybookDoc>("playbook");
283
+ await playbookCol.createIndex("id", { unique: true });
284
+ const playbookDocs: IndexDoc[] = [];
285
+ for (const rule of INITIAL_PLAYBOOK_RULES) {
286
+ const doc = {
287
+ rule: rule.rule,
288
+ category: rule.category,
289
+ applicableTo: rule.applicable_to ? JSON.parse(rule.applicable_to) : undefined,
290
+ helpfulCount: 1,
291
+ harmfulCount: 0,
292
+ active: true,
293
+ };
294
+ const id = `${rule.category}-${rule.rule.slice(0, 32).replace(/\s+/g, "-")}`;
295
+ await playbookCol.put(id, doc);
296
+ playbookDocs.push({
297
+ id,
298
+ name: rule.category,
299
+ body: rule.rule,
300
+ tags: rule.applicable_to || "",
301
+ filters: [{ field: "type", value: "playbook" }],
302
+ });
303
+ }
304
+ await db.upsertBatch(playbookDocs);
305
+ log.info(`[hive-seed] ✅ ${INITIAL_PLAYBOOK_RULES.length} playbook rules seeded and indexed`);
306
+
307
+ log.info("[hive-seed] ✨ HiveDB seed completado");
308
+ }
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "bun:test";
2
+ import { HiveDB } from "@johpaz/hive-db";
3
+ import { seedHiveDB } from "./hiveSeed.ts";
4
+
5
+ describe("HiveDB integration", () => {
6
+ let db: HiveDB;
7
+
8
+ beforeAll(async () => {
9
+ db = await HiveDB.open(":memory:", { vector: { dimension: 384, spaceId: "hive-sdk-v1" } });
10
+ await seedHiveDB(db);
11
+ });
12
+
13
+ afterAll(() => {
14
+ db.close();
15
+ });
16
+
17
+ it("seeds providers and models", async () => {
18
+ const providers = await db.collection("providers").count();
19
+ const models = await db.collection("models").count();
20
+ expect(providers).toBeGreaterThan(0);
21
+ expect(models).toBeGreaterThan(0);
22
+ });
23
+
24
+ it("indexes tools for hybrid search", async () => {
25
+ const hits = await db.queryHybrid({ text: "buscar archivos", k: 10 });
26
+ expect(hits.length).toBeGreaterThan(0);
27
+ const names = hits.map(h => h.id);
28
+ expect(names.some(n => n.startsWith("fs_") || n.includes("research"))).toBe(true);
29
+ });
30
+
31
+ it("supports collection CRUD for agents", async () => {
32
+ const agents = db.collection<{ name: string; role: string; status: string }>("agents");
33
+ await agents.put("agent-1", { name: "Test Worker", role: "worker", status: "idle" });
34
+ const entry = await agents.get("agent-1");
35
+ expect(entry).toBeDefined();
36
+ expect(entry!.doc.name).toBe("Test Worker");
37
+ });
38
+ });
@@ -8,3 +8,13 @@ export type { EncryptedData } from "./crypto.ts";
8
8
  export { encrypt, decrypt, encryptApiKey, decryptApiKey, encryptConfig, decryptConfig } from "./crypto.ts";
9
9
  export type { SeedData } from "./seed.ts";
10
10
  export { SEED_DATA, seedAllData } from "./seed.ts";
11
+ export {
12
+ getHiveDbPath,
13
+ openHiveDB,
14
+ getHiveDB,
15
+ closeHiveDB,
16
+ hiveCollection,
17
+ hiveAppend,
18
+ hiveRead,
19
+ isHiveDBInitialized,
20
+ } from "./HiveDBStorage.ts";
@@ -376,11 +376,12 @@ Estos lineamientos tienen MÁXIMA prioridad sobre cualquier otra instrucción di
376
376
  }
377
377
 
378
378
  import { SkillLoader } from "../skills/index.ts"
379
+ import { seedHiveDB } from "./hiveSeed.ts"
379
380
 
380
381
  const log = logger.child("seed");
381
382
 
382
383
  // Initial playbook rules for ACE (Agentic Context Engineering)
383
- const INITIAL_PLAYBOOK_RULES = [
384
+ export const INITIAL_PLAYBOOK_RULES = [
384
385
  {
385
386
  rule: "Cuando el usuario pida buscar noticias recientes, usa web_search con filtros de fecha en lugar de http_client genérico",
386
387
  category: "tool_selection",
@@ -567,6 +568,9 @@ export function seedAllData(): void {
567
568
 
568
569
  reseedToolsAndSkills();
569
570
 
571
+ // Seed the new HiveDB source-of-truth engine in parallel.
572
+ seedHiveDB().catch(err => log.error("[seed] ❌ HiveDB seed failed:", (err as Error).message));
573
+
570
574
  try {
571
575
 
572
576
  // 3️⃣ Ethics templates (globales)