claude-code-swarm 0.3.5 → 0.3.7

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 (42) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.claude-plugin/run-agent-inbox-mcp.sh +22 -3
  4. package/.gitattributes +3 -0
  5. package/.opentasks/config.json +9 -0
  6. package/.opentasks/graph.jsonl +0 -0
  7. package/e2e/helpers/opentasks-daemon.mjs +149 -0
  8. package/e2e/tier6-live-inbox-flow.test.mjs +938 -0
  9. package/e2e/tier7-hooks.test.mjs +992 -0
  10. package/e2e/tier7-minimem.test.mjs +461 -0
  11. package/e2e/tier7-opentasks.test.mjs +513 -0
  12. package/e2e/tier7-skilltree.test.mjs +506 -0
  13. package/e2e/vitest.config.e2e.mjs +1 -1
  14. package/package.json +6 -2
  15. package/references/agent-inbox/package-lock.json +2 -2
  16. package/references/agent-inbox/package.json +1 -1
  17. package/references/agent-inbox/src/index.ts +16 -2
  18. package/references/agent-inbox/src/ipc/ipc-server.ts +58 -0
  19. package/references/agent-inbox/src/mcp/mcp-proxy.ts +326 -0
  20. package/references/agent-inbox/src/types.ts +26 -0
  21. package/references/agent-inbox/test/ipc-new-commands.test.ts +200 -0
  22. package/references/agent-inbox/test/mcp-proxy.test.ts +191 -0
  23. package/references/minimem/package-lock.json +2 -2
  24. package/references/minimem/package.json +1 -1
  25. package/scripts/bootstrap.mjs +8 -1
  26. package/scripts/map-hook.mjs +6 -2
  27. package/scripts/map-sidecar.mjs +19 -0
  28. package/scripts/team-loader.mjs +15 -8
  29. package/skills/swarm/SKILL.md +16 -22
  30. package/src/__tests__/agent-generator.test.mjs +9 -10
  31. package/src/__tests__/context-output.test.mjs +13 -14
  32. package/src/__tests__/e2e-inbox-integration.test.mjs +732 -0
  33. package/src/__tests__/e2e-live-inbox.test.mjs +597 -0
  34. package/src/__tests__/inbox-integration.test.mjs +298 -0
  35. package/src/__tests__/integration.test.mjs +12 -11
  36. package/src/__tests__/skilltree-client.test.mjs +47 -1
  37. package/src/agent-generator.mjs +79 -88
  38. package/src/bootstrap.mjs +24 -3
  39. package/src/context-output.mjs +238 -64
  40. package/src/index.mjs +2 -0
  41. package/src/sidecar-server.mjs +30 -0
  42. package/src/skilltree-client.mjs +50 -5
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-swarm",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Launch Claude Code with swarmkit capabilities, including team orchestration, MAP observability, and session tracking.",
5
5
  "owner": {
6
6
  "name": "alexngai"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-code-swarm",
3
3
  "description": "Spin up Claude Code agent teams from openteams YAML topologies with optional MAP (Multi-Agent Protocol) observability and coordination. Provides hooks for session lifecycle, agent spawn/complete tracking, and a /swarm skill to launch team configurations.",
4
- "version": "0.3.5",
4
+ "version": "0.3.7",
5
5
  "author": {
6
6
  "name": "alexngai"
7
7
  },
@@ -1,7 +1,8 @@
1
1
  #!/bin/bash
2
2
  # Wrapper script to run agent-inbox MCP server
3
- # Reads scope from swarm config, discovers inbox socket
4
- # Exits silently if inbox is not enabled or not installed
3
+ # When the sidecar's inbox socket exists, runs in proxy mode (IPC client).
4
+ # Otherwise falls back to standalone mode with its own storage.
5
+ # Exits silently if inbox is not enabled or not installed.
5
6
 
6
7
  # Check if inbox is enabled in config
7
8
  ENABLED=false
@@ -45,9 +46,26 @@ if [ -n "$SWARM_INBOX_SCOPE" ]; then
45
46
  SCOPE="$SWARM_INBOX_SCOPE"
46
47
  fi
47
48
 
48
- # Set env vars for agent-inbox MCP mode
49
49
  export INBOX_SCOPE="$SCOPE"
50
50
 
51
+ # Discover sidecar inbox socket for proxy mode
52
+ # Check well-known paths: .swarm/claude-swarm/tmp/map/inbox.sock
53
+ INBOX_SOCK=""
54
+ if [ -S .swarm/claude-swarm/tmp/map/inbox.sock ]; then
55
+ INBOX_SOCK=".swarm/claude-swarm/tmp/map/inbox.sock"
56
+ fi
57
+
58
+ # Also check per-session paths
59
+ if [ -z "$INBOX_SOCK" ] && [ -d .swarm/claude-swarm/tmp/map/sessions ]; then
60
+ # Find the most recently modified inbox.sock in session dirs
61
+ INBOX_SOCK=$(find .swarm/claude-swarm/tmp/map/sessions -name inbox.sock -type s 2>/dev/null | head -1)
62
+ fi
63
+
64
+ # If inbox socket found, enable proxy mode
65
+ if [ -n "$INBOX_SOCK" ]; then
66
+ export INBOX_SOCKET_PATH="$INBOX_SOCK"
67
+ fi
68
+
51
69
  # Try to find the agent-inbox module entry point
52
70
  INBOX_MAIN=""
53
71
 
@@ -68,6 +86,7 @@ if [ -z "$INBOX_MAIN" ]; then
68
86
  fi
69
87
 
70
88
  if [ -n "$INBOX_MAIN" ]; then
89
+ # Uses proxy mode when INBOX_SOCKET_PATH is set, standalone otherwise
71
90
  exec node "$INBOX_MAIN" mcp
72
91
  fi
73
92
 
package/.gitattributes ADDED
@@ -0,0 +1,3 @@
1
+
2
+ # OpenTasks merge driver for graph.jsonl
3
+ .opentasks/graph.jsonl merge=opentasks
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": "1.0",
3
+ "location": {
4
+ "hash": "5bkyrjlx",
5
+ "uuid": "7b496a03-dd73-4d0b-a243-d9108ecc2f20",
6
+ "name": "claude-code-swarm"
7
+ },
8
+ "connections": []
9
+ }
File without changes
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Test helper: minimal opentasks daemon for e2e tests
3
+ *
4
+ * Creates a JSON-RPC 2.0 server on a Unix socket that implements the
5
+ * subset of opentasks daemon methods used by opentasks-client.mjs:
6
+ * - ping → { pong: true }
7
+ * - graph.create → stores node, returns { id, ...params }
8
+ * - graph.update → updates stored node, returns updated node
9
+ * - tools.link → stores edge, returns { ok: true }
10
+ *
11
+ * Uses in-memory storage. No persistence, no providers, no flush.
12
+ */
13
+
14
+ import net from "net";
15
+ import fs from "fs";
16
+ import { randomUUID } from "crypto";
17
+
18
+ /**
19
+ * Start a minimal opentasks daemon on a Unix socket.
20
+ * Returns { socketPath, stop(), nodes, edges }.
21
+ */
22
+ export function startTestDaemon(socketPath) {
23
+ const nodes = new Map();
24
+ const edges = [];
25
+ let server;
26
+
27
+ return new Promise((resolve, reject) => {
28
+ // Remove stale socket
29
+ try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
30
+
31
+ server = net.createServer((conn) => {
32
+ let buffer = "";
33
+
34
+ conn.on("data", (data) => {
35
+ buffer += data.toString();
36
+ const lines = buffer.split("\n");
37
+ buffer = lines.pop(); // Keep incomplete line
38
+
39
+ for (const line of lines) {
40
+ if (!line.trim()) continue;
41
+ try {
42
+ const req = JSON.parse(line);
43
+ const result = handleRequest(req, nodes, edges);
44
+ conn.write(JSON.stringify(result) + "\n");
45
+ } catch (err) {
46
+ conn.write(JSON.stringify({
47
+ jsonrpc: "2.0",
48
+ id: null,
49
+ error: { code: -32700, message: "Parse error", data: err.message },
50
+ }) + "\n");
51
+ }
52
+ }
53
+ });
54
+ });
55
+
56
+ server.on("error", reject);
57
+
58
+ server.listen(socketPath, () => {
59
+ resolve({
60
+ socketPath,
61
+ nodes,
62
+ edges,
63
+ stop: () => new Promise((res) => {
64
+ server.close(() => {
65
+ try { fs.unlinkSync(socketPath); } catch { /* ignore */ }
66
+ res();
67
+ });
68
+ // Force close connections
69
+ server.unref();
70
+ }),
71
+ });
72
+ });
73
+ });
74
+ }
75
+
76
+ function handleRequest(req, nodes, edges) {
77
+ const { id, method, params } = req;
78
+
79
+ switch (method) {
80
+ case "ping":
81
+ return { jsonrpc: "2.0", id, result: { pong: true } };
82
+
83
+ case "graph.create": {
84
+ const nodeId = randomUUID();
85
+ const node = {
86
+ id: nodeId,
87
+ type: params?.type || "task",
88
+ title: params?.title || "",
89
+ status: params?.status || "open",
90
+ assignee: params?.assignee || null,
91
+ uri: params?.uri || null,
92
+ metadata: params?.metadata || {},
93
+ createdAt: new Date().toISOString(),
94
+ updatedAt: new Date().toISOString(),
95
+ };
96
+ nodes.set(nodeId, node);
97
+ return { jsonrpc: "2.0", id, result: node };
98
+ }
99
+
100
+ case "graph.update": {
101
+ const nodeId = params?.id;
102
+ if (!nodeId || !nodes.has(nodeId)) {
103
+ return {
104
+ jsonrpc: "2.0", id,
105
+ error: { code: -32602, message: `Node not found: ${nodeId}` },
106
+ };
107
+ }
108
+ const existing = nodes.get(nodeId);
109
+ const updated = {
110
+ ...existing,
111
+ ...(params.status !== undefined && { status: params.status }),
112
+ ...(params.title !== undefined && { title: params.title }),
113
+ ...(params.assignee !== undefined && { assignee: params.assignee }),
114
+ ...(params.metadata !== undefined && { metadata: { ...existing.metadata, ...params.metadata } }),
115
+ updatedAt: new Date().toISOString(),
116
+ };
117
+ nodes.set(nodeId, updated);
118
+ return { jsonrpc: "2.0", id, result: updated };
119
+ }
120
+
121
+ case "graph.query": {
122
+ const allNodes = Array.from(nodes.values());
123
+ const filtered = params?.type
124
+ ? allNodes.filter((n) => n.type === params.type)
125
+ : allNodes;
126
+ return { jsonrpc: "2.0", id, result: filtered };
127
+ }
128
+
129
+ case "tools.link": {
130
+ const edge = {
131
+ fromId: params?.fromId,
132
+ toId: params?.toId,
133
+ type: params?.type || "related",
134
+ metadata: params?.metadata || {},
135
+ };
136
+ edges.push(edge);
137
+ return { jsonrpc: "2.0", id, result: { ok: true } };
138
+ }
139
+
140
+ case "shutdown":
141
+ return { jsonrpc: "2.0", id, result: { ok: true } };
142
+
143
+ default:
144
+ return {
145
+ jsonrpc: "2.0", id,
146
+ error: { code: -32601, message: `Method not found: ${method}` },
147
+ };
148
+ }
149
+ }