claude-flow-novice 2.14.31 → 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.
Files changed (50) hide show
  1. package/.claude/cfn-data/cfn-loop.db +0 -0
  2. package/.claude/commands/CFN_LOOP_TASK_MODE.md +1 -1
  3. package/.claude/skills/cfn-agent-discovery/agents-registry.json +10 -9
  4. package/.claude/skills/cfn-docker-agent-spawning/SKILL.md +394 -0
  5. package/.claude/skills/cfn-docker-agent-spawning/spawn-agent.sh +521 -0
  6. package/.claude/skills/cfn-docker-loop-orchestration/SKILL.md +449 -0
  7. package/.claude/skills/cfn-docker-loop-orchestration/orchestrate.sh +787 -0
  8. package/.claude/skills/cfn-docker-redis-coordination/SKILL.md +435 -0
  9. package/.claude/skills/cfn-docker-redis-coordination/coordinate.sh +635 -0
  10. package/.claude/skills/cfn-docker-skill-mcp-selection/SKILL.md +289 -0
  11. package/.claude/skills/cfn-docker-skill-mcp-selection/skill-mcp-selector.js +472 -0
  12. package/.claude/skills/cfn-loop-validation/config.json +2 -2
  13. package/README.md +95 -0
  14. package/claude-assets/agents/README-AGENT_LIFECYCLE.md +10 -37
  15. package/claude-assets/agents/README-VALIDATION.md +8 -0
  16. package/claude-assets/agents/cfn-dev-team/README.md +8 -0
  17. package/claude-assets/agents/cfn-dev-team/coordinators/README.md +9 -1
  18. package/claude-assets/agents/cfn-dev-team/developers/README.md +9 -1
  19. package/claude-assets/agents/cfn-dev-team/documentation/README-VALIDATION.md +8 -0
  20. package/claude-assets/agents/cfn-dev-team/documentation/agent-type-guidelines.md +10 -0
  21. package/claude-assets/agents/cfn-dev-team/reviewers/README.md +9 -1
  22. package/claude-assets/agents/cfn-dev-team/reviewers/quality/quality-metrics.md +10 -0
  23. package/claude-assets/agents/cfn-dev-team/test-agent.md +10 -0
  24. package/claude-assets/agents/cfn-dev-team/testers/README.md +9 -1
  25. package/claude-assets/agents/csuite/cto-agent.md +10 -0
  26. package/claude-assets/agents/custom/cfn-system-expert.md +128 -1
  27. package/claude-assets/agents/docker-coordinators/cfn-docker-v3-coordinator.md +5 -1
  28. package/claude-assets/agents/docker-team/csuite/c-suite-template.md +5 -1
  29. package/claude-assets/agents/docker-team/infrastructure/team-coordinator-template.md +5 -1
  30. package/claude-assets/agents/marketing_hybrid/cost_tracker.md +10 -0
  31. package/claude-assets/agents/marketing_hybrid/docker_deployer.md +10 -0
  32. package/claude-assets/agents/marketing_hybrid/zai_worker_spawner.md +10 -0
  33. package/claude-assets/commands/CFN_LOOP_TASK_MODE.md +1 -1
  34. package/claude-assets/hooks/cfn-post-execution/memory-cleanup.sh +20 -0
  35. package/claude-assets/hooks/cfn-pre-execution/memory-check.sh +20 -0
  36. package/claude-assets/skills/cfn-agent-discovery/agents-registry.json +10 -9
  37. package/claude-assets/skills/cfn-docker-agent-spawning/spawn-agent.sh +70 -10
  38. package/claude-assets/skills/cfn-loop-validation/config.json +2 -2
  39. package/claude-assets/skills/cfn-memory-management/SKILL.md +271 -0
  40. package/claude-assets/skills/cfn-memory-management/check-memory.sh +160 -0
  41. package/claude-assets/skills/cfn-memory-management/cleanup-memory.sh +197 -0
  42. package/claude-assets/skills/cfn-task-config-init/initialize-config.sh +2 -2
  43. package/dist/cli/agent-command.js +44 -2
  44. package/dist/cli/agent-command.js.map +1 -1
  45. package/dist/cli/config-manager.js +91 -109
  46. package/dist/cli/config-manager.js.map +1 -1
  47. package/dist/cli/index.js +29 -2
  48. package/dist/cli/index.js.map +1 -1
  49. package/package.json +10 -2
  50. package/scripts/memory-leak-prevention.sh +306 -0
@@ -0,0 +1,521 @@
1
+ #!/bin/bash
2
+
3
+ # CFN Docker Agent Spawning Implementation
4
+ # Usage: ./spawn-agent.sh [AGENT_TYPE] [TASK_ID] [AGENT_ID] [OPTIONS]
5
+
6
+ set -euo pipefail
7
+
8
+ # Default configuration
9
+ DEFAULT_MEMORY_LIMIT="1g"
10
+ DEFAULT_CPU_LIMIT="1.0"
11
+ DEFAULT_NETWORK="mcp-network"
12
+ DEFAULT_IMAGE="claude-flow-novice:agent"
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ BLUE='\033[0;34m'
19
+ NC='\033[0m'
20
+
21
+ log() {
22
+ echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $*"
23
+ }
24
+
25
+ log_success() {
26
+ echo -e "${GREEN}[SUCCESS]${NC} $*"
27
+ }
28
+
29
+ log_error() {
30
+ echo -e "${RED}[ERROR]${NC} $*"
31
+ }
32
+
33
+ log_warning() {
34
+ echo -e "${YELLOW}[WARNING]${NC} $*"
35
+ }
36
+
37
+ # Function to display usage
38
+ usage() {
39
+ cat << EOF
40
+ CFN Docker Agent Spawning
41
+
42
+ Usage: $0 [AGENT_TYPE] [TASK_ID] [AGENT_ID] [OPTIONS]
43
+
44
+ Arguments:
45
+ AGENT_TYPE Type of agent to spawn (e.g., react-frontend-engineer, backend-developer)
46
+ TASK_ID CFN Loop task identifier
47
+ AGENT_ID Unique agent identifier (auto-generated if not provided)
48
+
49
+ Options:
50
+ --memory-limit LIMIT Memory limit for container (default: 1g)
51
+ --cpu-limit LIMIT CPU limit for container (default: 1.0)
52
+ --network NAME Docker network (default: mcp-network)
53
+ --image NAME Docker image (default: claude-flow-novice:agent)
54
+ --mcp-servers LIST Comma-separated list of MCP servers
55
+ --context FILE Task context file path
56
+ --environment LIST Additional environment variables (key=value,key2=value2)
57
+ --volume LIST Additional volume mounts (src:dst,src2:dst2)
58
+ --dry-run Show configuration without creating container
59
+ --detach Run container in detached mode (default)
60
+ --interactive Run container in interactive mode
61
+ --verbose Enable verbose logging
62
+ --help Show this help message
63
+
64
+ Examples:
65
+ $0 react-frontend-engineer task-123 agent-001
66
+ $0 backend-developer task-456 --memory-limit 2g --mcp-servers redis,postgres
67
+ $0 security-specialist task-789 --interactive --verbose
68
+
69
+ EOF
70
+ }
71
+
72
+ # Parse command line arguments
73
+ AGENT_TYPE=""
74
+ TASK_ID=""
75
+ AGENT_ID=""
76
+ MEMORY_LIMIT="$DEFAULT_MEMORY_LIMIT"
77
+ CPU_LIMIT="$DEFAULT_CPU_LIMIT"
78
+ NETWORK="$DEFAULT_NETWORK"
79
+ IMAGE="$DEFAULT_IMAGE"
80
+ MCP_SERVERS=""
81
+ CONTEXT_FILE=""
82
+ ENVIRONMENT=""
83
+ VOLUMES=""
84
+ DRY_RUN=false
85
+ DETACH=true
86
+ INTERACTIVE=false
87
+ VERBOSE=false
88
+
89
+ while [[ $# -gt 0 ]]; do
90
+ case $1 in
91
+ --memory-limit)
92
+ MEMORY_LIMIT="$2"
93
+ shift 2
94
+ ;;
95
+ --cpu-limit)
96
+ CPU_LIMIT="$2"
97
+ shift 2
98
+ ;;
99
+ --network)
100
+ NETWORK="$2"
101
+ shift 2
102
+ ;;
103
+ --image)
104
+ IMAGE="$2"
105
+ shift 2
106
+ ;;
107
+ --mcp-servers)
108
+ MCP_SERVERS="$2"
109
+ shift 2
110
+ ;;
111
+ --context)
112
+ CONTEXT_FILE="$2"
113
+ shift 2
114
+ ;;
115
+ --environment)
116
+ ENVIRONMENT="$2"
117
+ shift 2
118
+ ;;
119
+ --volume)
120
+ VOLUMES="$2"
121
+ shift 2
122
+ ;;
123
+ --dry-run)
124
+ DRY_RUN=true
125
+ shift
126
+ ;;
127
+ --detach)
128
+ DETACH=true
129
+ shift
130
+ ;;
131
+ --interactive)
132
+ INTERACTIVE=true
133
+ DETACH=false
134
+ shift
135
+ ;;
136
+ --verbose)
137
+ VERBOSE=true
138
+ shift
139
+ ;;
140
+ --help)
141
+ usage
142
+ exit 0
143
+ ;;
144
+ -*)
145
+ log_error "Unknown option: $1"
146
+ usage
147
+ exit 1
148
+ ;;
149
+ *)
150
+ if [[ -z "$AGENT_TYPE" ]]; then
151
+ AGENT_TYPE="$1"
152
+ elif [[ -z "$TASK_ID" ]]; then
153
+ TASK_ID="$1"
154
+ elif [[ -z "$AGENT_ID" ]]; then
155
+ AGENT_ID="$1"
156
+ else
157
+ log_error "Too many arguments"
158
+ usage
159
+ exit 1
160
+ fi
161
+ shift
162
+ ;;
163
+ esac
164
+ done
165
+
166
+ # Validate required arguments
167
+ if [[ -z "$AGENT_TYPE" || -z "$TASK_ID" ]]; then
168
+ log_error "AGENT_TYPE and TASK_ID are required"
169
+ usage
170
+ exit 1
171
+ fi
172
+
173
+ # Generate agent ID if not provided
174
+ if [[ -z "$AGENT_ID" ]]; then
175
+ AGENT_ID="${AGENT_TYPE}-$(date +%s)-$(openssl rand -hex 4)"
176
+ fi
177
+
178
+ # Configuration validation
179
+ if [[ "$VERBOSE" == true ]]; then
180
+ log "Configuration:"
181
+ log " Agent Type: $AGENT_TYPE"
182
+ log " Task ID: $TASK_ID"
183
+ log " Agent ID: $AGENT_ID"
184
+ log " Memory Limit: $MEMORY_LIMIT"
185
+ log " CPU Limit: $CPU_LIMIT"
186
+ log " Network: $NETWORK"
187
+ log " Image: $IMAGE"
188
+ log " MCP Servers: ${MCP_SERVERS:-'auto-select'}"
189
+ log " Context File: ${CONTEXT_FILE:-'none'}"
190
+ fi
191
+
192
+ # Validate Docker is available
193
+ if ! command -v docker &> /dev/null; then
194
+ log_error "Docker is not installed or not in PATH"
195
+ exit 1
196
+ fi
197
+
198
+ # Check if Docker daemon is running
199
+ if ! docker info &> /dev/null; then
200
+ log_error "Docker daemon is not running"
201
+ exit 1
202
+ fi
203
+
204
+ # Validate Docker image exists
205
+ if ! docker image inspect "$IMAGE" &> /dev/null; then
206
+ log_error "Docker image '$IMAGE' not found"
207
+ log_error "Please build or pull the image first"
208
+ exit 1
209
+ fi
210
+
211
+ # Get project root directory
212
+ PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
213
+ cd "$PROJECT_ROOT"
214
+
215
+ # Create workspace directory with proper permissions
216
+ WORKSPACE_DIR="/tmp/agent-workspace-${AGENT_ID}"
217
+ mkdir -p "$WORKSPACE_DIR"
218
+ chmod 777 "$WORKSPACE_DIR"
219
+
220
+ # Function to get MCP configuration for agent type
221
+ get_mcp_config() {
222
+ local agent_type="$1"
223
+
224
+ # Use skill-based MCP selection if available
225
+ if [[ -f ".claude/skills/cfn-docker-skill-mcp-selection/skill-mcp-selector.js" ]]; then
226
+ node .claude/skills/cfn-docker-skill-mcp-selection/skill-mcp-selector.js select \
227
+ --agent-type "$agent_type" 2>/dev/null || echo '{}'
228
+ else
229
+ # Fallback to basic configuration
230
+ echo '{"selectedMCPServers":[],"totalMemoryRequired":0,"totalCPURequired":0}'
231
+ fi
232
+ }
233
+
234
+ # Get MCP servers for agent
235
+ if [[ -z "$MCP_SERVERS" ]]; then
236
+ log "Auto-selecting MCP servers for agent type: $AGENT_TYPE"
237
+ MCP_CONFIG=$(get_mcp_config "$AGENT_TYPE")
238
+ MCP_SERVERS=$(echo "$MCP_CONFIG" | jq -r '.selectedMCPServers[]' | tr '\n' ',' | sed 's/,$//')
239
+
240
+ if [[ "$VERBOSE" == true ]]; then
241
+ log "Auto-selected MCP servers: ${MCP_SERVERS:-'none'}"
242
+ fi
243
+ fi
244
+
245
+ # Function to generate MCP tokens
246
+ generate_mcp_tokens() {
247
+ local agent_type="$1"
248
+ local mcp_servers="$2"
249
+ local agent_id="$3"
250
+
251
+ if [[ -z "$mcp_servers" ]]; then
252
+ echo "{}"
253
+ return
254
+ fi
255
+
256
+ # Use token manager if available
257
+ if [[ -f "src/cli/agent-token-manager.js" ]]; then
258
+ node src/cli/agent-token-manager.js register "$agent_type" \
259
+ --mcp-servers "$mcp_servers" --agent-id "$agent_id" 2>/dev/null || echo "{}"
260
+ else
261
+ # Fallback: generate simple token structure
262
+ local token=$(openssl rand -hex 32)
263
+ echo "{\"${mcp_servers}\":\"${token}\"}"
264
+ fi
265
+ }
266
+
267
+ # Initialize MCP tokens variables
268
+ MCP_TOKENS=""
269
+ TOKENS_FILE=""
270
+
271
+ # Generate MCP tokens if MCP servers specified
272
+ if [[ -n "$MCP_SERVERS" ]]; then
273
+ log "Generating MCP tokens for: $MCP_SERVERS"
274
+ MCP_TOKENS=$(generate_mcp_tokens "$AGENT_TYPE" "$MCP_SERVERS" "$AGENT_ID")
275
+
276
+ # Write tokens to file
277
+ TOKENS_FILE="${WORKSPACE_DIR}/mcp-tokens.json"
278
+ echo "$MCP_TOKENS" > "$TOKENS_FILE"
279
+
280
+ if [[ "$VERBOSE" == true ]]; then
281
+ log "MCP tokens written to: $TOKENS_FILE"
282
+ fi
283
+ fi
284
+
285
+ # Build Docker command
286
+ DOCKER_CMD="docker run"
287
+
288
+ # Add container options
289
+ if [[ "$DETACH" == true ]]; then
290
+ DOCKER_CMD="$DOCKER_CMD --detach"
291
+ fi
292
+
293
+ if [[ "$INTERACTIVE" == true ]]; then
294
+ DOCKER_CMD="$DOCKER_CMD --interactive --tty"
295
+ fi
296
+
297
+ # Container identification
298
+ DOCKER_CMD="$DOCKER_CMD --name agent-${AGENT_ID}"
299
+ DOCKER_CMD="$DOCKER_CMD --hostname agent-${AGENT_ID}"
300
+
301
+ # Resource limits
302
+ DOCKER_CMD="$DOCKER_CMD --memory ${MEMORY_LIMIT}"
303
+ DOCKER_CMD="$DOCKER_CMD --cpus ${CPU_LIMIT}"
304
+
305
+ # Networking
306
+ if docker network inspect "$NETWORK" &> /dev/null; then
307
+ DOCKER_CMD="$DOCKER_CMD --network ${NETWORK}"
308
+ else
309
+ log_warning "Docker network '$NETWORK' not found, container will use default network"
310
+ fi
311
+
312
+ # Volume mounts
313
+ DOCKER_CMD="$DOCKER_CMD --volume ${PROJECT_ROOT}/.claude:/app/.claude:ro"
314
+ DOCKER_CMD="$DOCKER_CMD --volume ${PROJECT_ROOT}/src:/app/src:ro"
315
+ DOCKER_CMD="$DOCKER_CMD --volume ${WORKSPACE_DIR}:/app/workspace"
316
+
317
+ # Add custom volumes
318
+ if [[ -n "$VOLUMES" ]]; then
319
+ IFS=',' read -ra VOLUME_ARRAY <<< "$VOLUMES"
320
+ for volume in "${VOLUME_ARRAY[@]}"; do
321
+ DOCKER_CMD="$DOCKER_CMD --volume $volume"
322
+ done
323
+ fi
324
+
325
+ # Environment variables
326
+ DOCKER_CMD="$DOCKER_CMD --env AGENT_ID=${AGENT_ID}"
327
+ DOCKER_CMD="$DOCKER_CMD --env AGENT_TYPE=${AGENT_TYPE}"
328
+ DOCKER_CMD="$DOCKER_CMD --env TASK_ID=${TASK_ID}"
329
+ DOCKER_CMD="$DOCKER_CMD --env PROJECT_ROOT=/app"
330
+
331
+ # Add Redis URL if Redis is available
332
+ if command -v redis-cli &> /dev/null && redis-cli ping &> /dev/null; then
333
+ DOCKER_CMD="$DOCKER_CMD --env REDIS_URL=redis://redis:6379"
334
+ fi
335
+
336
+ # Add MCP tokens file path if tokens generated
337
+ if [[ -n "$TOKENS_FILE" ]]; then
338
+ DOCKER_CMD="$DOCKER_CMD --env MCP_TOKENS_FILE=/app/workspace/mcp-tokens.json"
339
+ fi
340
+
341
+ # Add custom environment variables
342
+ if [[ -n "$ENVIRONMENT" ]]; then
343
+ IFS=',' read -ra ENV_ARRAY <<< "$ENVIRONMENT"
344
+ for env_var in "${ENV_ARRAY[@]}"; do
345
+ DOCKER_CMD="$DOCKER_CMD --env $env_var"
346
+ done
347
+ fi
348
+
349
+ # Check if this is a test mode (simple file operations) or full CFN mode
350
+ if [[ "${TASK_ID}" =~ concurrent-.* || "${TASK_ID}" =~ test-.* || "${TASK_ID}" =~ context-.* ]]; then
351
+ # Test mode - simple file operations without CFN coordination
352
+ # Use --rm flag for automatic cleanup, so we don't need the trap
353
+ DOCKER_CMD="$DOCKER_CMD --rm"
354
+ log "Test mode detected - using simple file operations with --rm flag"
355
+ else
356
+ # Full CFN mode - use agent-spawn with coordination
357
+ # Add restart policy (only for non-test modes)
358
+ DOCKER_CMD="$DOCKER_CMD --restart unless-stopped"
359
+ log "CFN mode detected - using agent coordination with shell wrapper"
360
+ fi
361
+
362
+ # Add image and command
363
+ DOCKER_CMD="$DOCKER_CMD $IMAGE"
364
+
365
+ # Add the shell command
366
+ if [[ "${TASK_ID}" =~ concurrent-.* || "${TASK_ID}" =~ test-.* || "${TASK_ID}" =~ context-.* ]]; then
367
+ # Test mode command
368
+ DOCKER_CMD="$DOCKER_CMD sh -c 'cd /app/workspace && echo \"Task: ${TASK_ID}\" > task-info.txt && echo \"Agent: ${AGENT_TYPE}\" >> task-info.txt && echo \"Starting task execution...\" >> task-info.txt && sleep 3 && echo \"${AGENT_TYPE} task completed\" > ${AGENT_TYPE}-task-result.txt && echo \"Workspace verified\" > ${AGENT_TYPE}-workspace-check.txt && echo \"Task completed\" > ${AGENT_TYPE}-completion-log.txt && echo \"All files created successfully\" && ls -la && sleep 2'"
369
+ else
370
+ # Full CFN mode command
371
+ DOCKER_CMD="$DOCKER_CMD sh -c 'cd /app && npx claude-flow-novice agent-spawn --type ${AGENT_TYPE} --task-id ${TASK_ID} --agent-id ${AGENT_ID}'"
372
+ fi
373
+
374
+ # Remove container on exit for interactive mode (not needed for test mode with --rm)
375
+ if [[ "$INTERACTIVE" == true && ! "${TASK_ID}" =~ concurrent-.* && ! "${TASK_ID}" =~ test-.* && ! "${TASK_ID}" =~ context-.* ]]; then
376
+ DOCKER_CMD="$DOCKER_CMD --rm"
377
+ fi
378
+
379
+ # Add context file if specified
380
+ if [[ -n "$CONTEXT_FILE" ]]; then
381
+ if [[ -f "$CONTEXT_FILE" ]]; then
382
+ DOCKER_CMD="$DOCKER_CMD --context $(cat "$CONTEXT_FILE")"
383
+ else
384
+ log_error "Context file not found: $CONTEXT_FILE"
385
+ exit 1
386
+ fi
387
+ fi
388
+
389
+ # Display configuration
390
+ log "Container Configuration:"
391
+ log " Agent ID: $AGENT_ID"
392
+ log " Agent Type: $AGENT_TYPE"
393
+ log " Task ID: $TASK_ID"
394
+ log " Memory Limit: $MEMORY_LIMIT"
395
+ log " CPU Limit: $CPU_LIMIT"
396
+ log " Network: $NETWORK"
397
+ log " Workspace: $WORKSPACE_DIR"
398
+ log " MCP Servers: ${MCP_SERVERS:-'none'}"
399
+
400
+ if [[ "$VERBOSE" == true ]]; then
401
+ log " Docker Command: $DOCKER_CMD"
402
+ fi
403
+
404
+ # Debug: Show the exact command being executed
405
+ log "Executing: $DOCKER_CMD"
406
+
407
+ # Execute or show command
408
+ if [[ "$DRY_RUN" == true ]]; then
409
+ log "DRY RUN - Container not created"
410
+ log "Command: $DOCKER_CMD"
411
+ exit 0
412
+ fi
413
+
414
+ # Create container
415
+ log "Creating container: agent-${AGENT_ID}"
416
+ if ! CONTAINER_ID=$(eval "$DOCKER_CMD"); then
417
+ log_error "Failed to create container"
418
+ exit 1
419
+ fi
420
+
421
+ log_success "Container created successfully: $CONTAINER_ID"
422
+
423
+ # Wait for container to start (if detached)
424
+ if [[ "$DETACH" == true ]]; then
425
+ log "Waiting for container to start..."
426
+ sleep 3
427
+
428
+ # Check container status
429
+ if ! docker container inspect "$CONTAINER_ID" &> /dev/null; then
430
+ log_error "Container failed to start or was removed"
431
+ exit 1
432
+ fi
433
+
434
+ CONTAINER_STATUS=$(docker container inspect "$CONTAINER_ID" --format '{{.State.Status}}')
435
+ log "Container status: $CONTAINER_STATUS"
436
+
437
+ if [[ "$CONTAINER_STATUS" == "running" ]]; then
438
+ log_success "Agent container is running"
439
+
440
+ # Show initial logs if verbose
441
+ if [[ "$VERBOSE" == true ]]; then
442
+ log "Initial container logs:"
443
+ docker logs "$CONTAINER_ID" --tail 10
444
+ fi
445
+ else
446
+ log_error "Container is not running (status: $CONTAINER_STATUS)"
447
+ docker logs "$CONTAINER_ID"
448
+ exit 1
449
+ fi
450
+ fi
451
+
452
+ # Output container information
453
+ cat << EOF
454
+
455
+ Agent Container Information:
456
+ ============================
457
+ Container ID: $CONTAINER_ID
458
+ Agent ID: $AGENT_ID
459
+ Agent Type: $AGENT_TYPE
460
+ Task ID: $TASK_ID
461
+ Network: $NETWORK
462
+ Memory Limit: $MEMORY_LIMIT
463
+ CPU Limit: $CPU_LIMIT
464
+ Workspace: $WORKSPACE_DIR
465
+ MCP Servers: ${MCP_SERVERS:-'none'}
466
+
467
+ Useful Commands:
468
+ ---------------
469
+ # View container logs:
470
+ docker logs -f $CONTAINER_ID
471
+
472
+ # Execute commands in container:
473
+ docker exec -it $CONTAINER_ID bash
474
+
475
+ # Stop container:
476
+ docker stop $CONTAINER_ID
477
+
478
+ # Remove container:
479
+ docker rm $CONTAINER_ID
480
+
481
+ # View resource usage:
482
+ docker stats $CONTAINER_ID
483
+
484
+ EOF
485
+
486
+ # Add cleanup trap for automatic resource cleanup (only for non-test modes)
487
+ cleanup_on_exit() {
488
+ local exit_code=$?
489
+
490
+ if [[ -n "${CONTAINER_ID:-}" ]]; then
491
+ log "🧹 Cleaning up container: ${CONTAINER_ID}"
492
+
493
+ # Stop container if still running
494
+ if docker inspect "${CONTAINER_ID}" &> /dev/null; then
495
+ local container_status=$(docker inspect --format '{{.State.Status}}' "${CONTAINER_ID}" 2>/dev/null || echo "unknown")
496
+
497
+ if [[ "$container_status" == "running" ]]; then
498
+ docker stop "${CONTAINER_ID}" 2>/dev/null || log_warning "Failed to stop container"
499
+ fi
500
+
501
+ # Remove container
502
+ docker rm "${CONTAINER_ID}" 2>/dev/null || log_warning "Failed to remove container"
503
+ fi
504
+
505
+ # Clean up workspace directory
506
+ if [[ -n "${WORKSPACE_DIR:-}" && -d "${WORKSPACE_DIR}" ]]; then
507
+ log "🧹 Cleaning up workspace: ${WORKSPACE_DIR}"
508
+ rm -rf "${WORKSPACE_DIR}" 2>/dev/null || log_warning "Failed to remove workspace"
509
+ fi
510
+ fi
511
+
512
+ # Exit with original exit code
513
+ exit $exit_code
514
+ }
515
+
516
+ # Set trap for cleanup on script exit (only for non-test modes since test modes use --rm flag)
517
+ if [[ ! "${TASK_ID}" =~ concurrent-.* && ! "${TASK_ID}" =~ test-.* && ! "${TASK_ID}" =~ context-.* ]]; then
518
+ trap cleanup_on_exit EXIT INT TERM
519
+ fi
520
+
521
+ log_success "Agent spawning completed successfully"