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.
@@ -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
- task_context=$(redis-cli HGET "cfn_loop:task:$task_id:context" "task_description" 2>/dev/null || echo "")
123
- else
124
- task_context=""
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 "# ACE Context (No Task Description)"
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 - validate confidence based on deliverables
779
- echo "🔍 Validating agent confidence scores against deliverables..."
780
-
781
- # Re-calculate confidence based on actual deliverables
782
- if [ -n "$EXPECTED_FILES" ] && [ -f "$PROJECT_ROOT/.claude/skills/cfn-deliverable-validation/confidence-calculator.sh" ]; then
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