claude-flow-novice 2.14.13 → 2.14.15
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/commands/CFN_LOOP_TASK_MODE.md +7 -51
- package/.claude/commands/cfn-loop-cli.md +50 -125
- package/.claude/skills/cfn-agent-selector/SKILL.md +2 -2
- package/.claude/skills/cfn-agent-selector/select-agents.sh +0 -45
- package/.claude/skills/cfn-loop-orchestration/helpers/context-injection.sh +6 -69
- package/.claude/skills/cfn-loop-orchestration/orchestrate.sh +0 -17
- package/README.md +2 -2
- package/claude-assets/agents/cfn-dev-team/CLAUDE.md +3 -3
- package/claude-assets/agents/cfn-dev-team/README.md +1 -1
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md +2 -2
- package/claude-assets/agents/cfn-dev-team/developers/README.md +3 -3
- package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +1 -1
- package/claude-assets/agents/cfn-dev-team/test-agent.md +2 -2
- package/claude-assets/commands/CFN_LOOP_TASK_MODE.md +7 -51
- package/claude-assets/commands/cfn-loop-cli.md +50 -125
- package/claude-assets/skills/cfn-agent-selector/SKILL.md +2 -2
- package/claude-assets/skills/cfn-agent-selector/select-agents.sh +0 -45
- package/claude-assets/skills/cfn-loop-orchestration/helpers/context-injection.sh +6 -69
- package/claude-assets/skills/cfn-loop-orchestration/orchestrate.sh +0 -17
- package/claude-assets/skills/cfn-multi-coordinator-planning/README.md +256 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/SKILL.md +62 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/map-dependencies-conflicts.sh +376 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/plan-coordinator-resources.sh +258 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/plan-multi-coordinator-work.sh +267 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/plan-risk-rollout.sh +350 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/test-multi-coordinator-planning.sh +338 -0
- package/claude-assets/skills/cfn-multi-coordinator-planning/validate-task-planning.sh +189 -0
- package/dist/agents/agent-loader.js +165 -146
- package/dist/agents/agent-loader.js.map +1 -1
- package/package.json +1 -1
- package/.claude/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
- package/.claude/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +0 -241
- package/.claude/skills/pre-edit-backup/backup.sh +0 -130
- package/.claude/skills/pre-edit-backup/cleanup.sh +0 -155
- package/.claude/skills/pre-edit-backup/restore.sh +0 -128
- package/.claude/skills/pre-edit-backup/revert-file.sh +0 -168
- package/claude-assets/agents/cfn-dev-team/CLAUDE.md.backup_before_replace +0 -1086
- package/claude-assets/agents/cfn-dev-team/README.md.backup_before_replace +0 -116
- package/claude-assets/agents/cfn-dev-team/coordinators/cfn-v3-coordinator.md.backup_before_replace +0 -451
- package/claude-assets/agents/cfn-dev-team/developers/README.md.backup_before_replace +0 -69
- package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md.backup_before_replace +0 -465
- package/claude-assets/agents/cfn-dev-team/test-agent.md.backup_before_replace +0 -141
- package/claude-assets/skills/CFN-LOOP-VALIDATION.md +0 -202
- package/claude-assets/skills/REDIS-COORDINATION.md +0 -187
- package/claude-assets/skills/SKILL.md +0 -229
- package/claude-assets/skills/agent-discovery/agents-registry.json +0 -484
- package/claude-assets/skills/agent-name-validation/README.md +0 -28
- package/claude-assets/skills/agent-name-validation/SKILL.md +0 -168
- package/claude-assets/skills/agent-name-validation/validate-agent-names.sh +0 -47
- package/claude-assets/skills/cfn-agent-selector/SKILL.md.backup_before_replace +0 -91
- package/claude-assets/skills/cfn-loop-orchestration/helpers/validate-task-context.sh +0 -241
- package/claude-assets/skills/consensus-calculator.js +0 -45
- package/claude-assets/skills/evidence-chain.sql +0 -66
- package/claude-assets/skills/hook-pipeline/bash-dependency-checker.sh +0 -89
- package/claude-assets/skills/hook-pipeline/bash-pipe-safety.sh +0 -69
- package/claude-assets/skills/hook-pipeline/enforce-lf.sh +0 -36
- package/claude-assets/skills/hook-pipeline/js-promise-safety.sh +0 -110
- package/claude-assets/skills/hook-pipeline/python-async-safety.py +0 -124
- package/claude-assets/skills/hook-pipeline/python-import-checker.py +0 -114
- package/claude-assets/skills/hook-pipeline/python-subprocess-safety.py +0 -77
- package/claude-assets/skills/hook-pipeline/rust-command-safety.sh +0 -38
- package/claude-assets/skills/hook-pipeline/rust-dependency-checker.sh +0 -50
- package/claude-assets/skills/hook-pipeline/rust-future-safety.sh +0 -50
- package/claude-assets/skills/pre-edit-backup/backup.sh +0 -130
- package/claude-assets/skills/pre-edit-backup/cleanup.sh +0 -155
- package/claude-assets/skills/pre-edit-backup/restore.sh +0 -128
- package/claude-assets/skills/pre-edit-backup/revert-file.sh +0 -168
- package/claude-assets/skills/run-all-skill-tests.sh +0 -124
- package/claude-assets/skills/seo-orchestration/SKILL.md +0 -292
- package/claude-assets/skills/seo-orchestration/orchestrate-seo.sh +0 -566
- package/claude-assets/skills/seo-orchestration/orchestrate-seo.sh.backup +0 -755
- package/claude-assets/skills/seo-orchestration/validate-consensus.sh +0 -270
- package/claude-assets/skills/team-provider-routing/execute-agent.sh +0 -76
- package/claude-assets/skills/test-execution-coordinator-pattern.md +0 -228
|
@@ -1,755 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
|
|
3
|
-
##############################################################################
|
|
4
|
-
# SEO Pipeline Orchestration - 8-Step Content Creation
|
|
5
|
-
# Version: 1.0.0
|
|
6
|
-
#
|
|
7
|
-
# Orchestrates the SEO content pipeline using modular steps, Redis coordination,
|
|
8
|
-
# and validation loops.
|
|
9
|
-
#
|
|
10
|
-
# Usage:
|
|
11
|
-
# ./orchestrate-seo.sh --task-id <id> \
|
|
12
|
-
# --target-keyword <keyword> \
|
|
13
|
-
# --content-type <type> \
|
|
14
|
-
# --brand <brand> \
|
|
15
|
-
# --audience <audience> \
|
|
16
|
-
# [--mode <mvp|standard|enterprise>] \
|
|
17
|
-
# [--max-iterations <n>] \
|
|
18
|
-
# [--iteration <n>]
|
|
19
|
-
##############################################################################
|
|
20
|
-
|
|
21
|
-
set -euo pipefail
|
|
22
|
-
|
|
23
|
-
# Determine script directory
|
|
24
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
-
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
26
|
-
REDIS_COORD_SKILL="$PROJECT_ROOT/.claude/skills/cfn-redis-coordination"
|
|
27
|
-
|
|
28
|
-
# Configuration
|
|
29
|
-
TASK_ID=""
|
|
30
|
-
TARGET_KEYWORD=""
|
|
31
|
-
CONTENT_TYPE=""
|
|
32
|
-
BRAND=""
|
|
33
|
-
AUDIENCE=""
|
|
34
|
-
MODE="standard"
|
|
35
|
-
MAX_ITERATIONS=3
|
|
36
|
-
ITERATION=1
|
|
37
|
-
TARGET_LOCATION=""
|
|
38
|
-
WORD_COUNT_TARGET=""
|
|
39
|
-
|
|
40
|
-
# Mode-specific thresholds
|
|
41
|
-
declare -A VALIDATOR_GATE=(
|
|
42
|
-
[mvp]=0.70
|
|
43
|
-
[standard]=0.75
|
|
44
|
-
[enterprise]=0.80
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
declare -A CONSENSUS_THRESHOLD=(
|
|
48
|
-
[mvp]=0.90
|
|
49
|
-
[standard]=0.95
|
|
50
|
-
[enterprise]=0.98
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
# Execution tracking
|
|
54
|
-
START_TIME=$(date +%s)
|
|
55
|
-
CURRENT_STEP=0
|
|
56
|
-
VALIDATION_CONSENSUS=0.0
|
|
57
|
-
FINAL_ARTICLE_PATH=""
|
|
58
|
-
ITERATIONS_COMPLETED=0
|
|
59
|
-
|
|
60
|
-
##############################################################################
|
|
61
|
-
# Argument Parsing
|
|
62
|
-
##############################################################################
|
|
63
|
-
while [[ $# -gt 0 ]]; do
|
|
64
|
-
case $1 in
|
|
65
|
-
--task-id)
|
|
66
|
-
TASK_ID="$2"
|
|
67
|
-
shift 2
|
|
68
|
-
;;
|
|
69
|
-
--target-keyword)
|
|
70
|
-
TARGET_KEYWORD="$2"
|
|
71
|
-
shift 2
|
|
72
|
-
;;
|
|
73
|
-
--content-type)
|
|
74
|
-
CONTENT_TYPE="$2"
|
|
75
|
-
if [[ ! "$CONTENT_TYPE" =~ ^(blog|landing|product|local)$ ]]; then
|
|
76
|
-
echo "Invalid content type. Must be: blog, landing, product, or local"
|
|
77
|
-
exit 1
|
|
78
|
-
fi
|
|
79
|
-
shift 2
|
|
80
|
-
;;
|
|
81
|
-
--brand)
|
|
82
|
-
BRAND="$2"
|
|
83
|
-
shift 2
|
|
84
|
-
;;
|
|
85
|
-
--audience)
|
|
86
|
-
AUDIENCE="$2"
|
|
87
|
-
shift 2
|
|
88
|
-
;;
|
|
89
|
-
--mode)
|
|
90
|
-
MODE="$2"
|
|
91
|
-
if [[ ! "$MODE" =~ ^(mvp|standard|enterprise)$ ]]; then
|
|
92
|
-
echo "Invalid mode. Must be: mvp, standard, or enterprise"
|
|
93
|
-
exit 1
|
|
94
|
-
fi
|
|
95
|
-
shift 2
|
|
96
|
-
;;
|
|
97
|
-
--max-iterations)
|
|
98
|
-
MAX_ITERATIONS="$2"
|
|
99
|
-
if [[ ! "$MAX_ITERATIONS" =~ ^[1-9][0-9]*$ ]]; then
|
|
100
|
-
echo "Max iterations must be a positive integer"
|
|
101
|
-
exit 1
|
|
102
|
-
fi
|
|
103
|
-
shift 2
|
|
104
|
-
;;
|
|
105
|
-
--iteration)
|
|
106
|
-
ITERATION="$2"
|
|
107
|
-
shift 2
|
|
108
|
-
;;
|
|
109
|
-
--target-location)
|
|
110
|
-
TARGET_LOCATION="$2"
|
|
111
|
-
shift 2
|
|
112
|
-
;;
|
|
113
|
-
--word-count)
|
|
114
|
-
WORD_COUNT_TARGET="$2"
|
|
115
|
-
shift 2
|
|
116
|
-
;;
|
|
117
|
-
*)
|
|
118
|
-
echo "Error: Unknown option: '$1'"
|
|
119
|
-
echo ""
|
|
120
|
-
echo "Usage: $0 [OPTIONS]"
|
|
121
|
-
echo ""
|
|
122
|
-
echo "Required options:"
|
|
123
|
-
echo " --task-id <id> Unique task identifier"
|
|
124
|
-
echo " --target-keyword <keyword> Primary SEO keyword"
|
|
125
|
-
echo " --content-type <type> Content type: blog, landing, product, local"
|
|
126
|
-
echo " --brand <brand> Brand name"
|
|
127
|
-
echo " --audience <audience> Target audience"
|
|
128
|
-
echo ""
|
|
129
|
-
echo "Optional options:"
|
|
130
|
-
echo " --mode <mode> SEO mode: mvp, standard, enterprise (default: standard)"
|
|
131
|
-
echo " --max-iterations <n> Maximum validation iterations (default: 3)"
|
|
132
|
-
echo " --iteration <n> Current iteration (default: 1)"
|
|
133
|
-
echo " --target-location <loc> Target location (for local SEO)"
|
|
134
|
-
echo " --word-count <n> Target word count (default: auto)"
|
|
135
|
-
exit 1
|
|
136
|
-
;;
|
|
137
|
-
esac
|
|
138
|
-
done
|
|
139
|
-
|
|
140
|
-
# Validation
|
|
141
|
-
if [ -z "$TASK_ID" ] || [ -z "$TARGET_KEYWORD" ] || [ -z "$CONTENT_TYPE" ] || [ -z "$BRAND" ] || [ -z "$AUDIENCE" ]; then
|
|
142
|
-
echo "Error: Required parameters missing"
|
|
143
|
-
echo "Usage: $0 --task-id <id> --target-keyword <keyword> --content-type <type> --brand <brand> --audience <audience>"
|
|
144
|
-
exit 1
|
|
145
|
-
fi
|
|
146
|
-
|
|
147
|
-
# Get thresholds for mode
|
|
148
|
-
VALIDATOR_THRESHOLD=${VALIDATOR_GATE[$MODE]}
|
|
149
|
-
CONSENSUS=${CONSENSUS_THRESHOLD[$MODE]}
|
|
150
|
-
|
|
151
|
-
# Set word count target based on content type if not provided
|
|
152
|
-
if [ -z "$WORD_COUNT_TARGET" ]; then
|
|
153
|
-
case "$CONTENT_TYPE" in
|
|
154
|
-
blog)
|
|
155
|
-
WORD_COUNT_TARGET="1500-2000"
|
|
156
|
-
;;
|
|
157
|
-
landing)
|
|
158
|
-
WORD_COUNT_TARGET="800-1200"
|
|
159
|
-
;;
|
|
160
|
-
product)
|
|
161
|
-
WORD_COUNT_TARGET="400-800"
|
|
162
|
-
;;
|
|
163
|
-
local)
|
|
164
|
-
WORD_COUNT_TARGET="600-1000"
|
|
165
|
-
;;
|
|
166
|
-
esac
|
|
167
|
-
fi
|
|
168
|
-
|
|
169
|
-
echo "=============================================="
|
|
170
|
-
echo "SEO Pipeline Orchestration v1.0.0"
|
|
171
|
-
echo "=============================================="
|
|
172
|
-
echo "Task ID: $TASK_ID"
|
|
173
|
-
echo "Content Type: $CONTENT_TYPE"
|
|
174
|
-
echo "Target Keyword: $TARGET_KEYWORD"
|
|
175
|
-
echo "Brand: $BRAND"
|
|
176
|
-
echo "Audience: $AUDIENCE"
|
|
177
|
-
echo "Mode: $MODE"
|
|
178
|
-
echo "Word Count Target: $WORD_COUNT_TARGET"
|
|
179
|
-
echo "Validator Threshold: $VALIDATOR_THRESHOLD"
|
|
180
|
-
echo "Consensus Threshold: $CONSENSUS"
|
|
181
|
-
echo "Max Iterations: $MAX_ITERATIONS"
|
|
182
|
-
echo "=============================================="
|
|
183
|
-
echo ""
|
|
184
|
-
|
|
185
|
-
##############################################################################
|
|
186
|
-
# Helper Functions
|
|
187
|
-
##############################################################################
|
|
188
|
-
|
|
189
|
-
function log_step() {
|
|
190
|
-
local step_num="$1"
|
|
191
|
-
local step_name="$2"
|
|
192
|
-
local message="$3"
|
|
193
|
-
|
|
194
|
-
echo "[$step_name] $message"
|
|
195
|
-
redis-cli RPUSH "seo:task:${TASK_ID}:logs" "[$(date -Iseconds)] [Step $step_num] $message" >/dev/null
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function store_context() {
|
|
199
|
-
local task_id="$1"
|
|
200
|
-
|
|
201
|
-
log_step 0 "Init" "Storing SEO task context in Redis"
|
|
202
|
-
|
|
203
|
-
# Store task context using Redis HSET
|
|
204
|
-
redis-cli HSET "seo:task:${task_id}:context" \
|
|
205
|
-
target_keyword "$TARGET_KEYWORD" \
|
|
206
|
-
content_type "$CONTENT_TYPE" \
|
|
207
|
-
brand "$BRAND" \
|
|
208
|
-
audience "$AUDIENCE" \
|
|
209
|
-
mode "$MODE" \
|
|
210
|
-
word_count_target "$WORD_COUNT_TARGET" \
|
|
211
|
-
target_location "$TARGET_LOCATION" \
|
|
212
|
-
max_iterations "$MAX_ITERATIONS" >/dev/null
|
|
213
|
-
|
|
214
|
-
# Store status
|
|
215
|
-
redis-cli HSET "seo:task:${task_id}:status" \
|
|
216
|
-
current_step "0" \
|
|
217
|
-
iteration "$ITERATION" \
|
|
218
|
-
status "initializing" >/dev/null
|
|
219
|
-
|
|
220
|
-
log_step 0 "Init" "Context stored in Redis"
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function update_status() {
|
|
224
|
-
local step_num="$1"
|
|
225
|
-
local status="$2"
|
|
226
|
-
|
|
227
|
-
redis-cli HSET "seo:task:${TASK_ID}:status" \
|
|
228
|
-
current_step "$step_num" \
|
|
229
|
-
status "$status" \
|
|
230
|
-
last_updated "$(date -Iseconds)" >/dev/null
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function spawn_agent() {
|
|
234
|
-
local agent_type="$1"
|
|
235
|
-
local step_num="$2"
|
|
236
|
-
local context="$3"
|
|
237
|
-
local timeout="${4:-300}" # Default 5 minute timeout
|
|
238
|
-
|
|
239
|
-
local agent_id="${agent_type}-step${step_num}-iter${ITERATION}"
|
|
240
|
-
|
|
241
|
-
log_step "$step_num" "$(get_step_name $step_num)" "Spawning agent: $agent_type (ID: $agent_id)"
|
|
242
|
-
|
|
243
|
-
# Spawn agent via CLI
|
|
244
|
-
npx claude-flow-novice agent "$agent_type" \
|
|
245
|
-
--task-id "$TASK_ID" \
|
|
246
|
-
--agent-id "$agent_id" \
|
|
247
|
-
--iteration "$ITERATION" \
|
|
248
|
-
--context "$context" &
|
|
249
|
-
|
|
250
|
-
local agent_pid=$!
|
|
251
|
-
|
|
252
|
-
# Store agent PID
|
|
253
|
-
redis-cli HSET "seo:task:${TASK_ID}:agents" "$agent_id" "$agent_pid" >/dev/null
|
|
254
|
-
|
|
255
|
-
log_step "$step_num" "$(get_step_name $step_num)" "Agent spawned (PID: $agent_pid)"
|
|
256
|
-
|
|
257
|
-
# Wait for agent completion
|
|
258
|
-
if redis-cli blpop "swarm:${TASK_ID}:${agent_id}:done" "$timeout" >/dev/null 2>&1; then
|
|
259
|
-
log_step "$step_num" "$(get_step_name $step_num)" "Agent completed: $agent_id"
|
|
260
|
-
return 0
|
|
261
|
-
else
|
|
262
|
-
log_step "$step_num" "$(get_step_name $step_num)" "Warning: Agent timeout: $agent_id"
|
|
263
|
-
return 1
|
|
264
|
-
fi
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function get_step_name() {
|
|
268
|
-
local step="$1"
|
|
269
|
-
case "$step" in
|
|
270
|
-
1) echo "Keyword Research" ;;
|
|
271
|
-
2) echo "Competitor Analysis" ;;
|
|
272
|
-
3) echo "Content Outline" ;;
|
|
273
|
-
4) echo "Research" ;;
|
|
274
|
-
5) echo "Content Writing" ;;
|
|
275
|
-
6) echo "SEO Optimization" ;;
|
|
276
|
-
7) echo "Validation" ;;
|
|
277
|
-
8) echo "Publishing" ;;
|
|
278
|
-
*) echo "Unknown" ;;
|
|
279
|
-
esac
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function should_run_step() {
|
|
283
|
-
local step="$1"
|
|
284
|
-
|
|
285
|
-
# All content types run certain core steps
|
|
286
|
-
case "$CONTENT_TYPE" in
|
|
287
|
-
blog)
|
|
288
|
-
# Blog runs all 8 steps
|
|
289
|
-
return 0
|
|
290
|
-
;;
|
|
291
|
-
landing)
|
|
292
|
-
# Landing page skips competitor analysis (step 2), minimal research (step 4)
|
|
293
|
-
if [[ "$step" == "2" || "$step" == "4" ]]; then
|
|
294
|
-
return 1
|
|
295
|
-
fi
|
|
296
|
-
return 0
|
|
297
|
-
;;
|
|
298
|
-
product)
|
|
299
|
-
# Product page skips competitor analysis (2), outline (3), research (4)
|
|
300
|
-
if [[ "$step" == "2" || "$step" == "3" || "$step" == "4" ]]; then
|
|
301
|
-
return 1
|
|
302
|
-
fi
|
|
303
|
-
return 0
|
|
304
|
-
;;
|
|
305
|
-
local)
|
|
306
|
-
# Local content skips competitor analysis (2)
|
|
307
|
-
if [[ "$step" == "2" ]]; then
|
|
308
|
-
return 1
|
|
309
|
-
fi
|
|
310
|
-
return 0
|
|
311
|
-
;;
|
|
312
|
-
esac
|
|
313
|
-
|
|
314
|
-
return 0
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function store_step_output() {
|
|
318
|
-
local step_num="$1"
|
|
319
|
-
local output="$2"
|
|
320
|
-
|
|
321
|
-
redis-cli HSET "seo:task:${TASK_ID}:step:${step_num}:output" \
|
|
322
|
-
iteration "$ITERATION" \
|
|
323
|
-
timestamp "$(date -Iseconds)" \
|
|
324
|
-
output "$output" >/dev/null
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
##############################################################################
|
|
328
|
-
# Pipeline Steps
|
|
329
|
-
##############################################################################
|
|
330
|
-
|
|
331
|
-
function step1_keyword_research() {
|
|
332
|
-
if ! should_run_step "1"; then
|
|
333
|
-
log_step 1 "Keyword Research" "Skipped for content type: $CONTENT_TYPE"
|
|
334
|
-
return 0
|
|
335
|
-
fi
|
|
336
|
-
|
|
337
|
-
update_status 1 "running"
|
|
338
|
-
CURRENT_STEP=1
|
|
339
|
-
|
|
340
|
-
local context="Task: Keyword research for '$TARGET_KEYWORD' | Content Type: $CONTENT_TYPE | Brand: $BRAND | Audience: $AUDIENCE | Output: content/seo-data/keyword-research-${TASK_ID}.json"
|
|
341
|
-
|
|
342
|
-
if spawn_agent "seo-analytics-specialist" 1 "$context" 600; then
|
|
343
|
-
# Retrieve output from agent
|
|
344
|
-
local keyword_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:seo-analytics-specialist-step1-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
345
|
-
store_step_output 1 "$keyword_data"
|
|
346
|
-
log_step 1 "Keyword Research" "Completed successfully"
|
|
347
|
-
return 0
|
|
348
|
-
else
|
|
349
|
-
log_step 1 "Keyword Research" "Failed or timed out"
|
|
350
|
-
return 1
|
|
351
|
-
fi
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function step2_competitor_analysis() {
|
|
355
|
-
if ! should_run_step "2"; then
|
|
356
|
-
log_step 2 "Competitor Analysis" "Skipped for content type: $CONTENT_TYPE"
|
|
357
|
-
return 0
|
|
358
|
-
fi
|
|
359
|
-
|
|
360
|
-
update_status 2 "running"
|
|
361
|
-
CURRENT_STEP=2
|
|
362
|
-
|
|
363
|
-
local context="Task: Analyze top 3 competitors for keyword '$TARGET_KEYWORD' | Keyword Data: content/seo-data/keyword-research-${TASK_ID}.json | Output: content/seo-data/competitor-analysis-${TASK_ID}.md"
|
|
364
|
-
|
|
365
|
-
if spawn_agent "competitive-seo-analyst" 2 "$context" 600; then
|
|
366
|
-
local competitor_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:competitive-seo-analyst-step2-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
367
|
-
store_step_output 2 "$competitor_data"
|
|
368
|
-
log_step 2 "Competitor Analysis" "Completed successfully"
|
|
369
|
-
return 0
|
|
370
|
-
else
|
|
371
|
-
log_step 2 "Competitor Analysis" "Failed or timed out"
|
|
372
|
-
return 1
|
|
373
|
-
fi
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function step3_content_outline() {
|
|
377
|
-
if ! should_run_step "3"; then
|
|
378
|
-
log_step 3 "Content Outline" "Skipped for content type: $CONTENT_TYPE"
|
|
379
|
-
return 0
|
|
380
|
-
fi
|
|
381
|
-
|
|
382
|
-
update_status 3 "running"
|
|
383
|
-
CURRENT_STEP=3
|
|
384
|
-
|
|
385
|
-
local context="Task: Create SEO-optimized outline for '$TARGET_KEYWORD' | Keyword Data: content/seo-data/keyword-research-${TASK_ID}.json | Competitor Data: content/seo-data/competitor-analysis-${TASK_ID}.md | Brand: $BRAND | Word Count: $WORD_COUNT_TARGET | Output: content/outlines/outline-${TASK_ID}.md"
|
|
386
|
-
|
|
387
|
-
if spawn_agent "content-seo-strategist" 3 "$context" 600; then
|
|
388
|
-
local outline_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:content-seo-strategist-step3-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
389
|
-
store_step_output 3 "$outline_data"
|
|
390
|
-
log_step 3 "Content Outline" "Completed successfully"
|
|
391
|
-
return 0
|
|
392
|
-
else
|
|
393
|
-
log_step 3 "Content Outline" "Failed or timed out"
|
|
394
|
-
return 1
|
|
395
|
-
fi
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function step4_research() {
|
|
399
|
-
if ! should_run_step "4"; then
|
|
400
|
-
log_step 4 "Research" "Skipped for content type: $CONTENT_TYPE"
|
|
401
|
-
return 0
|
|
402
|
-
fi
|
|
403
|
-
|
|
404
|
-
update_status 4 "running"
|
|
405
|
-
CURRENT_STEP=4
|
|
406
|
-
|
|
407
|
-
log_step 4 "Research" "Performing research via Perplexity API"
|
|
408
|
-
|
|
409
|
-
# Check OpenRouter API key
|
|
410
|
-
if [ -z "${OPENROUTER_API_KEY:-}" ]; then
|
|
411
|
-
log_step 4 "Research" "Warning: OPENROUTER_API_KEY not set, skipping research"
|
|
412
|
-
return 0
|
|
413
|
-
fi
|
|
414
|
-
|
|
415
|
-
# Extract research questions from outline
|
|
416
|
-
local outline_path="content/outlines/outline-${TASK_ID}.md"
|
|
417
|
-
local research_query="Research comprehensive information about: $TARGET_KEYWORD. Focus on: latest statistics, expert quotes, credible sources, and supporting data."
|
|
418
|
-
|
|
419
|
-
# Call Perplexity API via OpenRouter
|
|
420
|
-
local research_response=$(curl -s https://openrouter.ai/api/v1/chat/completions \
|
|
421
|
-
-H "Authorization: Bearer ${OPENROUTER_API_KEY}" \
|
|
422
|
-
-H "Content-Type: application/json" \
|
|
423
|
-
-d "{
|
|
424
|
-
\"model\": \"perplexity/pplx-70b-online\",
|
|
425
|
-
\"messages\": [{\"role\": \"user\", \"content\": \"$research_query\"}]
|
|
426
|
-
}" 2>/dev/null || echo '{"error": "API call failed"}')
|
|
427
|
-
|
|
428
|
-
# Store research output
|
|
429
|
-
store_step_output 4 "$research_response"
|
|
430
|
-
|
|
431
|
-
# Save research to file
|
|
432
|
-
echo "$research_response" > "content/research/research-${TASK_ID}.json"
|
|
433
|
-
|
|
434
|
-
log_step 4 "Research" "Completed successfully"
|
|
435
|
-
return 0
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function step5_content_writing() {
|
|
439
|
-
if ! should_run_step "5"; then
|
|
440
|
-
log_step 5 "Content Writing" "Skipped for content type: $CONTENT_TYPE"
|
|
441
|
-
return 0
|
|
442
|
-
fi
|
|
443
|
-
|
|
444
|
-
update_status 5 "running"
|
|
445
|
-
CURRENT_STEP=5
|
|
446
|
-
|
|
447
|
-
# Build context with feedback if this is an iteration
|
|
448
|
-
local feedback=""
|
|
449
|
-
if [ "$ITERATION" -gt 1 ]; then
|
|
450
|
-
feedback=$(redis-cli HGET "seo:task:${TASK_ID}:validation:feedback" "iteration$((ITERATION - 1))" 2>/dev/null || echo "")
|
|
451
|
-
fi
|
|
452
|
-
|
|
453
|
-
local context="Task: Write $CONTENT_TYPE content for '$TARGET_KEYWORD' | Outline: content/outlines/outline-${TASK_ID}.md | Research: content/research/research-${TASK_ID}.json | Brand: $BRAND | Audience: $AUDIENCE | Word Count: $WORD_COUNT_TARGET | Tone: Conversational, human, natural | Output: content/drafts/draft-${TASK_ID}.md"
|
|
454
|
-
|
|
455
|
-
if [ -n "$feedback" ]; then
|
|
456
|
-
context="$context | Feedback from iteration $((ITERATION - 1)): $feedback"
|
|
457
|
-
fi
|
|
458
|
-
|
|
459
|
-
if spawn_agent "content-seo-strategist" 5 "$context" 900; then
|
|
460
|
-
local draft_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:content-seo-strategist-step5-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
461
|
-
store_step_output 5 "$draft_data"
|
|
462
|
-
log_step 5 "Content Writing" "Completed successfully"
|
|
463
|
-
return 0
|
|
464
|
-
else
|
|
465
|
-
log_step 5 "Content Writing" "Failed or timed out"
|
|
466
|
-
return 1
|
|
467
|
-
fi
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function step6_seo_optimization() {
|
|
471
|
-
if ! should_run_step "6"; then
|
|
472
|
-
log_step 6 "SEO Optimization" "Skipped for content type: $CONTENT_TYPE"
|
|
473
|
-
return 0
|
|
474
|
-
fi
|
|
475
|
-
|
|
476
|
-
update_status 6 "running"
|
|
477
|
-
CURRENT_STEP=6
|
|
478
|
-
|
|
479
|
-
local context="Task: SEO optimize content | Draft: content/drafts/draft-${TASK_ID}.md | Primary Keyword: $TARGET_KEYWORD | Content Type: $CONTENT_TYPE | Target URL: /blog/$TARGET_KEYWORD | Tasks: Meta title (50-60 chars), Meta description (150-160 chars), Header optimization, Internal linking (3-5 links), Image alt text, Schema preparation | Output: content/optimized/optimized-${TASK_ID}.md"
|
|
480
|
-
|
|
481
|
-
# Use technical-seo-specialist as primary agent
|
|
482
|
-
if spawn_agent "technical-seo-specialist" 6 "$context" 600; then
|
|
483
|
-
local optimized_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:technical-seo-specialist-step6-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
484
|
-
store_step_output 6 "$optimized_data"
|
|
485
|
-
log_step 6 "SEO Optimization" "Completed successfully"
|
|
486
|
-
return 0
|
|
487
|
-
else
|
|
488
|
-
log_step 6 "SEO Optimization" "Failed or timed out"
|
|
489
|
-
return 1
|
|
490
|
-
fi
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
function step7_validation() {
|
|
494
|
-
if ! should_run_step "7"; then
|
|
495
|
-
log_step 7 "Validation" "Skipped for content type: $CONTENT_TYPE"
|
|
496
|
-
return 0
|
|
497
|
-
fi
|
|
498
|
-
|
|
499
|
-
update_status 7 "running"
|
|
500
|
-
CURRENT_STEP=7
|
|
501
|
-
|
|
502
|
-
log_step 7 "Validation" "Spawning 3 validators in parallel"
|
|
503
|
-
|
|
504
|
-
local article_path="content/optimized/optimized-${TASK_ID}.md"
|
|
505
|
-
|
|
506
|
-
# Spawn validators in parallel
|
|
507
|
-
local validator_context_humanizer="Task: Validate article for natural, human-like writing | Article: $article_path | Iteration: $ITERATION | Check for: AI language patterns, conversational tone, personal examples, varied sentence structure | Output: Confidence score (0.0-1.0), Issues found, Recommended rewrites"
|
|
508
|
-
|
|
509
|
-
local validator_context_branding="Task: Validate article alignment with $BRAND brand | Article: $article_path | Brand: $BRAND | Iteration: $ITERATION | Check for: Brand voice consistency, value proposition, tone alignment, messaging | Output: Confidence score (0.0-1.0), Brand issues, Recommended adjustments"
|
|
510
|
-
|
|
511
|
-
local validator_context_audience="Task: Validate article fit for target audience | Article: $article_path | Audience: $AUDIENCE | Iteration: $ITERATION | Check for: Audience resonance, complexity level, relatable examples, clear value | Output: Confidence score (0.0-1.0), Audience fit issues, Suggested improvements"
|
|
512
|
-
|
|
513
|
-
# Spawn all validators in background
|
|
514
|
-
(spawn_agent "humanizer-validator" 7 "$validator_context_humanizer" 300) &
|
|
515
|
-
local pid_humanizer=$!
|
|
516
|
-
|
|
517
|
-
(spawn_agent "branding-validator" 7 "$validator_context_branding" 300) &
|
|
518
|
-
local pid_branding=$!
|
|
519
|
-
|
|
520
|
-
(spawn_agent "audience-validator" 7 "$validator_context_audience" 300) &
|
|
521
|
-
local pid_audience=$!
|
|
522
|
-
|
|
523
|
-
# Wait for all validators
|
|
524
|
-
wait "$pid_humanizer" "$pid_branding" "$pid_audience" 2>/dev/null || true
|
|
525
|
-
|
|
526
|
-
log_step 7 "Validation" "All validators completed"
|
|
527
|
-
|
|
528
|
-
# Collect confidence scores
|
|
529
|
-
local humanizer_score=$(redis-cli HGET "swarm:${TASK_ID}:humanizer-validator-step7-iter${ITERATION}:confidence" "score" 2>/dev/null || echo "0.0")
|
|
530
|
-
local branding_score=$(redis-cli HGET "swarm:${TASK_ID}:branding-validator-step7-iter${ITERATION}:confidence" "score" 2>/dev/null || echo "0.0")
|
|
531
|
-
local audience_score=$(redis-cli HGET "swarm:${TASK_ID}:audience-validator-step7-iter${ITERATION}:confidence" "score" 2>/dev/null || echo "0.0")
|
|
532
|
-
|
|
533
|
-
# Store validator scores
|
|
534
|
-
redis-cli HSET "seo:task:${TASK_ID}:validation:scores" \
|
|
535
|
-
"iteration${ITERATION}_humanizer" "$humanizer_score" \
|
|
536
|
-
"iteration${ITERATION}_branding" "$branding_score" \
|
|
537
|
-
"iteration${ITERATION}_audience" "$audience_score" >/dev/null
|
|
538
|
-
|
|
539
|
-
# Calculate consensus (average)
|
|
540
|
-
VALIDATION_CONSENSUS=$(echo "scale=2; ($humanizer_score + $branding_score + $audience_score) / 3" | bc)
|
|
541
|
-
|
|
542
|
-
log_step 7 "Validation" "Humanizer: $humanizer_score | Branding: $branding_score | Audience: $audience_score | Consensus: $VALIDATION_CONSENSUS"
|
|
543
|
-
|
|
544
|
-
# Check individual gate thresholds
|
|
545
|
-
local gate_pass=true
|
|
546
|
-
if (( $(echo "$humanizer_score < $VALIDATOR_THRESHOLD" | bc -l) )); then
|
|
547
|
-
log_step 7 "Validation" "Humanizer validator failed gate ($humanizer_score < $VALIDATOR_THRESHOLD)"
|
|
548
|
-
gate_pass=false
|
|
549
|
-
fi
|
|
550
|
-
if (( $(echo "$branding_score < $VALIDATOR_THRESHOLD" | bc -l) )); then
|
|
551
|
-
log_step 7 "Validation" "Branding validator failed gate ($branding_score < $VALIDATOR_THRESHOLD)"
|
|
552
|
-
gate_pass=false
|
|
553
|
-
fi
|
|
554
|
-
if (( $(echo "$audience_score < $VALIDATOR_THRESHOLD" | bc -l) )); then
|
|
555
|
-
log_step 7 "Validation" "Audience validator failed gate ($audience_score < $VALIDATOR_THRESHOLD)"
|
|
556
|
-
gate_pass=false
|
|
557
|
-
fi
|
|
558
|
-
|
|
559
|
-
# Check consensus threshold
|
|
560
|
-
if [[ "$gate_pass" == "true" ]] && (( $(echo "$VALIDATION_CONSENSUS >= $CONSENSUS" | bc -l) )); then
|
|
561
|
-
log_step 7 "Validation" "Consensus passed ($VALIDATION_CONSENSUS >= $CONSENSUS)"
|
|
562
|
-
return 0
|
|
563
|
-
else
|
|
564
|
-
log_step 7 "Validation" "Consensus failed ($VALIDATION_CONSENSUS < $CONSENSUS) or gate failed"
|
|
565
|
-
|
|
566
|
-
# Collect feedback from validators
|
|
567
|
-
local feedback=$(redis-cli HGET "seo:task:${TASK_ID}:validation:feedback" "iteration${ITERATION}" 2>/dev/null || echo "See validator outputs for specific feedback")
|
|
568
|
-
|
|
569
|
-
# Store feedback for next iteration
|
|
570
|
-
redis-cli HSET "seo:task:${TASK_ID}:validation:feedback" \
|
|
571
|
-
"iteration${ITERATION}" "$feedback" >/dev/null
|
|
572
|
-
|
|
573
|
-
return 1
|
|
574
|
-
fi
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
function step8_publishing() {
|
|
578
|
-
if ! should_run_step "8"; then
|
|
579
|
-
log_step 8 "Publishing" "Skipped for content type: $CONTENT_TYPE"
|
|
580
|
-
return 0
|
|
581
|
-
fi
|
|
582
|
-
|
|
583
|
-
update_status 8 "running"
|
|
584
|
-
CURRENT_STEP=8
|
|
585
|
-
|
|
586
|
-
local context="Task: Add schema markup and prepare for publishing | Article: content/optimized/optimized-${TASK_ID}.md | URL: https://${BRAND}.com/blog/${TARGET_KEYWORD} | Author: ${BRAND} Team | Published: $(date +%Y-%m-%d) | Tasks: Add Article schema (JSON-LD), Add BreadcrumbList schema, Add Organization schema, Validate with Google Rich Results Test, Final formatting | Output: content/published/published-${TASK_ID}.md"
|
|
587
|
-
|
|
588
|
-
if spawn_agent "schema-markup-engineer" 8 "$context" 600; then
|
|
589
|
-
local published_data=$(redis-cli HGET "seo:task:${TASK_ID}:agents:schema-markup-engineer-step8-iter${ITERATION}" "output" 2>/dev/null || echo "")
|
|
590
|
-
store_step_output 8 "$published_data"
|
|
591
|
-
|
|
592
|
-
# Set final article path
|
|
593
|
-
FINAL_ARTICLE_PATH="content/published/published-${TASK_ID}.md"
|
|
594
|
-
|
|
595
|
-
log_step 8 "Publishing" "Completed successfully - Article ready at $FINAL_ARTICLE_PATH"
|
|
596
|
-
return 0
|
|
597
|
-
else
|
|
598
|
-
log_step 8 "Publishing" "Failed or timed out"
|
|
599
|
-
return 1
|
|
600
|
-
fi
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
##############################################################################
|
|
604
|
-
# Main Pipeline Execution
|
|
605
|
-
##############################################################################
|
|
606
|
-
|
|
607
|
-
function run_pipeline() {
|
|
608
|
-
log_step 0 "Pipeline" "Starting SEO pipeline for iteration $ITERATION"
|
|
609
|
-
|
|
610
|
-
# Step 1: Keyword Research
|
|
611
|
-
if ! step1_keyword_research; then
|
|
612
|
-
log_step 0 "Pipeline" "Step 1 failed, retrying once"
|
|
613
|
-
sleep 2
|
|
614
|
-
if ! step1_keyword_research; then
|
|
615
|
-
log_step 0 "Pipeline" "Step 1 failed after retry, aborting"
|
|
616
|
-
return 1
|
|
617
|
-
fi
|
|
618
|
-
fi
|
|
619
|
-
|
|
620
|
-
# Step 2: Competitor Analysis
|
|
621
|
-
if ! step2_competitor_analysis; then
|
|
622
|
-
log_step 0 "Pipeline" "Step 2 failed, retrying once"
|
|
623
|
-
sleep 2
|
|
624
|
-
if ! step2_competitor_analysis; then
|
|
625
|
-
log_step 0 "Pipeline" "Step 2 failed after retry, continuing with degraded data"
|
|
626
|
-
# Non-critical step, continue
|
|
627
|
-
fi
|
|
628
|
-
fi
|
|
629
|
-
|
|
630
|
-
# Step 3: Content Outline
|
|
631
|
-
if ! step3_content_outline; then
|
|
632
|
-
log_step 0 "Pipeline" "Step 3 failed, retrying once"
|
|
633
|
-
sleep 2
|
|
634
|
-
if ! step3_content_outline; then
|
|
635
|
-
log_step 0 "Pipeline" "Step 3 failed after retry, aborting"
|
|
636
|
-
return 1
|
|
637
|
-
fi
|
|
638
|
-
fi
|
|
639
|
-
|
|
640
|
-
# Step 4: Research
|
|
641
|
-
if ! step4_research; then
|
|
642
|
-
log_step 0 "Pipeline" "Step 4 failed, continuing without external research"
|
|
643
|
-
# Non-critical step, continue
|
|
644
|
-
fi
|
|
645
|
-
|
|
646
|
-
# Step 5: Content Writing
|
|
647
|
-
if ! step5_content_writing; then
|
|
648
|
-
log_step 0 "Pipeline" "Step 5 failed, retrying once"
|
|
649
|
-
sleep 2
|
|
650
|
-
if ! step5_content_writing; then
|
|
651
|
-
log_step 0 "Pipeline" "Step 5 failed after retry, aborting"
|
|
652
|
-
return 1
|
|
653
|
-
fi
|
|
654
|
-
fi
|
|
655
|
-
|
|
656
|
-
# Step 6: SEO Optimization
|
|
657
|
-
if ! step6_seo_optimization; then
|
|
658
|
-
log_step 0 "Pipeline" "Step 6 failed, retrying once"
|
|
659
|
-
sleep 2
|
|
660
|
-
if ! step6_seo_optimization; then
|
|
661
|
-
log_step 0 "Pipeline" "Step 6 failed after retry, aborting"
|
|
662
|
-
return 1
|
|
663
|
-
fi
|
|
664
|
-
fi
|
|
665
|
-
|
|
666
|
-
# Step 7: Validation (with iteration loop)
|
|
667
|
-
if ! step7_validation; then
|
|
668
|
-
ITERATIONS_COMPLETED=$ITERATION
|
|
669
|
-
|
|
670
|
-
if [ "$ITERATION" -ge "$MAX_ITERATIONS" ]; then
|
|
671
|
-
log_step 7 "Validation" "Max iterations ($MAX_ITERATIONS) reached, proceeding to publishing"
|
|
672
|
-
# Proceed to step 8 even if validation consensus not met
|
|
673
|
-
else
|
|
674
|
-
log_step 7 "Validation" "Validation failed, starting iteration $((ITERATION + 1))"
|
|
675
|
-
|
|
676
|
-
# Recursive call with incremented iteration
|
|
677
|
-
ITERATION=$((ITERATION + 1))
|
|
678
|
-
run_pipeline
|
|
679
|
-
return $?
|
|
680
|
-
fi
|
|
681
|
-
fi
|
|
682
|
-
|
|
683
|
-
# Step 8: Publishing
|
|
684
|
-
if ! step8_publishing; then
|
|
685
|
-
log_step 0 "Pipeline" "Step 8 failed, retrying once"
|
|
686
|
-
sleep 2
|
|
687
|
-
if ! step8_publishing; then
|
|
688
|
-
log_step 0 "Pipeline" "Step 8 failed after retry, aborting"
|
|
689
|
-
return 1
|
|
690
|
-
fi
|
|
691
|
-
fi
|
|
692
|
-
|
|
693
|
-
log_step 0 "Pipeline" "SEO pipeline completed successfully"
|
|
694
|
-
return 0
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function output_result() {
|
|
698
|
-
local status="$1"
|
|
699
|
-
local end_time=$(date +%s)
|
|
700
|
-
local execution_time=$((end_time - START_TIME))
|
|
701
|
-
|
|
702
|
-
echo ""
|
|
703
|
-
echo "=============================================="
|
|
704
|
-
echo "SEO Pipeline Execution Complete"
|
|
705
|
-
echo "=============================================="
|
|
706
|
-
echo "Status: $status"
|
|
707
|
-
echo "Content Type: $CONTENT_TYPE"
|
|
708
|
-
echo "Target Keyword: $TARGET_KEYWORD"
|
|
709
|
-
echo "Iterations: $ITERATIONS_COMPLETED"
|
|
710
|
-
echo "Final Validation Consensus: $VALIDATION_CONSENSUS"
|
|
711
|
-
echo "Final Article Path: $FINAL_ARTICLE_PATH"
|
|
712
|
-
echo "Execution Time: ${execution_time}s"
|
|
713
|
-
echo "=============================================="
|
|
714
|
-
|
|
715
|
-
# Output structured JSON result
|
|
716
|
-
cat <<EOF
|
|
717
|
-
{
|
|
718
|
-
"status": "$status",
|
|
719
|
-
"content_type": "$CONTENT_TYPE",
|
|
720
|
-
"target_keyword": "$TARGET_KEYWORD",
|
|
721
|
-
"brand": "$BRAND",
|
|
722
|
-
"iterations_completed": $ITERATIONS_COMPLETED,
|
|
723
|
-
"validation_consensus": $VALIDATION_CONSENSUS,
|
|
724
|
-
"final_article_path": "$FINAL_ARTICLE_PATH",
|
|
725
|
-
"execution_time_seconds": $execution_time,
|
|
726
|
-
"task_id": "$TASK_ID"
|
|
727
|
-
}
|
|
728
|
-
EOF
|
|
729
|
-
|
|
730
|
-
# Store final result in Redis
|
|
731
|
-
redis-cli HSET "seo:task:${TASK_ID}:result" \
|
|
732
|
-
status "$status" \
|
|
733
|
-
iterations "$ITERATIONS_COMPLETED" \
|
|
734
|
-
consensus "$VALIDATION_CONSENSUS" \
|
|
735
|
-
article_path "$FINAL_ARTICLE_PATH" \
|
|
736
|
-
execution_time "$execution_time" >/dev/null
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
##############################################################################
|
|
740
|
-
# Main Execution
|
|
741
|
-
##############################################################################
|
|
742
|
-
|
|
743
|
-
# Store context in Redis
|
|
744
|
-
store_context "$TASK_ID"
|
|
745
|
-
|
|
746
|
-
# Run pipeline
|
|
747
|
-
if run_pipeline; then
|
|
748
|
-
ITERATIONS_COMPLETED=$ITERATION
|
|
749
|
-
output_result "success"
|
|
750
|
-
exit 0
|
|
751
|
-
else
|
|
752
|
-
ITERATIONS_COMPLETED=$ITERATION
|
|
753
|
-
output_result "failed"
|
|
754
|
-
exit 1
|
|
755
|
-
fi
|