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,570 @@
1
+ /**
2
+ * E2E tests: Real MeshPeer (0.2.0) + agent-inbox → sidecar command handler → real MapServer
3
+ *
4
+ * Tests the full mesh-mode pipeline with NO mocks:
5
+ * Socket command → sidecar command handler (mesh mode) →
6
+ * real embedded MeshPeer (via createEmbedded) → real MapServer
7
+ *
8
+ * Also tests the agent-inbox integration: spawn registers agents
9
+ * in both the MapServer and inbox storage.
10
+ *
11
+ * Verifies results by inspecting MapServer state (agents, scopes)
12
+ * and exercises 0.2.0 features (parent-child hierarchy, broadcastToScope,
13
+ * connection.isRegistered, connection.state).
14
+ */
15
+
16
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
17
+ import net from "net";
18
+ import path from "path";
19
+ import { createSocketServer, createCommandHandler } from "../sidecar-server.mjs";
20
+ import { createMeshPeer, createMeshInbox } from "../mesh-connection.mjs";
21
+ import { makeTmpDir, cleanupTmpDir } from "./helpers.mjs";
22
+
23
+ // ── Helpers ──────────────────────────────────────────────────────────────────
24
+
25
+ /**
26
+ * Send a JSON command over a UNIX socket and read the response.
27
+ */
28
+ function sendSocketCommand(socketPath, command) {
29
+ return new Promise((resolve, reject) => {
30
+ const client = net.createConnection(socketPath);
31
+ let data = "";
32
+ client.on("connect", () => {
33
+ client.write(JSON.stringify(command) + "\n");
34
+ });
35
+ client.on("data", (chunk) => {
36
+ data += chunk.toString();
37
+ try {
38
+ const parsed = JSON.parse(data.trim().split("\n").pop());
39
+ client.destroy();
40
+ resolve(parsed);
41
+ } catch {
42
+ // wait for more data
43
+ }
44
+ });
45
+ client.on("error", reject);
46
+ setTimeout(() => {
47
+ client.destroy();
48
+ try {
49
+ resolve(JSON.parse(data.trim().split("\n").pop()));
50
+ } catch {
51
+ reject(new Error("Timeout waiting for response"));
52
+ }
53
+ }, 3000);
54
+ });
55
+ }
56
+
57
+ // ── Tests ────────────────────────────────────────────────────────────────────
58
+
59
+ describe("E2E: sidecar socket → real MeshPeer 0.2.0 + agent-inbox (mesh mode)", () => {
60
+ let tmpDir;
61
+ let socketPath;
62
+ let inboxSocketPath;
63
+ let socketServer;
64
+ let meshResult;
65
+ let inboxInstance;
66
+ let registeredAgents;
67
+ let handler;
68
+
69
+ const SCOPE = "swarm:e2e-mesh";
70
+
71
+ beforeEach(async () => {
72
+ tmpDir = makeTmpDir("e2e-mesh-sidecar-");
73
+ socketPath = path.join(tmpDir, "sidecar.sock");
74
+ inboxSocketPath = path.join(tmpDir, "inbox.sock");
75
+
76
+ // Create real MeshPeer via createEmbedded (0.2.0 API)
77
+ meshResult = await createMeshPeer({
78
+ peerId: "e2e-mesh-sidecar",
79
+ scope: SCOPE,
80
+ systemId: "sys-e2e",
81
+ });
82
+
83
+ // Verify embedded peer is set up correctly
84
+ expect(meshResult.peer.server).toBeDefined();
85
+ expect(meshResult.connection.isRegistered).toBe(true);
86
+
87
+ // Create real agent-inbox on the MeshPeer
88
+ inboxInstance = await createMeshInbox({
89
+ meshPeer: meshResult.peer,
90
+ scope: SCOPE,
91
+ systemId: "sys-e2e",
92
+ socketPath: inboxSocketPath,
93
+ inboxConfig: {},
94
+ });
95
+
96
+ // Create sidecar command handler in mesh mode
97
+ registeredAgents = new Map();
98
+ handler = createCommandHandler(meshResult.connection, SCOPE, registeredAgents, {
99
+ inboxInstance,
100
+ meshPeer: meshResult.peer,
101
+ transportMode: "mesh",
102
+ });
103
+ socketServer = createSocketServer(socketPath, handler);
104
+ await new Promise((resolve) => socketServer.on("listening", resolve));
105
+ });
106
+
107
+ afterEach(async () => {
108
+ if (socketServer) {
109
+ await new Promise((resolve) => socketServer.close(resolve));
110
+ socketServer = null;
111
+ }
112
+ if (inboxInstance?.stop) {
113
+ try { await inboxInstance.stop(); } catch { /* ignore */ }
114
+ }
115
+ if (meshResult?.connection) {
116
+ try { await meshResult.connection.unregister(); } catch { /* ignore */ }
117
+ }
118
+ if (meshResult?.peer) {
119
+ try { await meshResult.peer.stop(); } catch { /* ignore */ }
120
+ }
121
+ cleanupTmpDir(tmpDir);
122
+ });
123
+
124
+ // ==========================================================================
125
+ // Spawn agent → verify in MapServer + inbox storage + local tracking
126
+ // ==========================================================================
127
+
128
+ describe("spawn agent (mesh mode)", () => {
129
+ it("registers agent in MapServer, inbox storage, and local tracking", async () => {
130
+ const resp = await sendSocketCommand(socketPath, {
131
+ action: "spawn",
132
+ agent: {
133
+ agentId: "mesh-worker-1",
134
+ name: "executor",
135
+ role: "executor",
136
+ scopes: [SCOPE],
137
+ metadata: { template: "gsd" },
138
+ },
139
+ });
140
+
141
+ expect(resp.ok).toBe(true);
142
+ expect(resp.agent.agentId).toBe("mesh-worker-1");
143
+
144
+ // Verify agent in MapServer
145
+ const agents = meshResult.peer.server.listAgents();
146
+ const worker = agents.find((a) => a.id === "mesh-worker-1");
147
+ expect(worker).toBeDefined();
148
+ expect(worker.name).toBe("executor");
149
+ expect(worker.role).toBe("executor");
150
+
151
+ // Verify agent in inbox storage
152
+ const inboxAgent = inboxInstance.storage.getAgent("mesh-worker-1");
153
+ expect(inboxAgent).toBeDefined();
154
+ expect(inboxAgent.status).toBe("active");
155
+
156
+ // Verify local tracking
157
+ expect(registeredAgents.has("mesh-worker-1")).toBe(true);
158
+ expect(registeredAgents.get("mesh-worker-1").role).toBe("executor");
159
+ });
160
+
161
+ it("spawned agent is visible via peer.server.listAgents()", async () => {
162
+ const agentsBefore = meshResult.peer.server.listAgents();
163
+ const countBefore = agentsBefore.length;
164
+
165
+ await sendSocketCommand(socketPath, {
166
+ action: "spawn",
167
+ agent: {
168
+ agentId: "visibility-test",
169
+ name: "visible-worker",
170
+ role: "worker",
171
+ scopes: [SCOPE],
172
+ metadata: {},
173
+ },
174
+ });
175
+
176
+ const agentsAfter = meshResult.peer.server.listAgents();
177
+ expect(agentsAfter.length).toBe(countBefore + 1);
178
+ expect(agentsAfter.find((a) => a.id === "visibility-test")).toBeDefined();
179
+ });
180
+ });
181
+
182
+ // ==========================================================================
183
+ // Done agent → verify removed from MapServer + local tracking
184
+ // ==========================================================================
185
+
186
+ describe("done agent (mesh mode)", () => {
187
+ it("removes agent from MapServer and local tracking", async () => {
188
+ // First spawn
189
+ await sendSocketCommand(socketPath, {
190
+ action: "spawn",
191
+ agent: {
192
+ agentId: "mesh-temp",
193
+ name: "temp-worker",
194
+ role: "worker",
195
+ scopes: [SCOPE],
196
+ metadata: {},
197
+ },
198
+ });
199
+
200
+ const agentsBefore = meshResult.peer.server.listAgents();
201
+ expect(agentsBefore.find((a) => a.id === "mesh-temp")).toBeDefined();
202
+ expect(registeredAgents.has("mesh-temp")).toBe(true);
203
+
204
+ // Now mark done
205
+ const resp = await sendSocketCommand(socketPath, {
206
+ action: "done",
207
+ agentId: "mesh-temp",
208
+ reason: "completed",
209
+ });
210
+
211
+ expect(resp.ok).toBe(true);
212
+
213
+ // Verify removed from local tracking
214
+ expect(registeredAgents.has("mesh-temp")).toBe(false);
215
+
216
+ // Verify unregistered from MapServer
217
+ const agentsAfter = meshResult.peer.server.listAgents();
218
+ expect(agentsAfter.find((a) => a.id === "mesh-temp")).toBeUndefined();
219
+ });
220
+
221
+ it("marks agent as disconnected in inbox storage", async () => {
222
+ await sendSocketCommand(socketPath, {
223
+ action: "spawn",
224
+ agent: {
225
+ agentId: "inbox-done-test",
226
+ name: "temp",
227
+ role: "worker",
228
+ scopes: [SCOPE],
229
+ metadata: {},
230
+ },
231
+ });
232
+
233
+ // Verify active in inbox
234
+ const beforeAgent = inboxInstance.storage.getAgent("inbox-done-test");
235
+ expect(beforeAgent.status).toBe("active");
236
+
237
+ await sendSocketCommand(socketPath, {
238
+ action: "done",
239
+ agentId: "inbox-done-test",
240
+ reason: "completed",
241
+ });
242
+
243
+ // Verify marked disconnected (not deleted) in inbox storage
244
+ const afterAgent = inboxInstance.storage.getAgent("inbox-done-test");
245
+ expect(afterAgent).toBeDefined();
246
+ expect(afterAgent.status).toBe("disconnected");
247
+ });
248
+ });
249
+
250
+ // ==========================================================================
251
+ // Task bridge events → verify messages sent via MeshPeer connection
252
+ // ==========================================================================
253
+
254
+ describe("bridge-task-created (mesh mode)", () => {
255
+ it("sends task.created message via MeshPeer connection", async () => {
256
+ const resp = await sendSocketCommand(socketPath, {
257
+ action: "bridge-task-created",
258
+ task: {
259
+ id: "mesh-task-1",
260
+ title: "Mesh E2E task",
261
+ status: "open",
262
+ assignee: "worker-1",
263
+ },
264
+ agentId: "worker-1",
265
+ });
266
+
267
+ expect(resp.ok).toBe(true);
268
+ // The message was sent via connection.send() — no error means success
269
+ });
270
+ });
271
+
272
+ describe("bridge-task-status (mesh mode)", () => {
273
+ it("sends task.status via MeshPeer connection for non-terminal status", async () => {
274
+ const resp = await sendSocketCommand(socketPath, {
275
+ action: "bridge-task-status",
276
+ taskId: "mesh-task-2",
277
+ previous: "open",
278
+ current: "in_progress",
279
+ agentId: "worker-2",
280
+ });
281
+
282
+ expect(resp.ok).toBe(true);
283
+ });
284
+
285
+ it("sends task.status + task.completed for terminal status", async () => {
286
+ const resp = await sendSocketCommand(socketPath, {
287
+ action: "bridge-task-status",
288
+ taskId: "mesh-task-3",
289
+ previous: "in_progress",
290
+ current: "completed",
291
+ agentId: "worker-3",
292
+ });
293
+
294
+ expect(resp.ok).toBe(true);
295
+ });
296
+ });
297
+
298
+ describe("bridge-task-assigned (mesh mode)", () => {
299
+ it("sends task.assigned via MeshPeer connection", async () => {
300
+ const resp = await sendSocketCommand(socketPath, {
301
+ action: "bridge-task-assigned",
302
+ taskId: "mesh-task-4",
303
+ assignee: "developer-1",
304
+ agentId: "developer-1",
305
+ });
306
+
307
+ expect(resp.ok).toBe(true);
308
+ });
309
+ });
310
+
311
+ // ==========================================================================
312
+ // State update → verify in local tracking + connection state
313
+ // ==========================================================================
314
+
315
+ describe("state update (mesh mode)", () => {
316
+ it("updates sidecar agent state via MeshPeer connection", async () => {
317
+ const resp = await sendSocketCommand(socketPath, {
318
+ action: "state",
319
+ state: "busy",
320
+ });
321
+
322
+ expect(resp.ok).toBe(true);
323
+ // Sidecar connection state updated via updateState()
324
+ expect(meshResult.connection.state).toBe("busy");
325
+ });
326
+
327
+ it("tracks child agent state in local registeredAgents map", async () => {
328
+ // Spawn a child first
329
+ await sendSocketCommand(socketPath, {
330
+ action: "spawn",
331
+ agent: {
332
+ agentId: "state-child",
333
+ name: "stateful-worker",
334
+ role: "worker",
335
+ scopes: [SCOPE],
336
+ metadata: {},
337
+ },
338
+ });
339
+
340
+ const resp = await sendSocketCommand(socketPath, {
341
+ action: "state",
342
+ state: "busy",
343
+ agentId: "state-child",
344
+ });
345
+
346
+ expect(resp.ok).toBe(true);
347
+ expect(registeredAgents.get("state-child").lastState).toBe("busy");
348
+ });
349
+ });
350
+
351
+ // ==========================================================================
352
+ // Emit action → verify sent via MeshPeer connection
353
+ // ==========================================================================
354
+
355
+ describe("emit action (mesh mode)", () => {
356
+ it("sends arbitrary event via MeshPeer connection", async () => {
357
+ const resp = await sendSocketCommand(socketPath, {
358
+ action: "emit",
359
+ event: { type: "task.sync", uri: "claude://team/1", status: "open" },
360
+ meta: { relationship: "broadcast" },
361
+ });
362
+
363
+ expect(resp.ok).toBe(true);
364
+ });
365
+ });
366
+
367
+ // ==========================================================================
368
+ // Ping with transport info
369
+ // ==========================================================================
370
+
371
+ describe("ping (mesh mode)", () => {
372
+ it("responds with ok, pid, and transport mode", async () => {
373
+ const resp = await sendSocketCommand(socketPath, { action: "ping" });
374
+ expect(resp.ok).toBe(true);
375
+ expect(resp.pid).toBe(process.pid);
376
+ expect(resp.transport).toBe("mesh");
377
+ });
378
+ });
379
+
380
+ // ==========================================================================
381
+ // Full lifecycle: spawn → tasks → state → done
382
+ // ==========================================================================
383
+
384
+ describe("full lifecycle (mesh mode)", () => {
385
+ it("executes entire swarm task lifecycle via real embedded MeshPeer", async () => {
386
+ // 1. Spawn agent
387
+ const spawnResp = await sendSocketCommand(socketPath, {
388
+ action: "spawn",
389
+ agent: {
390
+ agentId: "lifecycle-agent",
391
+ name: "lifecycle-worker",
392
+ role: "executor",
393
+ scopes: [SCOPE],
394
+ metadata: { template: "gsd" },
395
+ },
396
+ });
397
+ expect(spawnResp.ok).toBe(true);
398
+
399
+ // Verify in MapServer
400
+ const agents = meshResult.peer.server.listAgents();
401
+ expect(agents.find((a) => a.id === "lifecycle-agent")).toBeDefined();
402
+
403
+ // 2. Create task
404
+ const createResp = await sendSocketCommand(socketPath, {
405
+ action: "bridge-task-created",
406
+ task: {
407
+ id: "lc-task-1",
408
+ title: "Build feature X",
409
+ status: "open",
410
+ assignee: "lifecycle-agent",
411
+ },
412
+ agentId: "lifecycle-agent",
413
+ });
414
+ expect(createResp.ok).toBe(true);
415
+
416
+ // 3. Assign task
417
+ const assignResp = await sendSocketCommand(socketPath, {
418
+ action: "bridge-task-assigned",
419
+ taskId: "lc-task-1",
420
+ assignee: "lifecycle-agent",
421
+ agentId: "lifecycle-agent",
422
+ });
423
+ expect(assignResp.ok).toBe(true);
424
+
425
+ // 4. Start working
426
+ const progressResp = await sendSocketCommand(socketPath, {
427
+ action: "bridge-task-status",
428
+ taskId: "lc-task-1",
429
+ previous: "open",
430
+ current: "in_progress",
431
+ agentId: "lifecycle-agent",
432
+ });
433
+ expect(progressResp.ok).toBe(true);
434
+
435
+ // 5. Update state
436
+ const stateResp = await sendSocketCommand(socketPath, {
437
+ action: "state",
438
+ state: "busy",
439
+ agentId: "lifecycle-agent",
440
+ });
441
+ expect(stateResp.ok).toBe(true);
442
+
443
+ // 6. Complete task
444
+ const completeResp = await sendSocketCommand(socketPath, {
445
+ action: "bridge-task-status",
446
+ taskId: "lc-task-1",
447
+ previous: "in_progress",
448
+ current: "completed",
449
+ agentId: "lifecycle-agent",
450
+ });
451
+ expect(completeResp.ok).toBe(true);
452
+
453
+ // 7. Done agent
454
+ const doneResp = await sendSocketCommand(socketPath, {
455
+ action: "done",
456
+ agentId: "lifecycle-agent",
457
+ reason: "completed",
458
+ });
459
+ expect(doneResp.ok).toBe(true);
460
+
461
+ // ── Verify final state ──
462
+
463
+ // Agent removed from local tracking
464
+ expect(registeredAgents.has("lifecycle-agent")).toBe(false);
465
+
466
+ // Agent unregistered from MapServer
467
+ const finalAgents = meshResult.peer.server.listAgents();
468
+ expect(finalAgents.find((a) => a.id === "lifecycle-agent")).toBeUndefined();
469
+
470
+ // Inbox storage still has the agent record (marked disconnected)
471
+ const inboxAgent = inboxInstance.storage.getAgent("lifecycle-agent");
472
+ expect(inboxAgent).toBeDefined();
473
+ expect(inboxAgent.status).toBe("disconnected");
474
+ });
475
+ });
476
+
477
+ // ==========================================================================
478
+ // Multiple agents: spawn multiple, interact, done all
479
+ // ==========================================================================
480
+
481
+ describe("multiple agents (mesh mode)", () => {
482
+ it("manages multiple concurrent agents via embedded MeshPeer", async () => {
483
+ const agentIds = ["multi-1", "multi-2", "multi-3"];
484
+
485
+ // Spawn all
486
+ for (const id of agentIds) {
487
+ const resp = await sendSocketCommand(socketPath, {
488
+ action: "spawn",
489
+ agent: {
490
+ agentId: id,
491
+ name: `worker-${id}`,
492
+ role: "worker",
493
+ scopes: [SCOPE],
494
+ metadata: {},
495
+ },
496
+ });
497
+ expect(resp.ok).toBe(true);
498
+ }
499
+
500
+ // Verify all in MapServer
501
+ const agents = meshResult.peer.server.listAgents();
502
+ for (const id of agentIds) {
503
+ expect(agents.find((a) => a.id === id)).toBeDefined();
504
+ }
505
+ expect(registeredAgents.size).toBe(3);
506
+
507
+ // Each creates a task
508
+ for (const id of agentIds) {
509
+ await sendSocketCommand(socketPath, {
510
+ action: "bridge-task-created",
511
+ task: { id: `task-${id}`, title: `Task for ${id}`, status: "open", assignee: id },
512
+ agentId: id,
513
+ });
514
+ }
515
+
516
+ // Done all
517
+ for (const id of agentIds) {
518
+ await sendSocketCommand(socketPath, {
519
+ action: "done",
520
+ agentId: id,
521
+ reason: "completed",
522
+ });
523
+ }
524
+
525
+ expect(registeredAgents.size).toBe(0);
526
+
527
+ // All unregistered from MapServer
528
+ const finalAgents = meshResult.peer.server.listAgents();
529
+ for (const id of agentIds) {
530
+ expect(finalAgents.find((a) => a.id === id)).toBeUndefined();
531
+ }
532
+ });
533
+ });
534
+
535
+ // ==========================================================================
536
+ // 0.2.0-specific: verify embedded peer properties
537
+ // ==========================================================================
538
+
539
+ describe("embedded MeshPeer properties (0.2.0)", () => {
540
+ it("sidecar connection is registered and has correct initial state", () => {
541
+ expect(meshResult.connection.isRegistered).toBe(true);
542
+ expect(meshResult.connection.agent).toBeDefined();
543
+ expect(meshResult.connection.agentId).toBe("e2e-mesh-sidecar-agent");
544
+ });
545
+
546
+ it("MapServer tracks all agents including sidecar", async () => {
547
+ // The sidecar agent itself should be in the MapServer
548
+ const agents = meshResult.peer.server.listAgents();
549
+ const sidecar = agents.find((a) => a.id === "e2e-mesh-sidecar-agent");
550
+ expect(sidecar).toBeDefined();
551
+ expect(sidecar.role).toBe("sidecar");
552
+
553
+ // Spawn a worker — both sidecar and worker should be listed
554
+ await sendSocketCommand(socketPath, {
555
+ action: "spawn",
556
+ agent: {
557
+ agentId: "tracked-worker",
558
+ name: "worker",
559
+ role: "executor",
560
+ scopes: [SCOPE],
561
+ metadata: {},
562
+ },
563
+ });
564
+
565
+ const updatedAgents = meshResult.peer.server.listAgents();
566
+ expect(updatedAgents.find((a) => a.id === "e2e-mesh-sidecar-agent")).toBeDefined();
567
+ expect(updatedAgents.find((a) => a.id === "tracked-worker")).toBeDefined();
568
+ });
569
+ });
570
+ });