@claude-flow/cli 3.0.0-alpha.36 → 3.0.0-alpha.38
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/helpers/README.md +97 -0
- package/.claude/helpers/adr-compliance.sh +186 -0
- package/.claude/helpers/auto-commit.sh +178 -0
- package/.claude/helpers/checkpoint-manager.sh +251 -0
- package/.claude/helpers/daemon-manager.sh +252 -0
- package/.claude/helpers/ddd-tracker.sh +144 -0
- package/.claude/helpers/github-safe.js +106 -0
- package/.claude/helpers/github-setup.sh +28 -0
- package/.claude/helpers/guidance-hook.sh +13 -0
- package/.claude/helpers/guidance-hooks.sh +102 -0
- package/.claude/helpers/health-monitor.sh +108 -0
- package/.claude/helpers/learning-hooks.sh +329 -0
- package/.claude/helpers/learning-optimizer.sh +127 -0
- package/.claude/helpers/learning-service.mjs +1144 -0
- package/.claude/helpers/metrics-db.mjs +488 -0
- package/.claude/helpers/pattern-consolidator.sh +86 -0
- package/.claude/helpers/perf-worker.sh +160 -0
- package/.claude/helpers/quick-start.sh +19 -0
- package/.claude/helpers/security-scanner.sh +127 -0
- package/.claude/helpers/setup-mcp.sh +18 -0
- package/.claude/helpers/standard-checkpoint-hooks.sh +189 -0
- package/.claude/helpers/swarm-comms.sh +353 -0
- package/.claude/helpers/swarm-hooks.sh +761 -0
- package/.claude/helpers/swarm-monitor.sh +211 -0
- package/.claude/helpers/sync-v3-metrics.sh +245 -0
- package/.claude/helpers/update-v3-progress.sh +166 -0
- package/.claude/helpers/v3-quick-status.sh +58 -0
- package/.claude/helpers/v3.sh +111 -0
- package/.claude/helpers/validate-v3-config.sh +216 -0
- package/.claude/helpers/worker-manager.sh +170 -0
- package/dist/src/init/mcp-generator.js +2 -2
- package/dist/src/init/mcp-generator.js.map +1 -1
- package/dist/src/init/types.js +2 -2
- package/dist/src/init/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claude Flow V3 - Swarm Communication Hooks
|
|
3
|
+
# Enables agent-to-agent messaging, pattern sharing, consensus, and task handoffs
|
|
4
|
+
#
|
|
5
|
+
# Integration with:
|
|
6
|
+
# - @claude-flow/hooks SwarmCommunication module
|
|
7
|
+
# - agentic-flow@alpha swarm coordination
|
|
8
|
+
# - Local hooks system for real-time agent coordination
|
|
9
|
+
#
|
|
10
|
+
# Key mechanisms:
|
|
11
|
+
# - Exit 0 + stdout = Context added to Claude's view
|
|
12
|
+
# - Exit 2 + stderr = Block with explanation
|
|
13
|
+
# - JSON additionalContext = Swarm coordination messages
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
19
|
+
SWARM_DIR="$PROJECT_ROOT/.claude-flow/swarm"
|
|
20
|
+
MESSAGES_DIR="$SWARM_DIR/messages"
|
|
21
|
+
PATTERNS_DIR="$SWARM_DIR/patterns"
|
|
22
|
+
CONSENSUS_DIR="$SWARM_DIR/consensus"
|
|
23
|
+
HANDOFFS_DIR="$SWARM_DIR/handoffs"
|
|
24
|
+
AGENTS_FILE="$SWARM_DIR/agents.json"
|
|
25
|
+
STATS_FILE="$SWARM_DIR/stats.json"
|
|
26
|
+
|
|
27
|
+
# Agent identity
|
|
28
|
+
AGENT_ID="${AGENTIC_FLOW_AGENT_ID:-agent_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)}"
|
|
29
|
+
AGENT_NAME="${AGENTIC_FLOW_AGENT_NAME:-claude-code}"
|
|
30
|
+
|
|
31
|
+
# Initialize directories
|
|
32
|
+
mkdir -p "$MESSAGES_DIR" "$PATTERNS_DIR" "$CONSENSUS_DIR" "$HANDOFFS_DIR"
|
|
33
|
+
|
|
34
|
+
# =============================================================================
|
|
35
|
+
# UTILITY FUNCTIONS
|
|
36
|
+
# =============================================================================
|
|
37
|
+
|
|
38
|
+
init_stats() {
|
|
39
|
+
if [ ! -f "$STATS_FILE" ]; then
|
|
40
|
+
cat > "$STATS_FILE" << EOF
|
|
41
|
+
{
|
|
42
|
+
"messagesSent": 0,
|
|
43
|
+
"messagesReceived": 0,
|
|
44
|
+
"patternsBroadcast": 0,
|
|
45
|
+
"consensusInitiated": 0,
|
|
46
|
+
"consensusResolved": 0,
|
|
47
|
+
"handoffsInitiated": 0,
|
|
48
|
+
"handoffsCompleted": 0,
|
|
49
|
+
"lastUpdated": "$(date -Iseconds)"
|
|
50
|
+
}
|
|
51
|
+
EOF
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
update_stat() {
|
|
56
|
+
local key="$1"
|
|
57
|
+
local increment="${2:-1}"
|
|
58
|
+
init_stats
|
|
59
|
+
|
|
60
|
+
if command -v jq &>/dev/null; then
|
|
61
|
+
local current=$(jq -r ".$key // 0" "$STATS_FILE")
|
|
62
|
+
local new=$((current + increment))
|
|
63
|
+
jq ".$key = $new | .lastUpdated = \"$(date -Iseconds)\"" "$STATS_FILE" > "$STATS_FILE.tmp" && mv "$STATS_FILE.tmp" "$STATS_FILE"
|
|
64
|
+
fi
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
register_agent() {
|
|
68
|
+
init_stats
|
|
69
|
+
local timestamp=$(date +%s)
|
|
70
|
+
|
|
71
|
+
if [ ! -f "$AGENTS_FILE" ]; then
|
|
72
|
+
echo '{"agents":[]}' > "$AGENTS_FILE"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if command -v jq &>/dev/null; then
|
|
76
|
+
# Check if agent already exists
|
|
77
|
+
local exists=$(jq -r ".agents[] | select(.id == \"$AGENT_ID\") | .id" "$AGENTS_FILE" 2>/dev/null || echo "")
|
|
78
|
+
|
|
79
|
+
if [ -z "$exists" ]; then
|
|
80
|
+
jq ".agents += [{\"id\":\"$AGENT_ID\",\"name\":\"$AGENT_NAME\",\"status\":\"active\",\"lastSeen\":$timestamp}]" "$AGENTS_FILE" > "$AGENTS_FILE.tmp" && mv "$AGENTS_FILE.tmp" "$AGENTS_FILE"
|
|
81
|
+
else
|
|
82
|
+
# Update lastSeen
|
|
83
|
+
jq "(.agents[] | select(.id == \"$AGENT_ID\")).lastSeen = $timestamp" "$AGENTS_FILE" > "$AGENTS_FILE.tmp" && mv "$AGENTS_FILE.tmp" "$AGENTS_FILE"
|
|
84
|
+
fi
|
|
85
|
+
fi
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# =============================================================================
|
|
89
|
+
# AGENT-TO-AGENT MESSAGING
|
|
90
|
+
# =============================================================================
|
|
91
|
+
|
|
92
|
+
send_message() {
|
|
93
|
+
local to="${1:-*}"
|
|
94
|
+
local content="${2:-}"
|
|
95
|
+
local msg_type="${3:-context}"
|
|
96
|
+
local priority="${4:-normal}"
|
|
97
|
+
|
|
98
|
+
local msg_id="msg_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)"
|
|
99
|
+
local timestamp=$(date +%s)
|
|
100
|
+
|
|
101
|
+
local msg_file="$MESSAGES_DIR/$msg_id.json"
|
|
102
|
+
cat > "$msg_file" << EOF
|
|
103
|
+
{
|
|
104
|
+
"id": "$msg_id",
|
|
105
|
+
"from": "$AGENT_ID",
|
|
106
|
+
"fromName": "$AGENT_NAME",
|
|
107
|
+
"to": "$to",
|
|
108
|
+
"type": "$msg_type",
|
|
109
|
+
"content": $(echo "$content" | jq -Rs .),
|
|
110
|
+
"priority": "$priority",
|
|
111
|
+
"timestamp": $timestamp,
|
|
112
|
+
"read": false
|
|
113
|
+
}
|
|
114
|
+
EOF
|
|
115
|
+
|
|
116
|
+
update_stat "messagesSent"
|
|
117
|
+
|
|
118
|
+
echo "$msg_id"
|
|
119
|
+
exit 0
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get_messages() {
|
|
123
|
+
local limit="${1:-10}"
|
|
124
|
+
local msg_type="${2:-}"
|
|
125
|
+
|
|
126
|
+
register_agent
|
|
127
|
+
|
|
128
|
+
local messages="[]"
|
|
129
|
+
local count=0
|
|
130
|
+
|
|
131
|
+
for msg_file in $(ls -t "$MESSAGES_DIR"/*.json 2>/dev/null | head -n "$limit"); do
|
|
132
|
+
if [ -f "$msg_file" ]; then
|
|
133
|
+
local to=$(jq -r '.to' "$msg_file" 2>/dev/null)
|
|
134
|
+
|
|
135
|
+
# Check if message is for us or broadcast
|
|
136
|
+
if [ "$to" = "$AGENT_ID" ] || [ "$to" = "*" ] || [ "$to" = "$AGENT_NAME" ]; then
|
|
137
|
+
# Filter by type if specified
|
|
138
|
+
if [ -n "$msg_type" ]; then
|
|
139
|
+
local mtype=$(jq -r '.type' "$msg_file" 2>/dev/null)
|
|
140
|
+
if [ "$mtype" != "$msg_type" ]; then
|
|
141
|
+
continue
|
|
142
|
+
fi
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
if command -v jq &>/dev/null; then
|
|
146
|
+
messages=$(echo "$messages" | jq ". += [$(cat "$msg_file")]")
|
|
147
|
+
count=$((count + 1))
|
|
148
|
+
|
|
149
|
+
# Mark as read
|
|
150
|
+
jq '.read = true' "$msg_file" > "$msg_file.tmp" && mv "$msg_file.tmp" "$msg_file"
|
|
151
|
+
fi
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
done
|
|
155
|
+
|
|
156
|
+
update_stat "messagesReceived" "$count"
|
|
157
|
+
|
|
158
|
+
if command -v jq &>/dev/null; then
|
|
159
|
+
echo "$messages" | jq -c "{count: $count, messages: .}"
|
|
160
|
+
else
|
|
161
|
+
echo "{\"count\": $count, \"messages\": []}"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
exit 0
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
broadcast_context() {
|
|
168
|
+
local content="${1:-}"
|
|
169
|
+
send_message "*" "$content" "context" "normal"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# =============================================================================
|
|
173
|
+
# PATTERN BROADCASTING
|
|
174
|
+
# =============================================================================
|
|
175
|
+
|
|
176
|
+
broadcast_pattern() {
|
|
177
|
+
local strategy="${1:-}"
|
|
178
|
+
local domain="${2:-general}"
|
|
179
|
+
local quality="${3:-0.7}"
|
|
180
|
+
|
|
181
|
+
local bc_id="bc_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)"
|
|
182
|
+
local timestamp=$(date +%s)
|
|
183
|
+
|
|
184
|
+
local bc_file="$PATTERNS_DIR/$bc_id.json"
|
|
185
|
+
cat > "$bc_file" << EOF
|
|
186
|
+
{
|
|
187
|
+
"id": "$bc_id",
|
|
188
|
+
"sourceAgent": "$AGENT_ID",
|
|
189
|
+
"sourceAgentName": "$AGENT_NAME",
|
|
190
|
+
"pattern": {
|
|
191
|
+
"strategy": $(echo "$strategy" | jq -Rs .),
|
|
192
|
+
"domain": "$domain",
|
|
193
|
+
"quality": $quality
|
|
194
|
+
},
|
|
195
|
+
"broadcastTime": $timestamp,
|
|
196
|
+
"acknowledgments": []
|
|
197
|
+
}
|
|
198
|
+
EOF
|
|
199
|
+
|
|
200
|
+
update_stat "patternsBroadcast"
|
|
201
|
+
|
|
202
|
+
# Also store in learning hooks if available
|
|
203
|
+
if [ -f "$SCRIPT_DIR/learning-hooks.sh" ]; then
|
|
204
|
+
"$SCRIPT_DIR/learning-hooks.sh" store "$strategy" "$domain" "$quality" 2>/dev/null || true
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
cat << EOF
|
|
208
|
+
{"broadcastId":"$bc_id","strategy":$(echo "$strategy" | jq -Rs .),"domain":"$domain","quality":$quality}
|
|
209
|
+
EOF
|
|
210
|
+
|
|
211
|
+
exit 0
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
get_pattern_broadcasts() {
|
|
215
|
+
local domain="${1:-}"
|
|
216
|
+
local min_quality="${2:-0}"
|
|
217
|
+
local limit="${3:-10}"
|
|
218
|
+
|
|
219
|
+
local broadcasts="[]"
|
|
220
|
+
local count=0
|
|
221
|
+
|
|
222
|
+
for bc_file in $(ls -t "$PATTERNS_DIR"/*.json 2>/dev/null | head -n "$limit"); do
|
|
223
|
+
if [ -f "$bc_file" ] && command -v jq &>/dev/null; then
|
|
224
|
+
local bc_domain=$(jq -r '.pattern.domain' "$bc_file" 2>/dev/null)
|
|
225
|
+
local bc_quality=$(jq -r '.pattern.quality' "$bc_file" 2>/dev/null)
|
|
226
|
+
|
|
227
|
+
# Filter by domain if specified
|
|
228
|
+
if [ -n "$domain" ] && [ "$bc_domain" != "$domain" ]; then
|
|
229
|
+
continue
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# Filter by quality
|
|
233
|
+
if [ "$(echo "$bc_quality >= $min_quality" | bc -l 2>/dev/null || echo "1")" = "1" ]; then
|
|
234
|
+
broadcasts=$(echo "$broadcasts" | jq ". += [$(cat "$bc_file")]")
|
|
235
|
+
count=$((count + 1))
|
|
236
|
+
fi
|
|
237
|
+
fi
|
|
238
|
+
done
|
|
239
|
+
|
|
240
|
+
echo "$broadcasts" | jq -c "{count: $count, broadcasts: .}"
|
|
241
|
+
exit 0
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
import_pattern() {
|
|
245
|
+
local bc_id="$1"
|
|
246
|
+
local bc_file="$PATTERNS_DIR/$bc_id.json"
|
|
247
|
+
|
|
248
|
+
if [ ! -f "$bc_file" ]; then
|
|
249
|
+
echo '{"imported": false, "error": "Broadcast not found"}'
|
|
250
|
+
exit 1
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
# Acknowledge the broadcast
|
|
254
|
+
if command -v jq &>/dev/null; then
|
|
255
|
+
jq ".acknowledgments += [\"$AGENT_ID\"]" "$bc_file" > "$bc_file.tmp" && mv "$bc_file.tmp" "$bc_file"
|
|
256
|
+
|
|
257
|
+
# Import to local learning
|
|
258
|
+
local strategy=$(jq -r '.pattern.strategy' "$bc_file")
|
|
259
|
+
local domain=$(jq -r '.pattern.domain' "$bc_file")
|
|
260
|
+
local quality=$(jq -r '.pattern.quality' "$bc_file")
|
|
261
|
+
|
|
262
|
+
if [ -f "$SCRIPT_DIR/learning-hooks.sh" ]; then
|
|
263
|
+
"$SCRIPT_DIR/learning-hooks.sh" store "$strategy" "$domain" "$quality" 2>/dev/null || true
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
echo "{\"imported\": true, \"broadcastId\": \"$bc_id\"}"
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
exit 0
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# =============================================================================
|
|
273
|
+
# CONSENSUS GUIDANCE
|
|
274
|
+
# =============================================================================
|
|
275
|
+
|
|
276
|
+
initiate_consensus() {
|
|
277
|
+
local question="${1:-}"
|
|
278
|
+
local options_str="${2:-}" # comma-separated
|
|
279
|
+
local timeout="${3:-30000}"
|
|
280
|
+
|
|
281
|
+
local cons_id="cons_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)"
|
|
282
|
+
local timestamp=$(date +%s)
|
|
283
|
+
local deadline=$((timestamp + timeout / 1000))
|
|
284
|
+
|
|
285
|
+
# Parse options
|
|
286
|
+
local options_json="[]"
|
|
287
|
+
IFS=',' read -ra opts <<< "$options_str"
|
|
288
|
+
for opt in "${opts[@]}"; do
|
|
289
|
+
opt=$(echo "$opt" | xargs) # trim whitespace
|
|
290
|
+
if command -v jq &>/dev/null; then
|
|
291
|
+
options_json=$(echo "$options_json" | jq ". += [\"$opt\"]")
|
|
292
|
+
fi
|
|
293
|
+
done
|
|
294
|
+
|
|
295
|
+
local cons_file="$CONSENSUS_DIR/$cons_id.json"
|
|
296
|
+
cat > "$cons_file" << EOF
|
|
297
|
+
{
|
|
298
|
+
"id": "$cons_id",
|
|
299
|
+
"initiator": "$AGENT_ID",
|
|
300
|
+
"initiatorName": "$AGENT_NAME",
|
|
301
|
+
"question": $(echo "$question" | jq -Rs .),
|
|
302
|
+
"options": $options_json,
|
|
303
|
+
"votes": {},
|
|
304
|
+
"deadline": $deadline,
|
|
305
|
+
"status": "pending"
|
|
306
|
+
}
|
|
307
|
+
EOF
|
|
308
|
+
|
|
309
|
+
update_stat "consensusInitiated"
|
|
310
|
+
|
|
311
|
+
# Broadcast consensus request
|
|
312
|
+
send_message "*" "Consensus request: $question. Options: $options_str. Vote by replying with your choice." "consensus" "high" >/dev/null
|
|
313
|
+
|
|
314
|
+
cat << EOF
|
|
315
|
+
{"consensusId":"$cons_id","question":$(echo "$question" | jq -Rs .),"options":$options_json,"deadline":$deadline}
|
|
316
|
+
EOF
|
|
317
|
+
|
|
318
|
+
exit 0
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
vote_consensus() {
|
|
322
|
+
local cons_id="$1"
|
|
323
|
+
local vote="$2"
|
|
324
|
+
|
|
325
|
+
local cons_file="$CONSENSUS_DIR/$cons_id.json"
|
|
326
|
+
|
|
327
|
+
if [ ! -f "$cons_file" ]; then
|
|
328
|
+
echo '{"accepted": false, "error": "Consensus not found"}'
|
|
329
|
+
exit 1
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
if command -v jq &>/dev/null; then
|
|
333
|
+
local status=$(jq -r '.status' "$cons_file")
|
|
334
|
+
if [ "$status" != "pending" ]; then
|
|
335
|
+
echo '{"accepted": false, "error": "Consensus already resolved"}'
|
|
336
|
+
exit 1
|
|
337
|
+
fi
|
|
338
|
+
|
|
339
|
+
# Check if vote is valid option
|
|
340
|
+
local valid=$(jq -r ".options | index(\"$vote\") // -1" "$cons_file")
|
|
341
|
+
if [ "$valid" = "-1" ]; then
|
|
342
|
+
echo "{\"accepted\": false, \"error\": \"Invalid option: $vote\"}"
|
|
343
|
+
exit 1
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
# Record vote
|
|
347
|
+
jq ".votes[\"$AGENT_ID\"] = \"$vote\"" "$cons_file" > "$cons_file.tmp" && mv "$cons_file.tmp" "$cons_file"
|
|
348
|
+
|
|
349
|
+
echo "{\"accepted\": true, \"consensusId\": \"$cons_id\", \"vote\": \"$vote\"}"
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
exit 0
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
resolve_consensus() {
|
|
356
|
+
local cons_id="$1"
|
|
357
|
+
local cons_file="$CONSENSUS_DIR/$cons_id.json"
|
|
358
|
+
|
|
359
|
+
if [ ! -f "$cons_file" ]; then
|
|
360
|
+
echo '{"resolved": false, "error": "Consensus not found"}'
|
|
361
|
+
exit 1
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
if command -v jq &>/dev/null; then
|
|
365
|
+
# Count votes
|
|
366
|
+
local result=$(jq -r '
|
|
367
|
+
.votes | to_entries | group_by(.value) |
|
|
368
|
+
map({option: .[0].value, count: length}) |
|
|
369
|
+
sort_by(-.count) | .[0] // {option: "none", count: 0}
|
|
370
|
+
' "$cons_file")
|
|
371
|
+
|
|
372
|
+
local winner=$(echo "$result" | jq -r '.option')
|
|
373
|
+
local count=$(echo "$result" | jq -r '.count')
|
|
374
|
+
local total=$(jq '.votes | length' "$cons_file")
|
|
375
|
+
|
|
376
|
+
local confidence=0
|
|
377
|
+
if [ "$total" -gt 0 ]; then
|
|
378
|
+
confidence=$(echo "scale=2; $count / $total * 100" | bc 2>/dev/null || echo "0")
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
# Update status
|
|
382
|
+
jq ".status = \"resolved\" | .result = {\"winner\": \"$winner\", \"confidence\": $confidence, \"totalVotes\": $total}" "$cons_file" > "$cons_file.tmp" && mv "$cons_file.tmp" "$cons_file"
|
|
383
|
+
|
|
384
|
+
update_stat "consensusResolved"
|
|
385
|
+
|
|
386
|
+
echo "{\"resolved\": true, \"winner\": \"$winner\", \"confidence\": $confidence, \"totalVotes\": $total}"
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
exit 0
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
get_consensus_status() {
|
|
393
|
+
local cons_id="${1:-}"
|
|
394
|
+
|
|
395
|
+
if [ -n "$cons_id" ]; then
|
|
396
|
+
local cons_file="$CONSENSUS_DIR/$cons_id.json"
|
|
397
|
+
if [ -f "$cons_file" ]; then
|
|
398
|
+
cat "$cons_file"
|
|
399
|
+
else
|
|
400
|
+
echo '{"error": "Consensus not found"}'
|
|
401
|
+
exit 1
|
|
402
|
+
fi
|
|
403
|
+
else
|
|
404
|
+
# List pending consensus
|
|
405
|
+
local pending="[]"
|
|
406
|
+
for cons_file in "$CONSENSUS_DIR"/*.json; do
|
|
407
|
+
if [ -f "$cons_file" ] && command -v jq &>/dev/null; then
|
|
408
|
+
local status=$(jq -r '.status' "$cons_file")
|
|
409
|
+
if [ "$status" = "pending" ]; then
|
|
410
|
+
pending=$(echo "$pending" | jq ". += [$(cat "$cons_file")]")
|
|
411
|
+
fi
|
|
412
|
+
fi
|
|
413
|
+
done
|
|
414
|
+
echo "$pending" | jq -c .
|
|
415
|
+
fi
|
|
416
|
+
|
|
417
|
+
exit 0
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
# =============================================================================
|
|
421
|
+
# TASK HANDOFF
|
|
422
|
+
# =============================================================================
|
|
423
|
+
|
|
424
|
+
initiate_handoff() {
|
|
425
|
+
local to_agent="$1"
|
|
426
|
+
local description="${2:-}"
|
|
427
|
+
local context_json="$3"
|
|
428
|
+
[ -z "$context_json" ] && context_json='{}'
|
|
429
|
+
|
|
430
|
+
local ho_id="ho_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)"
|
|
431
|
+
local timestamp=$(date +%s)
|
|
432
|
+
|
|
433
|
+
# Parse context or use defaults - ensure valid JSON
|
|
434
|
+
local context
|
|
435
|
+
if command -v jq &>/dev/null && [ -n "$context_json" ] && [ "$context_json" != "{}" ]; then
|
|
436
|
+
# Try to parse and merge with defaults
|
|
437
|
+
context=$(jq -c '{
|
|
438
|
+
filesModified: (.filesModified // []),
|
|
439
|
+
patternsUsed: (.patternsUsed // []),
|
|
440
|
+
decisions: (.decisions // []),
|
|
441
|
+
blockers: (.blockers // []),
|
|
442
|
+
nextSteps: (.nextSteps // [])
|
|
443
|
+
}' <<< "$context_json" 2>/dev/null)
|
|
444
|
+
|
|
445
|
+
# If parsing failed, use defaults
|
|
446
|
+
if [ -z "$context" ] || [ "$context" = "null" ]; then
|
|
447
|
+
context='{"filesModified":[],"patternsUsed":[],"decisions":[],"blockers":[],"nextSteps":[]}'
|
|
448
|
+
fi
|
|
449
|
+
else
|
|
450
|
+
context='{"filesModified":[],"patternsUsed":[],"decisions":[],"blockers":[],"nextSteps":[]}'
|
|
451
|
+
fi
|
|
452
|
+
|
|
453
|
+
local desc_escaped=$(echo -n "$description" | jq -Rs .)
|
|
454
|
+
|
|
455
|
+
local ho_file="$HANDOFFS_DIR/$ho_id.json"
|
|
456
|
+
cat > "$ho_file" << EOF
|
|
457
|
+
{
|
|
458
|
+
"id": "$ho_id",
|
|
459
|
+
"fromAgent": "$AGENT_ID",
|
|
460
|
+
"fromAgentName": "$AGENT_NAME",
|
|
461
|
+
"toAgent": "$to_agent",
|
|
462
|
+
"description": $desc_escaped,
|
|
463
|
+
"context": $context,
|
|
464
|
+
"status": "pending",
|
|
465
|
+
"timestamp": $timestamp
|
|
466
|
+
}
|
|
467
|
+
EOF
|
|
468
|
+
|
|
469
|
+
update_stat "handoffsInitiated"
|
|
470
|
+
|
|
471
|
+
# Send handoff notification (inline, don't call function which exits)
|
|
472
|
+
local msg_id="msg_$(date +%s)_$(head -c 4 /dev/urandom | xxd -p)"
|
|
473
|
+
local msg_file="$MESSAGES_DIR/$msg_id.json"
|
|
474
|
+
cat > "$msg_file" << MSGEOF
|
|
475
|
+
{
|
|
476
|
+
"id": "$msg_id",
|
|
477
|
+
"from": "$AGENT_ID",
|
|
478
|
+
"fromName": "$AGENT_NAME",
|
|
479
|
+
"to": "$to_agent",
|
|
480
|
+
"type": "handoff",
|
|
481
|
+
"content": "Task handoff: $description",
|
|
482
|
+
"priority": "high",
|
|
483
|
+
"timestamp": $timestamp,
|
|
484
|
+
"read": false,
|
|
485
|
+
"handoffId": "$ho_id"
|
|
486
|
+
}
|
|
487
|
+
MSGEOF
|
|
488
|
+
update_stat "messagesSent"
|
|
489
|
+
|
|
490
|
+
cat << EOF
|
|
491
|
+
{"handoffId":"$ho_id","toAgent":"$to_agent","description":$desc_escaped,"status":"pending","context":$context}
|
|
492
|
+
EOF
|
|
493
|
+
|
|
494
|
+
exit 0
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
accept_handoff() {
|
|
498
|
+
local ho_id="$1"
|
|
499
|
+
local ho_file="$HANDOFFS_DIR/$ho_id.json"
|
|
500
|
+
|
|
501
|
+
if [ ! -f "$ho_file" ]; then
|
|
502
|
+
echo '{"accepted": false, "error": "Handoff not found"}'
|
|
503
|
+
exit 1
|
|
504
|
+
fi
|
|
505
|
+
|
|
506
|
+
if command -v jq &>/dev/null; then
|
|
507
|
+
jq ".status = \"accepted\" | .acceptedAt = $(date +%s)" "$ho_file" > "$ho_file.tmp" && mv "$ho_file.tmp" "$ho_file"
|
|
508
|
+
|
|
509
|
+
# Generate context for Claude
|
|
510
|
+
local description=$(jq -r '.description' "$ho_file")
|
|
511
|
+
local from=$(jq -r '.fromAgentName' "$ho_file")
|
|
512
|
+
local files=$(jq -r '.context.filesModified | join(", ")' "$ho_file")
|
|
513
|
+
local patterns=$(jq -r '.context.patternsUsed | join(", ")' "$ho_file")
|
|
514
|
+
local decisions=$(jq -r '.context.decisions | join("; ")' "$ho_file")
|
|
515
|
+
local next=$(jq -r '.context.nextSteps | join("; ")' "$ho_file")
|
|
516
|
+
|
|
517
|
+
cat << EOF
|
|
518
|
+
## Task Handoff Accepted
|
|
519
|
+
|
|
520
|
+
**From**: $from
|
|
521
|
+
**Task**: $description
|
|
522
|
+
|
|
523
|
+
**Files Modified**: $files
|
|
524
|
+
**Patterns Used**: $patterns
|
|
525
|
+
**Decisions Made**: $decisions
|
|
526
|
+
**Next Steps**: $next
|
|
527
|
+
|
|
528
|
+
This context has been transferred. Continue from where the previous agent left off.
|
|
529
|
+
EOF
|
|
530
|
+
fi
|
|
531
|
+
|
|
532
|
+
exit 0
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
complete_handoff() {
|
|
536
|
+
local ho_id="$1"
|
|
537
|
+
local result_json="${2:-{}}"
|
|
538
|
+
|
|
539
|
+
local ho_file="$HANDOFFS_DIR/$ho_id.json"
|
|
540
|
+
|
|
541
|
+
if [ ! -f "$ho_file" ]; then
|
|
542
|
+
echo '{"completed": false, "error": "Handoff not found"}'
|
|
543
|
+
exit 1
|
|
544
|
+
fi
|
|
545
|
+
|
|
546
|
+
if command -v jq &>/dev/null; then
|
|
547
|
+
jq ".status = \"completed\" | .completedAt = $(date +%s) | .result = $result_json" "$ho_file" > "$ho_file.tmp" && mv "$ho_file.tmp" "$ho_file"
|
|
548
|
+
|
|
549
|
+
update_stat "handoffsCompleted"
|
|
550
|
+
|
|
551
|
+
echo "{\"completed\": true, \"handoffId\": \"$ho_id\"}"
|
|
552
|
+
fi
|
|
553
|
+
|
|
554
|
+
exit 0
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
get_pending_handoffs() {
|
|
558
|
+
local pending="[]"
|
|
559
|
+
|
|
560
|
+
for ho_file in "$HANDOFFS_DIR"/*.json; do
|
|
561
|
+
if [ -f "$ho_file" ] && command -v jq &>/dev/null; then
|
|
562
|
+
local to=$(jq -r '.toAgent' "$ho_file")
|
|
563
|
+
local status=$(jq -r '.status' "$ho_file")
|
|
564
|
+
|
|
565
|
+
# Check if handoff is for us and pending
|
|
566
|
+
if [ "$status" = "pending" ] && ([ "$to" = "$AGENT_ID" ] || [ "$to" = "$AGENT_NAME" ]); then
|
|
567
|
+
pending=$(echo "$pending" | jq ". += [$(cat "$ho_file")]")
|
|
568
|
+
fi
|
|
569
|
+
fi
|
|
570
|
+
done
|
|
571
|
+
|
|
572
|
+
echo "$pending" | jq -c .
|
|
573
|
+
exit 0
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
# =============================================================================
|
|
577
|
+
# SWARM STATUS & AGENTS
|
|
578
|
+
# =============================================================================
|
|
579
|
+
|
|
580
|
+
get_agents() {
|
|
581
|
+
register_agent
|
|
582
|
+
|
|
583
|
+
if [ -f "$AGENTS_FILE" ] && command -v jq &>/dev/null; then
|
|
584
|
+
cat "$AGENTS_FILE"
|
|
585
|
+
else
|
|
586
|
+
echo '{"agents":[]}'
|
|
587
|
+
fi
|
|
588
|
+
|
|
589
|
+
exit 0
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
get_stats() {
|
|
593
|
+
init_stats
|
|
594
|
+
|
|
595
|
+
if command -v jq &>/dev/null; then
|
|
596
|
+
jq ". + {agentId: \"$AGENT_ID\", agentName: \"$AGENT_NAME\"}" "$STATS_FILE"
|
|
597
|
+
else
|
|
598
|
+
cat "$STATS_FILE"
|
|
599
|
+
fi
|
|
600
|
+
|
|
601
|
+
exit 0
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
# =============================================================================
|
|
605
|
+
# HOOK INTEGRATION - Output for Claude hooks
|
|
606
|
+
# =============================================================================
|
|
607
|
+
|
|
608
|
+
pre_task_swarm_context() {
|
|
609
|
+
local task="${1:-}"
|
|
610
|
+
|
|
611
|
+
register_agent
|
|
612
|
+
|
|
613
|
+
# Check for pending handoffs
|
|
614
|
+
local handoffs=$(get_pending_handoffs 2>/dev/null || echo "[]")
|
|
615
|
+
local handoff_count=$(echo "$handoffs" | jq 'length' 2>/dev/null || echo "0")
|
|
616
|
+
|
|
617
|
+
# Check for new messages
|
|
618
|
+
local messages=$(get_messages 5 2>/dev/null || echo '{"count":0}')
|
|
619
|
+
local msg_count=$(echo "$messages" | jq '.count' 2>/dev/null || echo "0")
|
|
620
|
+
|
|
621
|
+
# Check for pending consensus
|
|
622
|
+
local consensus=$(get_consensus_status 2>/dev/null || echo "[]")
|
|
623
|
+
local cons_count=$(echo "$consensus" | jq 'length' 2>/dev/null || echo "0")
|
|
624
|
+
|
|
625
|
+
if [ "$handoff_count" -gt 0 ] || [ "$msg_count" -gt 0 ] || [ "$cons_count" -gt 0 ]; then
|
|
626
|
+
cat << EOF
|
|
627
|
+
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","additionalContext":"**Swarm Activity**:\n- Pending handoffs: $handoff_count\n- New messages: $msg_count\n- Active consensus: $cons_count\n\nCheck swarm status before proceeding on complex tasks."}}
|
|
628
|
+
EOF
|
|
629
|
+
fi
|
|
630
|
+
|
|
631
|
+
exit 0
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
post_task_swarm_update() {
|
|
635
|
+
local task="${1:-}"
|
|
636
|
+
local success="${2:-true}"
|
|
637
|
+
|
|
638
|
+
# Broadcast task completion
|
|
639
|
+
if [ "$success" = "true" ]; then
|
|
640
|
+
send_message "*" "Completed: $(echo "$task" | head -c 100)" "result" "low" >/dev/null 2>&1 || true
|
|
641
|
+
fi
|
|
642
|
+
|
|
643
|
+
exit 0
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
# =============================================================================
|
|
647
|
+
# Main dispatcher
|
|
648
|
+
# =============================================================================
|
|
649
|
+
case "${1:-help}" in
|
|
650
|
+
# Messaging
|
|
651
|
+
"send")
|
|
652
|
+
send_message "${2:-*}" "${3:-}" "${4:-context}" "${5:-normal}"
|
|
653
|
+
;;
|
|
654
|
+
"messages")
|
|
655
|
+
get_messages "${2:-10}" "${3:-}"
|
|
656
|
+
;;
|
|
657
|
+
"broadcast")
|
|
658
|
+
broadcast_context "${2:-}"
|
|
659
|
+
;;
|
|
660
|
+
|
|
661
|
+
# Pattern broadcasting
|
|
662
|
+
"broadcast-pattern")
|
|
663
|
+
broadcast_pattern "${2:-}" "${3:-general}" "${4:-0.7}"
|
|
664
|
+
;;
|
|
665
|
+
"patterns")
|
|
666
|
+
get_pattern_broadcasts "${2:-}" "${3:-0}" "${4:-10}"
|
|
667
|
+
;;
|
|
668
|
+
"import-pattern")
|
|
669
|
+
import_pattern "${2:-}"
|
|
670
|
+
;;
|
|
671
|
+
|
|
672
|
+
# Consensus
|
|
673
|
+
"consensus")
|
|
674
|
+
initiate_consensus "${2:-}" "${3:-}" "${4:-30000}"
|
|
675
|
+
;;
|
|
676
|
+
"vote")
|
|
677
|
+
vote_consensus "${2:-}" "${3:-}"
|
|
678
|
+
;;
|
|
679
|
+
"resolve-consensus")
|
|
680
|
+
resolve_consensus "${2:-}"
|
|
681
|
+
;;
|
|
682
|
+
"consensus-status")
|
|
683
|
+
get_consensus_status "${2:-}"
|
|
684
|
+
;;
|
|
685
|
+
|
|
686
|
+
# Task handoff
|
|
687
|
+
"handoff")
|
|
688
|
+
initiate_handoff "${2:-}" "${3:-}" "${4:-}"
|
|
689
|
+
;;
|
|
690
|
+
"accept-handoff")
|
|
691
|
+
accept_handoff "${2:-}"
|
|
692
|
+
;;
|
|
693
|
+
"complete-handoff")
|
|
694
|
+
complete_handoff "${2:-}" "${3:-{}}"
|
|
695
|
+
;;
|
|
696
|
+
"pending-handoffs")
|
|
697
|
+
get_pending_handoffs
|
|
698
|
+
;;
|
|
699
|
+
|
|
700
|
+
# Status
|
|
701
|
+
"agents")
|
|
702
|
+
get_agents
|
|
703
|
+
;;
|
|
704
|
+
"stats")
|
|
705
|
+
get_stats
|
|
706
|
+
;;
|
|
707
|
+
|
|
708
|
+
# Hook integration
|
|
709
|
+
"pre-task")
|
|
710
|
+
pre_task_swarm_context "${2:-}"
|
|
711
|
+
;;
|
|
712
|
+
"post-task")
|
|
713
|
+
post_task_swarm_update "${2:-}" "${3:-true}"
|
|
714
|
+
;;
|
|
715
|
+
|
|
716
|
+
"help"|"-h"|"--help")
|
|
717
|
+
cat << 'EOF'
|
|
718
|
+
Claude Flow V3 - Swarm Communication Hooks
|
|
719
|
+
|
|
720
|
+
Usage: swarm-hooks.sh <command> [args]
|
|
721
|
+
|
|
722
|
+
Agent Messaging:
|
|
723
|
+
send <to> <content> [type] [priority] Send message to agent
|
|
724
|
+
messages [limit] [type] Get messages for this agent
|
|
725
|
+
broadcast <content> Broadcast to all agents
|
|
726
|
+
|
|
727
|
+
Pattern Broadcasting:
|
|
728
|
+
broadcast-pattern <strategy> [domain] [quality] Share pattern with swarm
|
|
729
|
+
patterns [domain] [min-quality] [limit] List pattern broadcasts
|
|
730
|
+
import-pattern <broadcast-id> Import broadcast pattern
|
|
731
|
+
|
|
732
|
+
Consensus:
|
|
733
|
+
consensus <question> <options> [timeout] Start consensus (options: comma-separated)
|
|
734
|
+
vote <consensus-id> <vote> Vote on consensus
|
|
735
|
+
resolve-consensus <consensus-id> Force resolve consensus
|
|
736
|
+
consensus-status [consensus-id] Get consensus status
|
|
737
|
+
|
|
738
|
+
Task Handoff:
|
|
739
|
+
handoff <to-agent> <description> [context-json] Initiate handoff
|
|
740
|
+
accept-handoff <handoff-id> Accept pending handoff
|
|
741
|
+
complete-handoff <handoff-id> [result-json] Complete handoff
|
|
742
|
+
pending-handoffs List pending handoffs
|
|
743
|
+
|
|
744
|
+
Status:
|
|
745
|
+
agents List registered agents
|
|
746
|
+
stats Get swarm statistics
|
|
747
|
+
|
|
748
|
+
Hook Integration:
|
|
749
|
+
pre-task <task> Check swarm before task (for hooks)
|
|
750
|
+
post-task <task> [success] Update swarm after task (for hooks)
|
|
751
|
+
|
|
752
|
+
Environment:
|
|
753
|
+
AGENTIC_FLOW_AGENT_ID Agent identifier
|
|
754
|
+
AGENTIC_FLOW_AGENT_NAME Agent display name
|
|
755
|
+
EOF
|
|
756
|
+
;;
|
|
757
|
+
*)
|
|
758
|
+
echo "Unknown command: $1" >&2
|
|
759
|
+
exit 1
|
|
760
|
+
;;
|
|
761
|
+
esac
|