@claude-flow/swarm 3.0.0-alpha.8 → 3.0.0-alpha.9

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 (117) hide show
  1. package/dist/agent-pool.d.ts.map +1 -1
  2. package/dist/agent-pool.js +10 -2
  3. package/dist/agent-pool.js.map +1 -1
  4. package/dist/attention-coordinator.d.ts +5 -4
  5. package/dist/attention-coordinator.d.ts.map +1 -1
  6. package/dist/attention-coordinator.js +17 -10
  7. package/dist/attention-coordinator.js.map +1 -1
  8. package/dist/consensus/byzantine.d.ts +2 -1
  9. package/dist/consensus/byzantine.d.ts.map +1 -1
  10. package/dist/consensus/byzantine.js +34 -8
  11. package/dist/consensus/byzantine.js.map +1 -1
  12. package/dist/consensus/gossip.d.ts +2 -1
  13. package/dist/consensus/gossip.d.ts.map +1 -1
  14. package/dist/consensus/gossip.js +27 -8
  15. package/dist/consensus/gossip.js.map +1 -1
  16. package/dist/consensus/index.d.ts +1 -1
  17. package/dist/consensus/index.d.ts.map +1 -1
  18. package/dist/consensus/index.js +2 -30
  19. package/dist/consensus/index.js.map +1 -1
  20. package/dist/consensus/raft.d.ts +2 -1
  21. package/dist/consensus/raft.d.ts.map +1 -1
  22. package/dist/consensus/raft.js +25 -9
  23. package/dist/consensus/raft.js.map +1 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/message-bus.d.ts.map +1 -1
  27. package/dist/message-bus.js +13 -4
  28. package/dist/message-bus.js.map +1 -1
  29. package/dist/queen-coordinator.d.ts +1 -1
  30. package/dist/queen-coordinator.d.ts.map +1 -1
  31. package/dist/queen-coordinator.js +10 -3
  32. package/dist/queen-coordinator.js.map +1 -1
  33. package/dist/topology-manager.d.ts.map +1 -1
  34. package/dist/topology-manager.js +26 -1
  35. package/dist/topology-manager.js.map +1 -1
  36. package/dist/types.d.ts +3 -12
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js.map +1 -1
  39. package/dist/unified-coordinator.d.ts +1 -1
  40. package/dist/unified-coordinator.d.ts.map +1 -1
  41. package/dist/unified-coordinator.js +85 -29
  42. package/dist/unified-coordinator.js.map +1 -1
  43. package/package.json +7 -2
  44. package/.claude-flow/data/pending-insights.jsonl +0 -15
  45. package/.claude-flow/hive-mind/state.json +0 -18
  46. package/__tests__/byzantine-transport.test.ts +0 -147
  47. package/__tests__/consensus-failure-injection.test.ts +0 -161
  48. package/__tests__/consensus-transport.test.ts +0 -200
  49. package/__tests__/consensus.test.ts +0 -577
  50. package/__tests__/coordinator.test.ts +0 -501
  51. package/__tests__/federation-transport.test.ts +0 -145
  52. package/__tests__/gossip-transport.test.ts +0 -81
  53. package/__tests__/queen-coordinator.test.ts +0 -1335
  54. package/__tests__/raft-transport.test.ts +0 -121
  55. package/__tests__/topology.test.ts +0 -621
  56. package/ruvector.db +0 -0
  57. package/src/agent-pool.ts +0 -476
  58. package/src/application/commands/create-task.command.ts +0 -124
  59. package/src/application/commands/spawn-agent.command.ts +0 -122
  60. package/src/application/index.ts +0 -30
  61. package/src/application/services/swarm-application-service.ts +0 -200
  62. package/src/attention-coordinator.ts +0 -1000
  63. package/src/consensus/byzantine.ts +0 -514
  64. package/src/consensus/federation-transport.ts +0 -185
  65. package/src/consensus/gossip.ts +0 -599
  66. package/src/consensus/index.ts +0 -326
  67. package/src/consensus/raft.ts +0 -561
  68. package/src/consensus/transport.ts +0 -284
  69. package/src/coordination/agent-registry.ts +0 -544
  70. package/src/coordination/index.ts +0 -23
  71. package/src/coordination/swarm-hub.ts +0 -776
  72. package/src/coordination/task-orchestrator.ts +0 -605
  73. package/src/domain/entities/agent.d.ts +0 -151
  74. package/src/domain/entities/agent.d.ts.map +0 -1
  75. package/src/domain/entities/agent.js +0 -280
  76. package/src/domain/entities/agent.js.map +0 -1
  77. package/src/domain/entities/agent.ts +0 -370
  78. package/src/domain/entities/task.d.ts +0 -133
  79. package/src/domain/entities/task.d.ts.map +0 -1
  80. package/src/domain/entities/task.js +0 -261
  81. package/src/domain/entities/task.js.map +0 -1
  82. package/src/domain/entities/task.ts +0 -319
  83. package/src/domain/index.ts +0 -41
  84. package/src/domain/repositories/agent-repository.interface.d.ts +0 -57
  85. package/src/domain/repositories/agent-repository.interface.d.ts.map +0 -1
  86. package/src/domain/repositories/agent-repository.interface.js +0 -9
  87. package/src/domain/repositories/agent-repository.interface.js.map +0 -1
  88. package/src/domain/repositories/agent-repository.interface.ts +0 -69
  89. package/src/domain/repositories/task-repository.interface.d.ts +0 -61
  90. package/src/domain/repositories/task-repository.interface.d.ts.map +0 -1
  91. package/src/domain/repositories/task-repository.interface.js +0 -9
  92. package/src/domain/repositories/task-repository.interface.js.map +0 -1
  93. package/src/domain/repositories/task-repository.interface.ts +0 -75
  94. package/src/domain/services/coordination-service.ts +0 -320
  95. package/src/federation-hub.d.ts +0 -284
  96. package/src/federation-hub.d.ts.map +0 -1
  97. package/src/federation-hub.js +0 -692
  98. package/src/federation-hub.js.map +0 -1
  99. package/src/federation-hub.ts +0 -979
  100. package/src/index.ts +0 -374
  101. package/src/message-bus.ts +0 -607
  102. package/src/queen-coordinator.ts +0 -2025
  103. package/src/shared/events.ts +0 -285
  104. package/src/shared/types.ts +0 -389
  105. package/src/topology-manager.ts +0 -656
  106. package/src/types.ts +0 -555
  107. package/src/unified-coordinator.ts +0 -1844
  108. package/src/workers/index.ts +0 -65
  109. package/src/workers/worker-dispatch.d.ts +0 -234
  110. package/src/workers/worker-dispatch.d.ts.map +0 -1
  111. package/src/workers/worker-dispatch.js +0 -842
  112. package/src/workers/worker-dispatch.js.map +0 -1
  113. package/src/workers/worker-dispatch.ts +0 -1076
  114. package/tmp.json +0 -0
  115. package/tsconfig.json +0 -9
  116. package/tsconfig.tsbuildinfo +0 -1
  117. package/vitest.config.ts +0 -20
@@ -1,284 +0,0 @@
1
- /**
2
- * ADR-095 G2 — pluggable transport for hive-mind consensus protocols.
3
- *
4
- * The raft/byzantine/gossip consensus implementations historically used a
5
- * local `EventEmitter` for *everything* — both observability events
6
- * ("leader.elected", "consensus.achieved") AND inter-node messages
7
- * (append-entries, vote requests, pre-prepare/prepare/commit). The latter
8
- * never actually crossed a process or node boundary: a node "sent" a
9
- * message by `emit`ting it locally and synthesizing the peer's reply
10
- * inline. That's the single-process limitation #G2 names.
11
- *
12
- * This module separates the inter-node-message dimension behind a
13
- * `ConsensusTransport` interface. Two implementations:
14
- *
15
- * - `LocalTransport` — an in-process registry. Multiple consensus
16
- * instances in the same Node process share a registry and deliver
17
- * messages to each other synchronously. Matches the current
18
- * single-process behavior; the default so nothing breaks.
19
- * - `FederationTransport` (separate file, ADR-104 wire) — serializes
20
- * ConsensusMessages into federation envelopes, signs them with the
21
- * node's Ed25519 key, sends over WS via agentic-flow/transport/loader,
22
- * and dispatches inbound envelopes with signature verification.
23
- *
24
- * Observability events stay on the consensus class's own EventEmitter —
25
- * this is purely the messaging layer.
26
- *
27
- * No new dependencies: Ed25519 signing uses Node's built-in `crypto`
28
- * (`generateKeyPairSync('ed25519')` + `sign`/`verify` with `null` algorithm,
29
- * which is correct for Ed25519).
30
- */
31
-
32
- import { createHash, generateKeyPairSync, sign as cryptoSign, verify as cryptoVerify, createPrivateKey, createPublicKey } from 'node:crypto';
33
-
34
- /** A message exchanged between consensus nodes. */
35
- export interface ConsensusMessage {
36
- /** Protocol message type — e.g. 'append-entries', 'request-vote', 'pre-prepare', 'prepare', 'commit', 'gossip', 'gossip-ack'. */
37
- readonly type: string;
38
- /** Sender node id. */
39
- readonly from: string;
40
- /** Recipient node id. Omit for broadcast. */
41
- readonly to?: string;
42
- /** Protocol payload (term, log entries, vote, digest, …). */
43
- readonly payload: unknown;
44
- /** Raft term, when applicable. Lets the transport drop stale-term messages cheaply. */
45
- readonly term?: number;
46
- /** PBFT view number, when applicable. */
47
- readonly viewNumber?: number;
48
- /** Monotonic per-sender sequence number — replay defense. */
49
- readonly seq?: number;
50
- /** Ed25519 signature (base64) over `canonicalizeForSigning(msg)`. */
51
- readonly signature?: string;
52
- }
53
-
54
- /**
55
- * A reply to a `send()`. Protocols use this for the request-response legs
56
- * (request-vote → vote-response, append-entries → append-entries-response).
57
- * Broadcasts don't get replies; responses arrive via `onMessage`.
58
- */
59
- export type ConsensusReply = ConsensusMessage | null;
60
-
61
- export type ConsensusMessageHandler = (msg: ConsensusMessage) => Promise<ConsensusReply | void> | ConsensusReply | void;
62
-
63
- export interface ConsensusTransport {
64
- /** This node's id (the one consensus protocols use as `from`). */
65
- readonly nodeId: string;
66
- /**
67
- * Send a message to a specific peer. Resolves with the peer's reply
68
- * (or `null` if the peer ack'd without a reply), rejects on timeout or
69
- * unreachable peer. `timeoutMs` defaults to the transport's configured value.
70
- */
71
- send(to: string, msg: Omit<ConsensusMessage, 'from'>, timeoutMs?: number): Promise<ConsensusReply>;
72
- /** Broadcast to all currently-reachable peers. Resolves once dispatched; replies (if any) arrive via onMessage. */
73
- broadcast(msg: Omit<ConsensusMessage, 'from'>): Promise<void>;
74
- /** Register the inbound-message handler. Calling again replaces the previous handler. */
75
- onMessage(handler: ConsensusMessageHandler): void;
76
- /** Currently-reachable peer node ids (excludes self). */
77
- peers(): readonly string[];
78
- /** Tear down. After close(), send/broadcast reject. */
79
- close(): Promise<void>;
80
- }
81
-
82
- // ---------------------------------------------------------------------------
83
- // Ed25519 signing helpers — used by transports that sign messages on the wire.
84
- // ---------------------------------------------------------------------------
85
-
86
- export interface NodeKeyPair {
87
- /** Ed25519 private key in PKCS8 PEM. */
88
- readonly privateKeyPem: string;
89
- /** Ed25519 public key in SPKI PEM. */
90
- readonly publicKeyPem: string;
91
- }
92
-
93
- /** Generate a fresh Ed25519 keypair for a consensus node. */
94
- export function generateNodeKeyPair(): NodeKeyPair {
95
- const { privateKey, publicKey } = generateKeyPairSync('ed25519');
96
- return {
97
- privateKeyPem: privateKey.export({ format: 'pem', type: 'pkcs8' }).toString(),
98
- publicKeyPem: publicKey.export({ format: 'pem', type: 'spki' }).toString(),
99
- };
100
- }
101
-
102
- /**
103
- * Recursively sort object keys so JSON serialization is deterministic
104
- * regardless of insertion order — at every nesting level, not just the top.
105
- * Arrays keep their order (order is semantically meaningful, e.g. log entries).
106
- */
107
- function deepSortKeys(v: unknown): unknown {
108
- if (Array.isArray(v)) return v.map(deepSortKeys);
109
- if (v && typeof v === 'object') {
110
- const out: Record<string, unknown> = {};
111
- for (const k of Object.keys(v as Record<string, unknown>).sort()) {
112
- const val = (v as Record<string, unknown>)[k];
113
- if (val !== undefined) out[k] = deepSortKeys(val);
114
- }
115
- return out;
116
- }
117
- return v;
118
- }
119
-
120
- /**
121
- * Canonical byte string for signing. Deterministic across hosts: deep-sorted-key
122
- * JSON of the message's content fields (everything except `signature`).
123
- */
124
- export function canonicalizeForSigning(msg: Omit<ConsensusMessage, 'signature'>): Buffer {
125
- return Buffer.from(JSON.stringify(deepSortKeys(msg)), 'utf-8');
126
- }
127
-
128
- /** Stable digest of a message's content — handy for dedup and logging. */
129
- export function messageDigest(msg: Omit<ConsensusMessage, 'signature'>): string {
130
- return createHash('sha256').update(canonicalizeForSigning(msg)).digest('hex');
131
- }
132
-
133
- /** Sign a message with an Ed25519 private key (PEM). Returns base64 signature. */
134
- export function signMessage(msg: Omit<ConsensusMessage, 'signature'>, privateKeyPem: string): string {
135
- const key = createPrivateKey(privateKeyPem);
136
- const sig = cryptoSign(null, canonicalizeForSigning(msg), key);
137
- return sig.toString('base64');
138
- }
139
-
140
- /**
141
- * Verify a signed message against a peer's Ed25519 public key (PEM).
142
- * Returns true iff the signature is present and valid over the message's
143
- * content fields. Fail-closed: a missing signature returns false.
144
- */
145
- export function verifyMessage(msg: ConsensusMessage, publicKeyPem: string): boolean {
146
- if (typeof msg.signature !== 'string' || msg.signature.length === 0) return false;
147
- try {
148
- const { signature, ...content } = msg;
149
- const key = createPublicKey(publicKeyPem);
150
- return cryptoVerify(null, canonicalizeForSigning(content), key, Buffer.from(signature, 'base64'));
151
- } catch {
152
- return false;
153
- }
154
- }
155
-
156
- // ---------------------------------------------------------------------------
157
- // LocalTransport — in-process registry. The default. Matches single-process.
158
- // ---------------------------------------------------------------------------
159
-
160
- /**
161
- * Shared registry of LocalTransport instances. Multiple consensus nodes in
162
- * the same process register here; send/broadcast deliver to peers' handlers.
163
- * Use a fresh registry per test to keep tests isolated.
164
- */
165
- export class LocalTransportRegistry {
166
- private readonly nodes = new Map<string, LocalTransport>();
167
-
168
- register(t: LocalTransport): void {
169
- this.nodes.set(t.nodeId, t);
170
- }
171
- unregister(nodeId: string): void {
172
- this.nodes.delete(nodeId);
173
- }
174
- get(nodeId: string): LocalTransport | undefined {
175
- return this.nodes.get(nodeId);
176
- }
177
- peerIds(exclude: string): string[] {
178
- return [...this.nodes.keys()].filter(id => id !== exclude);
179
- }
180
- }
181
-
182
- /** Process-wide default registry. Tests should pass their own. */
183
- export const defaultLocalRegistry = new LocalTransportRegistry();
184
-
185
- export interface LocalTransportOptions {
186
- readonly registry?: LocalTransportRegistry;
187
- readonly defaultTimeoutMs?: number;
188
- /** Optional Ed25519 keypair — when set, outbound messages are signed and inbound are verified against the sender's pubkey (resolved via `resolvePeerPublicKey`). */
189
- readonly keyPair?: NodeKeyPair;
190
- /** Map a peer nodeId → its Ed25519 public key PEM. Required if `keyPair` is set and you want verification. */
191
- readonly resolvePeerPublicKey?: (nodeId: string) => string | undefined;
192
- }
193
-
194
- export class LocalTransport implements ConsensusTransport {
195
- readonly nodeId: string;
196
- private readonly registry: LocalTransportRegistry;
197
- private readonly defaultTimeoutMs: number;
198
- private readonly keyPair?: NodeKeyPair;
199
- private readonly resolvePeerPublicKey?: (nodeId: string) => string | undefined;
200
- private handler: ConsensusMessageHandler | null = null;
201
- private closed = false;
202
- private seqCounter = 0;
203
- /** Per-sender last-seen seq for replay defense (only used when signed). */
204
- private readonly lastSeenSeq = new Map<string, number>();
205
-
206
- constructor(nodeId: string, opts: LocalTransportOptions = {}) {
207
- this.nodeId = nodeId;
208
- this.registry = opts.registry ?? defaultLocalRegistry;
209
- this.defaultTimeoutMs = opts.defaultTimeoutMs ?? 5_000;
210
- this.keyPair = opts.keyPair;
211
- this.resolvePeerPublicKey = opts.resolvePeerPublicKey;
212
- this.registry.register(this);
213
- }
214
-
215
- onMessage(handler: ConsensusMessageHandler): void {
216
- this.handler = handler;
217
- }
218
-
219
- peers(): readonly string[] {
220
- return this.registry.peerIds(this.nodeId);
221
- }
222
-
223
- private stamp(msg: Omit<ConsensusMessage, 'from'>): ConsensusMessage {
224
- const base: Omit<ConsensusMessage, 'signature'> = {
225
- ...msg,
226
- from: this.nodeId,
227
- seq: this.keyPair ? ++this.seqCounter : msg.seq,
228
- };
229
- if (this.keyPair) {
230
- return { ...base, signature: signMessage(base, this.keyPair.privateKeyPem) };
231
- }
232
- return base;
233
- }
234
-
235
- /** Deliver an inbound message to a target's handler, with optional sig + replay checks. */
236
- private async deliver(target: LocalTransport, msg: ConsensusMessage): Promise<ConsensusReply> {
237
- if (target.closed) throw new Error(`LocalTransport: peer ${target.nodeId} is closed`);
238
- // Verification path — only when the *target* expects signed messages.
239
- if (target.keyPair && target.resolvePeerPublicKey) {
240
- const pub = target.resolvePeerPublicKey(msg.from);
241
- if (!pub || !verifyMessage(msg, pub)) {
242
- throw new Error(`LocalTransport: signature verification failed for message from ${msg.from}`);
243
- }
244
- // Replay defense: seq must be strictly increasing per sender.
245
- if (typeof msg.seq === 'number') {
246
- const last = target.lastSeenSeq.get(msg.from) ?? 0;
247
- if (msg.seq <= last) throw new Error(`LocalTransport: replayed/out-of-order seq from ${msg.from} (${msg.seq} <= ${last})`);
248
- target.lastSeenSeq.set(msg.from, msg.seq);
249
- }
250
- }
251
- if (!target.handler) return null;
252
- const reply = await target.handler(msg);
253
- return (reply ?? null) as ConsensusReply;
254
- }
255
-
256
- async send(to: string, msg: Omit<ConsensusMessage, 'from'>, timeoutMs?: number): Promise<ConsensusReply> {
257
- if (this.closed) throw new Error('LocalTransport: closed');
258
- const target = this.registry.get(to);
259
- if (!target) throw new Error(`LocalTransport: unreachable peer ${to}`);
260
- const stamped = this.stamp(msg);
261
- const t = timeoutMs ?? this.defaultTimeoutMs;
262
- return Promise.race([
263
- this.deliver(target, stamped),
264
- new Promise<ConsensusReply>((_, rej) => setTimeout(() => rej(new Error(`LocalTransport: send to ${to} timed out (${t}ms)`)), t)),
265
- ]);
266
- }
267
-
268
- async broadcast(msg: Omit<ConsensusMessage, 'from'>): Promise<void> {
269
- if (this.closed) throw new Error('LocalTransport: closed');
270
- const stamped = this.stamp(msg);
271
- await Promise.allSettled(
272
- this.registry.peerIds(this.nodeId).map(id => {
273
- const target = this.registry.get(id);
274
- return target ? this.deliver(target, stamped).catch(() => {}) : Promise.resolve();
275
- }),
276
- );
277
- }
278
-
279
- async close(): Promise<void> {
280
- this.closed = true;
281
- this.handler = null;
282
- this.registry.unregister(this.nodeId);
283
- }
284
- }