@johpaz/hive 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/CONTRIBUTING.md +44 -0
  2. package/README.md +310 -0
  3. package/package.json +96 -0
  4. package/packages/cli/package.json +28 -0
  5. package/packages/cli/src/commands/agent-run.ts +168 -0
  6. package/packages/cli/src/commands/agents.ts +398 -0
  7. package/packages/cli/src/commands/chat.ts +142 -0
  8. package/packages/cli/src/commands/config.ts +50 -0
  9. package/packages/cli/src/commands/cron.ts +161 -0
  10. package/packages/cli/src/commands/dev.ts +95 -0
  11. package/packages/cli/src/commands/doctor.ts +133 -0
  12. package/packages/cli/src/commands/gateway.ts +443 -0
  13. package/packages/cli/src/commands/logs.ts +57 -0
  14. package/packages/cli/src/commands/mcp.ts +175 -0
  15. package/packages/cli/src/commands/message.ts +77 -0
  16. package/packages/cli/src/commands/onboard.ts +1868 -0
  17. package/packages/cli/src/commands/security.ts +144 -0
  18. package/packages/cli/src/commands/service.ts +50 -0
  19. package/packages/cli/src/commands/sessions.ts +116 -0
  20. package/packages/cli/src/commands/skills.ts +187 -0
  21. package/packages/cli/src/commands/update.ts +25 -0
  22. package/packages/cli/src/index.ts +185 -0
  23. package/packages/cli/src/utils/token.ts +6 -0
  24. package/packages/code-bridge/README.md +78 -0
  25. package/packages/code-bridge/package.json +18 -0
  26. package/packages/code-bridge/src/index.ts +95 -0
  27. package/packages/code-bridge/src/process-manager.ts +212 -0
  28. package/packages/code-bridge/src/schemas.ts +133 -0
  29. package/packages/core/package.json +46 -0
  30. package/packages/core/src/agent/agent-loop.ts +369 -0
  31. package/packages/core/src/agent/compaction.ts +140 -0
  32. package/packages/core/src/agent/context-compiler.ts +378 -0
  33. package/packages/core/src/agent/context-guard.ts +91 -0
  34. package/packages/core/src/agent/context.ts +138 -0
  35. package/packages/core/src/agent/conversation-store.ts +198 -0
  36. package/packages/core/src/agent/curator.ts +158 -0
  37. package/packages/core/src/agent/hooks.ts +166 -0
  38. package/packages/core/src/agent/index.ts +116 -0
  39. package/packages/core/src/agent/llm-client.ts +503 -0
  40. package/packages/core/src/agent/native-tools.ts +505 -0
  41. package/packages/core/src/agent/prompt-builder.ts +532 -0
  42. package/packages/core/src/agent/providers/index.ts +167 -0
  43. package/packages/core/src/agent/providers.ts +1 -0
  44. package/packages/core/src/agent/reflector.ts +170 -0
  45. package/packages/core/src/agent/service.ts +64 -0
  46. package/packages/core/src/agent/stuck-loop.ts +133 -0
  47. package/packages/core/src/agent/supervisor.ts +39 -0
  48. package/packages/core/src/agent/tracer.ts +102 -0
  49. package/packages/core/src/agent/workspace.ts +110 -0
  50. package/packages/core/src/canvas/canvas-manager.test.ts +161 -0
  51. package/packages/core/src/canvas/canvas-manager.ts +319 -0
  52. package/packages/core/src/canvas/canvas-tools.ts +420 -0
  53. package/packages/core/src/canvas/emitter.ts +115 -0
  54. package/packages/core/src/canvas/index.ts +2 -0
  55. package/packages/core/src/channels/base.ts +138 -0
  56. package/packages/core/src/channels/discord.ts +260 -0
  57. package/packages/core/src/channels/index.ts +7 -0
  58. package/packages/core/src/channels/manager.ts +383 -0
  59. package/packages/core/src/channels/slack.ts +287 -0
  60. package/packages/core/src/channels/telegram.ts +502 -0
  61. package/packages/core/src/channels/webchat.ts +128 -0
  62. package/packages/core/src/channels/whatsapp.ts +375 -0
  63. package/packages/core/src/config/index.ts +12 -0
  64. package/packages/core/src/config/loader.ts +529 -0
  65. package/packages/core/src/events/event-bus.ts +169 -0
  66. package/packages/core/src/gateway/index.ts +5 -0
  67. package/packages/core/src/gateway/initializer.ts +290 -0
  68. package/packages/core/src/gateway/lane-queue.ts +169 -0
  69. package/packages/core/src/gateway/resolver.ts +108 -0
  70. package/packages/core/src/gateway/router.ts +124 -0
  71. package/packages/core/src/gateway/server.ts +3317 -0
  72. package/packages/core/src/gateway/session.ts +95 -0
  73. package/packages/core/src/gateway/slash-commands.ts +192 -0
  74. package/packages/core/src/heartbeat/index.ts +157 -0
  75. package/packages/core/src/index.ts +19 -0
  76. package/packages/core/src/integrations/catalog.ts +286 -0
  77. package/packages/core/src/integrations/env.ts +64 -0
  78. package/packages/core/src/integrations/index.ts +2 -0
  79. package/packages/core/src/memory/index.ts +1 -0
  80. package/packages/core/src/memory/notes.ts +68 -0
  81. package/packages/core/src/plugins/api.ts +128 -0
  82. package/packages/core/src/plugins/index.ts +2 -0
  83. package/packages/core/src/plugins/loader.ts +365 -0
  84. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  85. package/packages/core/src/security/google-chat.ts +269 -0
  86. package/packages/core/src/security/index.ts +192 -0
  87. package/packages/core/src/security/pairing.ts +250 -0
  88. package/packages/core/src/security/rate-limit.ts +270 -0
  89. package/packages/core/src/security/signal.ts +321 -0
  90. package/packages/core/src/state/store.ts +312 -0
  91. package/packages/core/src/storage/bun-sqlite-store.ts +188 -0
  92. package/packages/core/src/storage/crypto.ts +101 -0
  93. package/packages/core/src/storage/db-context.ts +333 -0
  94. package/packages/core/src/storage/onboarding.ts +1087 -0
  95. package/packages/core/src/storage/schema.ts +541 -0
  96. package/packages/core/src/storage/seed.ts +571 -0
  97. package/packages/core/src/storage/sqlite.ts +387 -0
  98. package/packages/core/src/storage/usage.ts +212 -0
  99. package/packages/core/src/tools/bridge-events.ts +74 -0
  100. package/packages/core/src/tools/browser.ts +275 -0
  101. package/packages/core/src/tools/codebridge.ts +421 -0
  102. package/packages/core/src/tools/coordinator-tools.ts +179 -0
  103. package/packages/core/src/tools/cron.ts +611 -0
  104. package/packages/core/src/tools/exec.ts +140 -0
  105. package/packages/core/src/tools/fs.ts +364 -0
  106. package/packages/core/src/tools/index.ts +12 -0
  107. package/packages/core/src/tools/memory.ts +176 -0
  108. package/packages/core/src/tools/notify.ts +113 -0
  109. package/packages/core/src/tools/project-management.ts +376 -0
  110. package/packages/core/src/tools/project.ts +375 -0
  111. package/packages/core/src/tools/read.ts +158 -0
  112. package/packages/core/src/tools/web.ts +436 -0
  113. package/packages/core/src/tools/workspace.ts +171 -0
  114. package/packages/core/src/utils/benchmark.ts +80 -0
  115. package/packages/core/src/utils/crypto.ts +73 -0
  116. package/packages/core/src/utils/date.ts +42 -0
  117. package/packages/core/src/utils/index.ts +4 -0
  118. package/packages/core/src/utils/logger.ts +388 -0
  119. package/packages/core/src/utils/retry.ts +70 -0
  120. package/packages/core/src/voice/index.ts +583 -0
  121. package/packages/core/tsconfig.json +9 -0
  122. package/packages/mcp/package.json +26 -0
  123. package/packages/mcp/src/config.ts +13 -0
  124. package/packages/mcp/src/index.ts +1 -0
  125. package/packages/mcp/src/logger.ts +42 -0
  126. package/packages/mcp/src/manager.ts +434 -0
  127. package/packages/mcp/src/transports/index.ts +67 -0
  128. package/packages/mcp/src/transports/sse.ts +241 -0
  129. package/packages/mcp/src/transports/websocket.ts +159 -0
  130. package/packages/skills/package.json +21 -0
  131. package/packages/skills/src/bundled/agent_management/SKILL.md +24 -0
  132. package/packages/skills/src/bundled/browser_automation/SKILL.md +30 -0
  133. package/packages/skills/src/bundled/context_compact/SKILL.md +35 -0
  134. package/packages/skills/src/bundled/cron_manager/SKILL.md +52 -0
  135. package/packages/skills/src/bundled/file_manager/SKILL.md +76 -0
  136. package/packages/skills/src/bundled/http_client/SKILL.md +24 -0
  137. package/packages/skills/src/bundled/memory/SKILL.md +42 -0
  138. package/packages/skills/src/bundled/project_management/SKILL.md +26 -0
  139. package/packages/skills/src/bundled/shell/SKILL.md +43 -0
  140. package/packages/skills/src/bundled/system_notify/SKILL.md +52 -0
  141. package/packages/skills/src/bundled/voice/SKILL.md +25 -0
  142. package/packages/skills/src/bundled/web_search/SKILL.md +29 -0
  143. package/packages/skills/src/index.ts +1 -0
  144. package/packages/skills/src/loader.ts +282 -0
  145. package/packages/tools/package.json +43 -0
  146. package/packages/tools/src/browser/browser.test.ts +111 -0
  147. package/packages/tools/src/browser/index.ts +272 -0
  148. package/packages/tools/src/canvas/index.ts +220 -0
  149. package/packages/tools/src/cron/cron.test.ts +164 -0
  150. package/packages/tools/src/cron/index.ts +304 -0
  151. package/packages/tools/src/filesystem/filesystem.test.ts +240 -0
  152. package/packages/tools/src/filesystem/index.ts +379 -0
  153. package/packages/tools/src/git/index.ts +239 -0
  154. package/packages/tools/src/index.ts +4 -0
  155. package/packages/tools/src/shell/detect-env.ts +70 -0
  156. package/packages/tools/tsconfig.json +9 -0
@@ -0,0 +1,529 @@
1
+ import * as z from "zod";
2
+ import { mkdirSync, existsSync, readFileSync } from "node:fs";
3
+ import * as path from "node:path";
4
+
5
+ const LogLevelSchema = z.enum(["debug", "info", "warn", "error"]);
6
+ const DMPolicySchema = z.enum(["open", "pairing", "allowlist"]);
7
+ const TransportSchema = z.enum(["stdio", "sse", "websocket"]);
8
+
9
+ export function loadEnv(hiveDir: string): void {
10
+ const envPath = path.join(hiveDir, ".env");
11
+ if (existsSync(envPath)) {
12
+ try {
13
+ const text = readFileSync(envPath, "utf8");
14
+ const lines = text.split("\n");
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed || trimmed.startsWith("#")) continue;
18
+
19
+ const [key, ...valueParts] = trimmed.split("=");
20
+ if (key && valueParts.length > 0) {
21
+ const value = valueParts.join("=").trim().replace(/^['"]|['"]$/g, "");
22
+ process.env[key.trim()] = value;
23
+ }
24
+ }
25
+ } catch (e) {
26
+ // Ignore errors loading .env
27
+ }
28
+ }
29
+ }
30
+
31
+ export function getHiveDir(): string {
32
+ // Priority 1: HIVE_HOME explicitly set
33
+ if (process.env.HIVE_HOME) {
34
+ const hiveDir = process.env.HIVE_HOME.startsWith("~")
35
+ ? path.join(process.env.HOME || "", process.env.HIVE_HOME.slice(1))
36
+ : process.env.HIVE_HOME;
37
+ loadEnv(hiveDir);
38
+ return hiveDir;
39
+ }
40
+
41
+ // Priority 2: HIVE_DEV mode defaults (Local folder)
42
+ if (process.env.HIVE_DEV === "1" || process.env.HIVE_DEV === "true") {
43
+ const localDir = path.join(process.cwd(), ".hive-dev");
44
+ loadEnv(localDir);
45
+ return localDir;
46
+ }
47
+
48
+ // Priority 3: Default ~/.hive
49
+ const defaultDir = path.join(process.env.HOME || "", ".hive");
50
+ loadEnv(defaultDir);
51
+ return defaultDir;
52
+ }
53
+
54
+ const expandPath = (p: string): string => {
55
+ if (p.startsWith("~/.hive")) {
56
+ const hiveDir = getHiveDir();
57
+ return p.replace("~/.hive", hiveDir);
58
+ }
59
+ if (p.startsWith("~")) {
60
+ return path.join(process.env.HOME || "", p.slice(1));
61
+ }
62
+ return p;
63
+ };
64
+
65
+ const expandEnvVars = (value: string): string => {
66
+ return value.replace(/\$\{([^}]+)\}/g, (_, key) => {
67
+ return process.env[key] || "";
68
+ });
69
+ };
70
+
71
+ const expandEnvInObject = <T>(obj: T): T => {
72
+ if (typeof obj === "string") {
73
+ return expandEnvVars(obj) as T;
74
+ }
75
+ if (Array.isArray(obj)) {
76
+ return obj.map(expandEnvInObject) as T;
77
+ }
78
+ if (obj !== null && typeof obj === "object") {
79
+ const result: Record<string, unknown> = {};
80
+ for (const [key, value] of Object.entries(obj)) {
81
+ result[key] = expandEnvInObject(value);
82
+ }
83
+ return result as T;
84
+ }
85
+ return obj;
86
+ };
87
+
88
+ const ProviderConfigSchema = z.object({
89
+ apiKey: z.string().optional(),
90
+ baseUrl: z.string().optional(),
91
+ rateLimit: z.number().optional(),
92
+ retries: z.number().optional(),
93
+ retryDelayMs: z.number().optional(),
94
+ });
95
+
96
+ const ToolRestrictionsSchema = z.object({
97
+ allow: z.array(z.string()).optional(),
98
+ deny: z.array(z.string()).optional(),
99
+ });
100
+
101
+ const ExecConfigSchema = z.object({
102
+ enabled: z.boolean().optional(),
103
+ allowlist: z.array(z.string()).optional(),
104
+ denylist: z.array(z.string()).optional(),
105
+ timeoutSeconds: z.number().optional(),
106
+ workDir: z.string().optional(),
107
+ });
108
+
109
+ const WebConfigSchema = z.object({
110
+ allowlist: z.array(z.string()).optional(),
111
+ denylist: z.array(z.string()).optional(),
112
+ timeoutSeconds: z.number().optional(),
113
+ });
114
+
115
+ const BrowserConfigSchema = z.object({
116
+ enabled: z.boolean().optional(),
117
+ browserPath: z.string().optional(),
118
+ headless: z.boolean().optional(),
119
+ timeoutSeconds: z.number().optional(),
120
+ });
121
+
122
+ const CanvasConfigSchema = z.object({
123
+ enabled: z.boolean().optional(),
124
+ port: z.number().optional(),
125
+ });
126
+
127
+ const SandboxConfigSchema = z.object({
128
+ dm: ToolRestrictionsSchema.optional(),
129
+ group: ToolRestrictionsSchema.optional(),
130
+ });
131
+
132
+ const ToolsConfigSchema = z.object({
133
+ allow: z.array(z.string()).optional(),
134
+ deny: z.array(z.string()).optional(),
135
+ exec: ExecConfigSchema.optional(),
136
+ web: WebConfigSchema.optional(),
137
+ browser: BrowserConfigSchema.optional(),
138
+ canvas: CanvasConfigSchema.optional(),
139
+ sandbox: SandboxConfigSchema.optional(),
140
+ });
141
+
142
+ const ContextConfigSchema = z.object({
143
+ maxTokens: z.number().optional(),
144
+ compactionThreshold: z.number().optional(),
145
+ minMessagesAfterCompaction: z.number().optional(),
146
+ maxCompactionRetries: z.number().optional(),
147
+ });
148
+
149
+ const AgentEntrySchema = z.object({
150
+ id: z.string(),
151
+ default: z.boolean().optional(),
152
+ workspace: z.string(),
153
+ description: z.string().optional(),
154
+ });
155
+
156
+ const AccountConfigSchema = z.object({
157
+ botToken: z.string().optional(),
158
+ applicationId: z.string().optional(),
159
+ appToken: z.string().optional(),
160
+ signingSecret: z.string().optional(),
161
+ dmPolicy: DMPolicySchema.optional(),
162
+ allowFrom: z.array(z.string()).optional(),
163
+ });
164
+
165
+ const ChannelConfigSchema = z.object({
166
+ enabled: z.boolean().optional(),
167
+ accounts: z.record(z.string(), AccountConfigSchema).optional(),
168
+ dmPolicy: DMPolicySchema.optional(),
169
+ allowFrom: z.array(z.string()).optional(),
170
+ groups: z.boolean().optional(),
171
+ guilds: z.record(z.string(), z.unknown()).optional(),
172
+ experimental: z.boolean().optional(),
173
+ });
174
+
175
+ const PeerMatchSchema = z.object({
176
+ kind: z.enum(["direct", "group"]).optional(),
177
+ id: z.string().optional(),
178
+ });
179
+
180
+ const BindingMatchSchema = z.object({
181
+ channel: z.string().optional(),
182
+ accountId: z.string().optional(),
183
+ peer: PeerMatchSchema.optional(),
184
+ guildId: z.string().optional(),
185
+ teamId: z.string().optional(),
186
+ roles: z.array(z.string()).optional(),
187
+ });
188
+
189
+ const BindingSchema = z.object({
190
+ agentId: z.string(),
191
+ match: BindingMatchSchema,
192
+ });
193
+
194
+ const MCPServerConfigSchema = z.object({
195
+ enabled: z.boolean().optional(),
196
+ transport: TransportSchema,
197
+ command: z.string().optional(),
198
+ args: z.array(z.string()).optional(),
199
+ env: z.record(z.string(), z.string()).optional(),
200
+ url: z.string().optional(),
201
+ headers: z.record(z.string(), z.string()).optional(),
202
+ reconnect: z.object({
203
+ enabled: z.boolean().optional(),
204
+ maxRetries: z.number().optional(),
205
+ delayMs: z.number().optional(),
206
+ backoffMultiplier: z.number().optional(),
207
+ }).optional(),
208
+ });
209
+
210
+ const MCPConfigSchema = z.object({
211
+ enabled: z.boolean().optional(),
212
+ servers: z.record(z.string(), MCPServerConfigSchema).optional(),
213
+ healthCheck: z.object({
214
+ enabled: z.boolean().optional(),
215
+ intervalSeconds: z.number().optional(),
216
+ }).optional(),
217
+ });
218
+
219
+ const EpisodicMemoryConfigSchema = z.object({
220
+ enabled: z.boolean().optional(),
221
+ provider: z.enum(["openai", "local"]).optional(),
222
+ maxEpisodesPerSession: z.number().optional(),
223
+ });
224
+
225
+ const MemoryConfigSchema = z.object({
226
+ dbPath: z.string().optional(),
227
+ notesDir: z.string().optional(),
228
+ episodic: EpisodicMemoryConfigSchema.optional(),
229
+ });
230
+
231
+ const CronConfigSchema = z.object({
232
+ enabled: z.boolean().optional(),
233
+ dbPath: z.string().optional(),
234
+ maxConcurrentJobs: z.number().optional(),
235
+ timezone: z.string().optional(),
236
+ });
237
+
238
+ const RetryConfigSchema = z.object({
239
+ maxAttempts: z.number().optional(),
240
+ initialDelayMs: z.number().optional(),
241
+ backoffMultiplier: z.number().optional(),
242
+ maxDelayMs: z.number().optional(),
243
+ });
244
+
245
+ const HooksConfigSchema = z.object({
246
+ scripts: z.object({
247
+ before_model_resolve: z.string().optional(),
248
+ before_prompt_build: z.string().optional(),
249
+ before_tool_call: z.string().optional(),
250
+ after_tool_call: z.string().optional(),
251
+ tool_result_persist: z.string().optional(),
252
+ before_compaction: z.string().optional(),
253
+ after_compaction: z.string().optional(),
254
+ message_received: z.string().optional(),
255
+ message_sending: z.string().optional(),
256
+ message_sent: z.string().optional(),
257
+ session_start: z.string().optional(),
258
+ session_end: z.string().optional(),
259
+ gateway_start: z.string().optional(),
260
+ gateway_stop: z.string().optional(),
261
+ }).optional(),
262
+ });
263
+
264
+ const LoggingConfigSchema = z.object({
265
+ level: LogLevelSchema.optional(),
266
+ dir: z.string().optional(),
267
+ maxSizeMB: z.number().optional(),
268
+ maxFiles: z.number().optional(),
269
+ redactSensitive: z.boolean().optional(),
270
+ console: z.boolean().optional(),
271
+ });
272
+
273
+ const GatewayConfigSchema = z.object({
274
+ host: z.string().optional(),
275
+ port: z.number().optional(),
276
+ authToken: z.string().optional(),
277
+ pidFile: z.string().optional(),
278
+ tools: ToolRestrictionsSchema.optional(),
279
+ });
280
+
281
+ const ModelsConfigSchema = z.object({
282
+ defaultProvider: z.enum(["openai", "anthropic", "gemini", "mistral", "kimi", "ollama", "openrouter", "deepseek"]).optional(),
283
+ defaults: z.record(z.string(), z.string()).optional(),
284
+ providers: z.record(z.string(), ProviderConfigSchema).optional(),
285
+ });
286
+
287
+ const SessionsConfigSchema = z.object({
288
+ dir: z.string().optional(),
289
+ pruneAfterHours: z.number().optional(),
290
+ maxTranscriptSizeMB: z.number().optional(),
291
+ });
292
+
293
+ const SkillsConfigSchema = z.object({
294
+ allowBundled: z.array(z.string()).optional(),
295
+ managedDir: z.string().optional(),
296
+ extraDirs: z.array(z.string()).optional(),
297
+ hotReload: z.boolean().optional(),
298
+ maxSkillSizeKB: z.number().optional(),
299
+ });
300
+
301
+ const SecurityConfigSchema = z.object({
302
+ maxMessageLength: z.record(z.string(), z.number()).optional(),
303
+ skillScanning: z.boolean().optional(),
304
+ warnOnInsecureConfig: z.boolean().optional(),
305
+ allowedUsers: z.array(z.string()).optional(),
306
+ });
307
+
308
+ const UserConfigSchema = z.object({
309
+ id: z.string(),
310
+ name: z.string(),
311
+ channels: z.record(z.string(), z.string()).optional(),
312
+ });
313
+
314
+ const ConfigSchema = z.object({
315
+ gateway: GatewayConfigSchema.optional(),
316
+ logging: LoggingConfigSchema.optional(),
317
+ user: UserConfigSchema.optional(),
318
+ agent: z.object({
319
+ defaultAgentId: z.string().optional(),
320
+ baseDir: z.string().optional(),
321
+ context: ContextConfigSchema.optional(),
322
+ }).optional(),
323
+ models: ModelsConfigSchema.optional(),
324
+ sessions: SessionsConfigSchema.optional(),
325
+ agents: z.object({
326
+ list: z.array(AgentEntrySchema).optional(),
327
+ }).optional(),
328
+ bindings: z.array(BindingSchema).optional(),
329
+ channels: z.record(z.string(), ChannelConfigSchema).optional(),
330
+ tools: ToolsConfigSchema.optional(),
331
+ skills: SkillsConfigSchema.optional(),
332
+ mcp: MCPConfigSchema.optional(),
333
+ memory: MemoryConfigSchema.optional(),
334
+ cron: CronConfigSchema.optional(),
335
+ retry: RetryConfigSchema.optional(),
336
+ security: SecurityConfigSchema.optional(),
337
+ hooks: HooksConfigSchema.optional(),
338
+ });
339
+
340
+ export type Config = z.infer<typeof ConfigSchema>;
341
+
342
+ export type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
343
+ export type MCPServerConfig = z.infer<typeof MCPServerConfigSchema>;
344
+ export type AgentEntry = z.infer<typeof AgentEntrySchema>;
345
+ export type Binding = z.infer<typeof BindingSchema>;
346
+ export type UserConfig = z.infer<typeof UserConfigSchema>;
347
+
348
+ function buildDefaultConfig(): Config {
349
+ const hiveDir = getHiveDir();
350
+ return {
351
+ gateway: {
352
+ host: "127.0.0.1",
353
+ port: 18790,
354
+ pidFile: path.join(hiveDir, "gateway.pid"),
355
+ authToken: process.env.HIVE_AUTH_TOKEN || undefined,
356
+ tools: {
357
+ allow: ["*"],
358
+ deny: [],
359
+ },
360
+ },
361
+ logging: {
362
+ level: "info",
363
+ dir: path.join(hiveDir, "logs"),
364
+ maxSizeMB: 10,
365
+ maxFiles: 5,
366
+ redactSensitive: true,
367
+ console: true,
368
+ },
369
+ agent: {
370
+ defaultAgentId: "main",
371
+ baseDir: path.join(hiveDir, "agents"),
372
+ context: {
373
+ maxTokens: 0,
374
+ compactionThreshold: 0.8,
375
+ minMessagesAfterCompaction: 4,
376
+ maxCompactionRetries: 3,
377
+ },
378
+ },
379
+ models: {
380
+ defaultProvider: "openai",
381
+ defaults: {
382
+ openai: "gpt-4o",
383
+ anthropic: "claude-sonnet-4-20250514",
384
+ ollama: "llama3.2",
385
+ openrouter: "anthropic/claude-sonnet-4",
386
+ },
387
+ providers: {},
388
+ },
389
+ sessions: {
390
+ dir: path.join(hiveDir, "sessions"),
391
+ pruneAfterHours: 24,
392
+ maxTranscriptSizeMB: 50,
393
+ },
394
+ agents: {
395
+ list: [
396
+ {
397
+ id: "main",
398
+ default: true,
399
+ workspace: path.join(hiveDir, "agents", "main", "workspace"),
400
+ description: "Default personal assistant",
401
+ },
402
+ ],
403
+ },
404
+ bindings: [],
405
+ channels: {
406
+ webchat: { enabled: true },
407
+ },
408
+ tools: {
409
+ allow: ["*"],
410
+ deny: [],
411
+ exec: {
412
+ enabled: true,
413
+ allowlist: [],
414
+ denylist: ["rm -rf /", "sudo", "chmod 777", "> /dev/", "mkfs"],
415
+ timeoutSeconds: 30,
416
+ workDir: path.join(process.env.HOME || "", "exec"), // Points to home for exec by default
417
+ },
418
+ web: {
419
+ allowlist: [],
420
+ denylist: ["file://", "ftp://"],
421
+ timeoutSeconds: 30,
422
+ },
423
+ browser: {
424
+ enabled: true,
425
+ headless: true,
426
+ timeoutSeconds: 30,
427
+ },
428
+ canvas: {
429
+ enabled: true,
430
+ port: 18793,
431
+ },
432
+ sandbox: {
433
+ dm: { allow: ["*"], deny: [] },
434
+ group: { allow: ["*"], deny: [] },
435
+ },
436
+ },
437
+ skills: {
438
+ allowBundled: [],
439
+ managedDir: path.join(hiveDir, "skills"),
440
+ extraDirs: [],
441
+ hotReload: true,
442
+ maxSkillSizeKB: 100,
443
+ },
444
+ mcp: {
445
+ enabled: true,
446
+ servers: {},
447
+ healthCheck: {
448
+ enabled: true,
449
+ intervalSeconds: 60,
450
+ },
451
+ },
452
+ memory: {
453
+ dbPath: path.join(hiveDir, "memory.db"),
454
+ notesDir: path.join(hiveDir, "agents", "main", "workspace", "memory"),
455
+ episodic: {
456
+ enabled: false,
457
+ provider: "openai",
458
+ maxEpisodesPerSession: 100,
459
+ },
460
+ },
461
+ cron: {
462
+ enabled: true,
463
+ dbPath: path.join(hiveDir, "cron.db"),
464
+ maxConcurrentJobs: 5,
465
+ timezone: "UTC",
466
+ },
467
+ retry: {
468
+ maxAttempts: 3,
469
+ initialDelayMs: 1000,
470
+ backoffMultiplier: 2,
471
+ maxDelayMs: 30000,
472
+ },
473
+ security: {
474
+ maxMessageLength: {
475
+ telegram: 4096,
476
+ discord: 2000,
477
+ slack: 40000,
478
+ webchat: 100000,
479
+ whatsapp: 65536,
480
+ },
481
+ skillScanning: true,
482
+ warnOnInsecureConfig: true,
483
+ },
484
+ hooks: {
485
+ scripts: {},
486
+ },
487
+ };
488
+ }
489
+
490
+
491
+ // deepMerge kept for potential future use
492
+ function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {
493
+ const result = { ...target };
494
+
495
+ for (const key of Object.keys(source) as (keyof T)[]) {
496
+ const sourceValue = source[key];
497
+ const targetValue = result[key];
498
+
499
+ if (
500
+ sourceValue !== undefined &&
501
+ sourceValue !== null &&
502
+ typeof sourceValue === "object" &&
503
+ !Array.isArray(sourceValue) &&
504
+ targetValue !== undefined &&
505
+ targetValue !== null &&
506
+ typeof targetValue === "object" &&
507
+ !Array.isArray(targetValue)
508
+ ) {
509
+ result[key] = deepMerge(
510
+ targetValue as Record<string, unknown>,
511
+ sourceValue as Record<string, unknown>
512
+ ) as T[keyof T];
513
+ } else if (sourceValue !== undefined) {
514
+ result[key] = sourceValue as T[keyof T];
515
+ }
516
+ }
517
+
518
+ return result;
519
+ }
520
+ export function loadConfig(): Config {
521
+ return buildDefaultConfig();
522
+ }
523
+
524
+ export function expandConfigPath(p: string | undefined): string | undefined {
525
+ if (!p) return undefined;
526
+ return expandPath(p);
527
+ }
528
+
529
+ export { expandPath };
@@ -0,0 +1,169 @@
1
+ import { EventEmitter } from "events";
2
+ import { logger } from "../utils/logger";
3
+
4
+ export interface EventMap {
5
+ "message:received": {
6
+ channel: string;
7
+ userId: string;
8
+ content: string;
9
+ timestamp: number;
10
+ sessionId: string;
11
+ };
12
+ "message:sent": {
13
+ channel: string;
14
+ userId: string;
15
+ content: string;
16
+ messageId: string;
17
+ sessionId: string;
18
+ };
19
+ "agent:thinking": {
20
+ agentId: string;
21
+ sessionId: string;
22
+ stage: "planning" | "executing" | "responding";
23
+ };
24
+ "agent:response": {
25
+ agentId: string;
26
+ sessionId: string;
27
+ content: string;
28
+ toolsUsed: string[];
29
+ duration: number;
30
+ };
31
+ "tool:executing": {
32
+ toolName: string;
33
+ args: Record<string, unknown>;
34
+ sessionId: string;
35
+ };
36
+ "tool:completed": {
37
+ toolName: string;
38
+ result: unknown;
39
+ duration: number;
40
+ success: boolean;
41
+ };
42
+ "tool:error": {
43
+ toolName: string;
44
+ error: Error;
45
+ args: Record<string, unknown>;
46
+ };
47
+ "error": {
48
+ source: string;
49
+ error: Error;
50
+ context: Record<string, unknown>;
51
+ recoverable: boolean;
52
+ };
53
+ "session:started": {
54
+ sessionId: string;
55
+ agentId: string;
56
+ channel: string;
57
+ userId: string;
58
+ };
59
+ "session:ended": {
60
+ sessionId: string;
61
+ duration: number;
62
+ messageCount: number;
63
+ reason: "completed" | "cancelled" | "error" | "timeout";
64
+ };
65
+ "mcp:connected": {
66
+ serverName: string;
67
+ toolsCount: number;
68
+ resourcesCount: number;
69
+ };
70
+ "mcp:disconnected": {
71
+ serverName: string;
72
+ reason: string;
73
+ };
74
+ "mcp:error": {
75
+ serverName: string;
76
+ error: Error;
77
+ };
78
+ "channel:started": {
79
+ channel: string;
80
+ accountId: string;
81
+ };
82
+ "channel:stopped": {
83
+ channel: string;
84
+ accountId: string;
85
+ reason: string;
86
+ };
87
+ "gateway:started": {
88
+ host: string;
89
+ port: number;
90
+ };
91
+ "gateway:stopped": {
92
+ reason: string;
93
+ };
94
+ "pairing:requested": {
95
+ channel: string;
96
+ userId: string;
97
+ code: string;
98
+ expiresAt: number;
99
+ };
100
+ "pairing:approved": {
101
+ channel: string;
102
+ userId: string;
103
+ };
104
+ "pairing:rejected": {
105
+ channel: string;
106
+ userId: string;
107
+ reason: string;
108
+ };
109
+ "pairing:expired": {
110
+ code: string;
111
+ channel: string;
112
+ userId: string;
113
+ };
114
+ }
115
+
116
+ export type EventKey = keyof EventMap;
117
+
118
+ export interface EventHandler<K extends EventKey> {
119
+ (data: EventMap[K]): void | Promise<void>;
120
+ }
121
+
122
+ class TypedEventBusImpl {
123
+ private emitter = new EventEmitter();
124
+ private logPrefix = "[events]";
125
+
126
+ emit<K extends EventKey>(event: K, data: EventMap[K]): void {
127
+ const enrichedData = {
128
+ ...data,
129
+ _eventId: crypto.randomUUID(),
130
+ _timestamp: Date.now(),
131
+ _event: event,
132
+ } as EventMap[K] & { _eventId: string; _timestamp: number; _event: string };
133
+
134
+ this.emitter.emit(event, enrichedData);
135
+
136
+ if (process.env.DEBUG_EVENTS === "true") {
137
+ logger.debug(`${this.logPrefix} emitted: ${event}`, { data });
138
+ }
139
+ }
140
+
141
+ on<K extends EventKey>(event: K, handler: EventHandler<K>): () => void {
142
+ this.emitter.on(event, handler);
143
+ return () => this.off(event, handler);
144
+ }
145
+
146
+ once<K extends EventKey>(event: K, handler: EventHandler<K>): void {
147
+ this.emitter.once(event, handler);
148
+ }
149
+
150
+ off<K extends EventKey>(event: K, handler: EventHandler<K>): void {
151
+ this.emitter.off(event, handler);
152
+ }
153
+
154
+ removeAllListeners<K extends EventKey>(event?: K): void {
155
+ if (event) {
156
+ this.emitter.removeAllListeners(event);
157
+ } else {
158
+ this.emitter.removeAllListeners();
159
+ }
160
+ }
161
+
162
+ listenerCount<K extends EventKey>(event: K): number {
163
+ return this.emitter.listenerCount(event);
164
+ }
165
+ }
166
+
167
+ export const eventBus = new TypedEventBusImpl();
168
+
169
+ export type TypedEventBus = typeof eventBus;
@@ -0,0 +1,5 @@
1
+ import { loadConfig } from "../config/loader.ts";
2
+ import { startGateway } from "./server.ts";
3
+ import { logger } from "../utils/logger.ts";
4
+
5
+ export { loadConfig, startGateway, logger };