@pjmendonca/devflow 1.13.1 → 1.18.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.
- package/.claude/commands/agent.md +1 -1
- package/.claude/commands/bugfix.md +21 -0
- package/.claude/commands/checkpoint.md +0 -1
- package/.claude/commands/collab.md +0 -1
- package/.claude/commands/costs.md +88 -18
- package/.claude/commands/devflow.md +26 -0
- package/.claude/commands/handoff.md +0 -1
- package/.claude/commands/memory.md +0 -1
- package/.claude/commands/pair.md +0 -1
- package/.claude/commands/review.md +27 -0
- package/.claude/commands/route.md +0 -1
- package/.claude/commands/swarm.md +0 -1
- package/.claude/commands/validate.md +55 -0
- package/.claude/hooks/session-notification.sh +44 -0
- package/.claude/hooks/session-startup.sh +427 -0
- package/.claude/hooks/session-stop.sh +38 -0
- package/.claude/hooks/session_tracker.py +272 -0
- package/.claude/settings.json +38 -0
- package/.claude/skills/costs/SKILL.md +156 -0
- package/.claude/skills/validate/SKILL.md +101 -0
- package/CHANGELOG.md +254 -0
- package/README.md +207 -10
- package/bin/devflow-install.js +2 -1
- package/bin/devflow.js +5 -2
- package/lib/constants.js +0 -1
- package/lib/exec-python.js +1 -1
- package/package.json +1 -2
- package/tooling/.automation/.checkpoint_lock +1 -0
- package/tooling/.automation/agents/architect.md +19 -0
- package/tooling/.automation/agents/ba.md +19 -0
- package/tooling/.automation/agents/maintainer.md +19 -0
- package/tooling/.automation/agents/pm.md +19 -0
- package/tooling/.automation/agents/reviewer.md +1 -1
- package/tooling/.automation/agents/writer.md +19 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100119.json +314 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100216.json +314 -0
- package/tooling/.automation/costs/config.json +31 -0
- package/tooling/.automation/costs/sessions/2025-12-29_20251229_164128.json +22 -0
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +707 -1
- package/tooling/.automation/memory/knowledge/kg_test-story.json +3273 -2
- package/tooling/.automation/memory/shared/shared_integration-test.json +181 -1
- package/tooling/.automation/memory/shared/shared_test-story.json +721 -1
- package/tooling/.automation/memory/shared/shared_test.json +1254 -0
- package/tooling/.automation/memory/shared/shared_validation-check.json +227 -0
- package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +5 -5
- package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +23 -5
- package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +24 -6
- package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +4 -4
- package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +19 -1
- package/tooling/.automation/overrides/templates/dev/security-focused.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/user-advocate.yaml +54 -0
- package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/reliability-engineer.yaml +55 -0
- package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +3 -3
- package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +18 -0
- package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +18 -0
- package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +2 -2
- package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +3 -3
- package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +5 -5
- package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +4 -4
- package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +5 -5
- package/tooling/.automation/validation/history/2025-12-29_val_002a28c1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_01273bb1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_03369914.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_07a449ba.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_0df1f0a2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_10ff3d34.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_110771d7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_13f3a7f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_17ba9d21.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_22247089.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_227ea6a4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2335d5ae.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_246824bb.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_28b4b9cd.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2abd12cc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c801b2f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c8cfa8e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2ce76eb0.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30351948.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30eb7229.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_34df0e77.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_376e4d6a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3a4e8a1a.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3b77a628.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3ea4e1cf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_44aacdb4.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_457ddfa8.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_45af6238.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4735dba1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_486b203c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_49dc56cd.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4d863d6d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5149a808.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_52e0bb43.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_585d6319.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5b2d859a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_635a7081.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_64df4905.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_70634cee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_714553f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7f7bfdbf.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7faad91d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_81821f8f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8249f3c9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8422b50f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8446c134.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_879f4e26.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8b6d5bd7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8c5cd787.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_91d20bc7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_958a12b7.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_95d91108.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_980dbb74.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9e40c79b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f499b7c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f7c3b57.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a30d5bd4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a6eb09c7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a86f7b83.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ad5347e1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_b0a5a993.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bcb0192e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bf3c9aaa.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c461ff88.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c4f4e258.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c7f0fa6d.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c911b0e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cc581964.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cdd5a33b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cfd42495.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d1c7a4ee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2280d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2a6ff69.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d8c53ab2.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9c1247a.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9d58569.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dabb4fd9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dd8fe359.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_decdffc9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e3a95476.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e776dfca.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ea70969f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ef41ea95.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f384f9b1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f8adc38c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fa40b69e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fc538d54.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fe814665.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ffea4b12.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_02d001e5.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_0b8966dc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_15455fbf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_157e34b9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_28d1d933.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_3442a52c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_37f1ce1e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_4f1d8a93.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_56ff1de3.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_664fd4e2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_66afb0a7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_7634663c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_8ea830c3.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_998957c2.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a52177db.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a5b65a63.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ae391d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_c7895339.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ca416593.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_cee19422.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ddd4f4e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f2e1394b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f4a7fa06.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ffea3369.json +32 -0
- package/tooling/.automation/validation-config.yaml +103 -0
- package/tooling/completions/DevflowCompletion.ps1 +21 -21
- package/tooling/completions/_run-story +3 -3
- package/tooling/completions/run-story-completion.bash +8 -8
- package/tooling/docs/DOC-STANDARD.md +14 -14
- package/tooling/docs/templates/migration-spec.md +4 -4
- package/tooling/scripts/context_checkpoint.py +5 -15
- package/tooling/scripts/cost_dashboard.py +610 -13
- package/tooling/scripts/create-persona.py +1 -12
- package/tooling/scripts/create-persona.sh +44 -44
- package/tooling/scripts/lib/__init__.py +12 -1
- package/tooling/scripts/lib/agent_handoff.py +11 -2
- package/tooling/scripts/lib/agent_router.py +31 -10
- package/tooling/scripts/lib/colors.py +106 -0
- package/tooling/scripts/lib/context_monitor.py +766 -0
- package/tooling/scripts/lib/cost_config.py +229 -10
- package/tooling/scripts/lib/cost_display.py +20 -45
- package/tooling/scripts/lib/cost_tracker.py +462 -15
- package/tooling/scripts/lib/currency_converter.py +28 -5
- package/tooling/scripts/lib/pair_programming.py +102 -3
- package/tooling/scripts/lib/personality_system.py +949 -0
- package/tooling/scripts/lib/platform.py +55 -0
- package/tooling/scripts/lib/shared_memory.py +9 -3
- package/tooling/scripts/lib/swarm_orchestrator.py +514 -75
- package/tooling/scripts/lib/validation_loop.py +1014 -0
- package/tooling/scripts/memory_summarize.py +9 -2
- package/tooling/scripts/new-doc.py +2 -9
- package/tooling/scripts/personalize_agent.py +1 -12
- package/tooling/scripts/rollback-migration.sh +60 -60
- package/tooling/scripts/run-collab.ps1 +16 -16
- package/tooling/scripts/run-collab.py +88 -53
- package/tooling/scripts/run-collab.sh +4 -4
- package/tooling/scripts/run-story.py +278 -20
- package/tooling/scripts/run-story.sh +3 -3
- package/tooling/scripts/setup-checkpoint-service.py +2 -9
- package/tooling/scripts/tech-debt-tracker.py +1 -12
- package/tooling/scripts/test_adversarial_swarm.py +452 -0
- package/tooling/scripts/update_version.py +48 -2
- package/tooling/scripts/validate-overrides.py +1 -10
- package/tooling/scripts/validate-overrides.sh +40 -40
- package/tooling/scripts/validate_loop.py +162 -0
- package/tooling/scripts/validate_setup.py +2 -30
- package/.claude/skills/init/SKILL.md +0 -496
- package/bin/devflow-init.js +0 -10
- package/tooling/scripts/init-project-workflow.ps1 +0 -651
- package/tooling/scripts/init-project-workflow.py +0 -70
- package/tooling/scripts/init-project-workflow.sh +0 -746
|
@@ -80,42 +80,42 @@ info() {
|
|
|
80
80
|
# Check if file has valid YAML syntax using basic shell parsing
|
|
81
81
|
check_yaml_syntax() {
|
|
82
82
|
local file="$1"
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
# Check for common YAML syntax issues
|
|
85
85
|
local line_num=0
|
|
86
86
|
local in_list=false
|
|
87
87
|
local prev_indent=0
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
90
90
|
((line_num++))
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
# Skip empty lines and comments
|
|
93
93
|
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
# Check for tabs (YAML should use spaces)
|
|
96
96
|
if [[ "$line" == *$'\t'* ]]; then
|
|
97
97
|
error "Line $line_num: Contains tabs (use spaces instead)"
|
|
98
98
|
return 1
|
|
99
99
|
fi
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
# Check for trailing spaces
|
|
102
102
|
if [[ "$line" =~ [[:space:]]$ ]]; then
|
|
103
103
|
warning "Line $line_num: Trailing whitespace"
|
|
104
104
|
fi
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
# Check for unclosed quotes
|
|
107
107
|
local quote_count=$(echo "$line" | grep -o '"' | wc -l | tr -d ' ')
|
|
108
108
|
if [[ $((quote_count % 2)) -ne 0 ]]; then
|
|
109
109
|
error "Line $line_num: Unclosed double quote"
|
|
110
110
|
return 1
|
|
111
111
|
fi
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
local single_quote_count=$(echo "$line" | grep -o "'" | wc -l | tr -d ' ')
|
|
114
114
|
if [[ $((single_quote_count % 2)) -ne 0 ]]; then
|
|
115
115
|
error "Line $line_num: Unclosed single quote"
|
|
116
116
|
return 1
|
|
117
117
|
fi
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
# Check for proper colon spacing in key-value pairs
|
|
120
120
|
if [[ "$line" =~ ^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*:[^[:space:]] && ! "$line" =~ ^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*:$ ]]; then
|
|
121
121
|
# Allow for URLs and special cases
|
|
@@ -123,9 +123,9 @@ check_yaml_syntax() {
|
|
|
123
123
|
warning "Line $line_num: Missing space after colon"
|
|
124
124
|
fi
|
|
125
125
|
fi
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
done < "$file"
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
return 0
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -152,10 +152,10 @@ validate_override_file() {
|
|
|
152
152
|
local file="$1"
|
|
153
153
|
local filename=$(basename "$file")
|
|
154
154
|
local agent_name="${filename%.override.yaml}"
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
echo ""
|
|
157
157
|
echo -e "${BLUE}Validating:${NC} $filename"
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
# Check if corresponding agent exists
|
|
160
160
|
local agent_file="$AGENTS_DIR/${agent_name}.md"
|
|
161
161
|
if [[ ! -f "$agent_file" ]]; then
|
|
@@ -164,14 +164,14 @@ validate_override_file() {
|
|
|
164
164
|
else
|
|
165
165
|
info "Agent file found: ${agent_name}.md"
|
|
166
166
|
fi
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
# Check YAML syntax
|
|
169
169
|
if ! check_yaml_syntax "$file"; then
|
|
170
170
|
error "YAML syntax validation failed"
|
|
171
171
|
return 1
|
|
172
172
|
fi
|
|
173
173
|
success "YAML syntax is valid"
|
|
174
|
-
|
|
174
|
+
|
|
175
175
|
# Validate model override if present
|
|
176
176
|
local model=$(yaml_get "$file" "model")
|
|
177
177
|
if [[ -n "$model" ]]; then
|
|
@@ -182,14 +182,14 @@ validate_override_file() {
|
|
|
182
182
|
break
|
|
183
183
|
fi
|
|
184
184
|
done
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
if [[ "$valid" == "true" ]]; then
|
|
187
187
|
success "Model override is valid: $model"
|
|
188
188
|
else
|
|
189
189
|
error "Invalid model: '$model'. Valid options: ${VALID_MODELS[*]}"
|
|
190
190
|
fi
|
|
191
191
|
fi
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
# Validate budget override if present
|
|
194
194
|
local budget=$(yaml_get "$file" "max_budget_usd")
|
|
195
195
|
if [[ -n "$budget" ]]; then
|
|
@@ -206,56 +206,56 @@ validate_override_file() {
|
|
|
206
206
|
error "Invalid budget format: '$budget' (must be a number)"
|
|
207
207
|
fi
|
|
208
208
|
fi
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
# Check for additional_rules
|
|
211
211
|
if yaml_has_list "$file" "additional_rules"; then
|
|
212
212
|
local rule_count=$(awk '/^additional_rules:/{found=1; next} found && /^[[:space:]]*-/{count++} found && /^[a-zA-Z]/{exit} END{print count}' "$file")
|
|
213
213
|
success "Additional rules defined: ${rule_count:-0} rules"
|
|
214
214
|
fi
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
# Check for memories
|
|
217
217
|
if yaml_has_list "$file" "memories"; then
|
|
218
218
|
local memory_count=$(awk '/^memories:/{found=1; next} found && /^[[:space:]]*-/{count++} found && /^[a-zA-Z]/{exit} END{print count}' "$file")
|
|
219
219
|
success "Memories defined: ${memory_count:-0} items"
|
|
220
220
|
fi
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
# Check for critical_actions
|
|
223
223
|
if yaml_has_list "$file" "critical_actions"; then
|
|
224
224
|
local action_count=$(awk '/^critical_actions:/{found=1; next} found && /^[[:space:]]*-/{count++} found && /^[a-zA-Z]/{exit} END{print count}' "$file")
|
|
225
225
|
success "Critical actions defined: ${action_count:-0} actions"
|
|
226
226
|
fi
|
|
227
|
-
|
|
227
|
+
|
|
228
228
|
((VALIDATED++))
|
|
229
229
|
return 0
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
validate_user_profile() {
|
|
233
233
|
local file="$OVERRIDES_DIR/user-profile.yaml"
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
if [[ ! -f "$file" ]]; then
|
|
236
236
|
warning "No user-profile.yaml found"
|
|
237
237
|
return 0
|
|
238
238
|
fi
|
|
239
|
-
|
|
239
|
+
|
|
240
240
|
echo ""
|
|
241
241
|
echo -e "${BLUE}Validating:${NC} user-profile.yaml"
|
|
242
|
-
|
|
242
|
+
|
|
243
243
|
# Check YAML syntax
|
|
244
244
|
if ! check_yaml_syntax "$file"; then
|
|
245
245
|
error "YAML syntax validation failed"
|
|
246
246
|
return 1
|
|
247
247
|
fi
|
|
248
248
|
success "YAML syntax is valid"
|
|
249
|
-
|
|
249
|
+
|
|
250
250
|
# Check for user section
|
|
251
251
|
if grep -q "^user:" "$file"; then
|
|
252
252
|
success "User section found"
|
|
253
|
-
|
|
253
|
+
|
|
254
254
|
local name=$(grep -A10 "^user:" "$file" | grep "name:" | sed 's/.*name:[[:space:]]*//' | head -1)
|
|
255
255
|
if [[ -n "$name" && "$name" != "User" ]]; then
|
|
256
256
|
success "User name configured: $name"
|
|
257
257
|
fi
|
|
258
|
-
|
|
258
|
+
|
|
259
259
|
local level=$(grep -A10 "^user:" "$file" | grep "technical_level:" | sed 's/.*technical_level:[[:space:]]*//' | head -1)
|
|
260
260
|
if [[ -n "$level" ]]; then
|
|
261
261
|
local valid_levels=("beginner" "intermediate" "advanced" "expert")
|
|
@@ -266,7 +266,7 @@ validate_user_profile() {
|
|
|
266
266
|
break
|
|
267
267
|
fi
|
|
268
268
|
done
|
|
269
|
-
|
|
269
|
+
|
|
270
270
|
if [[ "$valid" == "true" ]]; then
|
|
271
271
|
success "Technical level: $level"
|
|
272
272
|
else
|
|
@@ -276,7 +276,7 @@ validate_user_profile() {
|
|
|
276
276
|
else
|
|
277
277
|
warning "No user section found in profile"
|
|
278
278
|
fi
|
|
279
|
-
|
|
279
|
+
|
|
280
280
|
((VALIDATED++))
|
|
281
281
|
return 0
|
|
282
282
|
}
|
|
@@ -305,13 +305,13 @@ auto_fix_file() {
|
|
|
305
305
|
local file="$1"
|
|
306
306
|
echo ""
|
|
307
307
|
echo -e "${YELLOW}Auto-fixing:${NC} $(basename "$file")"
|
|
308
|
-
|
|
308
|
+
|
|
309
309
|
# Backup original
|
|
310
310
|
cp "$file" "${file}.bak"
|
|
311
|
-
|
|
311
|
+
|
|
312
312
|
fix_trailing_whitespace "$file"
|
|
313
313
|
fix_tabs "$file"
|
|
314
|
-
|
|
314
|
+
|
|
315
315
|
# Remove backup if no changes
|
|
316
316
|
if diff -q "$file" "${file}.bak" > /dev/null 2>&1; then
|
|
317
317
|
rm "${file}.bak"
|
|
@@ -345,7 +345,7 @@ main() {
|
|
|
345
345
|
local target=""
|
|
346
346
|
local FIX_MODE=false
|
|
347
347
|
VERBOSE=false
|
|
348
|
-
|
|
348
|
+
|
|
349
349
|
# Parse arguments
|
|
350
350
|
while [[ $# -gt 0 ]]; do
|
|
351
351
|
case "$1" in
|
|
@@ -365,14 +365,14 @@ main() {
|
|
|
365
365
|
esac
|
|
366
366
|
shift
|
|
367
367
|
done
|
|
368
|
-
|
|
368
|
+
|
|
369
369
|
print_header
|
|
370
|
-
|
|
370
|
+
|
|
371
371
|
if [[ ! -d "$OVERRIDES_DIR" ]]; then
|
|
372
372
|
error "Overrides directory not found: $OVERRIDES_DIR"
|
|
373
373
|
exit 1
|
|
374
374
|
fi
|
|
375
|
-
|
|
375
|
+
|
|
376
376
|
if [[ -n "$target" ]]; then
|
|
377
377
|
# Validate specific override
|
|
378
378
|
local file="$OVERRIDES_DIR/${target}.override.yaml"
|
|
@@ -380,7 +380,7 @@ main() {
|
|
|
380
380
|
error "Override file not found: $file"
|
|
381
381
|
exit 1
|
|
382
382
|
fi
|
|
383
|
-
|
|
383
|
+
|
|
384
384
|
if [[ "$FIX_MODE" == "true" ]]; then
|
|
385
385
|
auto_fix_file "$file"
|
|
386
386
|
fi
|
|
@@ -388,13 +388,13 @@ main() {
|
|
|
388
388
|
else
|
|
389
389
|
# Validate all overrides
|
|
390
390
|
echo -e "${BLUE}Scanning:${NC} $OVERRIDES_DIR"
|
|
391
|
-
|
|
391
|
+
|
|
392
392
|
# Validate user profile first
|
|
393
393
|
if [[ "$FIX_MODE" == "true" && -f "$OVERRIDES_DIR/user-profile.yaml" ]]; then
|
|
394
394
|
auto_fix_file "$OVERRIDES_DIR/user-profile.yaml"
|
|
395
395
|
fi
|
|
396
396
|
validate_user_profile
|
|
397
|
-
|
|
397
|
+
|
|
398
398
|
# Validate all override files
|
|
399
399
|
for file in "$OVERRIDES_DIR"/*.override.yaml; do
|
|
400
400
|
if [[ -f "$file" ]]; then
|
|
@@ -405,7 +405,7 @@ main() {
|
|
|
405
405
|
fi
|
|
406
406
|
done
|
|
407
407
|
fi
|
|
408
|
-
|
|
408
|
+
|
|
409
409
|
# Summary
|
|
410
410
|
echo ""
|
|
411
411
|
echo -e "${CYAN}═══════════════════════════════════════════════════════════════${NC}"
|
|
@@ -416,7 +416,7 @@ main() {
|
|
|
416
416
|
echo -e " Errors: ${RED}$ERRORS${NC}"
|
|
417
417
|
echo -e " Warnings: ${YELLOW}$WARNINGS${NC}"
|
|
418
418
|
echo ""
|
|
419
|
-
|
|
419
|
+
|
|
420
420
|
if [[ $ERRORS -gt 0 ]]; then
|
|
421
421
|
echo -e "${RED} Validation failed with $ERRORS error(s)${NC}"
|
|
422
422
|
exit 1
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validation Loop CLI - Standalone validation runner for CI/CD and CLI usage.
|
|
4
|
+
|
|
5
|
+
Runs the three-tier validation system:
|
|
6
|
+
- Tier 1: Pre-flight (story exists, budget, dependencies)
|
|
7
|
+
- Tier 2: Inter-phase (code compiles, lint, transitions)
|
|
8
|
+
- Tier 3: Post-completion (tests, types, version sync)
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python validate_loop.py [options]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--story, -s Story key to validate
|
|
15
|
+
--tier, -t Validation tier (1, 2, 3) or omit for all
|
|
16
|
+
--all, -a Run all tiers
|
|
17
|
+
--auto-fix Attempt automatic fixes
|
|
18
|
+
--json Output as JSON
|
|
19
|
+
--quiet, -q Minimal output
|
|
20
|
+
--check Exit with non-zero if any failures (for CI)
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
python validate_loop.py --story 3-5 --tier 3
|
|
24
|
+
python validate_loop.py --all --json
|
|
25
|
+
python validate_loop.py --tier 3 --auto-fix --check
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import argparse
|
|
29
|
+
import json
|
|
30
|
+
import sys
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
|
|
33
|
+
# Add lib directory
|
|
34
|
+
SCRIPT_DIR = Path(__file__).parent
|
|
35
|
+
sys.path.insert(0, str(SCRIPT_DIR / "lib"))
|
|
36
|
+
|
|
37
|
+
from validation_loop import (
|
|
38
|
+
INTER_PHASE_GATES,
|
|
39
|
+
POST_COMPLETION_GATES,
|
|
40
|
+
PREFLIGHT_GATES,
|
|
41
|
+
LoopContext,
|
|
42
|
+
ValidationLoop,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def parse_args():
|
|
47
|
+
"""Parse command line arguments."""
|
|
48
|
+
parser = argparse.ArgumentParser(
|
|
49
|
+
description="Run validation loop checks",
|
|
50
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
51
|
+
epilog="""
|
|
52
|
+
Examples:
|
|
53
|
+
python validate_loop.py --story 3-5 --tier 3
|
|
54
|
+
python validate_loop.py --all --json
|
|
55
|
+
python validate_loop.py --tier 3 --auto-fix --check
|
|
56
|
+
""",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
parser.add_argument("--story", "-s", default="validation-check", help="Story key to validate")
|
|
60
|
+
parser.add_argument(
|
|
61
|
+
"--tier",
|
|
62
|
+
"-t",
|
|
63
|
+
type=int,
|
|
64
|
+
choices=[1, 2, 3],
|
|
65
|
+
help="Validation tier (1=preflight, 2=inter-phase, 3=post-completion)",
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument("--all", "-a", action="store_true", help="Run all tiers")
|
|
68
|
+
parser.add_argument("--auto-fix", action="store_true", help="Attempt automatic fixes")
|
|
69
|
+
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
70
|
+
parser.add_argument("--quiet", "-q", action="store_true", help="Minimal output")
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--check", action="store_true", help="Exit with non-zero if any failures (for CI)"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return parser.parse_args()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def run_tier(tier: int, story_key: str, auto_fix: bool, quiet: bool):
|
|
79
|
+
"""Run a specific validation tier."""
|
|
80
|
+
if tier == 1:
|
|
81
|
+
gates = PREFLIGHT_GATES
|
|
82
|
+
tier_name = "Pre-flight"
|
|
83
|
+
elif tier == 2:
|
|
84
|
+
gates = INTER_PHASE_GATES
|
|
85
|
+
tier_name = "Inter-phase"
|
|
86
|
+
else:
|
|
87
|
+
gates = POST_COMPLETION_GATES
|
|
88
|
+
tier_name = "Post-completion"
|
|
89
|
+
|
|
90
|
+
if not quiet:
|
|
91
|
+
print(f"\n[VALIDATION] Running {tier_name} checks (Tier {tier})...")
|
|
92
|
+
|
|
93
|
+
loop = ValidationLoop(
|
|
94
|
+
gates=gates,
|
|
95
|
+
config={"auto_fix_enabled": auto_fix},
|
|
96
|
+
story_key=story_key,
|
|
97
|
+
)
|
|
98
|
+
context = LoopContext(story_key=story_key, phase=f"tier_{tier}")
|
|
99
|
+
|
|
100
|
+
if tier == 1:
|
|
101
|
+
report = loop.run_preflight(context)
|
|
102
|
+
elif tier == 2:
|
|
103
|
+
report = loop.run_inter_phase(context)
|
|
104
|
+
else:
|
|
105
|
+
report = loop.run_post_completion(context)
|
|
106
|
+
|
|
107
|
+
return report
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def main():
|
|
111
|
+
args = parse_args()
|
|
112
|
+
|
|
113
|
+
reports = []
|
|
114
|
+
overall_passed = True
|
|
115
|
+
|
|
116
|
+
if args.all or args.tier is None:
|
|
117
|
+
# Run all tiers
|
|
118
|
+
for tier in [1, 2, 3]:
|
|
119
|
+
report = run_tier(tier, args.story, args.auto_fix, args.quiet)
|
|
120
|
+
reports.append(report)
|
|
121
|
+
if report.failed:
|
|
122
|
+
overall_passed = False
|
|
123
|
+
else:
|
|
124
|
+
# Run specific tier
|
|
125
|
+
report = run_tier(args.tier, args.story, args.auto_fix, args.quiet)
|
|
126
|
+
reports.append(report)
|
|
127
|
+
if report.failed:
|
|
128
|
+
overall_passed = False
|
|
129
|
+
|
|
130
|
+
# Output results
|
|
131
|
+
if args.json:
|
|
132
|
+
output = {
|
|
133
|
+
"story_key": args.story,
|
|
134
|
+
"overall_passed": overall_passed,
|
|
135
|
+
"reports": [r.to_dict() for r in reports],
|
|
136
|
+
}
|
|
137
|
+
print(json.dumps(output, indent=2))
|
|
138
|
+
elif not args.quiet:
|
|
139
|
+
print("\n" + "=" * 60)
|
|
140
|
+
print("VALIDATION SUMMARY")
|
|
141
|
+
print("=" * 60)
|
|
142
|
+
|
|
143
|
+
for report in reports:
|
|
144
|
+
print(f"\nTier {report.tier}: {report.overall_result.value.upper()}")
|
|
145
|
+
print(report.to_summary())
|
|
146
|
+
|
|
147
|
+
print("\n" + "=" * 60)
|
|
148
|
+
if overall_passed:
|
|
149
|
+
print("[PASS] All validation checks passed")
|
|
150
|
+
else:
|
|
151
|
+
print("[FAIL] Some validation checks failed")
|
|
152
|
+
print("=" * 60)
|
|
153
|
+
|
|
154
|
+
# Exit code for CI
|
|
155
|
+
if args.check:
|
|
156
|
+
sys.exit(0 if overall_passed else 1)
|
|
157
|
+
|
|
158
|
+
return 0 if overall_passed else 1
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
if __name__ == "__main__":
|
|
162
|
+
sys.exit(main())
|
|
@@ -24,6 +24,8 @@ from enum import Enum
|
|
|
24
24
|
from pathlib import Path
|
|
25
25
|
from typing import Optional
|
|
26
26
|
|
|
27
|
+
from lib.colors import Colors
|
|
28
|
+
|
|
27
29
|
|
|
28
30
|
class CheckStatus(Enum):
|
|
29
31
|
"""Status of a validation check."""
|
|
@@ -46,36 +48,6 @@ class CheckResult:
|
|
|
46
48
|
fix_command: Optional[str] = None
|
|
47
49
|
|
|
48
50
|
|
|
49
|
-
class Colors:
|
|
50
|
-
"""ANSI color codes."""
|
|
51
|
-
|
|
52
|
-
RESET = "\033[0m"
|
|
53
|
-
RED = "\033[31m"
|
|
54
|
-
GREEN = "\033[32m"
|
|
55
|
-
YELLOW = "\033[33m"
|
|
56
|
-
BLUE = "\033[34m"
|
|
57
|
-
CYAN = "\033[36m"
|
|
58
|
-
BOLD = "\033[1m"
|
|
59
|
-
DIM = "\033[2m"
|
|
60
|
-
|
|
61
|
-
@classmethod
|
|
62
|
-
def disable(cls):
|
|
63
|
-
"""Disable colors (for non-TTY output)."""
|
|
64
|
-
cls.RESET = ""
|
|
65
|
-
cls.RED = ""
|
|
66
|
-
cls.GREEN = ""
|
|
67
|
-
cls.YELLOW = ""
|
|
68
|
-
cls.BLUE = ""
|
|
69
|
-
cls.CYAN = ""
|
|
70
|
-
cls.BOLD = ""
|
|
71
|
-
cls.DIM = ""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Detect if running in non-TTY
|
|
75
|
-
if not sys.stdout.isatty():
|
|
76
|
-
Colors.disable()
|
|
77
|
-
|
|
78
|
-
|
|
79
51
|
# Project paths
|
|
80
52
|
SCRIPT_DIR = Path(__file__).parent
|
|
81
53
|
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|