claude-flow-novice 2.14.30 → 2.14.32
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/cfn-data/cfn-loop.db +0 -0
- package/.claude/commands/CFN_LOOP_TASK_MODE.md +1 -1
- package/.claude/skills/cfn-agent-discovery/agents-registry.json +10 -9
- package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +394 -0
- package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +521 -0
- package/.claude/skills/cfn-docker-loop-orchestration/SKILL.md +449 -0
- package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +787 -0
- package/.claude/skills/cfn-docker-redis-coordination/SKILL.md +435 -0
- package/.claude/skills/cfn-docker-redis-coordination/coordinate.sh +635 -0
- package/.claude/skills/cfn-docker-skill-mcp-selection/SKILL.md +289 -0
- package/.claude/skills/cfn-docker-skill-mcp-selection/skill-mcp-selector.js +472 -0
- package/.claude/skills/cfn-loop-validation/config.json +2 -2
- package/README.md +95 -0
- package/claude-assets/agents/README-AGENT_LIFECYCLE.md +10 -37
- package/claude-assets/agents/README-VALIDATION.md +8 -0
- package/claude-assets/agents/cfn-dev-team/CLAUDE.md +10 -9
- package/claude-assets/agents/cfn-dev-team/README.md +8 -0
- package/claude-assets/agents/cfn-dev-team/architecture/base-template-generator.md +2 -9
- package/claude-assets/agents/cfn-dev-team/coordinators/README.md +9 -1
- package/claude-assets/agents/cfn-dev-team/dev-ops/devops-engineer.md +7 -12
- package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +10 -5
- package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +11 -10
- package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +10 -5
- package/claude-assets/agents/cfn-dev-team/developers/README.md +9 -1
- package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +2 -5
- package/claude-assets/agents/cfn-dev-team/developers/backend-developer.md +11 -6
- package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +2 -5
- package/claude-assets/agents/cfn-dev-team/developers/frontend/mobile-dev.md +2 -19
- package/claude-assets/agents/cfn-dev-team/developers/frontend/react-frontend-engineer.md +11 -6
- package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +9 -23
- package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +10 -5
- package/claude-assets/agents/cfn-dev-team/developers/rust-developer.md +2 -9
- package/claude-assets/agents/cfn-dev-team/documentation/README-VALIDATION.md +8 -0
- package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +10 -0
- package/claude-assets/agents/cfn-dev-team/documentation/pseudocode.md +2 -9
- package/claude-assets/agents/cfn-dev-team/product-owners/accessibility-advocate-persona.md +11 -6
- package/claude-assets/agents/cfn-dev-team/product-owners/cto-agent.md +0 -5
- package/claude-assets/agents/cfn-dev-team/product-owners/power-user-persona.md +0 -3
- package/claude-assets/agents/cfn-dev-team/product-owners/product-owner.md +2 -8
- package/claude-assets/agents/cfn-dev-team/reviewers/README.md +9 -1
- package/claude-assets/agents/cfn-dev-team/reviewers/quality/quality-metrics.md +10 -0
- package/claude-assets/agents/cfn-dev-team/test-agent.md +10 -0
- package/claude-assets/agents/cfn-dev-team/testers/README.md +9 -1
- package/claude-assets/agents/cfn-dev-team/utility/analyst.md +0 -7
- package/claude-assets/agents/cfn-dev-team/utility/code-booster.md +1 -38
- package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +10 -5
- package/claude-assets/agents/cfn-dev-team/utility/researcher.md +8 -34
- package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +10 -5
- package/claude-assets/agents/csuite/cto-agent.md +10 -0
- package/claude-assets/agents/custom/cfn-system-expert.md +128 -1
- package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +5 -1
- package/claude-assets/agents/docker-team/csuite/c-suite-template.md +5 -1
- package/claude-assets/agents/docker-team/infrastructure/team-coordinator-template.md +5 -1
- package/claude-assets/agents/marketing_hybrid/cost_tracker.md +10 -0
- package/claude-assets/agents/marketing_hybrid/docker_deployer.md +10 -0
- package/claude-assets/agents/marketing_hybrid/zai_worker_spawner.md +10 -0
- package/claude-assets/agents/project-only-agents/npm-package-specialist.md +9 -26
- package/claude-assets/commands/CFN_LOOP_TASK_MODE.md +1 -1
- package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +20 -0
- package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +20 -0
- package/claude-assets/skills/agent-lifecycle/SKILL.md +60 -0
- package/claude-assets/skills/agent-lifecycle/execute-lifecycle-hook.sh +573 -0
- package/claude-assets/skills/agent-lifecycle/simple-audit.sh +31 -0
- package/claude-assets/skills/cfn-agent-discovery/agents-registry.json +10 -9
- package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +70 -10
- package/claude-assets/skills/cfn-loop-validation/config.json +2 -2
- package/claude-assets/skills/cfn-memory-management/SKILL.md +271 -0
- package/claude-assets/skills/cfn-memory-management/check-memory.sh +160 -0
- package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +197 -0
- package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +2 -2
- package/dist/agents/agent-loader.js +165 -146
- package/dist/agents/agent-loader.js.map +1 -1
- package/dist/cli/agent-command.js +44 -2
- package/dist/cli/agent-command.js.map +1 -1
- package/dist/cli/config-manager.js +91 -109
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/index.js +29 -2
- package/dist/cli/index.js.map +1 -1
- package/package.json +10 -2
- package/readme/README.md +71 -14
- package/scripts/memory-leak-prevention.sh +306 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# CFN Docker Loop Orchestration Implementation
|
|
4
|
+
# Usage: ./orchestrate.sh [OPERATION] [TASK_ID] [OPTIONS]
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# Default configuration
|
|
9
|
+
DEFAULT_MAX_ITERATIONS=10
|
|
10
|
+
DEFAULT_GATE_THRESHOLD=0.75
|
|
11
|
+
DEFAULT_CONSENSUS_THRESHOLD=0.90
|
|
12
|
+
DEFAULT_LOOP3_TIMEOUT=600
|
|
13
|
+
DEFAULT_LOOP2_TIMEOUT=300
|
|
14
|
+
DEFAULT_PO_TIMEOUT=180
|
|
15
|
+
|
|
16
|
+
# Colors for output
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
BLUE='\033[0;34m'
|
|
21
|
+
PURPLE='\033[0;35m'
|
|
22
|
+
NC='\033[0m'
|
|
23
|
+
|
|
24
|
+
log() {
|
|
25
|
+
echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $*"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
log_success() {
|
|
29
|
+
echo -e "${GREEN}[SUCCESS]${NC} $*"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
log_error() {
|
|
33
|
+
echo -e "${RED}[ERROR]${NC} $*"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
log_warning() {
|
|
37
|
+
echo -e "${YELLOW}[WARNING]${NC} $*"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
log_loop() {
|
|
41
|
+
echo -e "${PURPLE}[LOOP]${NC} $*"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Function to display usage
|
|
45
|
+
usage() {
|
|
46
|
+
cat << EOF
|
|
47
|
+
CFN Docker Loop Orchestration
|
|
48
|
+
|
|
49
|
+
Usage: $0 [OPERATION] [TASK_ID] [OPTIONS]
|
|
50
|
+
|
|
51
|
+
Operations:
|
|
52
|
+
execute Execute complete CFN Loop
|
|
53
|
+
init Initialize loop orchestration
|
|
54
|
+
spawn-loop3 Spawn Loop 3 implementer agents
|
|
55
|
+
monitor-loop3 Monitor Loop 3 completion
|
|
56
|
+
gate-check Check Loop 3 gate and decide next steps
|
|
57
|
+
spawn-loop2 Spawn Loop 2 validator agents
|
|
58
|
+
collect-consensus Collect Loop 2 consensus
|
|
59
|
+
trigger-po-decision Trigger Product Owner decision
|
|
60
|
+
analyze-task Analyze task and select agents
|
|
61
|
+
monitor-progress Monitor overall loop progress
|
|
62
|
+
validate-deliverables Validate required deliverables
|
|
63
|
+
handle-error Handle execution errors
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
--task-description TEXT Task description
|
|
67
|
+
--mode MODE Execution mode (mvp|standard|enterprise)
|
|
68
|
+
--agents LIST Comma-separated agent types
|
|
69
|
+
--max-iterations NUM Maximum iterations (default: 10)
|
|
70
|
+
--gate-threshold NUM Gate threshold (default: 0.75)
|
|
71
|
+
--consensus-threshold NUM Consensus threshold (default: 0.90)
|
|
72
|
+
--context-file PATH Task context file
|
|
73
|
+
--timeout SECONDS Operation timeout
|
|
74
|
+
--memory-limit LIMIT Agent memory limit
|
|
75
|
+
--network NAME Docker network
|
|
76
|
+
--adaptive-selection Enable adaptive agent selection
|
|
77
|
+
--force-iteration NUM Force specific iteration
|
|
78
|
+
--dry-run Show configuration without execution
|
|
79
|
+
--verbose Enable verbose logging
|
|
80
|
+
--help Show this help message
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
$0 execute --task-id task-auth --task-description "Implement user authentication" --mode standard
|
|
84
|
+
$0 spawn-loop3 --task-id task-auth --agents backend-developer,frontend-engineer,security-specialist
|
|
85
|
+
$0 monitor-loop3 --task-id task-auth --gate-threshold 0.80
|
|
86
|
+
$0 collect-consensus --task-id task-auth --required-consensus 0.90
|
|
87
|
+
|
|
88
|
+
EOF
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Mode configuration
|
|
92
|
+
get_mode_config() {
|
|
93
|
+
local mode="$1"
|
|
94
|
+
|
|
95
|
+
case "$mode" in
|
|
96
|
+
"mvp")
|
|
97
|
+
echo '{"maxIterations":3,"gateThreshold":0.70,"consensusThreshold":0.80,"validators":2}'
|
|
98
|
+
;;
|
|
99
|
+
"standard")
|
|
100
|
+
echo '{"maxIterations":10,"gateThreshold":0.75,"consensusThreshold":0.90,"validators":3}'
|
|
101
|
+
;;
|
|
102
|
+
"enterprise")
|
|
103
|
+
echo '{"maxIterations":15,"gateThreshold":0.85,"consensusThreshold":0.95,"validators":5}'
|
|
104
|
+
;;
|
|
105
|
+
*)
|
|
106
|
+
echo '{"maxIterations":10,"gateThreshold":0.75,"consensusThreshold":0.90,"validators":3}'
|
|
107
|
+
;;
|
|
108
|
+
esac
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Get script directory
|
|
112
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
113
|
+
PROJECT_ROOT="$(cd "$(dirname "$SCRIPT_DIR")/../.." && pwd)"
|
|
114
|
+
|
|
115
|
+
# Path to skills
|
|
116
|
+
REDIS_COORDINATION_SKILL="$PROJECT_ROOT/.claude/skills/cfn-docker-redis-coordination/coordinate.sh"
|
|
117
|
+
AGENT_SPAWNING_SKILL="$PROJECT_ROOT/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh"
|
|
118
|
+
|
|
119
|
+
# Parse command line arguments
|
|
120
|
+
OPERATION=""
|
|
121
|
+
TASK_ID=""
|
|
122
|
+
TASK_DESCRIPTION=""
|
|
123
|
+
MODE="standard"
|
|
124
|
+
AGENTS=""
|
|
125
|
+
MAX_ITERATIONS="$DEFAULT_MAX_ITERATIONS"
|
|
126
|
+
GATE_THRESHOLD="$DEFAULT_GATE_THRESHOLD"
|
|
127
|
+
CONSENSUS_THRESHOLD="$DEFAULT_CONSENSUS_THRESHOLD"
|
|
128
|
+
CONTEXT_FILE=""
|
|
129
|
+
TIMEOUT=""
|
|
130
|
+
MEMORY_LIMIT=""
|
|
131
|
+
NETWORK=""
|
|
132
|
+
ADAPTIVE_SELECTION=false
|
|
133
|
+
FORCE_ITERATION=""
|
|
134
|
+
DRY_RUN=false
|
|
135
|
+
VERBOSE=false
|
|
136
|
+
|
|
137
|
+
while [[ $# -gt 0 ]]; do
|
|
138
|
+
case $1 in
|
|
139
|
+
--task-description)
|
|
140
|
+
TASK_DESCRIPTION="$2"
|
|
141
|
+
shift 2
|
|
142
|
+
;;
|
|
143
|
+
--mode)
|
|
144
|
+
MODE="$2"
|
|
145
|
+
shift 2
|
|
146
|
+
;;
|
|
147
|
+
--agents)
|
|
148
|
+
AGENTS="$2"
|
|
149
|
+
shift 2
|
|
150
|
+
;;
|
|
151
|
+
--max-iterations)
|
|
152
|
+
MAX_ITERATIONS="$2"
|
|
153
|
+
shift 2
|
|
154
|
+
;;
|
|
155
|
+
--gate-threshold)
|
|
156
|
+
GATE_THRESHOLD="$2"
|
|
157
|
+
shift 2
|
|
158
|
+
;;
|
|
159
|
+
--consensus-threshold)
|
|
160
|
+
CONSENSUS_THRESHOLD="$2"
|
|
161
|
+
shift 2
|
|
162
|
+
;;
|
|
163
|
+
--context-file)
|
|
164
|
+
CONTEXT_FILE="$2"
|
|
165
|
+
shift 2
|
|
166
|
+
;;
|
|
167
|
+
--timeout)
|
|
168
|
+
TIMEOUT="$2"
|
|
169
|
+
shift 2
|
|
170
|
+
;;
|
|
171
|
+
--memory-limit)
|
|
172
|
+
MEMORY_LIMIT="$2"
|
|
173
|
+
shift 2
|
|
174
|
+
;;
|
|
175
|
+
--network)
|
|
176
|
+
NETWORK="$2"
|
|
177
|
+
shift 2
|
|
178
|
+
;;
|
|
179
|
+
--adaptive-selection)
|
|
180
|
+
ADAPTIVE_SELECTION=true
|
|
181
|
+
shift
|
|
182
|
+
;;
|
|
183
|
+
--force-iteration)
|
|
184
|
+
FORCE_ITERATION="$2"
|
|
185
|
+
shift 2
|
|
186
|
+
;;
|
|
187
|
+
--dry-run)
|
|
188
|
+
DRY_RUN=true
|
|
189
|
+
shift
|
|
190
|
+
;;
|
|
191
|
+
--verbose)
|
|
192
|
+
VERBOSE=true
|
|
193
|
+
shift
|
|
194
|
+
;;
|
|
195
|
+
--help)
|
|
196
|
+
usage
|
|
197
|
+
exit 0
|
|
198
|
+
;;
|
|
199
|
+
-*)
|
|
200
|
+
log_error "Unknown option: $1"
|
|
201
|
+
usage
|
|
202
|
+
exit 1
|
|
203
|
+
;;
|
|
204
|
+
*)
|
|
205
|
+
if [[ -z "$OPERATION" ]]; then
|
|
206
|
+
OPERATION="$1"
|
|
207
|
+
elif [[ -z "$TASK_ID" ]]; then
|
|
208
|
+
TASK_ID="$1"
|
|
209
|
+
else
|
|
210
|
+
log_error "Too many arguments"
|
|
211
|
+
usage
|
|
212
|
+
exit 1
|
|
213
|
+
fi
|
|
214
|
+
shift
|
|
215
|
+
;;
|
|
216
|
+
esac
|
|
217
|
+
done
|
|
218
|
+
|
|
219
|
+
# Apply mode configuration
|
|
220
|
+
MODE_CONFIG=$(get_mode_config "$MODE")
|
|
221
|
+
MAX_ITERATIONS=$(echo "$MODE_CONFIG" | jq -r '.maxIterations // 10')
|
|
222
|
+
GATE_THRESHOLD=$(echo "$MODE_CONFIG" | jq -r '.gateThreshold // 0.75')
|
|
223
|
+
CONSENSUS_THRESHOLD=$(echo "$MODE_CONFIG" | jq -r '.consensusThreshold // 0.90')
|
|
224
|
+
|
|
225
|
+
# Validate required arguments
|
|
226
|
+
if [[ -z "$OPERATION" ]]; then
|
|
227
|
+
log_error "Operation is required"
|
|
228
|
+
usage
|
|
229
|
+
exit 1
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
if [[ -z "$TASK_ID" && "$OPERATION" != "analyze-task" ]]; then
|
|
233
|
+
log_error "Task ID is required"
|
|
234
|
+
usage
|
|
235
|
+
exit 1
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
# Check dependencies
|
|
239
|
+
for dependency in "$REDIS_COORDINATION_SKILL" "$AGENT_SPAWNING_SKILL"; do
|
|
240
|
+
if [[ ! -f "$dependency" ]]; then
|
|
241
|
+
log_error "Required skill not found: $dependency"
|
|
242
|
+
exit 1
|
|
243
|
+
fi
|
|
244
|
+
done
|
|
245
|
+
|
|
246
|
+
# Change to project root
|
|
247
|
+
cd "$PROJECT_ROOT"
|
|
248
|
+
|
|
249
|
+
# Operation implementations
|
|
250
|
+
analyze_task() {
|
|
251
|
+
local task_description="$1"
|
|
252
|
+
|
|
253
|
+
if [[ -z "$task_description" ]]; then
|
|
254
|
+
log_error "Task description is required for task analysis"
|
|
255
|
+
return 1
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
log "Analyzing task: $task_description"
|
|
259
|
+
|
|
260
|
+
# Simple keyword-based agent selection (can be enhanced with ML)
|
|
261
|
+
local selected_agents=()
|
|
262
|
+
|
|
263
|
+
if [[ "$task_description" =~ (frontend|ui|user.interface|react|vue|angular) ]]; then
|
|
264
|
+
selected_agents+=("react-frontend-engineer")
|
|
265
|
+
fi
|
|
266
|
+
|
|
267
|
+
if [[ "$task_description" =~ (backend|api|server|database|authentication|security) ]]; then
|
|
268
|
+
selected_agents+=("backend-developer")
|
|
269
|
+
if [[ "$task_description" =~ (security|auth|encryption|password) ]]; then
|
|
270
|
+
selected_agents+=("security-specialist")
|
|
271
|
+
fi
|
|
272
|
+
fi
|
|
273
|
+
|
|
274
|
+
if [[ "$task_description" =~ (test|testing|quality|qa) ]]; then
|
|
275
|
+
selected_agents+=("tester")
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
if [[ "$task_description" =~ (review|code.quality|refactor) ]]; then
|
|
279
|
+
selected_agents+=("reviewer")
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
if [[ "$task_description" =~ (devops|deployment|docker|infrastructure) ]]; then
|
|
283
|
+
selected_agents+=("devops-engineer")
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# Default agents if none selected
|
|
287
|
+
if [[ ${#selected_agents[@]} -eq 0 ]]; then
|
|
288
|
+
selected_agents=("backend-developer" "react-frontend-engineer" "reviewer")
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# Limit to 3 agents for Loop 3
|
|
292
|
+
local loop3_agents=("${selected_agents[@]:0:3}")
|
|
293
|
+
|
|
294
|
+
log "Recommended Loop 3 agents: $(IFS=','; echo "${loop3_agents[*]}")"
|
|
295
|
+
log "Recommended Loop 2 agents: reviewer,tester"
|
|
296
|
+
|
|
297
|
+
echo "${loop3_agents[*]}"
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
init() {
|
|
301
|
+
local task_id="$1"
|
|
302
|
+
local context_file="$2"
|
|
303
|
+
|
|
304
|
+
log "Initializing loop orchestration for task: $task_id"
|
|
305
|
+
|
|
306
|
+
# Initialize Redis coordination
|
|
307
|
+
if [[ -n "$context_file" ]]; then
|
|
308
|
+
"$REDIS_COORDINATION_SKILL" init-task \
|
|
309
|
+
--task-id "$task_id" \
|
|
310
|
+
--context-file "$context_file"
|
|
311
|
+
else
|
|
312
|
+
"$REDIS_COORDINATION_SKILL" init-task \
|
|
313
|
+
--task-id "$task_id"
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# Store loop configuration
|
|
317
|
+
local config_file="/tmp/loop-config-${task_id}.json"
|
|
318
|
+
cat > "$config_file" << EOF
|
|
319
|
+
{
|
|
320
|
+
"taskId": "$task_id",
|
|
321
|
+
"mode": "$MODE",
|
|
322
|
+
"maxIterations": $MAX_ITERATIONS,
|
|
323
|
+
"gateThreshold": $GATE_THRESHOLD,
|
|
324
|
+
"consensusThreshold": $CONSENSUS_THRESHOLD,
|
|
325
|
+
"currentIteration": 1,
|
|
326
|
+
"currentLoop": 3,
|
|
327
|
+
"status": "initialized",
|
|
328
|
+
"createdAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
329
|
+
}
|
|
330
|
+
EOF
|
|
331
|
+
|
|
332
|
+
log_success "Loop orchestration initialized: $task_id"
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
spawn_loop3() {
|
|
336
|
+
local task_id="$1"
|
|
337
|
+
local agents="$2"
|
|
338
|
+
local iteration="${3:-1}"
|
|
339
|
+
|
|
340
|
+
if [[ -z "$agents" ]]; then
|
|
341
|
+
log_error "Agent list is required for Loop 3 spawning"
|
|
342
|
+
return 1
|
|
343
|
+
fi
|
|
344
|
+
|
|
345
|
+
log_loop "Spawning Loop 3 implementers (iteration $iteration)"
|
|
346
|
+
log "Agents: $agents"
|
|
347
|
+
|
|
348
|
+
# Store task context for agents
|
|
349
|
+
local context_file="/tmp/task-context-${task_id}-loop3-${iteration}.json"
|
|
350
|
+
|
|
351
|
+
# Create enhanced context with loop information
|
|
352
|
+
cat > "$context_file" << EOF
|
|
353
|
+
{
|
|
354
|
+
"task_id": "$task_id",
|
|
355
|
+
"loop_number": 3,
|
|
356
|
+
"iteration": $iteration,
|
|
357
|
+
"mode": "$MODE",
|
|
358
|
+
"role": "implementer",
|
|
359
|
+
"task_description": "$TASK_DESCRIPTION",
|
|
360
|
+
"gate_threshold": $GATE_THRESHOLD,
|
|
361
|
+
"max_iterations": $MAX_ITERATIONS,
|
|
362
|
+
"instructions": "Implement the required solution according to the task description. Focus on creating working, high-quality code that meets the acceptance criteria. Report your confidence in the implementation (0.0-1.0).",
|
|
363
|
+
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
364
|
+
}
|
|
365
|
+
EOF
|
|
366
|
+
|
|
367
|
+
# Get task context from Redis if available
|
|
368
|
+
if [[ -n "$CONTEXT_FILE" ]]; then
|
|
369
|
+
# Merge with existing context
|
|
370
|
+
local merged_context=$(jq -s '.[0] * .[1]' "$CONTEXT_FILE" "$context_file")
|
|
371
|
+
echo "$merged_context" > "$context_file"
|
|
372
|
+
fi
|
|
373
|
+
|
|
374
|
+
# Spawn agents
|
|
375
|
+
IFS=',' read -ra AGENT_ARRAY <<< "$agents"
|
|
376
|
+
local agent_ids=()
|
|
377
|
+
|
|
378
|
+
for agent_type in "${AGENT_ARRAY[@]}"; do
|
|
379
|
+
agent_type=$(echo "$agent_type" | xargs) # trim whitespace
|
|
380
|
+
|
|
381
|
+
log "Spawning agent: $agent_type"
|
|
382
|
+
|
|
383
|
+
if [[ "$DRY_RUN" == false ]]; then
|
|
384
|
+
local agent_id
|
|
385
|
+
agent_id=$("$AGENT_SPAWNING_SKILL" \
|
|
386
|
+
"$agent_type" \
|
|
387
|
+
"$task_id" \
|
|
388
|
+
"" \
|
|
389
|
+
--context-file "$context_file" \
|
|
390
|
+
--memory-limit "${MEMORY_LIMIT:-1g}" \
|
|
391
|
+
--network "${NETWORK:-mcp-network}" \
|
|
392
|
+
--mcp-auto-select 2>&1 | grep -o 'Agent ID: [^[:space:]]*' | cut -d' ' -f3)
|
|
393
|
+
|
|
394
|
+
if [[ -n "$agent_id" ]]; then
|
|
395
|
+
agent_ids+=("$agent_id")
|
|
396
|
+
|
|
397
|
+
# Register agent in Redis
|
|
398
|
+
"$REDIS_COORDINATION_SKILL" register-agent \
|
|
399
|
+
--agent-id "$agent_id" \
|
|
400
|
+
--agent-type "$agent_type" \
|
|
401
|
+
--task-id "$task_id"
|
|
402
|
+
|
|
403
|
+
log_success "Agent spawned: $agent_id ($agent_type)"
|
|
404
|
+
else
|
|
405
|
+
log_error "Failed to spawn agent: $agent_type"
|
|
406
|
+
fi
|
|
407
|
+
else
|
|
408
|
+
log "DRY RUN: Would spawn agent: $agent_type"
|
|
409
|
+
fi
|
|
410
|
+
done
|
|
411
|
+
|
|
412
|
+
if [[ "$DRY_RUN" == false && ${#agent_ids[@]} -gt 0 ]]; then
|
|
413
|
+
log_loop "Loop 3 agents spawned: ${#agent_ids[@]} agents"
|
|
414
|
+
# Store agent IDs for monitoring
|
|
415
|
+
printf '%s\n' "${agent_ids[@]}" > "/tmp/loop3-agents-${task_id}-${iteration}.txt"
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
# Cleanup
|
|
419
|
+
rm -f "$context_file"
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
monitor_loop3() {
|
|
423
|
+
local task_id="$1"
|
|
424
|
+
local gate_threshold="${2:-$GATE_THRESHOLD}"
|
|
425
|
+
local iteration="${3:-1}"
|
|
426
|
+
|
|
427
|
+
log_loop "Monitoring Loop 3 completion (iteration $iteration)"
|
|
428
|
+
|
|
429
|
+
# Get spawned agents
|
|
430
|
+
local agents_file="/tmp/loop3-agents-${task_id}-${iteration}.txt"
|
|
431
|
+
if [[ ! -f "$agents_file" ]]; then
|
|
432
|
+
log_error "No Loop 3 agents found for task: $task_id"
|
|
433
|
+
return 1
|
|
434
|
+
fi
|
|
435
|
+
|
|
436
|
+
local agent_count=$(wc -l < "$agents_file")
|
|
437
|
+
log "Waiting for $agent_count agents to complete"
|
|
438
|
+
|
|
439
|
+
# Wait for agent completion
|
|
440
|
+
if "$REDIS_COORDINATION_SKILL" wait-loop \
|
|
441
|
+
--task-id "$task_id" \
|
|
442
|
+
--loop-number 3 \
|
|
443
|
+
--agent-count "$agent_count" \
|
|
444
|
+
--timeout "${TIMEOUT:-$DEFAULT_LOOP3_TIMEOUT}"; then
|
|
445
|
+
|
|
446
|
+
log_success "All Loop 3 agents completed"
|
|
447
|
+
|
|
448
|
+
# Collect confidence scores for gate check
|
|
449
|
+
local total_confidence=0
|
|
450
|
+
local completed_agents=0
|
|
451
|
+
|
|
452
|
+
while IFS= read -r agent_id; do
|
|
453
|
+
local confidence=$("$REDIS_COORDINATION_SKILL" get-context "$task_id" "$agent_id" 2>/dev/null | jq -r '.confidence // 0.0')
|
|
454
|
+
if [[ "$confidence" != "0.0" && "$confidence" != "null" ]]; then
|
|
455
|
+
total_confidence=$(echo "$total_confidence + $confidence" | bc -l)
|
|
456
|
+
((completed_agents++))
|
|
457
|
+
if [[ "$VERBOSE" == true ]]; then
|
|
458
|
+
log "Agent $agent_id confidence: $confidence"
|
|
459
|
+
fi
|
|
460
|
+
fi
|
|
461
|
+
done < "$agents_file"
|
|
462
|
+
|
|
463
|
+
if [[ $completed_agents -gt 0 ]]; then
|
|
464
|
+
local average_confidence=$(echo "scale=3; $total_confidence / $completed_agents" | bc -l)
|
|
465
|
+
log "Gate result: $average_confidence >= $gate_threshold"
|
|
466
|
+
|
|
467
|
+
if (( $(echo "$average_confidence >= $gate_threshold" | bc -l) )); then
|
|
468
|
+
log_success "Loop 3 gate PASSED (confidence: $average_confidence)"
|
|
469
|
+
return 0
|
|
470
|
+
else
|
|
471
|
+
log_warning "Loop 3 gate FAILED (confidence: $average_confidence)"
|
|
472
|
+
return 1
|
|
473
|
+
fi
|
|
474
|
+
else
|
|
475
|
+
log_error "No confidence scores collected from agents"
|
|
476
|
+
return 1
|
|
477
|
+
fi
|
|
478
|
+
else
|
|
479
|
+
log_error "Loop 3 completion timeout or failure"
|
|
480
|
+
return 1
|
|
481
|
+
fi
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
gate_check() {
|
|
485
|
+
local task_id="$1"
|
|
486
|
+
local gate_threshold="${2:-$GATE_THRESHOLD}"
|
|
487
|
+
local iteration="${3:-1}"
|
|
488
|
+
local max_iterations="${4:-$MAX_ITERATIONS}"
|
|
489
|
+
|
|
490
|
+
log_loop "Performing gate check for iteration $iteration"
|
|
491
|
+
|
|
492
|
+
if monitor_loop3 "$task_id" "$gate_threshold" "$iteration"; then
|
|
493
|
+
# Gate passed - proceed to Loop 2
|
|
494
|
+
log_success "Gate PASSED - proceeding to Loop 2 validation"
|
|
495
|
+
|
|
496
|
+
# Signal gate passed for Loop 2 agents
|
|
497
|
+
"$REDIS_COORDINATION_SKILL" "$REDIS_CMD" LPUSH "cfn_docker:task:$task_id:gate-passed" "proceed" > /dev/null
|
|
498
|
+
|
|
499
|
+
return 0
|
|
500
|
+
else
|
|
501
|
+
# Gate failed - check if we can iterate
|
|
502
|
+
if [[ $iteration -lt $max_iterations ]]; then
|
|
503
|
+
log_warning "Gate FAILED - iterating Loop 3 ($iteration/$max_iterations)"
|
|
504
|
+
|
|
505
|
+
# Force next iteration
|
|
506
|
+
spawn_loop3 "$task_id" "$AGENTS" $((iteration + 1))
|
|
507
|
+
return 2 # Signal to iterate
|
|
508
|
+
else
|
|
509
|
+
log_error "Gate FAILED - max iterations reached ($max_iterations)"
|
|
510
|
+
return 1
|
|
511
|
+
fi
|
|
512
|
+
fi
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
spawn_loop2() {
|
|
516
|
+
local task_id="$1"
|
|
517
|
+
local loop3_work="$2"
|
|
518
|
+
|
|
519
|
+
log_loop "Spawning Loop 2 validators"
|
|
520
|
+
|
|
521
|
+
# Standard Loop 2 agents
|
|
522
|
+
local validators="reviewer,tester"
|
|
523
|
+
|
|
524
|
+
# Add security specialist for sensitive tasks
|
|
525
|
+
if [[ "$TASK_DESCRIPTION" =~ (security|auth|password|encryption) ]]; then
|
|
526
|
+
validators="$validators,security-specialist"
|
|
527
|
+
fi
|
|
528
|
+
|
|
529
|
+
# Create Loop 2 context
|
|
530
|
+
local context_file="/tmp/task-context-${task_id}-loop2.json"
|
|
531
|
+
cat > "$context_file" << EOF
|
|
532
|
+
{
|
|
533
|
+
"task_id": "$task_id",
|
|
534
|
+
"loop_number": 2,
|
|
535
|
+
"iteration": 1,
|
|
536
|
+
"mode": "$MODE",
|
|
537
|
+
"role": "validator",
|
|
538
|
+
"task_description": "$TASK_DESCRIPTION",
|
|
539
|
+
"consensus_threshold": $CONSENSUS_THRESHOLD,
|
|
540
|
+
"loop3_work": "$loop3_work",
|
|
541
|
+
"instructions": "Review and validate the implementation from Loop 3. Check for quality, correctness, and adherence to requirements. Provide your confidence in the implementation (0.0-1.0) and specific feedback.",
|
|
542
|
+
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
543
|
+
}
|
|
544
|
+
EOF
|
|
545
|
+
|
|
546
|
+
# Spawn validator agents
|
|
547
|
+
IFS=',' read -ra VALIDATOR_ARRAY <<< "$validators"
|
|
548
|
+
local validator_ids=()
|
|
549
|
+
|
|
550
|
+
for validator_type in "${VALIDATOR_ARRAY[@]}"; do
|
|
551
|
+
validator_type=$(echo "$validator_type" | xargs) # trim whitespace
|
|
552
|
+
|
|
553
|
+
log "Spawning validator: $validator_type"
|
|
554
|
+
|
|
555
|
+
if [[ "$DRY_RUN" == false ]]; then
|
|
556
|
+
local validator_id
|
|
557
|
+
validator_id=$("$AGENT_SPAWNING_SKILL" \
|
|
558
|
+
"$validator_type" \
|
|
559
|
+
"$task_id" \
|
|
560
|
+
"" \
|
|
561
|
+
--context-file "$context_file" \
|
|
562
|
+
--memory-limit "${MEMORY_LIMIT:-1g}" \
|
|
563
|
+
--network "${NETWORK:-mcp-network}" \
|
|
564
|
+
--mcp-auto-select 2>&1 | grep -o 'Agent ID: [^[:space:]]*' | cut -d' ' -f3)
|
|
565
|
+
|
|
566
|
+
if [[ -n "$validator_id" ]]; then
|
|
567
|
+
validator_ids+=("$validator_id")
|
|
568
|
+
|
|
569
|
+
# Register validator in Redis
|
|
570
|
+
"$REDIS_COORDINATION_SKILL" register-agent \
|
|
571
|
+
--agent-id "$validator_id" \
|
|
572
|
+
--agent-type "$validator_type" \
|
|
573
|
+
--task-id "$task_id"
|
|
574
|
+
|
|
575
|
+
log_success "Validator spawned: $validator_id ($validator_type)"
|
|
576
|
+
else
|
|
577
|
+
log_error "Failed to spawn validator: $validator_type"
|
|
578
|
+
fi
|
|
579
|
+
else
|
|
580
|
+
log "DRY RUN: Would spawn validator: $validator_type"
|
|
581
|
+
fi
|
|
582
|
+
done
|
|
583
|
+
|
|
584
|
+
if [[ "$DRY_RUN" == false && ${#validator_ids[@]} -gt 0 ]]; then
|
|
585
|
+
log_loop "Loop 2 validators spawned: ${#validator_ids[@]} validators"
|
|
586
|
+
# Store validator IDs for monitoring
|
|
587
|
+
printf '%s\n' "${validator_ids[@]}" > "/tmp/loop2-agents-${task_id}.txt"
|
|
588
|
+
fi
|
|
589
|
+
|
|
590
|
+
# Cleanup
|
|
591
|
+
rm -f "$context_file"
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
collect_consensus() {
|
|
595
|
+
local task_id="$1"
|
|
596
|
+
local consensus_threshold="${2:-$CONSENSUS_THRESHOLD}"
|
|
597
|
+
|
|
598
|
+
log_loop "Collecting Loop 2 consensus (threshold: $consensus_threshold)"
|
|
599
|
+
|
|
600
|
+
# Get spawned validators
|
|
601
|
+
local validators_file="/tmp/loop2-agents-${task_id}.txt"
|
|
602
|
+
if [[ ! -f "$validators_file" ]]; then
|
|
603
|
+
log_error "No Loop 2 validators found for task: $task_id"
|
|
604
|
+
return 1
|
|
605
|
+
fi
|
|
606
|
+
|
|
607
|
+
local validator_count=$(wc -l < "$validators_file")
|
|
608
|
+
log "Waiting for $validator_count validators to complete"
|
|
609
|
+
|
|
610
|
+
# Wait for validator completion
|
|
611
|
+
if "$REDIS_COORDINATION_SKILL" wait-loop \
|
|
612
|
+
--task-id "$task_id" \
|
|
613
|
+
--loop-number 2 \
|
|
614
|
+
--agent-count "$validator_count" \
|
|
615
|
+
--timeout "${TIMEOUT:-$DEFAULT_LOOP2_TIMEOUT}"; then
|
|
616
|
+
|
|
617
|
+
# Collect consensus
|
|
618
|
+
if "$REDIS_COORDINATION_SKILL" collect-consensus \
|
|
619
|
+
--task-id "$task_id" \
|
|
620
|
+
--loop-number 2 \
|
|
621
|
+
--required-consensus "$consensus_threshold"; then
|
|
622
|
+
|
|
623
|
+
log_success "Loop 2 consensus collected and PASSED"
|
|
624
|
+
return 0
|
|
625
|
+
else
|
|
626
|
+
log_error "Loop 2 consensus collection FAILED or threshold not met"
|
|
627
|
+
return 1
|
|
628
|
+
fi
|
|
629
|
+
else
|
|
630
|
+
log_error "Loop 2 validator completion timeout"
|
|
631
|
+
return 1
|
|
632
|
+
fi
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
trigger_po_decision() {
|
|
636
|
+
local task_id="$1"
|
|
637
|
+
local consensus_data="$2"
|
|
638
|
+
|
|
639
|
+
log_loop "Triggering Product Owner decision"
|
|
640
|
+
|
|
641
|
+
# Create PO context
|
|
642
|
+
local context_file="/tmp/task-context-${task_id}-po.json"
|
|
643
|
+
cat > "$context_file" << EOF
|
|
644
|
+
{
|
|
645
|
+
"task_id": "$task_id",
|
|
646
|
+
"loop_number": 4,
|
|
647
|
+
"role": "product-owner",
|
|
648
|
+
"mode": "$MODE",
|
|
649
|
+
"task_description": "$TASK_DESCRIPTION",
|
|
650
|
+
"consensus_data": "$consensus_data",
|
|
651
|
+
"instructions": "Review the consensus data and make a strategic decision: PROCEED (implementation complete), ITERATE (needs more work), or ABORT (task not feasible). Use GOAP methodology for decision analysis.",
|
|
652
|
+
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
653
|
+
}
|
|
654
|
+
EOF
|
|
655
|
+
|
|
656
|
+
# Spawn Product Owner
|
|
657
|
+
log "Spawning Product Owner for decision"
|
|
658
|
+
|
|
659
|
+
if [[ "$DRY_RUN" == false ]]; then
|
|
660
|
+
local po_id
|
|
661
|
+
po_id=$("$AGENT_SPAWNING_SKILL" \
|
|
662
|
+
"product-owner" \
|
|
663
|
+
"$task_id" \
|
|
664
|
+
"" \
|
|
665
|
+
--context-file "$context_file" \
|
|
666
|
+
--memory-limit "${MEMORY_LIMIT:-1g}" \
|
|
667
|
+
--network "${NETWORK:-mcp-network}" 2>&1 | grep -o 'Agent ID: [^[:space:]]*' | cut -d' ' -f3)
|
|
668
|
+
|
|
669
|
+
if [[ -n "$po_id" ]]; then
|
|
670
|
+
log_success "Product Owner spawned: $po_id"
|
|
671
|
+
|
|
672
|
+
# Wait for PO decision (with timeout)
|
|
673
|
+
if "$REDIS_COORDINATION_SKILL" wait-loop \
|
|
674
|
+
--task-id "$task_id" \
|
|
675
|
+
--loop-number 4 \
|
|
676
|
+
--agent-count 1 \
|
|
677
|
+
--timeout "${TIMEOUT:-$DEFAULT_PO_TIMEOUT}"; then
|
|
678
|
+
|
|
679
|
+
log_success "Product Owner decision completed"
|
|
680
|
+
return 0
|
|
681
|
+
else
|
|
682
|
+
log_error "Product Owner decision timeout"
|
|
683
|
+
return 1
|
|
684
|
+
fi
|
|
685
|
+
else
|
|
686
|
+
log_error "Failed to spawn Product Owner"
|
|
687
|
+
return 1
|
|
688
|
+
fi
|
|
689
|
+
else
|
|
690
|
+
log "DRY RUN: Would spawn Product Owner"
|
|
691
|
+
fi
|
|
692
|
+
|
|
693
|
+
# Cleanup
|
|
694
|
+
rm -f "$context_file"
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
execute() {
|
|
698
|
+
local task_id="$1"
|
|
699
|
+
local task_description="$2"
|
|
700
|
+
|
|
701
|
+
log "Starting complete CFN Loop execution for task: $task_id"
|
|
702
|
+
log "Description: $task_description"
|
|
703
|
+
log "Mode: $MODE"
|
|
704
|
+
|
|
705
|
+
# Analyze task and select agents if not specified
|
|
706
|
+
if [[ -z "$AGENTS" ]]; then
|
|
707
|
+
AGENTS=$(analyze_task "$task_description")
|
|
708
|
+
fi
|
|
709
|
+
|
|
710
|
+
# Initialize orchestration
|
|
711
|
+
init "$task_id" "$CONTEXT_FILE"
|
|
712
|
+
|
|
713
|
+
# Main loop execution
|
|
714
|
+
local iteration=1
|
|
715
|
+
while [[ $iteration -le $MAX_ITERATIONS ]]; do
|
|
716
|
+
log_loop "=== Iteration $iteration/$MAX_ITERATIONS ==="
|
|
717
|
+
|
|
718
|
+
# Spawn Loop 3 implementers
|
|
719
|
+
spawn_loop3 "$task_id" "$AGENTS" "$iteration"
|
|
720
|
+
|
|
721
|
+
# Gate check
|
|
722
|
+
gate_result=$(gate_check "$task_id" "$GATE_THRESHOLD" "$iteration" "$MAX_ITERATIONS")
|
|
723
|
+
case $gate_result in
|
|
724
|
+
0) # Gate passed
|
|
725
|
+
log_loop "Gate PASSED - proceeding to Loop 2"
|
|
726
|
+
break
|
|
727
|
+
;;
|
|
728
|
+
1) # Gate failed, max iterations reached
|
|
729
|
+
log_error "Gate FAILED - max iterations reached"
|
|
730
|
+
return 1
|
|
731
|
+
;;
|
|
732
|
+
2) # Gate failed, iterate
|
|
733
|
+
((iteration++))
|
|
734
|
+
continue
|
|
735
|
+
;;
|
|
736
|
+
esac
|
|
737
|
+
done
|
|
738
|
+
|
|
739
|
+
# Spawn Loop 2 validators
|
|
740
|
+
spawn_loop2 "$task_id" "Loop 3 implementation completed"
|
|
741
|
+
|
|
742
|
+
# Collect consensus
|
|
743
|
+
if collect_consensus "$task_id" "$CONSENSUS_THRESHOLD"; then
|
|
744
|
+
# Trigger Product Owner decision
|
|
745
|
+
trigger_po_decision "$task_id" "Consensus achieved"
|
|
746
|
+
log_success "CFN Loop execution completed successfully"
|
|
747
|
+
else
|
|
748
|
+
log_error "CFN Loop execution failed at consensus stage"
|
|
749
|
+
return 1
|
|
750
|
+
fi
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
# Main operation dispatcher
|
|
754
|
+
case "$OPERATION" in
|
|
755
|
+
execute)
|
|
756
|
+
execute "$TASK_ID" "$TASK_DESCRIPTION"
|
|
757
|
+
;;
|
|
758
|
+
init)
|
|
759
|
+
init "$TASK_ID" "$CONTEXT_FILE"
|
|
760
|
+
;;
|
|
761
|
+
analyze-task)
|
|
762
|
+
analyze_task "$TASK_DESCRIPTION"
|
|
763
|
+
;;
|
|
764
|
+
spawn-loop3)
|
|
765
|
+
spawn_loop3 "$TASK_ID" "$AGENTS" "${FORCE_ITERATION:-1}"
|
|
766
|
+
;;
|
|
767
|
+
monitor-loop3)
|
|
768
|
+
monitor_loop3 "$TASK_ID" "$GATE_THRESHOLD" "${FORCE_ITERATION:-1}"
|
|
769
|
+
;;
|
|
770
|
+
gate-check)
|
|
771
|
+
gate_check "$TASK_ID" "$GATE_THRESHOLD" "${FORCE_ITERATION:-1}" "$MAX_ITERATIONS"
|
|
772
|
+
;;
|
|
773
|
+
spawn-loop2)
|
|
774
|
+
spawn_loop2 "$TASK_ID" ""
|
|
775
|
+
;;
|
|
776
|
+
collect-consensus)
|
|
777
|
+
collect_consensus "$TASK_ID" "$CONSENSUS_THRESHOLD"
|
|
778
|
+
;;
|
|
779
|
+
trigger-po-decision)
|
|
780
|
+
trigger_po_decision "$TASK_ID" ""
|
|
781
|
+
;;
|
|
782
|
+
*)
|
|
783
|
+
log_error "Unknown operation: $OPERATION"
|
|
784
|
+
usage
|
|
785
|
+
exit 1
|
|
786
|
+
;;
|
|
787
|
+
esac
|