claude-flow-novice 2.16.0 → 2.16.1

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 (154) hide show
  1. package/.claude/cfn-extras/skills/GOOGLE_SHEETS_SKILLS_README.md +1 -1
  2. package/.claude/cfn-extras/skills/google-sheets-api-coordinator/SKILL.md +1 -1
  3. package/.claude/cfn-extras/skills/google-sheets-formula-builder/SKILL.md +1 -1
  4. package/.claude/cfn-extras/skills/google-sheets-progress/SKILL.md +1 -1
  5. package/.claude/commands/CFN_LOOP_FRONTEND.md +1 -1
  6. package/.claude/commands/cfn-loop-cli.md +124 -46
  7. package/.claude/commands/cfn-loop-frontend.md +1 -1
  8. package/.claude/commands/cfn-loop-task.md +2 -2
  9. package/.claude/commands/deprecated/cfn-loop.md +2 -2
  10. package/.claude/hooks/cfn-invoke-post-edit.sh +31 -5
  11. package/.claude/hooks/cfn-post-edit.config.json +9 -2
  12. package/.claude/root-claude-distribute/CFN-CLAUDE.md +1 -1
  13. package/.claude/skills/cfn-backlog-management/SKILL.md +1 -1
  14. package/.claude/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +1 -1
  15. package/claude-assets/agents/cfn-dev-team/analysts/root-cause-analyst.md +2 -2
  16. package/claude-assets/agents/cfn-dev-team/architecture/base-template-generator.md +1 -1
  17. package/claude-assets/agents/cfn-dev-team/coordinators/cfn-frontend-coordinator.md +2 -2
  18. package/claude-assets/agents/cfn-dev-team/coordinators/handoff-coordinator.md +1 -1
  19. package/claude-assets/agents/cfn-dev-team/dev-ops/devops-engineer.md +1 -1
  20. package/claude-assets/agents/cfn-dev-team/dev-ops/docker-specialist.md +2 -2
  21. package/claude-assets/agents/cfn-dev-team/dev-ops/github-commit-agent.md +2 -2
  22. package/claude-assets/agents/cfn-dev-team/dev-ops/kubernetes-specialist.md +1 -1
  23. package/claude-assets/agents/cfn-dev-team/developers/api-gateway-specialist.md +1 -1
  24. package/claude-assets/agents/cfn-dev-team/developers/data/data-engineer.md +1 -1
  25. package/claude-assets/agents/cfn-dev-team/developers/database/database-architect.md +1 -1
  26. package/claude-assets/agents/cfn-dev-team/developers/frontend/typescript-specialist.md +1 -1
  27. package/claude-assets/agents/cfn-dev-team/developers/frontend/ui-designer.md +1 -1
  28. package/claude-assets/agents/cfn-dev-team/developers/graphql-specialist.md +1 -1
  29. package/claude-assets/agents/cfn-dev-team/documentation/pseudocode.md +1 -1
  30. package/claude-assets/agents/cfn-dev-team/product-owners/accessibility-advocate-persona.md +1 -1
  31. package/claude-assets/agents/cfn-dev-team/product-owners/cto-agent.md +1 -1
  32. package/claude-assets/agents/cfn-dev-team/product-owners/power-user-persona.md +1 -1
  33. package/claude-assets/agents/cfn-dev-team/reviewers/quality/security-specialist.md +1 -1
  34. package/claude-assets/agents/cfn-dev-team/testers/api-testing-specialist.md +1 -1
  35. package/claude-assets/agents/cfn-dev-team/testers/chaos-engineering-specialist.md +1 -1
  36. package/claude-assets/agents/cfn-dev-team/testers/contract-tester.md +1 -1
  37. package/claude-assets/agents/cfn-dev-team/testers/e2e/playwright-tester.md +1 -1
  38. package/claude-assets/agents/cfn-dev-team/testers/integration-tester.md +1 -1
  39. package/claude-assets/agents/cfn-dev-team/testers/load-testing-specialist.md +1 -1
  40. package/claude-assets/agents/cfn-dev-team/testers/mutation-testing-specialist.md +1 -1
  41. package/claude-assets/agents/cfn-dev-team/testers/unit/tdd-london-unit-swarm.md +1 -1
  42. package/claude-assets/agents/cfn-dev-team/utility/agent-builder.md +11 -0
  43. package/claude-assets/agents/cfn-dev-team/utility/analyst.md +1 -1
  44. package/claude-assets/agents/cfn-dev-team/utility/claude-code-expert.md +1 -1
  45. package/claude-assets/agents/cfn-dev-team/utility/epic-creator.md +1 -1
  46. package/claude-assets/agents/cfn-dev-team/utility/memory-leak-specialist.md +1 -1
  47. package/claude-assets/agents/cfn-dev-team/utility/researcher.md +1 -1
  48. package/claude-assets/agents/cfn-dev-team/utility/z-ai-specialist.md +1 -1
  49. package/claude-assets/agents/custom/cfn-docker-expert.md +1 -0
  50. package/claude-assets/agents/custom/cfn-loops-cli-expert.md +326 -17
  51. package/claude-assets/agents/custom/cfn-redis-operations.md +529 -529
  52. package/claude-assets/agents/custom/cfn-system-expert.md +1 -1
  53. package/claude-assets/agents/custom/trigger-dev-expert.md +369 -0
  54. package/claude-assets/agents/docker-team/micro-sprint-planner.md +747 -747
  55. package/claude-assets/agents/project-only-agents/npm-package-specialist.md +1 -1
  56. package/claude-assets/cfn-extras/skills/GOOGLE_SHEETS_SKILLS_README.md +1 -1
  57. package/claude-assets/cfn-extras/skills/google-sheets-api-coordinator/SKILL.md +1 -1
  58. package/claude-assets/cfn-extras/skills/google-sheets-formula-builder/SKILL.md +1 -1
  59. package/claude-assets/cfn-extras/skills/google-sheets-progress/SKILL.md +1 -1
  60. package/claude-assets/commands/CFN_LOOP_FRONTEND.md +1 -1
  61. package/claude-assets/commands/cfn-loop-cli.md +124 -46
  62. package/claude-assets/commands/cfn-loop-frontend.md +1 -1
  63. package/claude-assets/commands/cfn-loop-task.md +2 -2
  64. package/claude-assets/commands/deprecated/cfn-loop.md +2 -2
  65. package/claude-assets/hooks/GIT-HOOKS-USAGE-EXAMPLES.md +116 -0
  66. package/claude-assets/hooks/README-GIT-HOOKS.md +443 -0
  67. package/claude-assets/hooks/cfn-invoke-post-edit.sh +31 -5
  68. package/claude-assets/hooks/cfn-post-edit.config.json +9 -2
  69. package/claude-assets/hooks/install-git-hooks.sh +243 -0
  70. package/claude-assets/hooks/subagent-start.sh +98 -0
  71. package/claude-assets/hooks/subagent-stop.sh +93 -0
  72. package/claude-assets/hooks/validators/credential-scanner.sh +172 -0
  73. package/claude-assets/root-claude-distribute/CFN-CLAUDE.md +1 -1
  74. package/claude-assets/skills/cfn-backlog-management/SKILL.md +1 -1
  75. package/claude-assets/skills/cfn-dependency-ingestion/SKILL.md +41 -13
  76. package/claude-assets/skills/cfn-dependency-ingestion/ingest.sh +237 -0
  77. package/claude-assets/skills/cfn-dependency-ingestion/manifests/cli-mode-dependencies.txt +73 -0
  78. package/claude-assets/skills/cfn-dependency-ingestion/manifests/shared-dependencies.txt +57 -0
  79. package/claude-assets/skills/cfn-dependency-ingestion/manifests/trigger-dev-dependencies.txt +82 -0
  80. package/claude-assets/skills/cfn-dependency-ingestion/manifests/trigger-mode-dependencies.txt +80 -0
  81. package/claude-assets/skills/cfn-environment-sanitization/sanitize-environment.sh +14 -4
  82. package/claude-assets/skills/cfn-loop-orchestration/NORTH_STAR_INDEX.md +1 -1
  83. package/claude-assets/skills/cfn-provider-routing/SKILL.md +23 -0
  84. package/claude-assets/skills/docker-build/build.sh +1 -1
  85. package/dist/agent/skill-mcp-selector.js +2 -1
  86. package/dist/agent/skill-mcp-selector.js.map +1 -1
  87. package/dist/agents/agent-loader.js +165 -146
  88. package/dist/agents/agent-loader.js.map +1 -1
  89. package/dist/cli/agent-executor.js +470 -26
  90. package/dist/cli/agent-executor.js.map +1 -1
  91. package/dist/cli/agent-prompt-builder.js +2 -2
  92. package/dist/cli/agent-prompt-builder.js.map +1 -1
  93. package/dist/cli/agent-spawn.js +7 -4
  94. package/dist/cli/agent-spawn.js.map +1 -1
  95. package/dist/cli/agent-spawner.js +51 -4
  96. package/dist/cli/agent-spawner.js.map +1 -1
  97. package/dist/cli/agent-token-manager.js +2 -1
  98. package/dist/cli/agent-token-manager.js.map +1 -1
  99. package/dist/cli/anthropic-client.js +117 -11
  100. package/dist/cli/anthropic-client.js.map +1 -1
  101. package/dist/cli/cfn-context.js +2 -1
  102. package/dist/cli/cfn-context.js.map +1 -1
  103. package/dist/cli/cfn-metrics.js +2 -1
  104. package/dist/cli/cfn-metrics.js.map +1 -1
  105. package/dist/cli/cfn-redis.js +2 -1
  106. package/dist/cli/cfn-redis.js.map +1 -1
  107. package/dist/cli/cli-agent-context.js +2 -0
  108. package/dist/cli/cli-agent-context.js.map +1 -1
  109. package/dist/cli/config-manager.js +4 -252
  110. package/dist/cli/config-manager.js.map +1 -1
  111. package/dist/cli/conversation-fork-cleanup.js +2 -1
  112. package/dist/cli/conversation-fork-cleanup.js.map +1 -1
  113. package/dist/cli/conversation-fork.js +2 -1
  114. package/dist/cli/conversation-fork.js.map +1 -1
  115. package/dist/cli/coordination/agent-messaging.js +415 -0
  116. package/dist/cli/coordination/agent-messaging.js.map +1 -0
  117. package/dist/cli/coordination/wait-for-threshold.js +232 -0
  118. package/dist/cli/coordination/wait-for-threshold.js.map +1 -0
  119. package/dist/cli/iteration-history.js +2 -1
  120. package/dist/cli/iteration-history.js.map +1 -1
  121. package/dist/cli/process-lifecycle.js +5 -1
  122. package/dist/cli/process-lifecycle.js.map +1 -1
  123. package/dist/cli/spawn-agent-cli.js +41 -6
  124. package/dist/cli/spawn-agent-cli.js.map +1 -1
  125. package/dist/coordination/redis-waiting-mode.js +4 -0
  126. package/dist/coordination/redis-waiting-mode.js.map +1 -1
  127. package/dist/lib/artifact-registry.js +4 -0
  128. package/dist/lib/artifact-registry.js.map +1 -1
  129. package/dist/lib/connection-pool.js +390 -0
  130. package/dist/lib/connection-pool.js.map +1 -0
  131. package/dist/lib/environment-contract.js +258 -0
  132. package/dist/lib/environment-contract.js.map +1 -0
  133. package/dist/lib/query-optimizer.js +388 -0
  134. package/dist/lib/query-optimizer.js.map +1 -0
  135. package/dist/lib/result-cache.js +285 -0
  136. package/dist/lib/result-cache.js.map +1 -0
  137. package/dist/mcp/auth-middleware.js +2 -1
  138. package/dist/mcp/auth-middleware.js.map +1 -1
  139. package/dist/mcp/playwright-mcp-server-auth.js +2 -1
  140. package/dist/mcp/playwright-mcp-server-auth.js.map +1 -1
  141. package/package.json +3 -1
  142. package/scripts/build-agent-image.sh +1 -1
  143. package/scripts/cost-allocation-tracker.sh +632 -0
  144. package/scripts/docker-rebuild-all-agents.sh +2 -2
  145. package/scripts/reorganize-tests.sh +280 -0
  146. package/scripts/trigger-dev-setup.sh +12 -0
  147. package/tests/README.md +45 -0
  148. package/.claude/commands/cost-savings-status.md +0 -34
  149. package/.claude/commands/metrics-summary.md +0 -58
  150. package/claude-assets/agents/cfn-dev-team/dev-ops/monitoring-specialist.md +0 -768
  151. package/claude-assets/agents/custom/test-mcp-access.md +0 -24
  152. package/claude-assets/commands/cost-savings-status.md +0 -34
  153. package/claude-assets/commands/metrics-summary.md +0 -58
  154. package/tests/test-memory-leak-task-mode.sh +0 -435
@@ -0,0 +1,632 @@
1
+ #!/bin/bash
2
+
3
+ # cost-allocation-tracker.sh - Container cost tracking and allocation
4
+ #
5
+ # Purpose: Track costs across Docker containers by team, project, and agent type
6
+ # Usage: ./cost-allocation-tracker.sh [command] [options]
7
+ #
8
+ # Commands:
9
+ # daily-report <date> Generate daily cost report
10
+ # by-team <team> Show costs for specific team
11
+ # by-project <project> Show costs for specific project
12
+ # by-agent <agent-type> Show costs by agent type
13
+ # anomalies Find high-cost containers
14
+ # forecast <days> Project costs for next N days
15
+ # export-csv <output-file> Export to CSV for billing
16
+ # quota-check Verify team quotas
17
+
18
+ set -euo pipefail
19
+
20
+ # Source validation framework for safe arithmetic
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ source "$SCRIPT_DIR/lib/validation.sh"
23
+
24
+ # Configuration
25
+ COST_CPU_PER_HOUR=0.05 # $0.05 per CPU core per hour
26
+ COST_MEMORY_PER_GB_HOUR=0.10 # $0.10 per GB per hour
27
+ COST_DISK_PER_GB=0.01 # $0.01 per GB disk
28
+ COST_API_TOKEN_MULTIPLIER=0.50 # $0.50 per 1M tokens
29
+
30
+ # Provider costs (per 1M tokens)
31
+ COST_ZAI=0.50
32
+ COST_KIMI=2.00
33
+ COST_OPENROUTER=1.00
34
+ COST_ANTHROPIC=15.00
35
+
36
+ # Color output
37
+ RED='\033[0;31m'
38
+ GREEN='\033[0;32m'
39
+ YELLOW='\033[1;33m'
40
+ BLUE='\033[0;34m'
41
+ NC='\033[0m' # No Color
42
+
43
+ # Logging functions
44
+ log_info() {
45
+ echo -e "${BLUE}[INFO]${NC} $*"
46
+ }
47
+
48
+ log_success() {
49
+ echo -e "${GREEN}[SUCCESS]${NC} $*"
50
+ }
51
+
52
+ log_warn() {
53
+ echo -e "${YELLOW}[WARN]${NC} $*"
54
+ }
55
+
56
+ log_error() {
57
+ echo -e "${RED}[ERROR]${NC} $*"
58
+ }
59
+
60
+ # Calculate container cost
61
+ calculate_container_cost() {
62
+ local container_id=$1
63
+ local cpu_percent=$2
64
+ local memory_mb=$3
65
+ local runtime_seconds=${4:-3600} # Default to 1 hour
66
+ local provider=${5:-zai}
67
+
68
+ # Validate inputs
69
+ if ! validate_numeric "$cpu_percent" 0 ; then
70
+ log_error "Invalid CPU percent: $cpu_percent"
71
+ echo "0"
72
+ return 1
73
+ fi
74
+
75
+ if ! validate_numeric "$memory_mb" 0 ; then
76
+ log_error "Invalid memory MB: $memory_mb"
77
+ echo "0"
78
+ return 1
79
+ fi
80
+
81
+ if ! validate_numeric "$runtime_seconds" 1 ; then
82
+ log_error "Invalid runtime seconds: $runtime_seconds"
83
+ echo "0"
84
+ return 1
85
+ fi
86
+
87
+ # Assume CPU_PERCENT is for 1 hour execution
88
+ # Convert to actual CPU-hours (safe division)
89
+ local cpu_hours
90
+ cpu_hours=$(safe_divide "$cpu_percent" "100" 4) || return 1
91
+ cpu_hours=$(safe_arithmetic "$cpu_hours * ($runtime_seconds / 3600)") || return 1
92
+
93
+ local memory_gb
94
+ memory_gb=$(safe_divide "$memory_mb" "1024" 4) || return 1
95
+
96
+ local memory_hours
97
+ memory_hours=$(safe_arithmetic "$memory_gb * ($runtime_seconds / 3600)") || return 1
98
+
99
+ # Calculate infrastructure costs
100
+ local cpu_cost
101
+ cpu_cost=$(safe_arithmetic "$cpu_hours * $COST_CPU_PER_HOUR") || return 1
102
+
103
+ local memory_cost
104
+ memory_cost=$(safe_arithmetic "$memory_hours * $COST_MEMORY_PER_GB_HOUR") || return 1
105
+
106
+ local total_cost
107
+ total_cost=$(safe_arithmetic "$cpu_cost + $memory_cost") || return 1
108
+
109
+ echo "$total_cost"
110
+ }
111
+
112
+ # Get API token cost for provider
113
+ get_api_cost() {
114
+ local provider=$1
115
+ local tokens=${2:-0}
116
+
117
+ # Validate token count
118
+ if ! validate_numeric "$tokens" 0 ; then
119
+ log_error "Invalid token count: $tokens"
120
+ echo "0"
121
+ return 1
122
+ fi
123
+
124
+ if [ "$tokens" -eq 0 ]; then
125
+ echo "0"
126
+ return 0
127
+ fi
128
+
129
+ local cost=0
130
+ case "$provider" in
131
+ zai)
132
+ cost=$(safe_divide "$COST_ZAI" "1000000" 6) || return 1
133
+ cost=$(safe_arithmetic "$tokens * $cost") || return 1
134
+ ;;
135
+ kimi)
136
+ cost=$(safe_divide "$COST_KIMI" "1000000" 6) || return 1
137
+ cost=$(safe_arithmetic "$tokens * $cost") || return 1
138
+ ;;
139
+ openrouter)
140
+ cost=$(safe_divide "$COST_OPENROUTER" "1000000" 6) || return 1
141
+ cost=$(safe_arithmetic "$tokens * $cost") || return 1
142
+ ;;
143
+ anthropic)
144
+ cost=$(safe_divide "$COST_ANTHROPIC" "1000000" 6) || return 1
145
+ cost=$(safe_arithmetic "$tokens * $cost") || return 1
146
+ ;;
147
+ *)
148
+ cost=0
149
+ ;;
150
+ esac
151
+
152
+ echo "$cost"
153
+ }
154
+
155
+ # Extract label from container (sanitized for security)
156
+ # Returns: Sanitized label value or empty string if invalid/missing
157
+ get_container_label() {
158
+ local container_id=$1
159
+ local label=$2
160
+
161
+ # Get raw label value from Docker
162
+ local raw_label
163
+ raw_label=$(docker inspect "$container_id" --format="{{index .Config.Labels \"$label\" }}" 2>/dev/null || echo "")
164
+
165
+ # Return empty if no label found
166
+ if [ -z "$raw_label" ]; then
167
+ echo ""
168
+ return 0
169
+ fi
170
+
171
+ # Sanitize label to prevent injection attacks (CVSS 7.5 mitigation)
172
+ local sanitized_label
173
+ if sanitized_label=$(sanitize_label "$raw_label" 2>/dev/null); then
174
+ echo "$sanitized_label"
175
+ else
176
+ # Invalid label - log warning and return empty
177
+ log_warn "Invalid label value for '$label' in container $container_id (rejected for security)"
178
+ echo ""
179
+ fi
180
+ }
181
+
182
+ # Get running container stats
183
+ get_running_container_stats() {
184
+ docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" 2>/dev/null | tail -n +2 || true
185
+ }
186
+
187
+ # Get exited container stats (from docker history)
188
+ get_exited_container_stats() {
189
+ docker ps -a --filter "status=exited" --format "table {{.ID}}\t{{.Label \"team\"}}\t{{.Label \"project\"}}" 2>/dev/null | tail -n +2 || true
190
+ }
191
+
192
+ # Daily cost report
193
+ daily_report() {
194
+ local date=${1:-$(date +%Y-%m-%d)}
195
+
196
+ log_info "Generating daily cost report for: $date"
197
+
198
+ echo ""
199
+ echo "=========================================="
200
+ echo "Daily Cost Report: $date"
201
+ echo "=========================================="
202
+ echo ""
203
+
204
+ # Get all containers (running and exited)
205
+ local total_cost=0
206
+ local total_containers=0
207
+
208
+ # Process running containers
209
+ echo "Running Containers:"
210
+ echo "---"
211
+
212
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
213
+ # Clean up CPU and memory values
214
+ cpu=$(echo "$cpu" | sed 's/%$//')
215
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
216
+
217
+ local team=$(get_container_label "$container_id" "team")
218
+ local project=$(get_container_label "$container_id" "project")
219
+ local agent_type=$(get_container_label "$container_id" "agent-type")
220
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
221
+
222
+ if [ -z "$team" ]; then
223
+ continue
224
+ fi
225
+
226
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
227
+
228
+ printf "%-12s %-30s %-20s CPU:%-6s MEM:%-8s Cost: \$%.4f\n" \
229
+ "$team" "$project" "$agent_type" "$cpu%" "$mem" "$cost"
230
+
231
+ total_cost=$(echo "scale=6; $total_cost + $cost" | bc)
232
+ total_containers=$((total_containers + 1))
233
+ done
234
+
235
+ echo ""
236
+ echo "Summary:"
237
+ echo "--------"
238
+ echo "Total containers: $total_containers"
239
+ echo "Total cost: \$$(printf '%.2f' "$total_cost")"
240
+ echo ""
241
+ }
242
+
243
+ # Costs by team
244
+ by_team() {
245
+ local team=${1:-all}
246
+
247
+ log_info "Generating cost report by team"
248
+ echo ""
249
+
250
+ declare -A team_costs
251
+ declare -A team_counts
252
+
253
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
254
+ cpu=$(echo "$cpu" | sed 's/%$//')
255
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
256
+
257
+ local container_team=$(get_container_label "$container_id" "team")
258
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
259
+
260
+ if [ -z "$container_team" ]; then
261
+ continue
262
+ fi
263
+
264
+ if [ "$team" != "all" ] && [ "$container_team" != "$team" ]; then
265
+ continue
266
+ fi
267
+
268
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
269
+
270
+ team_costs["$container_team"]=$(echo "scale=6; ${team_costs[$container_team]:-0} + $cost" | bc)
271
+ team_counts["$container_team"]=$((${team_counts[$container_team]:-0} + 1))
272
+ done
273
+
274
+ echo "Team Cost Summary:"
275
+ echo "==================="
276
+ for t in "${!team_costs[@]}"; do
277
+ printf "%-20s: Count: %-3d Cost: \$%.2f\n" \
278
+ "$t" "${team_counts[$t]}" "${team_costs[$t]}"
279
+ done | sort -k4 -rn
280
+
281
+ echo ""
282
+ }
283
+
284
+ # Costs by project
285
+ by_project() {
286
+ local project=${1}
287
+
288
+ if [ -z "$project" ]; then
289
+ log_error "Project name required"
290
+ exit 1
291
+ fi
292
+
293
+ log_info "Generating cost report for project: $project"
294
+ echo ""
295
+
296
+ local total_cost=0
297
+ local count=0
298
+
299
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
300
+ cpu=$(echo "$cpu" | sed 's/%$//')
301
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
302
+
303
+ local container_project=$(get_container_label "$container_id" "project")
304
+ local team=$(get_container_label "$container_id" "team")
305
+ local agent_type=$(get_container_label "$container_id" "agent-type")
306
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
307
+
308
+ if [ "$container_project" != "$project" ]; then
309
+ continue
310
+ fi
311
+
312
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
313
+
314
+ printf "%-15s %-20s %-12s CPU:%-6s Cost: \$%.4f\n" \
315
+ "$team" "$agent_type" "$container_id" "$cpu%" "$cost"
316
+
317
+ total_cost=$(echo "scale=6; $total_cost + $cost" | bc)
318
+ count=$((count + 1))
319
+ done
320
+
321
+ echo ""
322
+ echo "Project Summary: $project"
323
+ echo "Containers: $count"
324
+ echo "Total cost: \$$(printf '%.2f' "$total_cost")"
325
+ echo ""
326
+ }
327
+
328
+ # Costs by agent type
329
+ by_agent() {
330
+ local agent_type=${1}
331
+
332
+ if [ -z "$agent_type" ]; then
333
+ log_error "Agent type required"
334
+ exit 1
335
+ fi
336
+
337
+ log_info "Generating cost report for agent: $agent_type"
338
+ echo ""
339
+
340
+ local total_cost=0
341
+ local count=0
342
+
343
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
344
+ cpu=$(echo "$cpu" | sed 's/%$//')
345
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
346
+
347
+ local container_agent=$(get_container_label "$container_id" "agent-type")
348
+ local team=$(get_container_label "$container_id" "team")
349
+ local project=$(get_container_label "$container_id" "project")
350
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
351
+
352
+ if [ "$container_agent" != "$agent_type" ]; then
353
+ continue
354
+ fi
355
+
356
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
357
+
358
+ printf "%-15s %-30s CPU:%-6s Cost: \$%.4f\n" \
359
+ "$team" "$project" "$cpu%" "$cost"
360
+
361
+ total_cost=$(echo "scale=6; $total_cost + $cost" | bc)
362
+ count=$((count + 1))
363
+ done
364
+
365
+ echo ""
366
+ echo "Agent Type Summary: $agent_type"
367
+ echo "Containers: $count"
368
+ echo "Total cost: \$$(printf '%.2f' "$total_cost")"
369
+ echo ""
370
+ }
371
+
372
+ # Find cost anomalies
373
+ anomalies() {
374
+ log_info "Finding high-cost containers"
375
+ echo ""
376
+
377
+ echo "Containers with cost > \$1.00:"
378
+ echo "=============================="
379
+
380
+ local found=0
381
+
382
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
383
+ cpu=$(echo "$cpu" | sed 's/%$//')
384
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
385
+
386
+ local team=$(get_container_label "$container_id" "team")
387
+ local project=$(get_container_label "$container_id" "project")
388
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
389
+
390
+ if [ -z "$team" ]; then
391
+ continue
392
+ fi
393
+
394
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
395
+
396
+ # Convert cost to number for comparison
397
+ if (( $(echo "$cost > 1.00" | bc -l) )); then
398
+ printf "\$%.2f %-15s %-30s (CPU: %s%%, MEM: %s MB)\n" \
399
+ "$cost" "$team" "$project" "$cpu" "$mem"
400
+ found=$((found + 1))
401
+ fi
402
+ done | sort -rn -k1
403
+
404
+ echo ""
405
+ if [ $found -eq 0 ]; then
406
+ log_success "No anomalies found (all costs < \$1.00)"
407
+ else
408
+ log_warn "Found $found containers with high costs"
409
+ fi
410
+ echo ""
411
+ }
412
+
413
+ # Cost forecast
414
+ forecast() {
415
+ local days=${1:-7}
416
+
417
+ log_info "Forecasting costs for next $days days"
418
+ echo ""
419
+
420
+ # Calculate average daily cost
421
+ local total_cost=0
422
+ local count=0
423
+
424
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
425
+ cpu=$(echo "$cpu" | sed 's/%$//')
426
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
427
+
428
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
429
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
430
+
431
+ total_cost=$(echo "scale=6; $total_cost + $cost" | bc)
432
+ count=$((count + 1))
433
+ done
434
+
435
+ if [ $count -eq 0 ]; then
436
+ log_warn "No running containers to forecast"
437
+ return
438
+ fi
439
+
440
+ local avg_daily_cost=$total_cost
441
+ local forecast_cost=$(echo "scale=2; $avg_daily_cost * $days" | bc)
442
+
443
+ echo "Cost Forecast:"
444
+ echo "=============="
445
+ echo "Current running containers: $count"
446
+ echo "Average daily cost: \$$(printf '%.2f' "$avg_daily_cost")"
447
+ echo "Forecasted ${days}-day cost: \$$(printf '%.2f' "$forecast_cost")"
448
+ echo ""
449
+ }
450
+
451
+ # Export to CSV
452
+ export_csv() {
453
+ local output_file=${1:-costs-$(date +%Y-%m-%d).csv}
454
+
455
+ log_info "Exporting costs to CSV: $output_file"
456
+
457
+ # CSV header
458
+ cat > "$output_file" <<EOF
459
+ Container ID,Team,Cost Center,Project,Agent Type,CPU %,Memory MB,Provider,Cost,Timestamp
460
+ EOF
461
+
462
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
463
+ cpu=$(echo "$cpu" | sed 's/%$//')
464
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
465
+
466
+ local team=$(get_container_label "$container_id" "team" || echo "unknown")
467
+ local cost_center=$(get_container_label "$container_id" "cost-center" || echo "unknown")
468
+ local project=$(get_container_label "$container_id" "project" || echo "unknown")
469
+ local agent_type=$(get_container_label "$container_id" "agent-type" || echo "unknown")
470
+ local provider=$(get_container_label "$container_id" "provider" || echo "zai")
471
+ local cost=$(calculate_container_cost "$container_id" "$cpu" "$mem" 3600 "$provider")
472
+
473
+ printf "%s,%s,%s,%s,%s,%.1f,%.0f,%s,%.6f,%s\n" \
474
+ "$container_id" "$team" "$cost_center" "$project" "$agent_type" \
475
+ "$cpu" "$mem" "$provider" "$cost" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$output_file"
476
+ done
477
+
478
+ log_success "Costs exported to: $output_file"
479
+ log_info "Total rows: $(tail -n +2 "$output_file" | wc -l)"
480
+ }
481
+
482
+ # Check quotas
483
+ quota_check() {
484
+ log_info "Checking team quotas"
485
+ echo ""
486
+
487
+ # Define team quotas
488
+ declare -A team_daily_budgets=(
489
+ [engineering]=500
490
+ [marketing]=200
491
+ [data]=1000
492
+ )
493
+
494
+ declare -A team_max_cpu=(
495
+ [engineering]=4
496
+ [marketing]=2
497
+ [data]=8
498
+ )
499
+
500
+ declare -A team_max_memory=(
501
+ [engineering]=16
502
+ [marketing]=8
503
+ [data]=32
504
+ )
505
+
506
+ echo "Quota Status:"
507
+ echo "============="
508
+
509
+ local overall_ok=true
510
+
511
+ get_running_container_stats | while IFS=$'\t' read -r container_id cpu mem; do
512
+ cpu=$(echo "$cpu" | sed 's/%$//')
513
+ mem=$(echo "$mem" | sed 's/MiB$//' | sed 's/GiB$//')
514
+
515
+ local team=$(get_container_label "$container_id" "team")
516
+
517
+ if [ -z "$team" ]; then
518
+ continue
519
+ fi
520
+
521
+ # Check per-container limits (assume quotas are per-container max)
522
+ local max_cpu=${team_max_cpu[$team]:-4}
523
+ local max_mem=${team_max_memory[$team]:-16}
524
+
525
+ if (( $(echo "$cpu > $max_cpu" | bc -l) )); then
526
+ log_warn "Team $team exceeded CPU quota: $cpu% > $max_cpu%"
527
+ overall_ok=false
528
+ fi
529
+
530
+ if (( $(echo "${mem%.*} > $max_mem" | bc -l) )); then
531
+ log_warn "Team $team exceeded memory quota: ${mem}GB > ${max_mem}GB"
532
+ overall_ok=false
533
+ fi
534
+ done
535
+
536
+ if [ "$overall_ok" = true ]; then
537
+ log_success "All teams within quotas"
538
+ else
539
+ log_warn "Some teams exceeding quotas - review above"
540
+ fi
541
+ echo ""
542
+ }
543
+
544
+ # Main command dispatcher
545
+ main() {
546
+ local command=${1:-help}
547
+
548
+ case "$command" in
549
+ daily-report)
550
+ daily_report "${2:-}"
551
+ ;;
552
+ by-team)
553
+ by_team "${2:-all}"
554
+ ;;
555
+ by-project)
556
+ by_project "${2:-}"
557
+ ;;
558
+ by-agent)
559
+ by_agent "${2:-}"
560
+ ;;
561
+ anomalies)
562
+ anomalies
563
+ ;;
564
+ forecast)
565
+ forecast "${2:-7}"
566
+ ;;
567
+ export-csv)
568
+ export_csv "${2:-}"
569
+ ;;
570
+ quota-check)
571
+ quota_check
572
+ ;;
573
+ help|--help|-h)
574
+ cat <<EOF
575
+ Cost Allocation and Tracking Tool
576
+
577
+ Usage: $(basename "$0") [command] [options]
578
+
579
+ Commands:
580
+ daily-report [date] Generate daily cost report
581
+ date: YYYY-MM-DD (default: today)
582
+
583
+ by-team [team] Show costs by team
584
+ team: team name or 'all' (default: all)
585
+
586
+ by-project <project> Show costs for specific project
587
+ project: project name (required)
588
+
589
+ by-agent <agent-type> Show costs by agent type
590
+ agent-type: agent type (required)
591
+
592
+ anomalies Find high-cost containers (> \$1.00/hour)
593
+
594
+ forecast [days] Project future costs
595
+ days: number of days to forecast (default: 7)
596
+
597
+ export-csv [file] Export costs to CSV file
598
+ file: output file (default: costs-YYYY-MM-DD.csv)
599
+
600
+ quota-check Verify team resource quotas
601
+
602
+ help Show this help message
603
+
604
+ Pricing Configuration:
605
+ CPU: \$$COST_CPU_PER_HOUR per core per hour
606
+ Memory: \$$COST_MEMORY_PER_GB_HOUR per GB per hour
607
+ API (Z.ai): \$$COST_ZAI per 1M tokens
608
+
609
+ Examples:
610
+ # Daily report for today
611
+ $(basename "$0") daily-report
612
+
613
+ # Show costs for engineering team
614
+ $(basename "$0") by-team engineering
615
+
616
+ # Find expensive containers
617
+ $(basename "$0") anomalies
618
+
619
+ # Export all costs to CSV
620
+ $(basename "$0") export-csv costs.csv
621
+
622
+ EOF
623
+ ;;
624
+ *)
625
+ log_error "Unknown command: $command"
626
+ echo "Run '$(basename "$0") help' for usage"
627
+ exit 1
628
+ ;;
629
+ esac
630
+ }
631
+
632
+ main "$@"
@@ -28,11 +28,11 @@ BUILD_START=$(date +%s)
28
28
 
29
29
  # 1. Base agent image (used by all variants)
30
30
  echo "📦 [1/4] Building claude-flow-novice-agent:latest"
31
- echo " Dockerfile: Dockerfile.agent"
31
+ echo " Dockerfile: docker/agent/Dockerfile"
32
32
  docker build \
33
33
  --progress=plain \
34
34
  --cache-from claude-flow-novice-agent:latest \
35
- -f Dockerfile.agent \
35
+ -f docker/agent/Dockerfile \
36
36
  -t claude-flow-novice-agent:latest \
37
37
  . || {
38
38
  echo "❌ Failed to build claude-flow-novice-agent:latest"