claude-code-swarm 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +22 -1
  3. package/.claude-plugin/run-agent-inbox-mcp.sh +76 -0
  4. package/.claude-plugin/run-minimem-mcp.sh +98 -0
  5. package/.claude-plugin/run-opentasks-mcp.sh +65 -0
  6. package/CLAUDE.md +200 -36
  7. package/README.md +65 -0
  8. package/e2e/helpers/cleanup.mjs +17 -3
  9. package/e2e/helpers/map-mock-server.mjs +201 -25
  10. package/e2e/helpers/sidecar.mjs +222 -0
  11. package/e2e/helpers/workspace.mjs +2 -1
  12. package/e2e/tier5-sidecar-inbox.test.mjs +900 -0
  13. package/e2e/tier6-inbox-mcp.test.mjs +173 -0
  14. package/e2e/tier6-live-agent.test.mjs +759 -0
  15. package/e2e/vitest.config.e2e.mjs +1 -1
  16. package/hooks/hooks.json +15 -8
  17. package/package.json +13 -1
  18. package/references/agent-inbox/CLAUDE.md +151 -0
  19. package/references/agent-inbox/README.md +238 -0
  20. package/references/agent-inbox/docs/CLAUDE-CODE-SWARM-PROPOSAL.md +137 -0
  21. package/references/agent-inbox/docs/DESIGN.md +1156 -0
  22. package/references/agent-inbox/hooks/inbox-hook.mjs +119 -0
  23. package/references/agent-inbox/hooks/register-hook.mjs +69 -0
  24. package/references/agent-inbox/package-lock.json +3347 -0
  25. package/references/agent-inbox/package.json +58 -0
  26. package/references/agent-inbox/rules/agent-inbox.md +78 -0
  27. package/references/agent-inbox/src/federation/address.ts +61 -0
  28. package/references/agent-inbox/src/federation/connection-manager.ts +573 -0
  29. package/references/agent-inbox/src/federation/delivery-queue.ts +222 -0
  30. package/references/agent-inbox/src/federation/index.ts +6 -0
  31. package/references/agent-inbox/src/federation/routing-engine.ts +188 -0
  32. package/references/agent-inbox/src/federation/trust.ts +71 -0
  33. package/references/agent-inbox/src/index.ts +390 -0
  34. package/references/agent-inbox/src/ipc/ipc-server.ts +207 -0
  35. package/references/agent-inbox/src/jsonrpc/mail-server.ts +382 -0
  36. package/references/agent-inbox/src/map/map-client.ts +414 -0
  37. package/references/agent-inbox/src/mcp/mcp-server.ts +272 -0
  38. package/references/agent-inbox/src/mesh/delivery-bridge.ts +110 -0
  39. package/references/agent-inbox/src/mesh/mesh-connector.ts +41 -0
  40. package/references/agent-inbox/src/mesh/mesh-transport.ts +157 -0
  41. package/references/agent-inbox/src/mesh/type-mapper.ts +239 -0
  42. package/references/agent-inbox/src/push/notifier.ts +233 -0
  43. package/references/agent-inbox/src/registry/warm-registry.ts +255 -0
  44. package/references/agent-inbox/src/router/message-router.ts +175 -0
  45. package/references/agent-inbox/src/storage/interface.ts +48 -0
  46. package/references/agent-inbox/src/storage/memory.ts +145 -0
  47. package/references/agent-inbox/src/storage/sqlite.ts +671 -0
  48. package/references/agent-inbox/src/traceability/traceability.ts +183 -0
  49. package/references/agent-inbox/src/types.ts +303 -0
  50. package/references/agent-inbox/test/federation/address.test.ts +101 -0
  51. package/references/agent-inbox/test/federation/connection-manager.test.ts +546 -0
  52. package/references/agent-inbox/test/federation/delivery-queue.test.ts +159 -0
  53. package/references/agent-inbox/test/federation/integration.test.ts +857 -0
  54. package/references/agent-inbox/test/federation/routing-engine.test.ts +117 -0
  55. package/references/agent-inbox/test/federation/sdk-integration.test.ts +744 -0
  56. package/references/agent-inbox/test/federation/trust.test.ts +89 -0
  57. package/references/agent-inbox/test/ipc-jsonrpc.test.ts +113 -0
  58. package/references/agent-inbox/test/ipc-server.test.ts +197 -0
  59. package/references/agent-inbox/test/mail-server.test.ts +285 -0
  60. package/references/agent-inbox/test/map-client.test.ts +408 -0
  61. package/references/agent-inbox/test/mesh/delivery-bridge.test.ts +178 -0
  62. package/references/agent-inbox/test/mesh/e2e-mesh.test.ts +527 -0
  63. package/references/agent-inbox/test/mesh/e2e-real-meshpeer.test.ts +629 -0
  64. package/references/agent-inbox/test/mesh/federation-mesh.test.ts +269 -0
  65. package/references/agent-inbox/test/mesh/mesh-connector.test.ts +66 -0
  66. package/references/agent-inbox/test/mesh/mesh-transport.test.ts +191 -0
  67. package/references/agent-inbox/test/mesh/meshpeer-integration.test.ts +442 -0
  68. package/references/agent-inbox/test/mesh/mock-mesh.ts +125 -0
  69. package/references/agent-inbox/test/mesh/mock-meshpeer.ts +266 -0
  70. package/references/agent-inbox/test/mesh/type-mapper.test.ts +226 -0
  71. package/references/agent-inbox/test/message-router.test.ts +184 -0
  72. package/references/agent-inbox/test/push-notifier.test.ts +139 -0
  73. package/references/agent-inbox/test/registry/warm-registry.test.ts +171 -0
  74. package/references/agent-inbox/test/sqlite-prefix.test.ts +192 -0
  75. package/references/agent-inbox/test/sqlite-storage.test.ts +243 -0
  76. package/references/agent-inbox/test/storage.test.ts +196 -0
  77. package/references/agent-inbox/test/traceability.test.ts +123 -0
  78. package/references/agent-inbox/test/wake.test.ts +330 -0
  79. package/references/agent-inbox/tsconfig.json +20 -0
  80. package/references/agent-inbox/tsup.config.ts +10 -0
  81. package/references/agent-inbox/vitest.config.ts +8 -0
  82. package/references/minimem/.claude/settings.json +7 -0
  83. package/references/minimem/.sudocode/issues.jsonl +18 -0
  84. package/references/minimem/.sudocode/specs.jsonl +1 -0
  85. package/references/minimem/CLAUDE.md +329 -0
  86. package/references/minimem/README.md +565 -0
  87. package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
  88. package/references/minimem/claude-plugin/.mcp.json +7 -0
  89. package/references/minimem/claude-plugin/README.md +158 -0
  90. package/references/minimem/claude-plugin/commands/recall.md +47 -0
  91. package/references/minimem/claude-plugin/commands/remember.md +41 -0
  92. package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
  93. package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
  94. package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
  95. package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
  96. package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
  97. package/references/minimem/media/banner.png +0 -0
  98. package/references/minimem/package-lock.json +5373 -0
  99. package/references/minimem/package.json +76 -0
  100. package/references/minimem/scripts/postbuild.js +49 -0
  101. package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
  102. package/references/minimem/src/__tests__/errors.test.ts +265 -0
  103. package/references/minimem/src/__tests__/helpers.ts +199 -0
  104. package/references/minimem/src/__tests__/internal.test.ts +407 -0
  105. package/references/minimem/src/__tests__/knowledge-frontmatter.test.ts +148 -0
  106. package/references/minimem/src/__tests__/knowledge.test.ts +148 -0
  107. package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
  108. package/references/minimem/src/__tests__/session.test.ts +190 -0
  109. package/references/minimem/src/cli/__tests__/commands.test.ts +760 -0
  110. package/references/minimem/src/cli/__tests__/contained-layout.test.ts +286 -0
  111. package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
  112. package/references/minimem/src/cli/commands/append.ts +76 -0
  113. package/references/minimem/src/cli/commands/config.ts +262 -0
  114. package/references/minimem/src/cli/commands/conflicts.ts +415 -0
  115. package/references/minimem/src/cli/commands/daemon.ts +169 -0
  116. package/references/minimem/src/cli/commands/index.ts +12 -0
  117. package/references/minimem/src/cli/commands/init.ts +166 -0
  118. package/references/minimem/src/cli/commands/mcp.ts +221 -0
  119. package/references/minimem/src/cli/commands/push-pull.ts +213 -0
  120. package/references/minimem/src/cli/commands/search.ts +223 -0
  121. package/references/minimem/src/cli/commands/status.ts +84 -0
  122. package/references/minimem/src/cli/commands/store.ts +189 -0
  123. package/references/minimem/src/cli/commands/sync-init.ts +290 -0
  124. package/references/minimem/src/cli/commands/sync.ts +70 -0
  125. package/references/minimem/src/cli/commands/upsert.ts +197 -0
  126. package/references/minimem/src/cli/config.ts +611 -0
  127. package/references/minimem/src/cli/index.ts +299 -0
  128. package/references/minimem/src/cli/shared.ts +189 -0
  129. package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
  130. package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
  131. package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
  132. package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
  133. package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
  134. package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
  135. package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
  136. package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
  137. package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
  138. package/references/minimem/src/cli/sync/central.ts +292 -0
  139. package/references/minimem/src/cli/sync/conflicts.ts +205 -0
  140. package/references/minimem/src/cli/sync/daemon.ts +407 -0
  141. package/references/minimem/src/cli/sync/detection.ts +138 -0
  142. package/references/minimem/src/cli/sync/index.ts +107 -0
  143. package/references/minimem/src/cli/sync/operations.ts +373 -0
  144. package/references/minimem/src/cli/sync/registry.ts +279 -0
  145. package/references/minimem/src/cli/sync/state.ts +358 -0
  146. package/references/minimem/src/cli/sync/validation.ts +206 -0
  147. package/references/minimem/src/cli/sync/watcher.ts +237 -0
  148. package/references/minimem/src/cli/version.ts +34 -0
  149. package/references/minimem/src/core/index.ts +9 -0
  150. package/references/minimem/src/core/indexer.ts +628 -0
  151. package/references/minimem/src/core/searcher.ts +221 -0
  152. package/references/minimem/src/db/schema.ts +183 -0
  153. package/references/minimem/src/db/sqlite-vec.ts +24 -0
  154. package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
  155. package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
  156. package/references/minimem/src/embeddings/batch-openai.ts +409 -0
  157. package/references/minimem/src/embeddings/embeddings.ts +434 -0
  158. package/references/minimem/src/index.ts +132 -0
  159. package/references/minimem/src/internal.ts +299 -0
  160. package/references/minimem/src/minimem.ts +1291 -0
  161. package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
  162. package/references/minimem/src/search/graph.ts +234 -0
  163. package/references/minimem/src/search/hybrid.ts +151 -0
  164. package/references/minimem/src/search/search.ts +256 -0
  165. package/references/minimem/src/server/__tests__/mcp.test.ts +347 -0
  166. package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
  167. package/references/minimem/src/server/mcp.ts +326 -0
  168. package/references/minimem/src/server/tools.ts +720 -0
  169. package/references/minimem/src/session.ts +460 -0
  170. package/references/minimem/src/store/__tests__/manifest.test.ts +177 -0
  171. package/references/minimem/src/store/__tests__/materialize.test.ts +52 -0
  172. package/references/minimem/src/store/__tests__/store-graph.test.ts +228 -0
  173. package/references/minimem/src/store/index.ts +27 -0
  174. package/references/minimem/src/store/manifest.ts +203 -0
  175. package/references/minimem/src/store/materialize.ts +185 -0
  176. package/references/minimem/src/store/store-graph.ts +252 -0
  177. package/references/minimem/tsconfig.json +19 -0
  178. package/references/minimem/tsup.config.ts +26 -0
  179. package/references/minimem/vitest.config.ts +29 -0
  180. package/references/openteams/src/cli/generate.ts +23 -1
  181. package/references/openteams/src/generators/agent-prompt-generator.test.ts +94 -0
  182. package/references/openteams/src/generators/agent-prompt-generator.ts +42 -13
  183. package/references/openteams/src/generators/package-generator.ts +9 -1
  184. package/references/openteams/src/generators/skill-generator.test.ts +28 -0
  185. package/references/openteams/src/generators/skill-generator.ts +10 -4
  186. package/references/skill-tree/.claude/settings.json +6 -0
  187. package/references/skill-tree/.sudocode/issues.jsonl +19 -0
  188. package/references/skill-tree/.sudocode/specs.jsonl +3 -0
  189. package/references/skill-tree/CLAUDE.md +132 -0
  190. package/references/skill-tree/README.md +396 -0
  191. package/references/skill-tree/docs/GAPS_v1.md +221 -0
  192. package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
  193. package/references/skill-tree/docs/TODOS.md +91 -0
  194. package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
  195. package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
  196. package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
  197. package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
  198. package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
  199. package/references/skill-tree/docs/scraper/README.md +170 -0
  200. package/references/skill-tree/examples/basic-usage.ts +157 -0
  201. package/references/skill-tree/package-lock.json +1852 -0
  202. package/references/skill-tree/package.json +66 -0
  203. package/references/skill-tree/plan.md +78 -0
  204. package/references/skill-tree/scraper/README.md +123 -0
  205. package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
  206. package/references/skill-tree/scraper/docs/PLAN.md +336 -0
  207. package/references/skill-tree/scraper/drizzle.config.ts +10 -0
  208. package/references/skill-tree/scraper/package-lock.json +6329 -0
  209. package/references/skill-tree/scraper/package.json +68 -0
  210. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
  211. package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
  212. package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
  213. package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
  214. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
  215. package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
  216. package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
  217. package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
  218. package/references/skill-tree/scraper/tsup.config.ts +14 -0
  219. package/references/skill-tree/scraper/vitest.config.ts +17 -0
  220. package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
  221. package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
  222. package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
  223. package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
  224. package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
  225. package/references/skill-tree/test/run-all.ts +106 -0
  226. package/references/skill-tree/test/utils.ts +128 -0
  227. package/references/skill-tree/vitest.config.ts +16 -0
  228. package/references/swarmkit/src/commands/init/phases/configure.ts +0 -22
  229. package/references/swarmkit/src/commands/init/phases/global-setup.ts +5 -3
  230. package/references/swarmkit/src/commands/init/wizard.ts +2 -2
  231. package/references/swarmkit/src/packages/setup.test.ts +53 -7
  232. package/references/swarmkit/src/packages/setup.ts +37 -1
  233. package/scripts/bootstrap.mjs +26 -1
  234. package/scripts/generate-agents.mjs +5 -1
  235. package/scripts/map-hook.mjs +97 -64
  236. package/scripts/map-sidecar.mjs +179 -25
  237. package/scripts/team-loader.mjs +12 -41
  238. package/skills/swarm/SKILL.md +89 -25
  239. package/src/__tests__/agent-generator.test.mjs +6 -13
  240. package/src/__tests__/bootstrap.test.mjs +124 -1
  241. package/src/__tests__/config.test.mjs +200 -27
  242. package/src/__tests__/e2e-live-map.test.mjs +536 -0
  243. package/src/__tests__/e2e-mesh-sidecar.test.mjs +570 -0
  244. package/src/__tests__/e2e-native-task-hooks.test.mjs +376 -0
  245. package/src/__tests__/e2e-sidecar-bridge.test.mjs +477 -0
  246. package/src/__tests__/helpers.mjs +13 -0
  247. package/src/__tests__/inbox.test.mjs +22 -89
  248. package/src/__tests__/index.test.mjs +35 -9
  249. package/src/__tests__/integration.test.mjs +513 -0
  250. package/src/__tests__/map-events.test.mjs +514 -150
  251. package/src/__tests__/mesh-connection.test.mjs +308 -0
  252. package/src/__tests__/opentasks-client.test.mjs +517 -0
  253. package/src/__tests__/paths.test.mjs +185 -41
  254. package/src/__tests__/sidecar-client.test.mjs +35 -0
  255. package/src/__tests__/sidecar-server.test.mjs +124 -0
  256. package/src/__tests__/skilltree-client.test.mjs +80 -0
  257. package/src/agent-generator.mjs +104 -33
  258. package/src/bootstrap.mjs +150 -10
  259. package/src/config.mjs +81 -17
  260. package/src/context-output.mjs +58 -8
  261. package/src/inbox.mjs +9 -54
  262. package/src/index.mjs +39 -8
  263. package/src/map-connection.mjs +4 -3
  264. package/src/map-events.mjs +350 -80
  265. package/src/mesh-connection.mjs +148 -0
  266. package/src/opentasks-client.mjs +269 -0
  267. package/src/paths.mjs +182 -27
  268. package/src/sessionlog.mjs +14 -9
  269. package/src/sidecar-client.mjs +81 -27
  270. package/src/sidecar-server.mjs +175 -16
  271. package/src/skilltree-client.mjs +173 -0
  272. package/src/template.mjs +68 -4
  273. package/vitest.config.mjs +1 -0
@@ -0,0 +1,390 @@
1
+ import { EventEmitter } from "node:events";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ import { InMemoryStorage } from "./storage/memory.js";
5
+ import { SqliteStorage } from "./storage/sqlite.js";
6
+ import { MessageRouter } from "./router/message-router.js";
7
+ import { TraceabilityLayer } from "./traceability/traceability.js";
8
+ import { IpcServer } from "./ipc/ipc-server.js";
9
+ import { MapClient } from "./map/map-client.js";
10
+ import { InboxMcpServer } from "./mcp/mcp-server.js";
11
+ import { MailJsonRpcServer } from "./jsonrpc/mail-server.js";
12
+ import { PushNotifier } from "./push/notifier.js";
13
+ import { ConnectionManager } from "./federation/connection-manager.js";
14
+ import { MeshConnector } from "./mesh/mesh-connector.js";
15
+ import { DeliveryBridge } from "./mesh/delivery-bridge.js";
16
+ import type { MeshContextLike } from "./mesh/mesh-transport.js";
17
+ import type { MeshPeerLike, MeshMapServer } from "./map/map-client.js";
18
+ import { WarmRegistry } from "./registry/warm-registry.js";
19
+ import type { InboxConfig } from "./types.js";
20
+ import type { Storage } from "./storage/interface.js";
21
+
22
+ export { InMemoryStorage } from "./storage/memory.js";
23
+ export { SqliteStorage } from "./storage/sqlite.js";
24
+ export { MessageRouter, normalizeContent } from "./router/message-router.js";
25
+ export { TraceabilityLayer } from "./traceability/traceability.js";
26
+ export { IpcServer } from "./ipc/ipc-server.js";
27
+ export { MapClient } from "./map/map-client.js";
28
+ export { InboxMcpServer } from "./mcp/mcp-server.js";
29
+ export { MailJsonRpcServer } from "./jsonrpc/mail-server.js";
30
+ export { PushNotifier, formatInboxMarkdown, parseCommand } from "./push/notifier.js";
31
+ export type { InboxMessageEvent, NotifierConfig, InboxFileEntry } from "./push/notifier.js";
32
+ export { ConnectionManager } from "./federation/connection-manager.js";
33
+ export type { DeliveryResult, IncomingMessageHandler } from "./federation/connection-manager.js";
34
+ export type { MapConnection, MapAgentConnectionClass, IncomingMapMessage } from "./map/map-client.js";
35
+ export { WarmRegistry } from "./registry/warm-registry.js";
36
+ export { RoutingEngine } from "./federation/routing-engine.js";
37
+ export { DeliveryQueue } from "./federation/delivery-queue.js";
38
+ export { TrustManager } from "./federation/trust.js";
39
+ export {
40
+ parseAddress,
41
+ formatAddress,
42
+ isRemoteAddress,
43
+ isBroadcastAddress,
44
+ } from "./federation/address.js";
45
+ export { MeshTransport, DEFAULT_CHANNEL_NAME } from "./mesh/mesh-transport.js";
46
+ export type { MeshContextLike, MeshChannel, MeshPeerInfo, InboxWireMessage } from "./mesh/mesh-transport.js";
47
+ export { MeshConnector } from "./mesh/mesh-connector.js";
48
+ export { DeliveryBridge } from "./mesh/delivery-bridge.js";
49
+ export type { MeshDeliveryHandler } from "./mesh/delivery-bridge.js";
50
+ export { mapMessageToInbox, inboxMessageToMap } from "./mesh/type-mapper.js";
51
+ export type { MapMessage as MeshMapMessage, MapAddress as MeshMapAddress } from "./mesh/type-mapper.js";
52
+ export type { MeshPeerLike, MeshAgentConnection, MeshMapServer } from "./map/map-client.js";
53
+ export type * from "./types.js";
54
+ export type { Storage, InboxQuery, ThreadQuery } from "./storage/interface.js";
55
+
56
+ function defaultSocketPath(): string {
57
+ const home = os.homedir();
58
+ return path.join(home, ".claude", "agent-inbox", "inbox.sock");
59
+ }
60
+
61
+ function defaultInboxDir(): string {
62
+ const home = os.homedir();
63
+ return path.join(home, ".claude", "agent-inbox", "inboxes");
64
+ }
65
+
66
+ function defaultSqlitePath(): string {
67
+ const home = os.homedir();
68
+ return path.join(home, ".claude", "agent-inbox", "inbox.db");
69
+ }
70
+
71
+ function loadConfig(): InboxConfig {
72
+ return {
73
+ socketPath: process.env.INBOX_SOCKET_PATH ?? defaultSocketPath(),
74
+ scope: process.env.INBOX_SCOPE ?? "default",
75
+ map: {
76
+ enabled: process.env.INBOX_MAP_ENABLED === "true",
77
+ server: process.env.INBOX_MAP_SERVER,
78
+ scope: process.env.INBOX_MAP_SCOPE ?? process.env.INBOX_SCOPE ?? "default",
79
+ systemId: process.env.INBOX_MAP_SYSTEM_ID ?? "agent-inbox",
80
+ },
81
+ };
82
+ }
83
+
84
+ export interface AgentInbox {
85
+ storage: Storage;
86
+ router: MessageRouter;
87
+ traceability: TraceabilityLayer;
88
+ ipcServer: IpcServer;
89
+ mapClient: MapClient;
90
+ jsonRpc: MailJsonRpcServer;
91
+ notifier: PushNotifier;
92
+ federation: ConnectionManager | null;
93
+ registry: WarmRegistry | null;
94
+ events: EventEmitter;
95
+ stop(): Promise<void>;
96
+ }
97
+
98
+ export interface CreateOptions {
99
+ config?: Partial<InboxConfig>;
100
+ /** Use SQLite storage at this path (":memory:" for in-memory SQLite) */
101
+ sqlitePath?: string;
102
+ /** Use an external better-sqlite3 Database handle (co-locate tables in another DB) */
103
+ sqliteDb?: import("better-sqlite3").Database;
104
+ /** Table name prefix when co-locating in an external DB (e.g. "inbox_") */
105
+ sqlitePrefix?: string;
106
+ /** HTTP port for JSON-RPC endpoint (0 = disabled) */
107
+ httpPort?: number;
108
+ /** Webhook URLs for push notifications */
109
+ webhooks?: string[];
110
+ /** Enable federation with peer systems */
111
+ enableFederation?: boolean;
112
+ /** Use an externally-managed MAP connection instead of creating one.
113
+ * When provided, Agent Inbox borrows this connection for messaging
114
+ * but does not own its lifecycle (won't disconnect it on stop()). */
115
+ connection?: import("./map/map-client.js").MapConnection;
116
+ /** Phase 1: agentic-mesh context for P2P federation transport.
117
+ * When provided, federation peers with meshPeerId use encrypted
118
+ * mesh channels instead of WebSocket MAP connections. */
119
+ mesh?: {
120
+ context: MeshContextLike;
121
+ localPeerId: string;
122
+ channelName?: string;
123
+ };
124
+ /** Phase 2: Full MeshPeer integration.
125
+ * When provided, agent-inbox registers as an agent on the MeshPeer's
126
+ * MapServer, uses FederationGateway for cross-mesh routing, and
127
+ * installs a DeliveryHandler bridge for incoming messages.
128
+ * Supersedes `mesh` option — if both are set, meshPeer takes priority. */
129
+ meshPeer?: MeshPeerLike;
130
+ }
131
+
132
+ export async function createAgentInbox(
133
+ opts: CreateOptions = {}
134
+ ): Promise<AgentInbox> {
135
+ const config = { ...loadConfig(), ...opts.config };
136
+
137
+ // 1. Storage — SQLite (own file, external DB, or in-memory fallback)
138
+ let storage: Storage;
139
+ if (opts.sqliteDb) {
140
+ storage = new SqliteStorage({
141
+ db: opts.sqliteDb,
142
+ prefix: opts.sqlitePrefix,
143
+ });
144
+ } else if (opts.sqlitePath) {
145
+ storage = new SqliteStorage({
146
+ path: opts.sqlitePath,
147
+ prefix: opts.sqlitePrefix,
148
+ });
149
+ } else {
150
+ storage = new InMemoryStorage();
151
+ }
152
+
153
+ // 2. Event bus (internal)
154
+ const events = new EventEmitter();
155
+
156
+ // 3. Message router
157
+ const router = new MessageRouter(storage, events, config.scope);
158
+
159
+ // 4. Traceability layer (subscribes to message.created events)
160
+ const traceability = new TraceabilityLayer(storage, events);
161
+
162
+ // 5. Push notifier (per-agent inbox files + webhooks + event emission)
163
+ const notifier = new PushNotifier(
164
+ { inboxDir: defaultInboxDir(), webhooks: opts.webhooks },
165
+ storage,
166
+ events
167
+ );
168
+
169
+ // 6. MAP client (connects first to obtain SDK class for federation)
170
+ const mapClient = new MapClient(
171
+ storage,
172
+ router,
173
+ events,
174
+ );
175
+
176
+ // Phase 2: MeshPeer integration (if provided)
177
+ if (opts.meshPeer) {
178
+ const meshSystemId = await mapClient.connectViaMesh(opts.meshPeer);
179
+
180
+ // Install DeliveryHandler bridge on the MeshPeer's MapServer
181
+ const server = opts.meshPeer.server as MeshMapServer & {
182
+ setDeliveryHandler?(handler: unknown): unknown;
183
+ };
184
+ if (typeof server.setDeliveryHandler === "function") {
185
+ // Get the current handler, then replace with our bridge that delegates back
186
+ const prev = server.setDeliveryHandler(
187
+ new DeliveryBridge(storage, events, config.scope)
188
+ );
189
+ if (prev) {
190
+ // Re-install with the previous handler as fallback
191
+ server.setDeliveryHandler(
192
+ new DeliveryBridge(
193
+ storage,
194
+ events,
195
+ config.scope,
196
+ prev as import("./mesh/delivery-bridge.js").MeshDeliveryHandler
197
+ )
198
+ );
199
+ }
200
+ }
201
+
202
+ console.error(`Connected to MeshPeer (systemId: ${meshSystemId})`);
203
+ } else if (opts.connection) {
204
+ // External connection — borrow it, don't manage its lifecycle
205
+ mapClient.useConnection(opts.connection);
206
+ } else if (config.map?.enabled) {
207
+ const connected = await mapClient.connect(config.map);
208
+ if (connected) {
209
+ // Replay missed messages from MAP server
210
+ const replayed = await mapClient.replayMissed();
211
+ if (replayed > 0) {
212
+ console.error(`Replayed ${replayed} missed messages from MAP server`);
213
+ }
214
+ }
215
+ }
216
+
217
+ // 7. Registry + Federation (optional)
218
+ let federation: ConnectionManager | null = null;
219
+ let registry: WarmRegistry | null = null;
220
+
221
+ const needsRegistry = opts.enableFederation || config.federation?.peers?.length;
222
+
223
+ if (needsRegistry) {
224
+ registry = new WarmRegistry(storage, events, config.federation?.registry);
225
+ }
226
+
227
+ if (opts.enableFederation || config.federation?.peers?.length) {
228
+ const sdkClass = mapClient.getAgentConnectionClass() ?? undefined;
229
+
230
+ let meshConnector: MeshConnector | undefined;
231
+ if (opts.mesh) {
232
+ meshConnector = new MeshConnector(
233
+ opts.mesh.context,
234
+ opts.mesh.localPeerId,
235
+ opts.mesh.channelName
236
+ );
237
+ } else if (opts.meshPeer) {
238
+ // Phase 2: Derive mesh context from MeshPeer if available
239
+ const peerObj = opts.meshPeer as MeshPeerLike & { mesh?: MeshContextLike };
240
+ if (peerObj.mesh) {
241
+ meshConnector = new MeshConnector(
242
+ peerObj.mesh,
243
+ opts.meshPeer.peerId
244
+ );
245
+ }
246
+ }
247
+
248
+ federation = new ConnectionManager(events, config.federation, {
249
+ sdkClass,
250
+ meshConnector,
251
+ meshPeer: opts.meshPeer,
252
+ onIncomingMessage: ({ from, peerId, payload, meta }) => {
253
+ // Delegate incoming federation messages to the router.
254
+ // The targetAgent in meta tells us which local agent this is for.
255
+ const targetAgent = (meta?.targetAgent as string) ?? from;
256
+ router.routeMessage({
257
+ from: `${from}@${peerId}`,
258
+ to: targetAgent,
259
+ payload,
260
+ scope: meta?.scope as string | undefined,
261
+ subject: meta?.subject as string | undefined,
262
+ importance: meta?.importance as "high" | "normal" | undefined,
263
+ threadTag: meta?.threadTag as string | undefined,
264
+ inReplyTo: meta?.inReplyTo as string | undefined,
265
+ metadata: meta,
266
+ }).catch((err) => {
267
+ console.error(
268
+ `Failed to route incoming federation message from ${from}@${peerId}: ${err instanceof Error ? err.message : err}`
269
+ );
270
+ });
271
+ },
272
+ });
273
+ router.setFederation(federation);
274
+
275
+ // Tier 2 system ID resolution: update from MAP or MeshPeer systemInfo
276
+ const mapSystemName = mapClient.getSystemName();
277
+ if (mapSystemName) {
278
+ federation.updateSystemIdFromMap(mapSystemName);
279
+ } else if (opts.meshPeer) {
280
+ federation.updateSystemIdFromMap(opts.meshPeer.server.systemId);
281
+ }
282
+
283
+ // Connect to configured federation peers
284
+ if (config.federation?.peers) {
285
+ for (const peer of config.federation.peers) {
286
+ try {
287
+ await federation.federate(peer);
288
+ const via = peer.meshPeerId ? `mesh:${peer.meshPeerId}` : peer.url;
289
+ console.error(`Federated with peer: ${peer.systemId} (${via})`);
290
+ } catch (err) {
291
+ console.error(
292
+ `Failed to federate with ${peer.systemId}: ${err instanceof Error ? err.message : err}`
293
+ );
294
+ }
295
+ }
296
+ }
297
+
298
+ // Start delivery queue tick timer
299
+ federation.queue.startTicking();
300
+ }
301
+
302
+ // 8. JSON-RPC server (mail/* methods)
303
+ const jsonRpc = new MailJsonRpcServer(storage, router, events);
304
+ if (opts.httpPort && opts.httpPort > 0) {
305
+ await jsonRpc.startHttp(opts.httpPort);
306
+ console.error(`JSON-RPC HTTP server listening on port ${opts.httpPort}`);
307
+ }
308
+
309
+ // 9. IPC server (UNIX socket — handles both NDJSON commands and JSON-RPC inline)
310
+ const socketPath = config.socketPath ?? defaultSocketPath();
311
+ const ipcServer = new IpcServer(socketPath, router, storage, jsonRpc);
312
+ await ipcServer.start();
313
+
314
+ const stop = async () => {
315
+ await ipcServer.stop();
316
+ await jsonRpc.stopHttp();
317
+ await mapClient.disconnect();
318
+ if (federation) await federation.destroy();
319
+ if (registry) registry.destroy();
320
+ if ("close" in storage && typeof storage.close === "function") {
321
+ (storage as SqliteStorage).close();
322
+ }
323
+ };
324
+
325
+ return {
326
+ storage,
327
+ router,
328
+ traceability,
329
+ ipcServer,
330
+ mapClient,
331
+ jsonRpc,
332
+ notifier,
333
+ federation,
334
+ registry,
335
+ events,
336
+ stop,
337
+ };
338
+ }
339
+
340
+ // CLI entry point
341
+ const isMainModule =
342
+ process.argv[1] &&
343
+ (process.argv[1].endsWith("/index.js") ||
344
+ process.argv[1].endsWith("/index.ts"));
345
+
346
+ if (isMainModule) {
347
+ const mode = process.argv[2] ?? "ipc";
348
+
349
+ if (mode === "mcp") {
350
+ // MCP-only mode (stdio transport for Claude Code integration)
351
+ const config = loadConfig();
352
+ const sqlitePath = process.env.INBOX_SQLITE_PATH;
353
+ const storage: Storage = sqlitePath
354
+ ? new SqliteStorage({ path: sqlitePath })
355
+ : new InMemoryStorage();
356
+ const events = new EventEmitter();
357
+ const router = new MessageRouter(storage, events, config.scope);
358
+ const _traceability = new TraceabilityLayer(storage, events);
359
+ const mcpServer = new InboxMcpServer(router, storage, config.scope);
360
+ mcpServer.start().catch((err) => {
361
+ console.error("MCP server failed:", err);
362
+ process.exit(1);
363
+ });
364
+ } else {
365
+ // IPC server mode (default)
366
+ const httpPort = process.env.INBOX_HTTP_PORT
367
+ ? parseInt(process.env.INBOX_HTTP_PORT, 10)
368
+ : 0;
369
+ const sqlitePath = process.env.INBOX_SQLITE_PATH;
370
+
371
+ createAgentInbox({ httpPort, sqlitePath })
372
+ .then((inbox) => {
373
+ console.error(
374
+ `Agent Inbox IPC server listening on ${process.env.INBOX_SOCKET_PATH ?? defaultSocketPath()}`
375
+ );
376
+ process.on("SIGINT", async () => {
377
+ await inbox.stop();
378
+ process.exit(0);
379
+ });
380
+ process.on("SIGTERM", async () => {
381
+ await inbox.stop();
382
+ process.exit(0);
383
+ });
384
+ })
385
+ .catch((err) => {
386
+ console.error("Failed to start Agent Inbox:", err);
387
+ process.exit(1);
388
+ });
389
+ }
390
+ }
@@ -0,0 +1,207 @@
1
+ import * as net from "node:net";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import type {
5
+ IpcCommand,
6
+ IpcResponse,
7
+ Agent,
8
+ } from "../types.js";
9
+ import type { Storage } from "../storage/interface.js";
10
+ import type { MessageRouter } from "../router/message-router.js";
11
+ import type { MailJsonRpcServer } from "../jsonrpc/mail-server.js";
12
+
13
+ export class IpcServer {
14
+ private server: net.Server | null = null;
15
+
16
+ constructor(
17
+ private socketPath: string,
18
+ private router: MessageRouter,
19
+ private storage: Storage,
20
+ private jsonRpc?: MailJsonRpcServer
21
+ ) {}
22
+
23
+ async start(): Promise<void> {
24
+ // Clean up stale socket file
25
+ try {
26
+ fs.unlinkSync(this.socketPath);
27
+ } catch {
28
+ // Doesn't exist, fine
29
+ }
30
+
31
+ // Ensure directory exists
32
+ const dir = path.dirname(this.socketPath);
33
+ fs.mkdirSync(dir, { recursive: true });
34
+
35
+ return new Promise((resolve, reject) => {
36
+ this.server = net.createServer((conn) => this.handleConnection(conn));
37
+ this.server.on("error", reject);
38
+ this.server.listen(this.socketPath, () => resolve());
39
+ });
40
+ }
41
+
42
+ async stop(): Promise<void> {
43
+ return new Promise((resolve) => {
44
+ if (!this.server) return resolve();
45
+ this.server.close(() => {
46
+ try {
47
+ fs.unlinkSync(this.socketPath);
48
+ } catch {
49
+ // Already gone
50
+ }
51
+ resolve();
52
+ });
53
+ });
54
+ }
55
+
56
+ private handleConnection(conn: net.Socket): void {
57
+ let buffer = "";
58
+
59
+ conn.on("data", (data) => {
60
+ buffer += data.toString();
61
+ // Process complete lines (NDJSON)
62
+ let newlineIdx: number;
63
+ while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
64
+ const line = buffer.slice(0, newlineIdx).trim();
65
+ buffer = buffer.slice(newlineIdx + 1);
66
+ if (!line) continue;
67
+
68
+ this.processLine(line)
69
+ .then((response) => {
70
+ conn.write(JSON.stringify(response) + "\n");
71
+ })
72
+ .catch((err) => {
73
+ conn.write(
74
+ JSON.stringify({ ok: false, error: String(err) }) + "\n"
75
+ );
76
+ });
77
+ }
78
+ });
79
+
80
+ conn.on("error", () => {
81
+ // Client disconnected, ignore
82
+ });
83
+ }
84
+
85
+ private async processLine(line: string): Promise<IpcResponse | object> {
86
+ let parsed: Record<string, unknown>;
87
+ try {
88
+ parsed = JSON.parse(line) as Record<string, unknown>;
89
+ } catch {
90
+ return { ok: false, error: "Invalid JSON" };
91
+ }
92
+
93
+ // Detect JSON-RPC requests (have "jsonrpc" field) vs IPC commands (have "action" field)
94
+ if (parsed.jsonrpc === "2.0" && typeof parsed.method === "string") {
95
+ if (this.jsonRpc) {
96
+ return this.jsonRpc.handleRequest(
97
+ parsed as { jsonrpc: "2.0"; id?: string | number | null; method: string; params?: Record<string, unknown> }
98
+ );
99
+ }
100
+ return { jsonrpc: "2.0", id: parsed.id ?? null, error: { code: -32603, message: "JSON-RPC not configured" } };
101
+ }
102
+
103
+ return this.handleCommand(parsed as unknown as IpcCommand);
104
+ }
105
+
106
+ async handleCommand(command: IpcCommand): Promise<IpcResponse> {
107
+ switch (command.action) {
108
+ case "ping":
109
+ return { ok: true, pid: process.pid };
110
+
111
+ case "send":
112
+ return this.handleSend(command);
113
+
114
+ case "notify":
115
+ return this.handleNotify(command);
116
+
117
+ case "check_inbox":
118
+ return this.handleCheckInbox(command);
119
+
120
+ case "emit":
121
+ // For Phase 1, emit is acknowledged but not forwarded to MAP
122
+ return { ok: true };
123
+
124
+ default:
125
+ return { ok: false, error: `Unknown action: ${(command as { action: string }).action}` };
126
+ }
127
+ }
128
+
129
+ private async handleSend(
130
+ command: Extract<IpcCommand, { action: "send" }>
131
+ ): Promise<IpcResponse> {
132
+ try {
133
+ const message = await this.router.routeMessage({
134
+ from: command.from,
135
+ to: command.to,
136
+ payload: command.payload,
137
+ scope: command.scope,
138
+ threadTag: command.threadTag,
139
+ inReplyTo: command.inReplyTo,
140
+ importance: command.importance,
141
+ metadata: command.meta,
142
+ });
143
+ return { ok: true, messageId: message.id };
144
+ } catch (err) {
145
+ return { ok: false, error: String(err) };
146
+ }
147
+ }
148
+
149
+ private handleCheckInbox(
150
+ command: Extract<IpcCommand, { action: "check_inbox" }>
151
+ ): IpcResponse {
152
+ const agentId = command.agentId ?? command.scope ?? "default";
153
+ const messages = this.storage.getInbox(agentId, {
154
+ unreadOnly: command.unreadOnly,
155
+ });
156
+
157
+ // Mark messages as read
158
+ if (command.clear) {
159
+ const now = new Date().toISOString();
160
+ for (const msg of messages) {
161
+ for (const r of msg.recipients) {
162
+ if (r.agent_id === agentId && !r.read_at) {
163
+ r.read_at = now;
164
+ }
165
+ }
166
+ this.storage.putMessage(msg);
167
+ }
168
+ }
169
+
170
+ return { ok: true, messages };
171
+ }
172
+
173
+ private handleNotify(
174
+ command: Extract<IpcCommand, { action: "notify" }>
175
+ ): IpcResponse {
176
+ const event = command.event;
177
+
178
+ if (event.type === "agent.spawn" && event.agent) {
179
+ const now = new Date().toISOString();
180
+ const agent: Agent = {
181
+ agent_id: event.agent.agentId,
182
+ display_name: event.agent.name,
183
+ scope: event.agent.scopes?.[0] ?? "default",
184
+ status: "active",
185
+ metadata: event.agent.metadata ?? {},
186
+ registered_at: now,
187
+ last_active_at: now,
188
+ };
189
+ this.storage.putAgent(agent);
190
+ return { ok: true };
191
+ }
192
+
193
+ if (event.type === "agent.done") {
194
+ const agentId = event.agentId ?? event.agent?.agentId;
195
+ if (agentId) {
196
+ const agent = this.storage.getAgent(agentId);
197
+ if (agent) {
198
+ agent.status = "offline";
199
+ this.storage.putAgent(agent);
200
+ }
201
+ }
202
+ return { ok: true };
203
+ }
204
+
205
+ return { ok: true };
206
+ }
207
+ }