ma-agents 3.2.0 → 3.4.0

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 (161) hide show
  1. package/.opencode/skills/.ma-agents.json +99 -99
  2. package/.roo/rules/00-ma-agents.md +13 -0
  3. package/.roo/skills/.ma-agents.json +241 -0
  4. package/.roo/skills/MANIFEST.yaml +254 -0
  5. package/.roo/skills/ai-audit-trail/SKILL.md +23 -0
  6. package/.roo/skills/auto-bug-detection/SKILL.md +169 -0
  7. package/.roo/skills/cmake-best-practices/SKILL.md +64 -0
  8. package/.roo/skills/cmake-best-practices/examples/cmake.md +59 -0
  9. package/.roo/skills/code-documentation/SKILL.md +57 -0
  10. package/.roo/skills/code-documentation/examples/cpp.md +29 -0
  11. package/.roo/skills/code-documentation/examples/csharp.md +28 -0
  12. package/.roo/skills/code-documentation/examples/javascript_typescript.md +28 -0
  13. package/.roo/skills/code-documentation/examples/python.md +57 -0
  14. package/.roo/skills/code-review/SKILL.md +43 -0
  15. package/.roo/skills/commit-message/SKILL.md +79 -0
  16. package/.roo/skills/cpp-best-practices/SKILL.md +234 -0
  17. package/.roo/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
  18. package/.roo/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
  19. package/.roo/skills/cpp-concurrency-safety/SKILL.md +60 -0
  20. package/.roo/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
  21. package/.roo/skills/cpp-const-correctness/SKILL.md +63 -0
  22. package/.roo/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
  23. package/.roo/skills/cpp-memory-handling/SKILL.md +42 -0
  24. package/.roo/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
  25. package/.roo/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
  26. package/.roo/skills/cpp-modern-composition/SKILL.md +64 -0
  27. package/.roo/skills/cpp-modern-composition/examples/composition.md +51 -0
  28. package/.roo/skills/cpp-robust-interfaces/SKILL.md +55 -0
  29. package/.roo/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
  30. package/.roo/skills/create-hardened-docker-skill/SKILL.md +637 -0
  31. package/.roo/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
  32. package/.roo/skills/csharp-best-practices/SKILL.md +278 -0
  33. package/.roo/skills/docker-hardening-verification/SKILL.md +28 -0
  34. package/.roo/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
  35. package/.roo/skills/docker-image-signing/SKILL.md +28 -0
  36. package/.roo/skills/docker-image-signing/scripts/sign-image.sh +33 -0
  37. package/.roo/skills/document-revision-history/SKILL.md +104 -0
  38. package/.roo/skills/git-workflow-skill/SKILL.md +194 -0
  39. package/.roo/skills/git-workflow-skill/hooks/commit-msg +61 -0
  40. package/.roo/skills/git-workflow-skill/hooks/pre-commit +38 -0
  41. package/.roo/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
  42. package/.roo/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
  43. package/.roo/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
  44. package/.roo/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
  45. package/.roo/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
  46. package/.roo/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
  47. package/.roo/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
  48. package/.roo/skills/js-ts-security-skill/SKILL.md +64 -0
  49. package/.roo/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
  50. package/.roo/skills/logging-best-practices/SKILL.md +50 -0
  51. package/.roo/skills/logging-best-practices/examples/cpp.md +36 -0
  52. package/.roo/skills/logging-best-practices/examples/csharp.md +49 -0
  53. package/.roo/skills/logging-best-practices/examples/javascript.md +77 -0
  54. package/.roo/skills/logging-best-practices/examples/python.md +57 -0
  55. package/.roo/skills/logging-best-practices/references/logging-standards.md +29 -0
  56. package/.roo/skills/open-presentation/SKILL.md +35 -0
  57. package/.roo/skills/opentelemetry-best-practices/SKILL.md +34 -0
  58. package/.roo/skills/opentelemetry-best-practices/examples/go.md +32 -0
  59. package/.roo/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
  60. package/.roo/skills/opentelemetry-best-practices/examples/python.md +37 -0
  61. package/.roo/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
  62. package/.roo/skills/python-best-practices/SKILL.md +385 -0
  63. package/.roo/skills/python-dependency-mgmt/SKILL.md +42 -0
  64. package/.roo/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
  65. package/.roo/skills/python-security-skill/SKILL.md +56 -0
  66. package/.roo/skills/python-security-skill/examples/security.md +56 -0
  67. package/.roo/skills/self-signed-cert/SKILL.md +42 -0
  68. package/.roo/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
  69. package/.roo/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
  70. package/.roo/skills/skill-creator/SKILL.md +196 -0
  71. package/.roo/skills/skill-creator/references/output-patterns.md +82 -0
  72. package/.roo/skills/skill-creator/references/workflows.md +28 -0
  73. package/.roo/skills/skill-creator/scripts/init_skill.py +208 -0
  74. package/.roo/skills/skill-creator/scripts/package_skill.py +99 -0
  75. package/.roo/skills/skill-creator/scripts/quick_validate.py +113 -0
  76. package/.roo/skills/story-status-lookup/SKILL.md +78 -0
  77. package/.roo/skills/test-accompanied-development/SKILL.md +50 -0
  78. package/.roo/skills/test-generator/SKILL.md +65 -0
  79. package/.roo/skills/vercel-react-best-practices/SKILL.md +109 -0
  80. package/.roo/skills/verify-hardened-docker-skill/SKILL.md +442 -0
  81. package/.roo/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
  82. package/README.md +21 -2
  83. package/bin/cli.js +55 -0
  84. package/lib/agents.js +46 -0
  85. package/lib/bmad-cache/cache-manifest.json +1 -1
  86. package/lib/bmad-customizations/bmm-demerzel.customize.yaml +36 -0
  87. package/lib/bmad-customizations/demerzel.md +32 -0
  88. package/lib/bmad-extension/module-help.csv +13 -0
  89. package/lib/bmad-extension/skills/bmad-ma-agent-ml/.gitkeep +0 -0
  90. package/lib/bmad-extension/skills/bmad-ma-agent-ml/SKILL.md +59 -0
  91. package/lib/bmad-extension/skills/bmad-ma-agent-ml/bmad-skill-manifest.yaml +11 -0
  92. package/lib/bmad-extension/skills/generate-backlog/.gitkeep +0 -0
  93. package/lib/bmad-extension/skills/ml-advise/.gitkeep +0 -0
  94. package/lib/bmad-extension/skills/ml-advise/SKILL.md +76 -0
  95. package/lib/bmad-extension/skills/ml-advise/bmad-skill-manifest.yaml +3 -0
  96. package/lib/bmad-extension/skills/ml-advise/skill.json +7 -0
  97. package/lib/bmad-extension/skills/ml-analysis/.gitkeep +0 -0
  98. package/lib/bmad-extension/skills/ml-analysis/SKILL.md +60 -0
  99. package/lib/bmad-extension/skills/ml-analysis/bmad-skill-manifest.yaml +3 -0
  100. package/lib/bmad-extension/skills/ml-analysis/skill.json +7 -0
  101. package/lib/bmad-extension/skills/ml-architecture/.gitkeep +0 -0
  102. package/lib/bmad-extension/skills/ml-architecture/SKILL.md +55 -0
  103. package/lib/bmad-extension/skills/ml-architecture/bmad-skill-manifest.yaml +3 -0
  104. package/lib/bmad-extension/skills/ml-architecture/skill.json +7 -0
  105. package/lib/bmad-extension/skills/ml-detailed-design/.gitkeep +0 -0
  106. package/lib/bmad-extension/skills/ml-detailed-design/SKILL.md +67 -0
  107. package/lib/bmad-extension/skills/ml-detailed-design/bmad-skill-manifest.yaml +3 -0
  108. package/lib/bmad-extension/skills/ml-detailed-design/skill.json +7 -0
  109. package/lib/bmad-extension/skills/ml-eda/.gitkeep +0 -0
  110. package/lib/bmad-extension/skills/ml-eda/SKILL.md +56 -0
  111. package/lib/bmad-extension/skills/ml-eda/bmad-skill-manifest.yaml +3 -0
  112. package/lib/bmad-extension/skills/ml-eda/scripts/baseline_classifier.py +522 -0
  113. package/lib/bmad-extension/skills/ml-eda/scripts/class_weights_calculator.py +295 -0
  114. package/lib/bmad-extension/skills/ml-eda/scripts/clustering_explorer.py +383 -0
  115. package/lib/bmad-extension/skills/ml-eda/scripts/eda_analyzer.py +654 -0
  116. package/lib/bmad-extension/skills/ml-eda/skill.json +7 -0
  117. package/lib/bmad-extension/skills/ml-experiment/.gitkeep +0 -0
  118. package/lib/bmad-extension/skills/ml-experiment/SKILL.md +74 -0
  119. package/lib/bmad-extension/skills/ml-experiment/assets/advanced_trainer_configs.py +430 -0
  120. package/lib/bmad-extension/skills/ml-experiment/assets/quick_trainer_setup.py +233 -0
  121. package/lib/bmad-extension/skills/ml-experiment/assets/template_datamodule.py +219 -0
  122. package/lib/bmad-extension/skills/ml-experiment/assets/template_gnn_module.py +341 -0
  123. package/lib/bmad-extension/skills/ml-experiment/assets/template_lightning_module.py +158 -0
  124. package/lib/bmad-extension/skills/ml-experiment/bmad-skill-manifest.yaml +3 -0
  125. package/lib/bmad-extension/skills/ml-experiment/skill.json +7 -0
  126. package/lib/bmad-extension/skills/ml-hparam/.gitkeep +0 -0
  127. package/lib/bmad-extension/skills/ml-hparam/SKILL.md +81 -0
  128. package/lib/bmad-extension/skills/ml-hparam/bmad-skill-manifest.yaml +3 -0
  129. package/lib/bmad-extension/skills/ml-hparam/skill.json +7 -0
  130. package/lib/bmad-extension/skills/ml-ideation/.gitkeep +0 -0
  131. package/lib/bmad-extension/skills/ml-ideation/SKILL.md +50 -0
  132. package/lib/bmad-extension/skills/ml-ideation/bmad-skill-manifest.yaml +3 -0
  133. package/lib/bmad-extension/skills/ml-ideation/scripts/validate_ml_prd.py +287 -0
  134. package/lib/bmad-extension/skills/ml-ideation/skill.json +7 -0
  135. package/lib/bmad-extension/skills/ml-infra/.gitkeep +0 -0
  136. package/lib/bmad-extension/skills/ml-infra/SKILL.md +58 -0
  137. package/lib/bmad-extension/skills/ml-infra/bmad-skill-manifest.yaml +3 -0
  138. package/lib/bmad-extension/skills/ml-infra/skill.json +7 -0
  139. package/lib/bmad-extension/skills/ml-retrospective/.gitkeep +0 -0
  140. package/lib/bmad-extension/skills/ml-retrospective/SKILL.md +63 -0
  141. package/lib/bmad-extension/skills/ml-retrospective/bmad-skill-manifest.yaml +3 -0
  142. package/lib/bmad-extension/skills/ml-retrospective/skill.json +7 -0
  143. package/lib/bmad-extension/skills/ml-revision/.gitkeep +0 -0
  144. package/lib/bmad-extension/skills/ml-revision/SKILL.md +82 -0
  145. package/lib/bmad-extension/skills/ml-revision/bmad-skill-manifest.yaml +3 -0
  146. package/lib/bmad-extension/skills/ml-revision/skill.json +7 -0
  147. package/lib/bmad-extension/skills/ml-techspec/.gitkeep +0 -0
  148. package/lib/bmad-extension/skills/ml-techspec/SKILL.md +80 -0
  149. package/lib/bmad-extension/skills/ml-techspec/bmad-skill-manifest.yaml +3 -0
  150. package/lib/bmad-extension/skills/ml-techspec/skill.json +7 -0
  151. package/lib/bmad.js +85 -8
  152. package/lib/skill-authoring.js +1 -1
  153. package/package.json +5 -4
  154. package/test/agent-injection-strategy.test.js +4 -4
  155. package/test/bmad-version-bump.test.js +34 -34
  156. package/test/build-bmad-args.test.js +13 -6
  157. package/test/convert-agents-to-skills.test.js +11 -1
  158. package/test/extension-module-restructure.test.js +31 -7
  159. package/test/migration-validation.test.js +14 -11
  160. package/test/roo-code-agent.test.js +166 -0
  161. package/test/roo-code-injection.test.js +172 -0
@@ -0,0 +1,439 @@
1
+ #!/bin/bash
2
+ #
3
+ # verify-docker-hardening.sh
4
+ # Comprehensive Docker security verification script
5
+ # Checks Dockerfile, docker-compose.yml, and running containers
6
+ # against CIS, OWASP, and NIST standards
7
+ #
8
+
9
+ set -e
10
+
11
+ # Colors for output
12
+ RED='\033[0;31m'
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ BLUE='\033[0;34m'
16
+ NC='\033[0m' # No Color
17
+
18
+ # Configuration
19
+ IMAGE_NAME="${1:-contacts-app}"
20
+ CONTAINER_NAME="${2:-contacts-app}"
21
+ EXIT_CODE=0
22
+
23
+ # Counters
24
+ TOTAL_CHECKS=0
25
+ PASSED_CHECKS=0
26
+ FAILED_CHECKS=0
27
+ WARNING_CHECKS=0
28
+
29
+ # Helper functions
30
+ print_header() {
31
+ echo ""
32
+ echo -e "${BLUE}========================================${NC}"
33
+ echo -e "${BLUE}$1${NC}"
34
+ echo -e "${BLUE}========================================${NC}"
35
+ }
36
+
37
+ print_check() {
38
+ TOTAL_CHECKS=$((TOTAL_CHECKS + 1))
39
+ echo -ne " [$TOTAL_CHECKS] $1... "
40
+ }
41
+
42
+ pass() {
43
+ PASSED_CHECKS=$((PASSED_CHECKS + 1))
44
+ echo -e "${GREEN}✅ PASS${NC}"
45
+ }
46
+
47
+ fail() {
48
+ FAILED_CHECKS=$((FAILED_CHECKS + 1))
49
+ EXIT_CODE=2
50
+ echo -e "${RED}❌ FAIL${NC}"
51
+ [ -n "$1" ] && echo -e " ${RED}→ $1${NC}"
52
+ }
53
+
54
+ warn() {
55
+ WARNING_CHECKS=$((WARNING_CHECKS + 1))
56
+ echo -e "${YELLOW}⚠️ WARN${NC}"
57
+ [ -n "$1" ] && echo -e " ${YELLOW}→ $1${NC}"
58
+ }
59
+
60
+ critical() {
61
+ FAILED_CHECKS=$((FAILED_CHECKS + 1))
62
+ EXIT_CODE=1
63
+ echo -e "${RED}🚨 CRITICAL${NC}"
64
+ [ -n "$1" ] && echo -e " ${RED}→ $1${NC}"
65
+ }
66
+
67
+ # Start verification
68
+ echo -e "${BLUE}🔍 Docker Security Verification${NC}"
69
+ echo -e "${BLUE}================================${NC}"
70
+ echo "Image: $IMAGE_NAME"
71
+ echo "Container: $CONTAINER_NAME"
72
+
73
+ # ============================================================================
74
+ # 1. Dockerfile Verification
75
+ # ============================================================================
76
+ print_header "1. Dockerfile Security"
77
+
78
+ if [ ! -f "Dockerfile" ]; then
79
+ print_check "Dockerfile exists"
80
+ critical "Dockerfile not found in current directory"
81
+ EXIT_CODE=5
82
+ exit $EXIT_CODE
83
+ fi
84
+
85
+ # Check for specific version tags
86
+ print_check "Specific version tags (no :latest)"
87
+ if grep -qE "^FROM.*:(latest|alpine)$" Dockerfile; then
88
+ fail "Using :latest or unversioned :alpine tag"
89
+ else
90
+ pass
91
+ fi
92
+
93
+ # Check for non-root user
94
+ print_check "Non-root user configured"
95
+ if grep -qE "^USER (root|[0-9]+)" Dockerfile; then
96
+ if grep -qE "^USER root" Dockerfile; then
97
+ fail "Running as root user"
98
+ else
99
+ pass
100
+ fi
101
+ elif grep -qE "^USER [a-zA-Z]" Dockerfile; then
102
+ pass
103
+ else
104
+ fail "No USER directive found"
105
+ fi
106
+
107
+ # Check for HEALTHCHECK
108
+ print_check "HEALTHCHECK instruction"
109
+ if grep -q "^HEALTHCHECK" Dockerfile; then
110
+ pass
111
+ else
112
+ warn "Missing HEALTHCHECK instruction"
113
+ fi
114
+
115
+ # Check for hardcoded secrets
116
+ print_check "No hardcoded secrets in ENV/ARG"
117
+ if grep -iE "^(ENV|ARG).*(SECRET|PASSWORD|KEY|TOKEN|CLIENT_ID)=" Dockerfile | grep -v "REACT_APP_API_BASE_URL" > /dev/null; then
118
+ fail "Potential hardcoded secrets found"
119
+ else
120
+ pass
121
+ fi
122
+
123
+ # Check for multi-stage build
124
+ print_check "Multi-stage build pattern"
125
+ if [ $(grep -c "^FROM" Dockerfile) -ge 2 ]; then
126
+ pass
127
+ else
128
+ warn "Not using multi-stage build"
129
+ fi
130
+
131
+ # Check for Alpine base images
132
+ print_check "Minimal Alpine base images"
133
+ if grep -qE "^FROM.*alpine" Dockerfile; then
134
+ pass
135
+ else
136
+ warn "Not using Alpine base images"
137
+ fi
138
+
139
+ # ============================================================================
140
+ # 2. docker-compose.yml Verification
141
+ # ============================================================================
142
+ print_header "2. docker-compose.yml Security"
143
+
144
+ if [ ! -f "docker-compose.yml" ]; then
145
+ print_check "docker-compose.yml exists"
146
+ warn "docker-compose.yml not found (optional)"
147
+ else
148
+ # Check for read-only filesystem
149
+ print_check "Read-only root filesystem"
150
+ if grep -q "read_only: true" docker-compose.yml; then
151
+ pass
152
+ else
153
+ fail "Missing read_only: true"
154
+ fi
155
+
156
+ # Check for no-new-privileges
157
+ print_check "No new privileges"
158
+ if grep -q "no-new-privileges:true" docker-compose.yml; then
159
+ pass
160
+ else
161
+ fail "Missing security_opt: no-new-privileges:true"
162
+ fi
163
+
164
+ # Check for capability dropping
165
+ print_check "Capabilities dropped"
166
+ if grep -q "cap_drop:" docker-compose.yml; then
167
+ pass
168
+ else
169
+ fail "Missing cap_drop configuration"
170
+ fi
171
+
172
+ # Check for tmpfs mounts
173
+ print_check "Tmpfs mounts for writable dirs"
174
+ if grep -q "tmpfs:" docker-compose.yml; then
175
+ pass
176
+ else
177
+ fail "Missing tmpfs mounts"
178
+ fi
179
+
180
+ # Check for resource limits
181
+ print_check "Memory limits configured"
182
+ if grep -q "memory:" docker-compose.yml; then
183
+ pass
184
+ else
185
+ warn "Missing memory limits"
186
+ fi
187
+
188
+ print_check "CPU limits configured"
189
+ if grep -q "cpus:" docker-compose.yml; then
190
+ pass
191
+ else
192
+ warn "Missing CPU limits"
193
+ fi
194
+
195
+ # Check for health check
196
+ print_check "Healthcheck configured"
197
+ if grep -q "healthcheck:" docker-compose.yml; then
198
+ pass
199
+ else
200
+ warn "Missing healthcheck configuration"
201
+ fi
202
+
203
+ # Check for privileged mode
204
+ print_check "Not running in privileged mode"
205
+ if grep -q "privileged: true" docker-compose.yml; then
206
+ critical "Running in privileged mode"
207
+ else
208
+ pass
209
+ fi
210
+ fi
211
+
212
+ # ============================================================================
213
+ # 3. .dockerignore Verification
214
+ # ============================================================================
215
+ print_header "3. .dockerignore Configuration"
216
+
217
+ if [ ! -f ".dockerignore" ]; then
218
+ print_check ".dockerignore exists"
219
+ warn ".dockerignore not found"
220
+ else
221
+ print_check ".env excluded from Docker context"
222
+ if grep -qE "^\.env$" .dockerignore; then
223
+ pass
224
+ else
225
+ critical ".env not in .dockerignore - secret leakage risk!"
226
+ fi
227
+
228
+ print_check "node_modules excluded"
229
+ if grep -q "node_modules" .dockerignore; then
230
+ pass
231
+ else
232
+ warn "node_modules not excluded"
233
+ fi
234
+
235
+ print_check ".git excluded"
236
+ if grep -qE "^\.git" .dockerignore; then
237
+ pass
238
+ else
239
+ warn ".git not excluded"
240
+ fi
241
+ fi
242
+
243
+ # ============================================================================
244
+ # 4. Image Security Scanning
245
+ # ============================================================================
246
+ print_header "4. Image Vulnerability Scanning"
247
+
248
+ # Check if image exists
249
+ if ! docker images --format "{{.Repository}}" | grep -q "^${IMAGE_NAME}$"; then
250
+ print_check "Docker image exists"
251
+ warn "Image '$IMAGE_NAME' not found locally. Skipping image scans."
252
+ echo " Run 'docker build -t $IMAGE_NAME .' to build the image."
253
+ else
254
+ # Check if trivy is installed
255
+ if ! command -v trivy &> /dev/null; then
256
+ print_check "Trivy scanner installed"
257
+ warn "Trivy not installed. Skipping vulnerability scans."
258
+ echo " Install: brew install aquasecurity/trivy/trivy (macOS)"
259
+ echo " : apt-get install trivy (Linux)"
260
+ else
261
+ # Scan for CRITICAL vulnerabilities
262
+ print_check "No CRITICAL vulnerabilities"
263
+ if trivy image --quiet --severity CRITICAL --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
264
+ pass
265
+ else
266
+ critical "CRITICAL vulnerabilities found. Run: trivy image --severity CRITICAL $IMAGE_NAME"
267
+ fi
268
+
269
+ # Scan for HIGH vulnerabilities
270
+ print_check "No HIGH vulnerabilities"
271
+ if trivy image --quiet --severity HIGH --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
272
+ pass
273
+ else
274
+ fail "HIGH vulnerabilities found. Run: trivy image --severity HIGH $IMAGE_NAME"
275
+ fi
276
+
277
+ # Scan for leaked secrets
278
+ print_check "No leaked secrets in image"
279
+ if trivy image --quiet --scanners secret --exit-code 1 "$IMAGE_NAME" > /dev/null 2>&1; then
280
+ pass
281
+ else
282
+ critical "Secrets detected in image! Run: trivy image --scanners secret $IMAGE_NAME"
283
+ fi
284
+ fi
285
+
286
+ # Check image size
287
+ print_check "Optimized image size (< 100MB)"
288
+ IMAGE_SIZE=$(docker images --format "{{.Size}}" "$IMAGE_NAME" | head -1 | sed 's/MB//' | sed 's/GB/*1024/' | bc 2>/dev/null || echo "0")
289
+ if [ -n "$IMAGE_SIZE" ] && [ "$IMAGE_SIZE" != "0" ]; then
290
+ if (( $(echo "$IMAGE_SIZE < 100" | bc -l) )); then
291
+ pass
292
+ else
293
+ warn "Image size is ${IMAGE_SIZE}MB (recommended < 100MB)"
294
+ fi
295
+ else
296
+ warn "Could not determine image size"
297
+ fi
298
+
299
+ # Check for .env in image
300
+ print_check ".env file not baked into image"
301
+ if docker run --rm "$IMAGE_NAME" sh -c "ls -la / 2>/dev/null | grep -q .env"; then
302
+ critical ".env file found in image! Secrets leaked!"
303
+ else
304
+ pass
305
+ fi
306
+ fi
307
+
308
+ # ============================================================================
309
+ # 5. Runtime Security (if container is running)
310
+ # ============================================================================
311
+ print_header "5. Runtime Security Verification"
312
+
313
+ if ! docker ps --filter "name=$CONTAINER_NAME" --format "{{.Names}}" | grep -q "^$CONTAINER_NAME$"; then
314
+ echo -e "${YELLOW} Container '$CONTAINER_NAME' is not running.${NC}"
315
+ echo -e "${YELLOW} Run 'docker-compose up -d' to enable runtime checks.${NC}"
316
+ else
317
+ # Check container runs as non-root
318
+ print_check "Container runs as non-root"
319
+ CONTAINER_USER=$(docker exec "$CONTAINER_NAME" whoami 2>/dev/null || echo "root")
320
+ if [ "$CONTAINER_USER" != "root" ]; then
321
+ pass
322
+ else
323
+ critical "Container running as root user!"
324
+ fi
325
+
326
+ # Check user ID is not 0
327
+ print_check "User ID is not 0 (root)"
328
+ USER_ID=$(docker exec "$CONTAINER_NAME" id -u 2>/dev/null || echo "0")
329
+ if [ "$USER_ID" != "0" ]; then
330
+ pass
331
+ else
332
+ critical "Container running with UID 0 (root)!"
333
+ fi
334
+
335
+ # Check read-only filesystem
336
+ print_check "Root filesystem is read-only"
337
+ if docker exec "$CONTAINER_NAME" sh -c "touch /test 2>/dev/null"; then
338
+ fail "Root filesystem is writable"
339
+ docker exec "$CONTAINER_NAME" sh -c "rm /test 2>/dev/null" || true
340
+ else
341
+ pass
342
+ fi
343
+
344
+ # Check tmpfs is writable
345
+ print_check "Tmpfs mount is writable"
346
+ if docker exec "$CONTAINER_NAME" sh -c "touch /tmp/test 2>/dev/null && rm /tmp/test 2>/dev/null"; then
347
+ pass
348
+ else
349
+ warn "Tmpfs mount /tmp is not writable"
350
+ fi
351
+
352
+ # Check health status
353
+ print_check "Container is healthy"
354
+ HEALTH_STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "none")
355
+ if [ "$HEALTH_STATUS" = "healthy" ]; then
356
+ pass
357
+ elif [ "$HEALTH_STATUS" = "none" ]; then
358
+ warn "No health check configured"
359
+ else
360
+ fail "Container health status: $HEALTH_STATUS"
361
+ fi
362
+
363
+ # Check capabilities
364
+ print_check "Capabilities dropped"
365
+ CAPS_DROPPED=$(docker inspect --format='{{.HostConfig.CapDrop}}' "$CONTAINER_NAME" 2>/dev/null || echo "[]")
366
+ if echo "$CAPS_DROPPED" | grep -q "ALL"; then
367
+ pass
368
+ else
369
+ warn "Not all capabilities dropped"
370
+ fi
371
+
372
+ # Check memory limit
373
+ print_check "Memory limit enforced"
374
+ MEMORY_LIMIT=$(docker inspect --format='{{.HostConfig.Memory}}' "$CONTAINER_NAME" 2>/dev/null || echo "0")
375
+ if [ "$MEMORY_LIMIT" != "0" ]; then
376
+ pass
377
+ else
378
+ warn "No memory limit set"
379
+ fi
380
+ fi
381
+
382
+ # ============================================================================
383
+ # 6. Git Secret Protection
384
+ # ============================================================================
385
+ print_header "6. Git Secret Protection"
386
+
387
+ if [ -d ".git" ]; then
388
+ # Check .env in .gitignore
389
+ print_check ".env in .gitignore"
390
+ if [ -f ".gitignore" ] && grep -qE "^\.env$" .gitignore; then
391
+ pass
392
+ else
393
+ critical ".env not in .gitignore! Secrets may be committed!"
394
+ fi
395
+
396
+ # Check .env.example exists
397
+ print_check ".env.example exists (template)"
398
+ if [ -f ".env.example" ]; then
399
+ pass
400
+ else
401
+ warn ".env.example not found"
402
+ fi
403
+
404
+ # Check if .env is committed
405
+ print_check ".env not committed to git"
406
+ if git ls-files --error-unmatch .env > /dev/null 2>&1; then
407
+ critical ".env is tracked by git! Remove immediately!"
408
+ else
409
+ pass
410
+ fi
411
+ else
412
+ echo -e "${YELLOW} Not a git repository. Skipping git checks.${NC}"
413
+ fi
414
+
415
+ # ============================================================================
416
+ # Summary
417
+ # ============================================================================
418
+ print_header "Verification Summary"
419
+
420
+ echo ""
421
+ echo " Total checks: $TOTAL_CHECKS"
422
+ echo -e " ${GREEN}Passed: $PASSED_CHECKS${NC}"
423
+ echo -e " ${YELLOW}Warnings: $WARNING_CHECKS${NC}"
424
+ echo -e " ${RED}Failed: $FAILED_CHECKS${NC}"
425
+ echo ""
426
+
427
+ if [ $FAILED_CHECKS -eq 0 ]; then
428
+ echo -e "${GREEN}✅ All critical security checks passed!${NC}"
429
+ if [ $WARNING_CHECKS -gt 0 ]; then
430
+ echo -e "${YELLOW}⚠️ $WARNING_CHECKS warning(s) - consider addressing these.${NC}"
431
+ fi
432
+ else
433
+ echo -e "${RED}❌ $FAILED_CHECKS security check(s) failed!${NC}"
434
+ echo -e "${RED} Please fix the issues above before deploying.${NC}"
435
+ fi
436
+
437
+ echo ""
438
+
439
+ exit $EXIT_CODE
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ma-agents
2
2
 
3
- A universal NPX tool to install AI coding agent skills. Write skills once, install them across Claude Code, Gemini, Copilot, Cline, Cursor, and Kilocode.
3
+ A universal NPX tool to install AI coding agent skills. Write skills once, install them across Claude Code, Gemini, Copilot, Cline, Cursor, Kilocode, and Roo Code.
4
4
 
5
5
  ## Installation & Usage
6
6
 
@@ -115,13 +115,15 @@ The file is version-controlled as part of `_bmad-output/` project knowledge. Com
115
115
  | Cursor | `.cursor/skills/` | `generic` | `.cursor/cursor.md` |
116
116
  | Kilocode | `.kilocode/skills/` | `generic` | `.kilocode/kilocode.md` |
117
117
  | Cline | `.cline/skills/` | `cline` | `.cline/clinerules.md` |
118
+ | Roo Code | `.roo/skills/` | `generic` | `.roo/rules/00-ma-agents.md` |
118
119
  | SRE Agent (Alex) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/sre.md` |
119
120
  | DevOps Agent (Amit) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/devops.md` |
120
121
  | Cyber Analyst (Yael) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/cyber.md` |
121
122
  | Joseph (MIL-STD-498) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/mil498.md` |
123
+ | Demerzel (ML Scientist) | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/demerzel.md` |
122
124
  | Antigravity | `_bmad/skills/` | `generic` | `_bmad/bmm/agents/antigravity.md` |
123
125
 
124
- ## Available Skills (34)
126
+ ## Available Skills (46)
125
127
 
126
128
  | Skill ID | Domain | Description |
127
129
  | :--- | :--- | :--- |
@@ -158,6 +160,19 @@ The file is version-controlled as part of `_bmad-output/` project knowledge. Com
158
160
  | `self-signed-cert` | Security | Automated Root CA and self-signed certificate generation |
159
161
  | `docker-image-signing` | Security | Automated cryptographic signing for Docker images |
160
162
  | `docker-hardening-verification` | Security | Audits images for least-privilege and OpenShift compatibility |
163
+ | **Machine Learning** | | |
164
+ | `ml-ideation` | Research | Frame ML research problem, define requirements, produce Research Thesis and PRD |
165
+ | `ml-eda` | Data Science | Exploratory Data Analysis, establish baselines, produce EDA report |
166
+ | `ml-architecture` | Design | Model architecture, stack, and experiment tracking strategy |
167
+ | `ml-detailed-design` | Tech Lead | Implementation task breakdown (INF-* and EXP-* namespaces) |
168
+ | `ml-techspec` | Contract | Lock experiment parameters and performance tiers before training |
169
+ | `ml-infra` | MLOps | Build ML infrastructure, manage dependencies, run smoke tests |
170
+ | `ml-experiment` | Developer | Execute training experiments against locked TechSpec, log metrics |
171
+ | `ml-analysis` | Evaluation | Evaluate experiment outcomes against TechSpec success tiers |
172
+ | `ml-hparam` | Tuning | Automated hyperparameter optimization (Optuna, W&B Sweeps, Ray Tune) |
173
+ | `ml-revision` | Iterative | Amend hypothesis and requirements based on experiment findings |
174
+ | `ml-advise` | Advisory | Search past experiments, surface findings and failure warnings |
175
+ | `ml-retrospective` | Meta | Capture session learnings and update project context |
161
176
  | **Sprint Management** | | |
162
177
  | `add-sprint` | Agile | Create sprint entities with capacity, ISO dates, and structured YAML schema |
163
178
  | `generate-backlog` | Agile | Generate or refresh a flat prioritized backlog from epics and bug stories |
@@ -245,6 +260,10 @@ npx ma-agents install --yes # fully offline BMAD install — no network neede
245
260
  - **Focus**: Technical standards compliance and military document generation.
246
261
  - **Capabilities**: Document Data Descriptions (DIDs), requirements traceability, and complex specification writing.
247
262
  - **Workflows**: SRS, SSS, and SSDD generation with strict structural validation.
263
+ 5. **Demerzel (ML Scientist)**:
264
+ - **Focus**: Hypothesis-driven machine learning lifecycle with scientific rigor.
265
+ - **Capabilities**: EDA, architecture design, locked TechSpec contracts, experiment execution, failure-cost analysis.
266
+ - **Workflows**: 12-stage ML lifecycle from ideation through retrospective, with mandatory review gates.
248
267
 
249
268
  #### Operational Workflows
250
269
  The integration includes a suite of specialized playbooks:
package/bin/cli.js CHANGED
@@ -13,6 +13,46 @@ const PKG = require('../package.json');
13
13
  const NAME = PKG.name;
14
14
  const VERSION = PKG.version;
15
15
 
16
+ /**
17
+ * Set up logging to tee all stdout/stderr output to a file.
18
+ * Returns a cleanup function to close the file descriptor.
19
+ *
20
+ * @param {string} logFilePath - Path to the log file
21
+ * @returns {Function} cleanup function
22
+ */
23
+ function setupLogging(logFilePath) {
24
+ const logFd = fs.openSync(logFilePath, 'w');
25
+ const header = `[${new Date().toISOString()}] ${NAME} v${VERSION} — log started\n`;
26
+ fs.writeSync(logFd, header);
27
+
28
+ const origStdoutWrite = process.stdout.write.bind(process.stdout);
29
+ const origStderrWrite = process.stderr.write.bind(process.stderr);
30
+
31
+ process.stdout.write = function (chunk, encoding, callback) {
32
+ const str = typeof chunk === 'string' ? chunk : chunk.toString();
33
+ try { fs.writeSync(logFd, str); } catch { /* ignore write errors */ }
34
+ return origStdoutWrite(chunk, encoding, callback);
35
+ };
36
+
37
+ process.stderr.write = function (chunk, encoding, callback) {
38
+ const str = typeof chunk === 'string' ? chunk : chunk.toString();
39
+ try { fs.writeSync(logFd, str); } catch { /* ignore write errors */ }
40
+ return origStderrWrite(chunk, encoding, callback);
41
+ };
42
+
43
+ // Store log fd globally so bmad.js can use pipe mode
44
+ process.env.MA_AGENTS_LOG_ACTIVE = '1';
45
+
46
+ return function cleanup() {
47
+ process.stdout.write = origStdoutWrite;
48
+ process.stderr.write = origStderrWrite;
49
+ const footer = `\n[${new Date().toISOString()}] log ended\n`;
50
+ try { fs.writeSync(logFd, footer); } catch { /* ignore */ }
51
+ try { fs.closeSync(logFd); } catch { /* ignore */ }
52
+ delete process.env.MA_AGENTS_LOG_ACTIVE;
53
+ };
54
+ }
55
+
16
56
  function showHelp() {
17
57
  console.log(`
18
58
  ${chalk.bold.cyan(NAME)} ${chalk.gray(`v${VERSION}`)}
@@ -40,6 +80,7 @@ ${chalk.bold('Install options:')}
40
80
  ${chalk.cyan('--force')} Skip upgrade prompts, always overwrite
41
81
  ${chalk.cyan('--yes')} Skip all prompts, use defaults (for CI/CD)
42
82
  ${chalk.cyan('--agent <name>')} Target a specific agent (skip agent selection)
83
+ ${chalk.cyan('--log')} Log all console output to install_<datetime>.log
43
84
 
44
85
  ${chalk.bold('Examples:')}
45
86
  npx ${NAME} install
@@ -1164,6 +1205,18 @@ async function interactiveMode() {
1164
1205
 
1165
1206
  async function main() {
1166
1207
  const args = process.argv.slice(2);
1208
+
1209
+ // Handle --log flag globally (before command routing)
1210
+ let cleanupLog = null;
1211
+ const logIdx = args.indexOf('--log');
1212
+ if (logIdx !== -1) {
1213
+ const ts = new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').replace('Z', '');
1214
+ const logFile = `install_${ts}.log`;
1215
+ cleanupLog = setupLogging(logFile);
1216
+ console.log(chalk.gray(` Logging to ${logFile}`));
1217
+ args.splice(logIdx, 1);
1218
+ }
1219
+
1167
1220
  const command = args[0];
1168
1221
 
1169
1222
  switch (command) {
@@ -1223,6 +1276,8 @@ async function main() {
1223
1276
  await interactiveMode();
1224
1277
  break;
1225
1278
  }
1279
+
1280
+ if (cleanupLog) cleanupLog();
1226
1281
  }
1227
1282
 
1228
1283
  if (require.main === module) {
package/lib/agents.js CHANGED
@@ -135,6 +135,29 @@ const agents = [
135
135
  instructionFiles: ['.cline/clinerules.md', '.clinerules'],
136
136
  injectionStrategy: { position: 'top', skipPatterns: ['---'] }
137
137
  },
138
+ {
139
+ id: 'roo-code',
140
+ name: 'Roo Code',
141
+ version: '1.0.0',
142
+ category: 'ide',
143
+ description: 'Roo Code AI Assistant (Enhanced Cline fork)',
144
+ skillsDir: '.roo/skills',
145
+ getProjectPath: () => path.join(process.cwd(), '.roo', 'skills'),
146
+ getGlobalPath: () => {
147
+ const platform = os.platform();
148
+ if (platform === 'win32') {
149
+ return path.join(os.homedir(), 'AppData', 'Roaming', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'skills');
150
+ } else if (platform === 'darwin') {
151
+ return path.join(os.homedir(), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'skills');
152
+ } else {
153
+ return path.join(os.homedir(), '.config', 'Code', 'User', 'globalStorage', 'rooveterinaryinc.roo-cline', 'skills');
154
+ }
155
+ },
156
+ fileExtension: '.md',
157
+ template: 'generic',
158
+ instructionFiles: ['.roo/rules/00-ma-agents.md'],
159
+ injectionStrategy: { position: 'top', skipPatterns: ['---'] }
160
+ },
138
161
  {
139
162
  id: 'cursor',
140
163
  name: 'Cursor',
@@ -295,6 +318,29 @@ const agents = [
295
318
  template: 'generic',
296
319
  instructionFiles: ['_bmad/bmm/agents/mil498.md'],
297
320
  injectionStrategy: { position: 'top', skipPatterns: ['---'] }
321
+ },
322
+ {
323
+ id: 'bmm-demerzel',
324
+ name: 'ML Scientist (Demerzel)',
325
+ version: '1.0.0',
326
+ category: 'bmad',
327
+ description: 'Machine Learning Lifecycle Agent (Demerzel)',
328
+ skillsDir: '_bmad/skills/demerzel',
329
+ getProjectPath: () => path.join(process.cwd(), '_bmad', 'skills', 'demerzel'),
330
+ getGlobalPath: () => {
331
+ const platform = os.platform();
332
+ if (platform === 'win32') {
333
+ return path.join(os.homedir(), 'AppData', 'Roaming', 'Demerzel', 'skills');
334
+ } else if (platform === 'darwin') {
335
+ return path.join(os.homedir(), 'Library', 'Application Support', 'Demerzel', 'skills');
336
+ } else {
337
+ return path.join(os.homedir(), '.config', 'demerzel', 'skills');
338
+ }
339
+ },
340
+ fileExtension: '.md',
341
+ template: 'generic',
342
+ instructionFiles: ['_bmad/bmm/agents/demerzel.md'],
343
+ injectionStrategy: { position: 'top', skipPatterns: ['---'] }
298
344
  }
299
345
  ];
300
346
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "generated": "2026-03-28T12:59:06.172Z",
3
- "bmadMethodVersion": "6.2.1",
3
+ "bmadMethodVersion": "6.2.2",
4
4
  "modules": {
5
5
  "bmb": {
6
6
  "url": "https://github.com/bmad-code-org/bmad-builder",
@@ -0,0 +1,36 @@
1
+ persona:
2
+ name: Demerzel
3
+ role: Machine Learning Scientist
4
+ alias: ML Scientist
5
+ description: Senior AI/ML Architect and Data Scientist specialized in falsifiable hypothesis validation and failure-cost analysis.
6
+
7
+ memories:
8
+ - "The scientific method: No modeling without EDA. No modeling without a locked TechSpec."
9
+ - "Dependency integrity: Always use uv for project reproducibility."
10
+ - "Failure Costs: A false negative for Class A costs the domain $50K."
11
+
12
+ critical_actions:
13
+ 1: "Perform ML Ideation using /ml-ideation"
14
+ 2: "Conduct EDA and publish Research Thesis using /ml-eda"
15
+ 3: "Design ML Architecture using /ml-architecture"
16
+ 4: "Lock experiment parameters in TechSpec using /ml-techspec"
17
+ 5: "Build ML Infrastructure using /ml-infra"
18
+ 6: "Execute training experiments using /ml-experiment"
19
+ 7: "Analyze experiment results against TechSpec using /ml-analysis"
20
+ 8: "Iterate hypothesis and documents using /ml-revision"
21
+ 9: "Consult previous findings using /ml-advise"
22
+ 10: "Capture session learnings with /ml-retrospective"
23
+
24
+ skills:
25
+ - ml-ideation
26
+ - ml-eda
27
+ - ml-architecture
28
+ - ml-detailed-design
29
+ - ml-techspec
30
+ - ml-infra
31
+ - ml-experiment
32
+ - ml-analysis
33
+ - ml-hparam
34
+ - ml-revision
35
+ - ml-advise
36
+ - ml-retrospective