claude-flow-novice 2.14.11 → 2.14.13
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/skills/cfn-agent-selector/select-agents.sh +45 -0
- package/.claude/skills/cfn-loop-orchestration/helpers/context-injection.sh +69 -6
- package/.claude/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +241 -0
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +22 -72
- package/.claude/skills/cfn-redis-coordination/get-context.sh +113 -0
- package/.claude/skills/cfn-redis-coordination/store-context.sh +74 -19
- package/claude-assets/skills/cfn-agent-selector/select-agents.sh +45 -0
- package/claude-assets/skills/cfn-loop-orchestration/helpers/context-injection.sh +69 -6
- package/claude-assets/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +241 -0
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +22 -72
- package/claude-assets/skills/cfn-redis-coordination/get-context.sh +113 -0
- package/claude-assets/skills/cfn-redis-coordination/store-context.sh +74 -19
- package/package.json +1 -1
- package/scripts/init-project.js +56 -3
|
@@ -28,12 +28,57 @@ if [[ ! -f "$REGISTRY_PATH" ]]; then
|
|
|
28
28
|
exit 1
|
|
29
29
|
fi
|
|
30
30
|
|
|
31
|
+
# Smart agent selection for React Router and specialized tasks
|
|
32
|
+
smart_agent_selection() {
|
|
33
|
+
local description="$1"
|
|
34
|
+
local task_type="$2"
|
|
35
|
+
|
|
36
|
+
# React Router specialization - Zone A fix
|
|
37
|
+
if [[ "$description" =~ (React Router|react-router|TS2786|jsx.*component|route.*migration) ]]; then
|
|
38
|
+
echo '["react-frontend-engineer", "reviewer", "tester"]'
|
|
39
|
+
return 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# TypeScript/TSX specialization
|
|
43
|
+
if [[ "$description" =~ (TypeScript|tsx|TS[0-9]+|interface.*error) ]]; then
|
|
44
|
+
echo '["react-frontend-engineer", "reviewer", "tester"]'
|
|
45
|
+
return 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Frontend UI specialization
|
|
49
|
+
if [[ "$description" =~ (frontend|ui|component|css|style|responsive) ]]; then
|
|
50
|
+
echo '["react-frontend-engineer", "reviewer", "accessibility-advocate-persona"]'
|
|
51
|
+
return 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# Authentication/Security specialization
|
|
55
|
+
if [[ "$description" =~ (auth|jwt|token|security|password|login|register) ]]; then
|
|
56
|
+
echo '["backend-developer", "security-specialist", "reviewer"]'
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# API/Backend specialization
|
|
61
|
+
if [[ "$description" =~ (api|endpoint|server|backend|database|orm|sql) ]]; then
|
|
62
|
+
echo '["backend-developer", "reviewer", "tester"]'
|
|
63
|
+
return 0
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
return 1 # Fall back to registry-based selection
|
|
67
|
+
}
|
|
68
|
+
|
|
31
69
|
# Score agents function with improved flat namespace matching
|
|
32
70
|
score_agents() {
|
|
33
71
|
local registry_path="$1"
|
|
34
72
|
local description="$2"
|
|
35
73
|
local task_type="$3"
|
|
36
74
|
|
|
75
|
+
# Try smart selection first
|
|
76
|
+
local smart_result
|
|
77
|
+
if smart_result=$(smart_agent_selection "$description" "$task_type"); then
|
|
78
|
+
echo "$smart_result"
|
|
79
|
+
return 0
|
|
80
|
+
fi
|
|
81
|
+
|
|
37
82
|
# Complex JQ query for flexible matching
|
|
38
83
|
jq -r --arg desc "$description" --arg task_type "$task_type" '
|
|
39
84
|
[
|
|
@@ -116,16 +116,79 @@ inject_context_for_agent() {
|
|
|
116
116
|
local task_id="$2"
|
|
117
117
|
local iteration="${3:-1}"
|
|
118
118
|
|
|
119
|
-
# Retrieve task context from Redis
|
|
120
|
-
local task_context
|
|
119
|
+
# Retrieve structured task context from Redis
|
|
120
|
+
local task_context=""
|
|
121
|
+
local epic_context=""
|
|
122
|
+
local phase_context=""
|
|
123
|
+
local success_criteria=""
|
|
124
|
+
local expected_files=""
|
|
125
|
+
|
|
121
126
|
if command -v redis-cli &> /dev/null; then
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
# Get all structured context fields
|
|
128
|
+
task_context=$(redis-cli HGET "swarm:$task_id:context" "task_description" 2>/dev/null || echo "")
|
|
129
|
+
epic_context=$(redis-cli HGET "swarm:$task_id:context" "epic-context" 2>/dev/null || echo "")
|
|
130
|
+
phase_context=$(redis-cli HGET "swarm:$task_id:context" "phase-context" 2>/dev/null || echo "")
|
|
131
|
+
success_criteria=$(redis-cli HGET "swarm:$task_id:context" "success-criteria" 2>/dev/null || echo "")
|
|
132
|
+
expected_files=$(redis-cli HGET "swarm:$task_id:context" "expected-files" 2>/dev/null || echo "")
|
|
125
133
|
fi
|
|
126
134
|
|
|
135
|
+
# Build comprehensive task description from all available context
|
|
136
|
+
local comprehensive_context=""
|
|
137
|
+
|
|
138
|
+
# Start with task description if available
|
|
139
|
+
if [ -n "$task_context" ]; then
|
|
140
|
+
comprehensive_context="$task_context"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Add epic context
|
|
144
|
+
if [ -n "$epic_context" ]; then
|
|
145
|
+
if [ -n "$comprehensive_context" ]; then
|
|
146
|
+
comprehensive_context="$comprehensive_context
|
|
147
|
+
|
|
148
|
+
Epic Context: $epic_context"
|
|
149
|
+
else
|
|
150
|
+
comprehensive_context="Epic Context: $epic_context"
|
|
151
|
+
fi
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Add phase context
|
|
155
|
+
if [ -n "$phase_context" ]; then
|
|
156
|
+
if [ -n "$comprehensive_context" ]; then
|
|
157
|
+
comprehensive_context="$comprehensive_context
|
|
158
|
+
|
|
159
|
+
Phase Context: $phase_context"
|
|
160
|
+
else
|
|
161
|
+
comprehensive_context="Phase Context: $phase_context"
|
|
162
|
+
fi
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# Add success criteria
|
|
166
|
+
if [ -n "$success_criteria" ]; then
|
|
167
|
+
if [ -n "$comprehensive_context" ]; then
|
|
168
|
+
comprehensive_context="$comprehensive_context
|
|
169
|
+
|
|
170
|
+
Success Criteria: $success_criteria"
|
|
171
|
+
else
|
|
172
|
+
comprehensive_context="Success Criteria: $success_criteria"
|
|
173
|
+
fi
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
# Add expected files
|
|
177
|
+
if [ -n "$expected_files" ]; then
|
|
178
|
+
if [ -n "$comprehensive_context" ]; then
|
|
179
|
+
comprehensive_context="$comprehensive_context
|
|
180
|
+
|
|
181
|
+
Expected Files: $expected_files"
|
|
182
|
+
else
|
|
183
|
+
comprehensive_context="Expected Files: $expected_files"
|
|
184
|
+
fi
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# Use comprehensive context for further processing
|
|
188
|
+
task_context="$comprehensive_context"
|
|
189
|
+
|
|
127
190
|
if [ -z "$task_context" ]; then
|
|
128
|
-
echo "#
|
|
191
|
+
echo "# CFN Loop Context (No Task Description)"
|
|
129
192
|
echo ""
|
|
130
193
|
echo "_Task description not available for context injection._"
|
|
131
194
|
return 1
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Task Context Validation Helper
|
|
3
|
+
# Validates that CLI mode has complete task context (prevents "consensus on vapor")
|
|
4
|
+
#
|
|
5
|
+
# Usage: validate-task-context.sh --task-id <id> [--task-description <desc>] [--expected-files <files>] [--success-criteria <criteria>]
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
# Initialize variables
|
|
10
|
+
TASK_ID=""
|
|
11
|
+
TASK_DESCRIPTION=""
|
|
12
|
+
EXPECTED_FILES=""
|
|
13
|
+
SUCCESS_CRITERIA=""
|
|
14
|
+
NAMESPACE="swarm"
|
|
15
|
+
|
|
16
|
+
# Parse arguments
|
|
17
|
+
while [[ $# -gt 0 ]]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--task-id)
|
|
20
|
+
TASK_ID="$2"
|
|
21
|
+
shift 2
|
|
22
|
+
;;
|
|
23
|
+
--task-description)
|
|
24
|
+
TASK_DESCRIPTION="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--expected-files)
|
|
28
|
+
EXPECTED_FILES="$2"
|
|
29
|
+
shift 2
|
|
30
|
+
;;
|
|
31
|
+
--success-criteria)
|
|
32
|
+
SUCCESS_CRITERIA="$2"
|
|
33
|
+
shift 2
|
|
34
|
+
;;
|
|
35
|
+
--namespace)
|
|
36
|
+
NAMESPACE="$2"
|
|
37
|
+
shift 2
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
echo "Unknown parameter: $1" >&2
|
|
41
|
+
exit 1
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
|
|
46
|
+
# Validate required arguments
|
|
47
|
+
if [[ -z "$TASK_ID" ]]; then
|
|
48
|
+
echo "Error: --task-id is required" >&2
|
|
49
|
+
echo "Usage: $0 --task-id <id> [--task-description <desc>] [--expected-files <files>] [--success-criteria <criteria>]" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Validation functions
|
|
54
|
+
validate_task_description() {
|
|
55
|
+
local task_desc="$1"
|
|
56
|
+
|
|
57
|
+
if [[ -z "$task_desc" ]]; then
|
|
58
|
+
echo "❌ Task description is empty or missing"
|
|
59
|
+
return 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Check minimum length (should be meaningful)
|
|
63
|
+
if [[ ${#task_desc} -lt 10 ]]; then
|
|
64
|
+
echo "❌ Task description too short (${#task_desc} chars, minimum 10)"
|
|
65
|
+
return 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Check for actionable verbs
|
|
69
|
+
if [[ ! "$task_desc" =~ (create|build|implement|fix|migrate|update|add|remove|refactor|test|review|validate) ]]; then
|
|
70
|
+
echo "⚠️ Task description lacks clear action verb"
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Check for specific deliverables (Zone A fix: prevent generic context)
|
|
74
|
+
if [[ "$task_desc" =~ (zone-d-round2|checkpoint|iteration [0-9]+) ]]; then
|
|
75
|
+
echo "❌ Task description contains generic identifier (Zone A issue)"
|
|
76
|
+
return 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
echo "✅ Task description validation passed"
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
validate_expected_files() {
|
|
84
|
+
local files="$1"
|
|
85
|
+
local errors=0
|
|
86
|
+
|
|
87
|
+
if [[ -z "$files" ]]; then
|
|
88
|
+
echo "⚠️ No expected files specified (may be OK for analysis tasks)"
|
|
89
|
+
return 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Split files by comma and validate each
|
|
93
|
+
IFS=',' read -ra file_array <<< "$files"
|
|
94
|
+
for file in "${file_array[@]}"; do
|
|
95
|
+
# Remove whitespace
|
|
96
|
+
file=$(echo "$file" | xargs)
|
|
97
|
+
|
|
98
|
+
if [[ -z "$file" ]]; then
|
|
99
|
+
continue
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Check file path format
|
|
103
|
+
if [[ ! "$file" =~ ^[a-zA-Z0-9_/-]+\.[a-zA-Z]+$ && ! "$file" =~ ^[a-zA-Z0-9_/-]+/ ]]; then
|
|
104
|
+
echo "❌ Invalid file format: $file"
|
|
105
|
+
((errors++))
|
|
106
|
+
continue
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Check for generic placeholders
|
|
110
|
+
if [[ "$file" =~ (placeholder|example|template) ]]; then
|
|
111
|
+
echo "❌ Generic file placeholder: $file"
|
|
112
|
+
((errors++))
|
|
113
|
+
continue
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
done
|
|
117
|
+
|
|
118
|
+
if [[ $errors -eq 0 ]]; then
|
|
119
|
+
echo "✅ Expected files validation passed"
|
|
120
|
+
return 0
|
|
121
|
+
else
|
|
122
|
+
return 1
|
|
123
|
+
fi
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
validate_success_criteria() {
|
|
127
|
+
local criteria="$1"
|
|
128
|
+
local errors=0
|
|
129
|
+
|
|
130
|
+
if [[ -z "$criteria" ]]; then
|
|
131
|
+
echo "⚠️ No success criteria specified (may be OK for discovery tasks)"
|
|
132
|
+
return 0
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# Check criteria length
|
|
136
|
+
if [[ ${#criteria} -lt 5 ]]; then
|
|
137
|
+
echo "❌ Success criteria too short: $criteria"
|
|
138
|
+
((errors++))
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Check for measurable outcomes
|
|
142
|
+
if [[ ! "$criteria" =~ (test|pass|fail|error|success|complete|0.*errors|100%) ]]; then
|
|
143
|
+
echo "⚠️ Success criteria lacks measurable outcomes"
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# Check for generic statements
|
|
147
|
+
if [[ "$criteria" =~ (done|finished|complete|good) && ${#criteria} -lt 20 ]]; then
|
|
148
|
+
echo "❌ Success criteria too generic: $criteria"
|
|
149
|
+
((errors++))
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
if [[ $errors -eq 0 ]]; then
|
|
153
|
+
echo "✅ Success criteria validation passed"
|
|
154
|
+
return 0
|
|
155
|
+
else
|
|
156
|
+
return 1
|
|
157
|
+
fi
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
check_redis_context() {
|
|
161
|
+
local task_id="$1"
|
|
162
|
+
local redis_key="${NAMESPACE}:${task_id}:context"
|
|
163
|
+
|
|
164
|
+
# Check if context exists
|
|
165
|
+
if ! redis-cli EXISTS "$redis_key" >/dev/null 2>&1; then
|
|
166
|
+
echo "❌ No context found in Redis for task: $task_id"
|
|
167
|
+
return 1
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Get all context fields
|
|
171
|
+
local context_fields
|
|
172
|
+
context_fields=$(redis-cli HGETALL "$redis_key" 2>/dev/null || echo "")
|
|
173
|
+
|
|
174
|
+
if [[ -z "$context_fields" ]]; then
|
|
175
|
+
echo "❌ Context exists but is empty for task: $task_id"
|
|
176
|
+
return 1
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Count non-metadata fields
|
|
180
|
+
local field_count=0
|
|
181
|
+
while IFS= read -r field; do
|
|
182
|
+
# Skip metadata fields
|
|
183
|
+
if [[ ! "$field" =~ (updated_at|stored_at) ]]; then
|
|
184
|
+
((field_count++))
|
|
185
|
+
fi
|
|
186
|
+
done <<< "$context_fields"
|
|
187
|
+
|
|
188
|
+
if [[ $field_count -eq 0 ]]; then
|
|
189
|
+
echo "❌ Context contains only metadata fields"
|
|
190
|
+
return 1
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
echo "✅ Redis context validation passed ($field_count data fields)"
|
|
194
|
+
return 0
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# Main validation
|
|
198
|
+
validation_errors=0
|
|
199
|
+
echo "🔍 Validating task context for: $TASK_ID"
|
|
200
|
+
echo ""
|
|
201
|
+
|
|
202
|
+
# Validate task description
|
|
203
|
+
if [[ -n "$TASK_DESCRIPTION" ]]; then
|
|
204
|
+
if ! validate_task_description "$TASK_DESCRIPTION"; then
|
|
205
|
+
((validation_errors++))
|
|
206
|
+
fi
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
# Validate expected files
|
|
210
|
+
if [[ -n "$EXPECTED_FILES" ]]; then
|
|
211
|
+
if ! validate_expected_files "$EXPECTED_FILES"; then
|
|
212
|
+
((validation_errors++))
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
# Validate success criteria
|
|
217
|
+
if [[ -n "$SUCCESS_CRITERIA" ]]; then
|
|
218
|
+
if ! validate_success_criteria "$SUCCESS_CRITERIA"; then
|
|
219
|
+
((validation_errors++))
|
|
220
|
+
fi
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
# Check Redis context
|
|
224
|
+
if ! check_redis_context "$TASK_ID"; then
|
|
225
|
+
((validation_errors++))
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
echo ""
|
|
229
|
+
|
|
230
|
+
# Final result
|
|
231
|
+
if [[ $validation_errors -eq 0 ]]; then
|
|
232
|
+
echo "🎉 All context validations passed!"
|
|
233
|
+
echo "✅ CLI Mode has complete, structured task context"
|
|
234
|
+
echo "✅ Zone A 'consensus on vapor' issue prevented"
|
|
235
|
+
exit 0
|
|
236
|
+
else
|
|
237
|
+
echo "❌ $validation_errors validation(s) failed"
|
|
238
|
+
echo "⚠️ Task context may be incomplete"
|
|
239
|
+
echo "⚠️ Risk of 'consensus on vapor' - please add missing context"
|
|
240
|
+
exit 1
|
|
241
|
+
fi
|
|
@@ -66,19 +66,6 @@ LOOP3_FINAL_CONFIDENCE=0.0
|
|
|
66
66
|
LOOP2_FINAL_CONSENSUS=0.0
|
|
67
67
|
DELIVERABLES_VERIFIED=false
|
|
68
68
|
|
|
69
|
-
# Cleanup Redis keys before exit
|
|
70
|
-
cleanup_redis_keys() {
|
|
71
|
-
if [ -n "$TASK_ID" ]; then
|
|
72
|
-
echo "🧹 Cleaning up Redis keys for task $TASK_ID"
|
|
73
|
-
# Set TTL on remaining task keys (1 hour)
|
|
74
|
-
redis-cli keys "swarm:${TASK_ID}:*" 2>/dev/null | xargs -I {} redis-cli expire {} 3600 2>/dev/null || true
|
|
75
|
-
redis-cli keys "cfn_loop:task:${TASK_ID}:*" 2>/dev/null | xargs -I {} redis-cli expire {} 3600 2>/dev/null || true
|
|
76
|
-
fi
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
# Trap cleanup on script exit
|
|
80
|
-
trap cleanup_redis_keys EXIT
|
|
81
|
-
|
|
82
69
|
##############################################################################
|
|
83
70
|
# Argument Parsing
|
|
84
71
|
##############################################################################
|
|
@@ -707,20 +694,26 @@ EOF
|
|
|
707
694
|
# Main CFN Loop
|
|
708
695
|
##############################################################################
|
|
709
696
|
|
|
710
|
-
# Validate CLI environment before spawning agents
|
|
711
|
-
echo "🔧 Validating CLI environment..."
|
|
712
|
-
if [ -f "$PROJECT_ROOT/.claude/skills/cfn-cli-setup/validate-cli-environment.sh" ]; then
|
|
713
|
-
if ! bash "$PROJECT_ROOT/.claude/skills/cfn-cli-setup/validate-cli-environment.sh"; then
|
|
714
|
-
echo "❌ CLI environment validation failed. Agents may not have required tools."
|
|
715
|
-
echo "⚠️ Continuing anyway, but expect potential tool failures..."
|
|
716
|
-
fi
|
|
717
|
-
else
|
|
718
|
-
echo "⚠️ CLI environment validation script not found. Skipping validation."
|
|
719
|
-
fi
|
|
720
|
-
|
|
721
697
|
# Store context in Redis
|
|
722
698
|
store_context "$TASK_ID"
|
|
723
699
|
|
|
700
|
+
# Validate context completeness (Zone A fix: prevent "consensus on vapor")
|
|
701
|
+
echo "Validating task context completeness..."
|
|
702
|
+
if [[ -n "$SUCCESS_CRITERIA" || -n "$EXPECTED_FILES" ]]; then
|
|
703
|
+
validation_script="$HELPERS_DIR/validate-task-context.sh"
|
|
704
|
+
if [[ -f "$validation_script" ]]; then
|
|
705
|
+
if ! "$validation_script" \
|
|
706
|
+
--task-id "$TASK_ID" \
|
|
707
|
+
--success-criteria "$SUCCESS_CRITERIA" \
|
|
708
|
+
--expected-files "$EXPECTED_FILES"; then
|
|
709
|
+
echo "⚠️ WARNING: Task context validation failed"
|
|
710
|
+
echo "⚠️ This may result in 'consensus on vapor' (high confidence, zero deliverables)"
|
|
711
|
+
echo "⚠️ Consider adding more specific task context"
|
|
712
|
+
echo ""
|
|
713
|
+
fi
|
|
714
|
+
fi
|
|
715
|
+
fi
|
|
716
|
+
|
|
724
717
|
# Iteration loop
|
|
725
718
|
for ((ITERATION=1; ITERATION<=MAX_ITERATIONS; ITERATION++)); do
|
|
726
719
|
echo ""
|
|
@@ -775,41 +768,11 @@ for ((ITERATION=1; ITERATION<=MAX_ITERATIONS; ITERATION++)); do
|
|
|
775
768
|
--agents "$LOOP3_IDS" \
|
|
776
769
|
--threshold "$GATE" \
|
|
777
770
|
--min-quorum "$MIN_QUORUM_LOOP3"; then
|
|
778
|
-
# Gate passed -
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
VALIDATED_CONFIDENCE=0
|
|
784
|
-
|
|
785
|
-
for agent_id in ${LOOP3_IDS//,/ }; do
|
|
786
|
-
# Get agent's reported confidence
|
|
787
|
-
agent_confidence=$(redis-cli get "swarm:${TASK_ID}:${agent_id}:confidence" 2>/dev/null || echo "0.5")
|
|
788
|
-
|
|
789
|
-
# Calculate deliverable-based confidence
|
|
790
|
-
deliverable_confidence=$("$PROJECT_ROOT/.claude/skills/cfn-deliverable-validation/confidence-calculator.sh" \
|
|
791
|
-
"$TASK_ID" "$agent_id" "$EXPECTED_FILES" "$PROJECT_ROOT")
|
|
792
|
-
|
|
793
|
-
echo " Agent $agent_id: reported=$agent_confidence, deliverable-based=$deliverable_confidence"
|
|
794
|
-
|
|
795
|
-
# Use the lower of the two scores (inflation prevention)
|
|
796
|
-
if (( $(echo "$deliverable_confidence < $agent_confidence" | bc -l) )); then
|
|
797
|
-
echo " ⚠️ Downgrading confidence for $agent_id (inflated score detected)"
|
|
798
|
-
VALIDATED_CONFIDENCE=$deliverable_confidence
|
|
799
|
-
else
|
|
800
|
-
VALIDATED_CONFIDENCE=$agent_confidence
|
|
801
|
-
fi
|
|
802
|
-
done
|
|
803
|
-
|
|
804
|
-
LOOP3_FINAL_CONFIDENCE=$VALIDATED_CONFIDENCE
|
|
805
|
-
echo "✅ Final validated Loop 3 confidence: $LOOP3_FINAL_CONFIDENCE"
|
|
806
|
-
else
|
|
807
|
-
# Store confidence (fallback method)
|
|
808
|
-
LOOP3_FINAL_CONFIDENCE=$("$REDIS_COORD_SKILL/invoke-waiting-mode.sh" collect \
|
|
809
|
-
--task-id "$TASK_ID" \
|
|
810
|
-
--agent-ids "$LOOP3_IDS" \
|
|
811
|
-
--min-quorum "$MIN_QUORUM_LOOP3")
|
|
812
|
-
fi
|
|
771
|
+
# Gate passed - store confidence
|
|
772
|
+
LOOP3_FINAL_CONFIDENCE=$("$REDIS_COORD_SKILL/invoke-waiting-mode.sh" collect \
|
|
773
|
+
--task-id "$TASK_ID" \
|
|
774
|
+
--agent-ids "$LOOP3_IDS" \
|
|
775
|
+
--min-quorum "$MIN_QUORUM_LOOP3")
|
|
813
776
|
else
|
|
814
777
|
# Gate failed - iterate Loop 3
|
|
815
778
|
echo "❌ Gate check failed - iterating Loop 3"
|
|
@@ -932,19 +895,6 @@ EOF
|
|
|
932
895
|
esac
|
|
933
896
|
done
|
|
934
897
|
|
|
935
|
-
# Cleanup Redis keys before exit
|
|
936
|
-
cleanup_redis_keys() {
|
|
937
|
-
if [ -n "$TASK_ID" ]; then
|
|
938
|
-
echo "🧹 Cleaning up Redis keys for task $TASK_ID"
|
|
939
|
-
# Set TTL on remaining task keys (1 hour)
|
|
940
|
-
redis-cli keys "swarm:${TASK_ID}:*" 2>/dev/null | xargs -I {} redis-cli expire {} 3600 2>/dev/null || true
|
|
941
|
-
redis-cli keys "cfn_loop:task:${TASK_ID}:*" 2>/dev/null | xargs -I {} redis-cli expire {} 3600 2>/dev/null || true
|
|
942
|
-
fi
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
# Trap cleanup on script exit
|
|
946
|
-
trap cleanup_redis_keys EXIT
|
|
947
|
-
|
|
948
898
|
# Max iterations reached without success
|
|
949
899
|
echo "❌ Max iterations ($MAX_ITERATIONS) reached without PROCEED decision"
|
|
950
900
|
output_result "failed"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Retrieve CFN Loop task context from Redis
|
|
3
|
+
# Used by CLI-spawned agents to get structured context from orchestrator
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# get-context.sh --task-id <id> [--namespace <ns>]
|
|
7
|
+
# get-context.sh --task-id <id> --key <key> [--namespace <ns>]
|
|
8
|
+
# get-context.sh <task_id> (legacy mode)
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
# Initialize variables
|
|
13
|
+
TASK_ID=""
|
|
14
|
+
KEY=""
|
|
15
|
+
NAMESPACE="swarm"
|
|
16
|
+
FORMAT="json" # json or raw
|
|
17
|
+
|
|
18
|
+
# Parse arguments
|
|
19
|
+
while [[ $# -gt 0 ]]; do
|
|
20
|
+
case $1 in
|
|
21
|
+
--task-id)
|
|
22
|
+
TASK_ID="$2"
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
--key)
|
|
26
|
+
KEY="$2"
|
|
27
|
+
shift 2
|
|
28
|
+
;;
|
|
29
|
+
--namespace)
|
|
30
|
+
NAMESPACE="$2"
|
|
31
|
+
shift 2
|
|
32
|
+
;;
|
|
33
|
+
--format)
|
|
34
|
+
FORMAT="$2"
|
|
35
|
+
shift 2
|
|
36
|
+
;;
|
|
37
|
+
*)
|
|
38
|
+
# Legacy mode: positional argument
|
|
39
|
+
if [ -z "$TASK_ID" ]; then
|
|
40
|
+
TASK_ID="$1"
|
|
41
|
+
fi
|
|
42
|
+
shift
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
# Validate required arguments
|
|
48
|
+
if [ -z "$TASK_ID" ]; then
|
|
49
|
+
echo "Error: --task-id or TASK_ID required" >&2
|
|
50
|
+
echo "Usage: $0 --task-id <id> [--key <key>] [--namespace <ns>] [--format <json|raw>]" >&2
|
|
51
|
+
echo " or: $0 <task_id> (legacy)" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
REDIS_KEY="${NAMESPACE}:${TASK_ID}:context"
|
|
56
|
+
|
|
57
|
+
# Check if context exists
|
|
58
|
+
if ! redis-cli EXISTS "$REDIS_KEY" >/dev/null 2>&1; then
|
|
59
|
+
echo "⚠️ No context found for task: $TASK_ID" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Handle specific key retrieval
|
|
64
|
+
if [ -n "$KEY" ]; then
|
|
65
|
+
VALUE=$(redis-cli HGET "$REDIS_KEY" "$KEY" 2>/dev/null || echo "")
|
|
66
|
+
if [ -z "$VALUE" ]; then
|
|
67
|
+
echo "⚠️ Key '$KEY' not found in context for task: $TASK_ID" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [ "$FORMAT" = "raw" ]; then
|
|
72
|
+
echo "$VALUE"
|
|
73
|
+
else
|
|
74
|
+
echo "{\"$KEY\":$VALUE}"
|
|
75
|
+
fi
|
|
76
|
+
exit 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Handle full context retrieval
|
|
80
|
+
ALL_FIELDS=$(redis-cli HGETALL "$REDIS_KEY" 2>/dev/null || echo "")
|
|
81
|
+
|
|
82
|
+
if [ -z "$ALL_FIELDS" ]; then
|
|
83
|
+
echo "⚠️ Empty context for task: $TASK_ID" >&2
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# Format as JSON
|
|
88
|
+
if [ "$FORMAT" = "json" ]; then
|
|
89
|
+
echo "{"
|
|
90
|
+
first=true
|
|
91
|
+
while IFS= read -r field; do
|
|
92
|
+
if [ -z "$field" ]; then continue; fi
|
|
93
|
+
if [ "$first" = true ]; then
|
|
94
|
+
first=false
|
|
95
|
+
else
|
|
96
|
+
echo ","
|
|
97
|
+
fi
|
|
98
|
+
# Skip empty lines and properly format JSON values
|
|
99
|
+
if [[ $field =~ ^[0-9]+$ ]]; then
|
|
100
|
+
# Numeric value
|
|
101
|
+
echo -n " \"$field\": $(redis-cli HGET "$REDIS_KEY" "$field")"
|
|
102
|
+
else
|
|
103
|
+
# String value
|
|
104
|
+
value=$(redis-cli HGET "$REDIS_KEY" "$field" | sed 's/"/\\"/g')
|
|
105
|
+
echo -n " \"$field\": \"$value\""
|
|
106
|
+
fi
|
|
107
|
+
done <<< "$ALL_FIELDS"
|
|
108
|
+
echo ""
|
|
109
|
+
echo "}"
|
|
110
|
+
else
|
|
111
|
+
# Raw format
|
|
112
|
+
redis-cli HGETALL "$REDIS_KEY"
|
|
113
|
+
fi
|