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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +22 -1
- package/.claude-plugin/run-agent-inbox-mcp.sh +76 -0
- package/.claude-plugin/run-minimem-mcp.sh +98 -0
- package/.claude-plugin/run-opentasks-mcp.sh +65 -0
- package/CLAUDE.md +200 -36
- package/README.md +65 -0
- package/e2e/helpers/cleanup.mjs +17 -3
- package/e2e/helpers/map-mock-server.mjs +201 -25
- package/e2e/helpers/sidecar.mjs +222 -0
- package/e2e/helpers/workspace.mjs +2 -1
- package/e2e/tier5-sidecar-inbox.test.mjs +900 -0
- package/e2e/tier6-inbox-mcp.test.mjs +173 -0
- package/e2e/tier6-live-agent.test.mjs +759 -0
- package/e2e/vitest.config.e2e.mjs +1 -1
- package/hooks/hooks.json +15 -8
- package/package.json +13 -1
- package/references/agent-inbox/CLAUDE.md +151 -0
- package/references/agent-inbox/README.md +238 -0
- package/references/agent-inbox/docs/CLAUDE-CODE-SWARM-PROPOSAL.md +137 -0
- package/references/agent-inbox/docs/DESIGN.md +1156 -0
- package/references/agent-inbox/hooks/inbox-hook.mjs +119 -0
- package/references/agent-inbox/hooks/register-hook.mjs +69 -0
- package/references/agent-inbox/package-lock.json +3347 -0
- package/references/agent-inbox/package.json +58 -0
- package/references/agent-inbox/rules/agent-inbox.md +78 -0
- package/references/agent-inbox/src/federation/address.ts +61 -0
- package/references/agent-inbox/src/federation/connection-manager.ts +573 -0
- package/references/agent-inbox/src/federation/delivery-queue.ts +222 -0
- package/references/agent-inbox/src/federation/index.ts +6 -0
- package/references/agent-inbox/src/federation/routing-engine.ts +188 -0
- package/references/agent-inbox/src/federation/trust.ts +71 -0
- package/references/agent-inbox/src/index.ts +390 -0
- package/references/agent-inbox/src/ipc/ipc-server.ts +207 -0
- package/references/agent-inbox/src/jsonrpc/mail-server.ts +382 -0
- package/references/agent-inbox/src/map/map-client.ts +414 -0
- package/references/agent-inbox/src/mcp/mcp-server.ts +272 -0
- package/references/agent-inbox/src/mesh/delivery-bridge.ts +110 -0
- package/references/agent-inbox/src/mesh/mesh-connector.ts +41 -0
- package/references/agent-inbox/src/mesh/mesh-transport.ts +157 -0
- package/references/agent-inbox/src/mesh/type-mapper.ts +239 -0
- package/references/agent-inbox/src/push/notifier.ts +233 -0
- package/references/agent-inbox/src/registry/warm-registry.ts +255 -0
- package/references/agent-inbox/src/router/message-router.ts +175 -0
- package/references/agent-inbox/src/storage/interface.ts +48 -0
- package/references/agent-inbox/src/storage/memory.ts +145 -0
- package/references/agent-inbox/src/storage/sqlite.ts +671 -0
- package/references/agent-inbox/src/traceability/traceability.ts +183 -0
- package/references/agent-inbox/src/types.ts +303 -0
- package/references/agent-inbox/test/federation/address.test.ts +101 -0
- package/references/agent-inbox/test/federation/connection-manager.test.ts +546 -0
- package/references/agent-inbox/test/federation/delivery-queue.test.ts +159 -0
- package/references/agent-inbox/test/federation/integration.test.ts +857 -0
- package/references/agent-inbox/test/federation/routing-engine.test.ts +117 -0
- package/references/agent-inbox/test/federation/sdk-integration.test.ts +744 -0
- package/references/agent-inbox/test/federation/trust.test.ts +89 -0
- package/references/agent-inbox/test/ipc-jsonrpc.test.ts +113 -0
- package/references/agent-inbox/test/ipc-server.test.ts +197 -0
- package/references/agent-inbox/test/mail-server.test.ts +285 -0
- package/references/agent-inbox/test/map-client.test.ts +408 -0
- package/references/agent-inbox/test/mesh/delivery-bridge.test.ts +178 -0
- package/references/agent-inbox/test/mesh/e2e-mesh.test.ts +527 -0
- package/references/agent-inbox/test/mesh/e2e-real-meshpeer.test.ts +629 -0
- package/references/agent-inbox/test/mesh/federation-mesh.test.ts +269 -0
- package/references/agent-inbox/test/mesh/mesh-connector.test.ts +66 -0
- package/references/agent-inbox/test/mesh/mesh-transport.test.ts +191 -0
- package/references/agent-inbox/test/mesh/meshpeer-integration.test.ts +442 -0
- package/references/agent-inbox/test/mesh/mock-mesh.ts +125 -0
- package/references/agent-inbox/test/mesh/mock-meshpeer.ts +266 -0
- package/references/agent-inbox/test/mesh/type-mapper.test.ts +226 -0
- package/references/agent-inbox/test/message-router.test.ts +184 -0
- package/references/agent-inbox/test/push-notifier.test.ts +139 -0
- package/references/agent-inbox/test/registry/warm-registry.test.ts +171 -0
- package/references/agent-inbox/test/sqlite-prefix.test.ts +192 -0
- package/references/agent-inbox/test/sqlite-storage.test.ts +243 -0
- package/references/agent-inbox/test/storage.test.ts +196 -0
- package/references/agent-inbox/test/traceability.test.ts +123 -0
- package/references/agent-inbox/test/wake.test.ts +330 -0
- package/references/agent-inbox/tsconfig.json +20 -0
- package/references/agent-inbox/tsup.config.ts +10 -0
- package/references/agent-inbox/vitest.config.ts +8 -0
- package/references/minimem/.claude/settings.json +7 -0
- package/references/minimem/.sudocode/issues.jsonl +18 -0
- package/references/minimem/.sudocode/specs.jsonl +1 -0
- package/references/minimem/CLAUDE.md +329 -0
- package/references/minimem/README.md +565 -0
- package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
- package/references/minimem/claude-plugin/.mcp.json +7 -0
- package/references/minimem/claude-plugin/README.md +158 -0
- package/references/minimem/claude-plugin/commands/recall.md +47 -0
- package/references/minimem/claude-plugin/commands/remember.md +41 -0
- package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
- package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
- package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
- package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
- package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
- package/references/minimem/media/banner.png +0 -0
- package/references/minimem/package-lock.json +5373 -0
- package/references/minimem/package.json +76 -0
- package/references/minimem/scripts/postbuild.js +49 -0
- package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
- package/references/minimem/src/__tests__/errors.test.ts +265 -0
- package/references/minimem/src/__tests__/helpers.ts +199 -0
- package/references/minimem/src/__tests__/internal.test.ts +407 -0
- package/references/minimem/src/__tests__/knowledge-frontmatter.test.ts +148 -0
- package/references/minimem/src/__tests__/knowledge.test.ts +148 -0
- package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
- package/references/minimem/src/__tests__/session.test.ts +190 -0
- package/references/minimem/src/cli/__tests__/commands.test.ts +760 -0
- package/references/minimem/src/cli/__tests__/contained-layout.test.ts +286 -0
- package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
- package/references/minimem/src/cli/commands/append.ts +76 -0
- package/references/minimem/src/cli/commands/config.ts +262 -0
- package/references/minimem/src/cli/commands/conflicts.ts +415 -0
- package/references/minimem/src/cli/commands/daemon.ts +169 -0
- package/references/minimem/src/cli/commands/index.ts +12 -0
- package/references/minimem/src/cli/commands/init.ts +166 -0
- package/references/minimem/src/cli/commands/mcp.ts +221 -0
- package/references/minimem/src/cli/commands/push-pull.ts +213 -0
- package/references/minimem/src/cli/commands/search.ts +223 -0
- package/references/minimem/src/cli/commands/status.ts +84 -0
- package/references/minimem/src/cli/commands/store.ts +189 -0
- package/references/minimem/src/cli/commands/sync-init.ts +290 -0
- package/references/minimem/src/cli/commands/sync.ts +70 -0
- package/references/minimem/src/cli/commands/upsert.ts +197 -0
- package/references/minimem/src/cli/config.ts +611 -0
- package/references/minimem/src/cli/index.ts +299 -0
- package/references/minimem/src/cli/shared.ts +189 -0
- package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
- package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
- package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
- package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
- package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
- package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
- package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
- package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
- package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
- package/references/minimem/src/cli/sync/central.ts +292 -0
- package/references/minimem/src/cli/sync/conflicts.ts +205 -0
- package/references/minimem/src/cli/sync/daemon.ts +407 -0
- package/references/minimem/src/cli/sync/detection.ts +138 -0
- package/references/minimem/src/cli/sync/index.ts +107 -0
- package/references/minimem/src/cli/sync/operations.ts +373 -0
- package/references/minimem/src/cli/sync/registry.ts +279 -0
- package/references/minimem/src/cli/sync/state.ts +358 -0
- package/references/minimem/src/cli/sync/validation.ts +206 -0
- package/references/minimem/src/cli/sync/watcher.ts +237 -0
- package/references/minimem/src/cli/version.ts +34 -0
- package/references/minimem/src/core/index.ts +9 -0
- package/references/minimem/src/core/indexer.ts +628 -0
- package/references/minimem/src/core/searcher.ts +221 -0
- package/references/minimem/src/db/schema.ts +183 -0
- package/references/minimem/src/db/sqlite-vec.ts +24 -0
- package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
- package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
- package/references/minimem/src/embeddings/batch-openai.ts +409 -0
- package/references/minimem/src/embeddings/embeddings.ts +434 -0
- package/references/minimem/src/index.ts +132 -0
- package/references/minimem/src/internal.ts +299 -0
- package/references/minimem/src/minimem.ts +1291 -0
- package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
- package/references/minimem/src/search/graph.ts +234 -0
- package/references/minimem/src/search/hybrid.ts +151 -0
- package/references/minimem/src/search/search.ts +256 -0
- package/references/minimem/src/server/__tests__/mcp.test.ts +347 -0
- package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
- package/references/minimem/src/server/mcp.ts +326 -0
- package/references/minimem/src/server/tools.ts +720 -0
- package/references/minimem/src/session.ts +460 -0
- package/references/minimem/src/store/__tests__/manifest.test.ts +177 -0
- package/references/minimem/src/store/__tests__/materialize.test.ts +52 -0
- package/references/minimem/src/store/__tests__/store-graph.test.ts +228 -0
- package/references/minimem/src/store/index.ts +27 -0
- package/references/minimem/src/store/manifest.ts +203 -0
- package/references/minimem/src/store/materialize.ts +185 -0
- package/references/minimem/src/store/store-graph.ts +252 -0
- package/references/minimem/tsconfig.json +19 -0
- package/references/minimem/tsup.config.ts +26 -0
- package/references/minimem/vitest.config.ts +29 -0
- package/references/openteams/src/cli/generate.ts +23 -1
- package/references/openteams/src/generators/agent-prompt-generator.test.ts +94 -0
- package/references/openteams/src/generators/agent-prompt-generator.ts +42 -13
- package/references/openteams/src/generators/package-generator.ts +9 -1
- package/references/openteams/src/generators/skill-generator.test.ts +28 -0
- package/references/openteams/src/generators/skill-generator.ts +10 -4
- package/references/skill-tree/.claude/settings.json +6 -0
- package/references/skill-tree/.sudocode/issues.jsonl +19 -0
- package/references/skill-tree/.sudocode/specs.jsonl +3 -0
- package/references/skill-tree/CLAUDE.md +132 -0
- package/references/skill-tree/README.md +396 -0
- package/references/skill-tree/docs/GAPS_v1.md +221 -0
- package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
- package/references/skill-tree/docs/TODOS.md +91 -0
- package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
- package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
- package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
- package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
- package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
- package/references/skill-tree/docs/scraper/README.md +170 -0
- package/references/skill-tree/examples/basic-usage.ts +157 -0
- package/references/skill-tree/package-lock.json +1852 -0
- package/references/skill-tree/package.json +66 -0
- package/references/skill-tree/plan.md +78 -0
- package/references/skill-tree/scraper/README.md +123 -0
- package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
- package/references/skill-tree/scraper/docs/PLAN.md +336 -0
- package/references/skill-tree/scraper/drizzle.config.ts +10 -0
- package/references/skill-tree/scraper/package-lock.json +6329 -0
- package/references/skill-tree/scraper/package.json +68 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
- package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
- package/references/skill-tree/scraper/tsup.config.ts +14 -0
- package/references/skill-tree/scraper/vitest.config.ts +17 -0
- package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
- package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
- package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
- package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
- package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
- package/references/skill-tree/test/run-all.ts +106 -0
- package/references/skill-tree/test/utils.ts +128 -0
- package/references/skill-tree/vitest.config.ts +16 -0
- package/references/swarmkit/src/commands/init/phases/configure.ts +0 -22
- package/references/swarmkit/src/commands/init/phases/global-setup.ts +5 -3
- package/references/swarmkit/src/commands/init/wizard.ts +2 -2
- package/references/swarmkit/src/packages/setup.test.ts +53 -7
- package/references/swarmkit/src/packages/setup.ts +37 -1
- package/scripts/bootstrap.mjs +26 -1
- package/scripts/generate-agents.mjs +5 -1
- package/scripts/map-hook.mjs +97 -64
- package/scripts/map-sidecar.mjs +179 -25
- package/scripts/team-loader.mjs +12 -41
- package/skills/swarm/SKILL.md +89 -25
- package/src/__tests__/agent-generator.test.mjs +6 -13
- package/src/__tests__/bootstrap.test.mjs +124 -1
- package/src/__tests__/config.test.mjs +200 -27
- package/src/__tests__/e2e-live-map.test.mjs +536 -0
- package/src/__tests__/e2e-mesh-sidecar.test.mjs +570 -0
- package/src/__tests__/e2e-native-task-hooks.test.mjs +376 -0
- package/src/__tests__/e2e-sidecar-bridge.test.mjs +477 -0
- package/src/__tests__/helpers.mjs +13 -0
- package/src/__tests__/inbox.test.mjs +22 -89
- package/src/__tests__/index.test.mjs +35 -9
- package/src/__tests__/integration.test.mjs +513 -0
- package/src/__tests__/map-events.test.mjs +514 -150
- package/src/__tests__/mesh-connection.test.mjs +308 -0
- package/src/__tests__/opentasks-client.test.mjs +517 -0
- package/src/__tests__/paths.test.mjs +185 -41
- package/src/__tests__/sidecar-client.test.mjs +35 -0
- package/src/__tests__/sidecar-server.test.mjs +124 -0
- package/src/__tests__/skilltree-client.test.mjs +80 -0
- package/src/agent-generator.mjs +104 -33
- package/src/bootstrap.mjs +150 -10
- package/src/config.mjs +81 -17
- package/src/context-output.mjs +58 -8
- package/src/inbox.mjs +9 -54
- package/src/index.mjs +39 -8
- package/src/map-connection.mjs +4 -3
- package/src/map-events.mjs +350 -80
- package/src/mesh-connection.mjs +148 -0
- package/src/opentasks-client.mjs +269 -0
- package/src/paths.mjs +182 -27
- package/src/sessionlog.mjs +14 -9
- package/src/sidecar-client.mjs +81 -27
- package/src/sidecar-server.mjs +175 -16
- package/src/skilltree-client.mjs +173 -0
- package/src/template.mjs +68 -4
- 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
|
+
});
|