@the-bearded-bear/claude-craft 8.26.0 → 8.27.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/Dev/i18n/base/Common/commands/aliases.md +48 -48
- package/Dev/i18n/base/Common/skills/sub-agents-patterns/SKILL.md +1 -0
- package/Dev/i18n/de/Common/agents/devops-engineer.md +19 -14
- package/Dev/i18n/de/Common/agents/migration-specialist.md +10 -15
- package/Dev/i18n/de/Common/agents/mlops-engineer.md +19 -15
- package/Dev/i18n/de/Common/agents/ralph-conductor.md +4 -15
- package/Dev/i18n/de/Common/agents/refactoring-specialist.md +0 -9
- package/Dev/i18n/de/Common/agents/tdd-coach.md +0 -9
- package/Dev/i18n/de/Common/agents/uiux-orchestrator.md +0 -9
- package/Dev/i18n/de/Common/commands/ralph-run.md +52 -0
- package/Dev/i18n/de/Common/commands/research-context7.md +5 -253
- package/Dev/i18n/de/Common/rules/12-context-management.md +10 -8
- package/Dev/i18n/de/Common/templates/settings.json.template +4 -0
- package/Dev/i18n/de/Python/skills/coding-standards/SKILL.md +1 -1
- package/Dev/i18n/de/Python/skills/testing-python/SKILL.md +1 -1
- package/Dev/i18n/de/Python/skills/tooling/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/commands/check-security.md +20 -20
- package/Dev/i18n/de/Symfony/skills/aggregates/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/async/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/cqrs/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/domain-events/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/i18n/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/multitenant/SKILL.md +1 -1
- package/Dev/i18n/de/Symfony/skills/value-objects/SKILL.md +1 -1
- package/Dev/i18n/de/Team/commands/audit.md +29 -4
- package/Dev/i18n/de/Team/commands/delivery.md +29 -4
- package/Dev/i18n/de/Team/commands/security.md +31 -4
- package/Dev/i18n/de/Team/commands/sprint.md +30 -5
- package/Dev/i18n/de/UIUX/commands/audit.md +1 -30
- package/Dev/i18n/de/UIUX/commands/component-spec.md +1 -5
- package/Dev/i18n/de/UIUX/commands/orchestrator.md +5 -98
- package/Dev/i18n/de/Workflow/commands/auto-sprint.md +7 -4
- package/Dev/i18n/de/Workflow/commands/plan.md +1 -2
- package/Dev/i18n/en/Common/agents/devops-engineer.md +19 -14
- package/Dev/i18n/en/Common/agents/migration-specialist.md +10 -15
- package/Dev/i18n/en/Common/agents/mlops-engineer.md +19 -15
- package/Dev/i18n/en/Common/agents/ralph-conductor.md +4 -15
- package/Dev/i18n/en/Common/agents/refactoring-specialist.md +0 -9
- package/Dev/i18n/en/Common/agents/tdd-coach.md +0 -9
- package/Dev/i18n/en/Common/agents/uiux-orchestrator.md +0 -9
- package/Dev/i18n/en/Common/commands/ralph-run.md +52 -0
- package/Dev/i18n/en/Common/commands/research-context7.md +5 -253
- package/Dev/i18n/en/Common/rules/12-context-management.md +12 -10
- package/Dev/i18n/en/Common/templates/settings.json.template +4 -0
- package/Dev/i18n/en/Python/skills/coding-standards/SKILL.md +1 -1
- package/Dev/i18n/en/Python/skills/testing-python/SKILL.md +1 -1
- package/Dev/i18n/en/Python/skills/tooling/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/commands/check-security.md +20 -20
- package/Dev/i18n/en/Symfony/skills/aggregates/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/async/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/cqrs/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/domain-events/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/i18n/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/multitenant/SKILL.md +1 -1
- package/Dev/i18n/en/Symfony/skills/value-objects/SKILL.md +1 -1
- package/Dev/i18n/en/Team/commands/audit.md +29 -4
- package/Dev/i18n/en/Team/commands/delivery.md +29 -4
- package/Dev/i18n/en/Team/commands/security.md +31 -4
- package/Dev/i18n/en/Team/commands/sprint.md +30 -5
- package/Dev/i18n/en/UIUX/commands/audit.md +1 -30
- package/Dev/i18n/en/UIUX/commands/component-spec.md +1 -5
- package/Dev/i18n/en/UIUX/commands/orchestrator.md +5 -98
- package/Dev/i18n/en/Workflow/commands/auto-sprint.md +7 -4
- package/Dev/i18n/en/Workflow/commands/plan.md +1 -2
- package/Dev/i18n/es/Common/agents/devops-engineer.md +19 -14
- package/Dev/i18n/es/Common/agents/migration-specialist.md +10 -15
- package/Dev/i18n/es/Common/agents/mlops-engineer.md +19 -15
- package/Dev/i18n/es/Common/agents/ralph-conductor.md +4 -15
- package/Dev/i18n/es/Common/agents/refactoring-specialist.md +0 -9
- package/Dev/i18n/es/Common/agents/tdd-coach.md +0 -9
- package/Dev/i18n/es/Common/agents/uiux-orchestrator.md +0 -9
- package/Dev/i18n/es/Common/commands/ralph-run.md +52 -0
- package/Dev/i18n/es/Common/commands/research-context7.md +5 -253
- package/Dev/i18n/es/Common/rules/12-context-management.md +9 -7
- package/Dev/i18n/es/Common/templates/settings.json.template +4 -0
- package/Dev/i18n/es/Python/skills/coding-standards/SKILL.md +1 -1
- package/Dev/i18n/es/Python/skills/testing-python/SKILL.md +1 -1
- package/Dev/i18n/es/Python/skills/tooling/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/commands/check-security.md +20 -20
- package/Dev/i18n/es/Symfony/skills/aggregates/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/async/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/cqrs/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/domain-events/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/i18n/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/multitenant/SKILL.md +1 -1
- package/Dev/i18n/es/Symfony/skills/value-objects/SKILL.md +1 -1
- package/Dev/i18n/es/Team/commands/audit.md +29 -4
- package/Dev/i18n/es/Team/commands/delivery.md +29 -4
- package/Dev/i18n/es/Team/commands/security.md +31 -4
- package/Dev/i18n/es/Team/commands/sprint.md +30 -5
- package/Dev/i18n/es/UIUX/commands/audit.md +1 -30
- package/Dev/i18n/es/UIUX/commands/component-spec.md +1 -5
- package/Dev/i18n/es/UIUX/commands/orchestrator.md +5 -98
- package/Dev/i18n/es/Workflow/commands/auto-sprint.md +7 -4
- package/Dev/i18n/es/Workflow/commands/plan.md +1 -2
- package/Dev/i18n/fr/Common/agents/devops-engineer.md +19 -14
- package/Dev/i18n/fr/Common/agents/migration-specialist.md +10 -15
- package/Dev/i18n/fr/Common/agents/mlops-engineer.md +19 -15
- package/Dev/i18n/fr/Common/agents/ralph-conductor.md +4 -15
- package/Dev/i18n/fr/Common/agents/refactoring-specialist.md +0 -9
- package/Dev/i18n/fr/Common/agents/tdd-coach.md +0 -9
- package/Dev/i18n/fr/Common/agents/uiux-orchestrator.md +0 -9
- package/Dev/i18n/fr/Common/commands/ralph-run.md +52 -0
- package/Dev/i18n/fr/Common/commands/research-context7.md +5 -253
- package/Dev/i18n/fr/Common/rules/12-context-management.md +10 -8
- package/Dev/i18n/fr/Common/templates/settings.json.template +4 -0
- package/Dev/i18n/fr/React/commands/check-compliance.md +1 -1
- package/Dev/i18n/fr/React/commands/check-security.md +2 -2
- package/Dev/i18n/fr/Symfony/commands/check-security.md +20 -20
- package/Dev/i18n/fr/Symfony/skills/aggregates/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/async/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/cqrs/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/domain-events/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/i18n/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/multitenant/SKILL.md +1 -1
- package/Dev/i18n/fr/Symfony/skills/value-objects/SKILL.md +1 -1
- package/Dev/i18n/fr/Team/commands/audit.md +29 -4
- package/Dev/i18n/fr/Team/commands/delivery.md +29 -4
- package/Dev/i18n/fr/Team/commands/security.md +31 -4
- package/Dev/i18n/fr/Team/commands/sprint.md +30 -5
- package/Dev/i18n/fr/UIUX/commands/audit.md +1 -30
- package/Dev/i18n/fr/UIUX/commands/component-spec.md +1 -5
- package/Dev/i18n/fr/UIUX/commands/orchestrator.md +5 -98
- package/Dev/i18n/fr/Workflow/commands/auto-sprint.md +7 -4
- package/Dev/i18n/fr/Workflow/commands/plan.md +1 -2
- package/Dev/i18n/pt/Common/agents/devops-engineer.md +19 -14
- package/Dev/i18n/pt/Common/agents/migration-specialist.md +10 -15
- package/Dev/i18n/pt/Common/agents/mlops-engineer.md +19 -15
- package/Dev/i18n/pt/Common/agents/ralph-conductor.md +4 -15
- package/Dev/i18n/pt/Common/agents/refactoring-specialist.md +0 -9
- package/Dev/i18n/pt/Common/agents/tdd-coach.md +0 -9
- package/Dev/i18n/pt/Common/agents/uiux-orchestrator.md +0 -9
- package/Dev/i18n/pt/Common/commands/ralph-run.md +52 -0
- package/Dev/i18n/pt/Common/commands/research-context7.md +5 -253
- package/Dev/i18n/pt/Common/rules/12-context-management.md +9 -7
- package/Dev/i18n/pt/Common/templates/settings.json.template +4 -0
- package/Dev/i18n/pt/Python/skills/coding-standards/SKILL.md +1 -1
- package/Dev/i18n/pt/Python/skills/testing-python/SKILL.md +1 -1
- package/Dev/i18n/pt/Python/skills/tooling/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/commands/check-security.md +20 -20
- package/Dev/i18n/pt/Symfony/skills/aggregates/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/async/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/cqrs/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/domain-events/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/i18n/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/multitenant/SKILL.md +1 -1
- package/Dev/i18n/pt/Symfony/skills/value-objects/SKILL.md +1 -1
- package/Dev/i18n/pt/Team/commands/audit.md +29 -4
- package/Dev/i18n/pt/Team/commands/delivery.md +29 -4
- package/Dev/i18n/pt/Team/commands/security.md +31 -4
- package/Dev/i18n/pt/Team/commands/sprint.md +30 -5
- package/Dev/i18n/pt/UIUX/commands/audit.md +1 -30
- package/Dev/i18n/pt/UIUX/commands/component-spec.md +1 -5
- package/Dev/i18n/pt/UIUX/commands/orchestrator.md +5 -98
- package/Dev/i18n/pt/Workflow/commands/auto-sprint.md +7 -4
- package/Dev/i18n/pt/Workflow/commands/plan.md +1 -2
- package/Dev/scripts/install-common-rules.sh +8 -0
- package/README.md +12 -8
- package/Tools/Ralph/lib/checkpoint.sh +3 -3
- package/Tools/Ralph/lib/circuit-breaker.sh +10 -10
- package/Tools/Ralph/lib/context-manager.sh +56 -65
- package/Tools/Ralph/lib/context-reconstruction.sh +46 -79
- package/Tools/Ralph/lib/dod-templates.sh +2 -2
- package/Tools/Ralph/lib/dod-validator.sh +18 -18
- package/Tools/Ralph/lib/escalation-service.sh +9 -7
- package/Tools/Ralph/lib/hooks-generator.sh +2 -1
- package/Tools/Ralph/lib/loop-finalizer.sh +1 -1
- package/Tools/Ralph/lib/loop.sh +44 -10
- package/Tools/Ralph/lib/metrics-exporter.sh +1 -1
- package/Tools/Ralph/lib/parallel-manager.sh +173 -88
- package/Tools/Ralph/lib/project-detector.sh +3 -3
- package/Tools/Ralph/lib/recovery-engine.sh +8 -8
- package/Tools/Ralph/lib/session.sh +2 -2
- package/Tools/Ralph/lib/sprint-conductor.sh +167 -124
- package/Tools/Ralph/lib/sprint-progress.sh +9 -9
- package/Tools/Ralph/ralph.sh +66 -38
- package/Tools/StatusLine/statusline.sh +0 -0
- package/Tools/i18n/ralph/de.sh +165 -33
- package/Tools/i18n/ralph/en.sh +132 -0
- package/Tools/i18n/ralph/es.sh +209 -77
- package/Tools/i18n/ralph/fr.sh +234 -102
- package/Tools/i18n/ralph/pt.sh +227 -95
- package/bundles/cursor/.cursorrules +3 -3
- package/bundles/windsurf/.windsurfrules +3 -3
- package/cli/lib/doctor.js +1 -1
- package/config/removed-commands.yaml +61 -1
- package/package.json +1 -1
|
@@ -129,7 +129,7 @@ EOF
|
|
|
129
129
|
PARALLEL_MAX_CONCURRENT="$ASC_PARALLEL_MAX"
|
|
130
130
|
init_parallel_manager
|
|
131
131
|
else
|
|
132
|
-
print_warning "Parallel manager not available, falling back to sequential"
|
|
132
|
+
print_warning "$(asc_msg MSG_ASC_NO_PARALLEL_MANAGER "Parallel manager not available, falling back to sequential")"
|
|
133
133
|
ASC_PARALLEL_ENABLED="false"
|
|
134
134
|
fi
|
|
135
135
|
fi
|
|
@@ -139,14 +139,14 @@ EOF
|
|
|
139
139
|
enable_autonomous_mode
|
|
140
140
|
fi
|
|
141
141
|
|
|
142
|
-
log_conductor "Initialized Sprint Conductor"
|
|
143
|
-
log_conductor " Session: $ASC_SESSION_ID"
|
|
144
|
-
log_conductor " Mode: $ASC_MODE"
|
|
145
|
-
log_conductor " Max stories: $ASC_MAX_STORIES"
|
|
146
|
-
log_conductor " Max runtime:
|
|
147
|
-
log_conductor " Parallel:
|
|
142
|
+
log_conductor "$(asc_msg MSG_ASC_INITIALIZED "Initialized Sprint Conductor")"
|
|
143
|
+
log_conductor "$(asc_msg MSG_ASC_INIT_SESSION " Session: {0}" "$ASC_SESSION_ID")"
|
|
144
|
+
log_conductor "$(asc_msg MSG_ASC_INIT_MODE " Mode: {0}" "$ASC_MODE")"
|
|
145
|
+
log_conductor "$(asc_msg MSG_ASC_INIT_MAX_STORIES " Max stories: {0}" "$ASC_MAX_STORIES")"
|
|
146
|
+
log_conductor "$(asc_msg MSG_ASC_INIT_MAX_RUNTIME " Max runtime: {0}h" "$ASC_MAX_RUNTIME_HOURS")"
|
|
147
|
+
log_conductor "$(asc_msg MSG_ASC_INIT_PARALLEL " Parallel: {0} (max {1})" "$ASC_PARALLEL_ENABLED" "$ASC_PARALLEL_MAX")"
|
|
148
148
|
|
|
149
|
-
print_info "Sprint Conductor initialized: $ASC_SESSION_ID"
|
|
149
|
+
print_info "$(asc_msg MSG_ASC_INITIALIZED_ID "Sprint Conductor initialized: {0}" "$ASC_SESSION_ID")"
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
# =============================================================================
|
|
@@ -164,7 +164,7 @@ run_sprint_conductor() {
|
|
|
164
164
|
[[ "$overnight" == "true" ]] && ASC_MODE="bounded"
|
|
165
165
|
[[ "$supervised" == "true" ]] && ASC_MODE="supervised"
|
|
166
166
|
|
|
167
|
-
log_conductor "Starting sprint conductor for:
|
|
167
|
+
log_conductor "$(asc_msg MSG_ASC_STARTING "Starting sprint conductor for: {0} (mode: {1})" "$sprint_name" "$ASC_MODE")"
|
|
168
168
|
|
|
169
169
|
# Use parallel or sequential execution based on configuration
|
|
170
170
|
if [[ "$ASC_PARALLEL_ENABLED" == "true" ]] && type process_stories_parallel &>/dev/null; then
|
|
@@ -184,20 +184,20 @@ run_sprint_conductor() {
|
|
|
184
184
|
run_sprint_conductor_parallel() {
|
|
185
185
|
local sprint_name="$1"
|
|
186
186
|
|
|
187
|
-
log_conductor "Running in PARALLEL mode (max
|
|
187
|
+
log_conductor "$(asc_msg MSG_ASC_PARALLEL_MODE "Running in PARALLEL mode (max {0} concurrent)" "$ASC_PARALLEL_MAX")"
|
|
188
188
|
|
|
189
189
|
# Get all stories for the sprint
|
|
190
190
|
local all_stories
|
|
191
191
|
all_stories=$(get_all_ready_stories)
|
|
192
192
|
|
|
193
193
|
if [[ -z "$all_stories" ]]; then
|
|
194
|
-
log_conductor "No stories available for parallel processing"
|
|
194
|
+
log_conductor "$(asc_msg MSG_ASC_NO_PARALLEL_STORIES "No stories available for parallel processing")"
|
|
195
195
|
return 0
|
|
196
196
|
fi
|
|
197
197
|
|
|
198
198
|
local story_count
|
|
199
|
-
story_count=$(echo "$all_stories" | wc -
|
|
200
|
-
log_conductor "Found
|
|
199
|
+
story_count=$(echo "$all_stories" | wc -l | tr -d ' ') || story_count=0
|
|
200
|
+
log_conductor "$(asc_msg MSG_ASC_FOUND_STORIES "Found {0} stories for parallel processing" "$story_count")"
|
|
201
201
|
|
|
202
202
|
# Build dependency graph
|
|
203
203
|
if type build_dependency_graph &>/dev/null; then
|
|
@@ -211,23 +211,17 @@ run_sprint_conductor_parallel() {
|
|
|
211
211
|
while [[ $processed -lt $story_count ]]; do
|
|
212
212
|
# Check stop conditions
|
|
213
213
|
if ! check_continue_conditions; then
|
|
214
|
-
log_conductor "Stop condition met, halting parallel processing"
|
|
214
|
+
log_conductor "$(asc_msg MSG_ASC_STOP_PARALLEL "Stop condition met, halting parallel processing")"
|
|
215
215
|
break
|
|
216
216
|
fi
|
|
217
217
|
|
|
218
|
-
log_conductor "=== Wave
|
|
218
|
+
log_conductor "$(asc_msg MSG_ASC_WAVE "=== Wave {0} ===" "$wave")"
|
|
219
219
|
|
|
220
|
-
# Collect completed sessions from previous wave
|
|
220
|
+
# Collect completed sessions from previous wave (in this shell: it
|
|
221
|
+
# updates the tracking arrays that free the slots)
|
|
221
222
|
if type collect_completed_sessions &>/dev/null; then
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
for story_id in $completed_stories; do
|
|
226
|
-
ASC_STORIES_COMPLETED=$((ASC_STORIES_COMPLETED + 1))
|
|
227
|
-
ASC_CONSECUTIVE_FAILURES=0
|
|
228
|
-
transition_story "$story_id" "review"
|
|
229
|
-
log_conductor "Story completed in parallel: $story_id"
|
|
230
|
-
done
|
|
223
|
+
collect_completed_sessions > /dev/null
|
|
224
|
+
process_collected_parallel_stories
|
|
231
225
|
fi
|
|
232
226
|
|
|
233
227
|
# Get stories ready for this wave (dependencies satisfied)
|
|
@@ -244,7 +238,7 @@ run_sprint_conductor_parallel() {
|
|
|
244
238
|
local active
|
|
245
239
|
active=$(get_active_count)
|
|
246
240
|
if [[ $active -gt 0 ]]; then
|
|
247
|
-
log_conductor "Waiting for
|
|
241
|
+
log_conductor "$(asc_msg MSG_ASC_WAITING_ACTIVE "Waiting for {0} active sessions to complete..." "$active")"
|
|
248
242
|
sleep 10
|
|
249
243
|
continue
|
|
250
244
|
fi
|
|
@@ -257,7 +251,7 @@ run_sprint_conductor_parallel() {
|
|
|
257
251
|
fi
|
|
258
252
|
|
|
259
253
|
if [[ $pending_escalations -gt 0 ]]; then
|
|
260
|
-
log_conductor "Waiting for
|
|
254
|
+
log_conductor "$(asc_msg MSG_ASC_WAITING_ESCALATIONS "Waiting for {0} pending escalations..." "$pending_escalations")"
|
|
261
255
|
sleep 60
|
|
262
256
|
continue
|
|
263
257
|
fi
|
|
@@ -274,9 +268,13 @@ run_sprint_conductor_parallel() {
|
|
|
274
268
|
slots=$ASC_PARALLEL_MAX
|
|
275
269
|
fi
|
|
276
270
|
|
|
277
|
-
# Spawn sessions for ready stories (up to available slots)
|
|
271
|
+
# Spawn sessions for ready stories (up to available slots), one id
|
|
272
|
+
# per line: ids may contain spaces
|
|
278
273
|
local spawned=0
|
|
279
|
-
|
|
274
|
+
local -a ready_list=()
|
|
275
|
+
mapfile -t ready_list <<< "$ready_stories"
|
|
276
|
+
for story_id in "${ready_list[@]}"; do
|
|
277
|
+
[[ -z "$story_id" ]] && continue
|
|
280
278
|
[[ $spawned -ge $slots ]] && break
|
|
281
279
|
|
|
282
280
|
# Skip if already processed or in progress
|
|
@@ -287,16 +285,16 @@ run_sprint_conductor_parallel() {
|
|
|
287
285
|
# Supervised mode - pause for confirmation
|
|
288
286
|
if [[ "$ASC_MODE" == "supervised" ]]; then
|
|
289
287
|
if ! confirm_story_start "$story_id"; then
|
|
290
|
-
log_conductor "Story skipped by user: $story_id"
|
|
288
|
+
log_conductor "$(asc_msg MSG_ASC_SKIPPED_BY_USER "Story skipped by user: {0}" "$story_id")"
|
|
291
289
|
ASC_STORIES_SKIPPED=$((ASC_STORIES_SKIPPED + 1))
|
|
292
|
-
((processed
|
|
290
|
+
processed=$((processed + 1))
|
|
293
291
|
continue
|
|
294
292
|
fi
|
|
295
293
|
fi
|
|
296
294
|
|
|
297
295
|
# Claim the story
|
|
298
296
|
if ! claim_story "$story_id"; then
|
|
299
|
-
log_conductor "Failed to claim story:
|
|
297
|
+
log_conductor "$(asc_msg MSG_ASC_CLAIM_FAILED_OTHER "Failed to claim story: {0} (may be claimed by another process)" "$story_id")"
|
|
300
298
|
continue
|
|
301
299
|
fi
|
|
302
300
|
|
|
@@ -304,23 +302,26 @@ run_sprint_conductor_parallel() {
|
|
|
304
302
|
local prompt
|
|
305
303
|
prompt=$(build_story_prompt "$story_id")
|
|
306
304
|
|
|
307
|
-
# Spawn parallel session
|
|
305
|
+
# Spawn parallel session. Not in `$(...)`: the background worker
|
|
306
|
+
# would keep the substitution open until it ends (no parallelism).
|
|
308
307
|
if type spawn_session &>/dev/null; then
|
|
309
|
-
local session_id
|
|
310
|
-
|
|
308
|
+
local session_id=""
|
|
309
|
+
if spawn_session "$story_id" "$prompt"; then
|
|
310
|
+
session_id="$PARALLEL_SPAWNED_SESSION_ID"
|
|
311
|
+
fi
|
|
311
312
|
if [[ -n "$session_id" ]]; then
|
|
312
|
-
log_conductor "Spawned parallel session
|
|
313
|
-
((spawned
|
|
314
|
-
((processed
|
|
313
|
+
log_conductor "$(asc_msg MSG_ASC_SPAWNED "Spawned parallel session {0} for story {1}" "$session_id" "$story_id")"
|
|
314
|
+
spawned=$((spawned + 1))
|
|
315
|
+
processed=$((processed + 1))
|
|
315
316
|
else
|
|
316
|
-
log_conductor "Failed to spawn session for $story_id"
|
|
317
|
+
log_conductor "$(asc_msg MSG_ASC_SPAWN_FAILED "Failed to spawn session for {0}" "$story_id")"
|
|
317
318
|
unclaim_story "$story_id"
|
|
318
319
|
ASC_STORIES_FAILED=$((ASC_STORIES_FAILED + 1))
|
|
319
320
|
fi
|
|
320
321
|
else
|
|
321
322
|
# Fallback: execute sequentially
|
|
322
323
|
execute_story_with_ralph "$story_id"
|
|
323
|
-
((processed
|
|
324
|
+
processed=$((processed + 1))
|
|
324
325
|
fi
|
|
325
326
|
done
|
|
326
327
|
|
|
@@ -331,7 +332,7 @@ run_sprint_conductor_parallel() {
|
|
|
331
332
|
# Create checkpoint
|
|
332
333
|
create_conductor_checkpoint
|
|
333
334
|
|
|
334
|
-
((wave
|
|
335
|
+
wave=$((wave + 1))
|
|
335
336
|
|
|
336
337
|
# Small delay between waves
|
|
337
338
|
sleep 2
|
|
@@ -339,18 +340,13 @@ run_sprint_conductor_parallel() {
|
|
|
339
340
|
|
|
340
341
|
# Wait for remaining sessions
|
|
341
342
|
if type wait_all_sessions &>/dev/null; then
|
|
342
|
-
log_conductor "Waiting for all parallel sessions to complete..."
|
|
343
|
+
log_conductor "$(asc_msg MSG_ASC_WAITING_ALL "Waiting for all parallel sessions to complete...")"
|
|
343
344
|
wait_all_sessions 0
|
|
344
345
|
|
|
345
|
-
# Final collection
|
|
346
|
+
# Final collection (wait_all_sessions already collected them)
|
|
346
347
|
if type collect_completed_sessions &>/dev/null; then
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
for story_id in $final_completed; do
|
|
351
|
-
ASC_STORIES_COMPLETED=$((ASC_STORIES_COMPLETED + 1))
|
|
352
|
-
transition_story "$story_id" "review"
|
|
353
|
-
done
|
|
348
|
+
collect_completed_sessions > /dev/null
|
|
349
|
+
process_collected_parallel_stories
|
|
354
350
|
fi
|
|
355
351
|
fi
|
|
356
352
|
|
|
@@ -360,14 +356,42 @@ run_sprint_conductor_parallel() {
|
|
|
360
356
|
fi
|
|
361
357
|
}
|
|
362
358
|
|
|
359
|
+
# Count and transition the stories collected from finished workers:
|
|
360
|
+
# completed -> review, failed -> blocked (as in sequential mode).
|
|
361
|
+
process_collected_parallel_stories() {
|
|
362
|
+
local -a completed_list=() failed_list=()
|
|
363
|
+
mapfile -t completed_list <<< "$PARALLEL_COLLECTED_STORIES"
|
|
364
|
+
mapfile -t failed_list <<< "$PARALLEL_FAILED_STORIES"
|
|
365
|
+
PARALLEL_COLLECTED_STORIES=""
|
|
366
|
+
PARALLEL_FAILED_STORIES=""
|
|
367
|
+
|
|
368
|
+
local story_id
|
|
369
|
+
for story_id in "${completed_list[@]}"; do
|
|
370
|
+
[[ -z "$story_id" ]] && continue
|
|
371
|
+
ASC_STORIES_COMPLETED=$((ASC_STORIES_COMPLETED + 1))
|
|
372
|
+
ASC_CONSECUTIVE_FAILURES=0
|
|
373
|
+
transition_story "$story_id" "review"
|
|
374
|
+
log_conductor "$(asc_msg MSG_ASC_PAR_COMPLETED "Story completed in parallel: {0}" "$story_id")"
|
|
375
|
+
done
|
|
376
|
+
|
|
377
|
+
for story_id in "${failed_list[@]}"; do
|
|
378
|
+
[[ -z "$story_id" ]] && continue
|
|
379
|
+
ASC_STORIES_FAILED=$((ASC_STORIES_FAILED + 1))
|
|
380
|
+
ASC_CONSECUTIVE_FAILURES=$((ASC_CONSECUTIVE_FAILURES + 1))
|
|
381
|
+
transition_story "$story_id" "blocked"
|
|
382
|
+
log_conductor "$(asc_msg MSG_ASC_PAR_FAILED "Story failed in parallel: {0}" "$story_id")"
|
|
383
|
+
done
|
|
384
|
+
}
|
|
385
|
+
|
|
363
386
|
# Check if a story is already in progress (parallel tracking)
|
|
364
387
|
is_story_in_progress() {
|
|
365
388
|
local story_id="$1"
|
|
366
389
|
|
|
367
|
-
# Check in parallel sessions
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
390
|
+
# Check in parallel sessions (keyed by session id, the value is the story)
|
|
391
|
+
local session_id
|
|
392
|
+
for session_id in "${!PARALLEL_SESSIONS[@]}"; do
|
|
393
|
+
[[ "${PARALLEL_SESSIONS[$session_id]}" == "$story_id" ]] && return 0
|
|
394
|
+
done
|
|
371
395
|
|
|
372
396
|
# Check in BMAD status
|
|
373
397
|
local bmad_dir="${BMAD_DIR:-.bmad}"
|
|
@@ -375,7 +399,7 @@ is_story_in_progress() {
|
|
|
375
399
|
|
|
376
400
|
if [[ -f "$status_file" ]] && command -v yq &>/dev/null; then
|
|
377
401
|
local status
|
|
378
|
-
status=$(yq
|
|
402
|
+
status=$(STORY_ID="$story_id" yq '.stories[strenv(STORY_ID)].status' "$status_file" 2>/dev/null)
|
|
379
403
|
[[ "$status" == "in-progress" ]] && return 0
|
|
380
404
|
fi
|
|
381
405
|
|
|
@@ -412,7 +436,7 @@ update_parallel_conductor_state() {
|
|
|
412
436
|
run_sprint_conductor_sequential() {
|
|
413
437
|
local sprint_name="$1"
|
|
414
438
|
|
|
415
|
-
log_conductor "Running in SEQUENTIAL mode"
|
|
439
|
+
log_conductor "$(asc_msg MSG_ASC_SEQUENTIAL_MODE "Running in SEQUENTIAL mode")"
|
|
416
440
|
|
|
417
441
|
# Main loop
|
|
418
442
|
while true; do
|
|
@@ -426,14 +450,14 @@ run_sprint_conductor_sequential() {
|
|
|
426
450
|
next_story=$(get_next_ready_story)
|
|
427
451
|
|
|
428
452
|
if [[ -z "$next_story" ]]; then
|
|
429
|
-
log_conductor "No more stories available"
|
|
453
|
+
log_conductor "$(asc_msg MSG_ASC_NO_MORE_STORIES "No more stories available")"
|
|
430
454
|
|
|
431
455
|
# Check escalation queue
|
|
432
456
|
if type get_pending_count &>/dev/null; then
|
|
433
457
|
local pending
|
|
434
458
|
pending=$(get_pending_count)
|
|
435
459
|
if [[ $pending -gt 0 ]]; then
|
|
436
|
-
log_conductor "Waiting for
|
|
460
|
+
log_conductor "$(asc_msg MSG_ASC_WAITING_ESCALATIONS "Waiting for {0} pending escalations..." "$pending")"
|
|
437
461
|
if type check_escalation_timeouts &>/dev/null; then
|
|
438
462
|
check_escalation_timeouts
|
|
439
463
|
fi
|
|
@@ -449,11 +473,11 @@ run_sprint_conductor_sequential() {
|
|
|
449
473
|
ASC_CURRENT_STORY="$next_story"
|
|
450
474
|
update_conductor_state "current" "$next_story"
|
|
451
475
|
|
|
452
|
-
log_conductor "Processing story: $next_story"
|
|
476
|
+
log_conductor "$(asc_msg MSG_ASC_PROCESSING "Processing story: {0}" "$next_story")"
|
|
453
477
|
|
|
454
478
|
# Claim the story
|
|
455
479
|
if ! claim_story "$next_story"; then
|
|
456
|
-
log_conductor "Failed to claim story: $next_story"
|
|
480
|
+
log_conductor "$(asc_msg MSG_ASC_CLAIM_FAILED "Failed to claim story: {0}" "$next_story")"
|
|
457
481
|
ASC_STORIES_SKIPPED=$((ASC_STORIES_SKIPPED + 1))
|
|
458
482
|
continue
|
|
459
483
|
fi
|
|
@@ -461,7 +485,7 @@ run_sprint_conductor_sequential() {
|
|
|
461
485
|
# Supervised mode - pause for confirmation
|
|
462
486
|
if [[ "$ASC_MODE" == "supervised" ]]; then
|
|
463
487
|
if ! confirm_story_start "$next_story"; then
|
|
464
|
-
log_conductor "Story skipped by user: $next_story"
|
|
488
|
+
log_conductor "$(asc_msg MSG_ASC_SKIPPED_BY_USER "Story skipped by user: {0}" "$next_story")"
|
|
465
489
|
unclaim_story "$next_story"
|
|
466
490
|
ASC_STORIES_SKIPPED=$((ASC_STORIES_SKIPPED + 1))
|
|
467
491
|
continue
|
|
@@ -469,34 +493,35 @@ run_sprint_conductor_sequential() {
|
|
|
469
493
|
fi
|
|
470
494
|
|
|
471
495
|
# Execute story with Ralph
|
|
496
|
+
# `|| status=$?`: a failed story must be counted, not kill the loop.
|
|
472
497
|
local result
|
|
473
|
-
|
|
474
|
-
|
|
498
|
+
local status=0
|
|
499
|
+
result=$(execute_story_with_ralph "$next_story") || status=$?
|
|
475
500
|
|
|
476
501
|
# Process result
|
|
477
502
|
case $status in
|
|
478
503
|
0)
|
|
479
504
|
# Success
|
|
480
|
-
log_conductor "Story completed: $next_story"
|
|
505
|
+
log_conductor "$(asc_msg MSG_ASC_COMPLETED "Story completed: {0}" "$next_story")"
|
|
481
506
|
ASC_STORIES_COMPLETED=$((ASC_STORIES_COMPLETED + 1))
|
|
482
507
|
ASC_CONSECUTIVE_FAILURES=0
|
|
483
508
|
transition_story "$next_story" "review"
|
|
484
509
|
;;
|
|
485
510
|
1)
|
|
486
511
|
# Failed but recoverable
|
|
487
|
-
log_conductor "Story failed: $next_story"
|
|
512
|
+
log_conductor "$(asc_msg MSG_ASC_FAILED "Story failed: {0}" "$next_story")"
|
|
488
513
|
ASC_STORIES_FAILED=$((ASC_STORIES_FAILED + 1))
|
|
489
514
|
ASC_CONSECUTIVE_FAILURES=$((ASC_CONSECUTIVE_FAILURES + 1))
|
|
490
515
|
transition_story "$next_story" "blocked"
|
|
491
516
|
;;
|
|
492
517
|
2)
|
|
493
518
|
# Escalated
|
|
494
|
-
log_conductor "Story escalated: $next_story"
|
|
519
|
+
log_conductor "$(asc_msg MSG_ASC_ESCALATED "Story escalated: {0}" "$next_story")"
|
|
495
520
|
# Keep in-progress, will be handled by escalation resolution
|
|
496
521
|
;;
|
|
497
522
|
3)
|
|
498
523
|
# Skipped
|
|
499
|
-
log_conductor "Story skipped: $next_story"
|
|
524
|
+
log_conductor "$(asc_msg MSG_ASC_SKIPPED "Story skipped: {0}" "$next_story")"
|
|
500
525
|
ASC_STORIES_SKIPPED=$((ASC_STORIES_SKIPPED + 1))
|
|
501
526
|
transition_story "$next_story" "ready-for-dev"
|
|
502
527
|
;;
|
|
@@ -521,13 +546,13 @@ check_continue_conditions() {
|
|
|
521
546
|
# Check max stories
|
|
522
547
|
local total_processed=$((ASC_STORIES_COMPLETED + ASC_STORIES_FAILED + ASC_STORIES_SKIPPED))
|
|
523
548
|
if [[ $total_processed -ge $ASC_MAX_STORIES ]]; then
|
|
524
|
-
log_conductor "Max stories reached: $total_processed"
|
|
549
|
+
log_conductor "$(asc_msg MSG_ASC_MAX_STORIES "Max stories reached: {0}" "$total_processed")"
|
|
525
550
|
return 1
|
|
526
551
|
fi
|
|
527
552
|
|
|
528
553
|
# Check consecutive failures
|
|
529
554
|
if [[ $ASC_CONSECUTIVE_FAILURES -ge $ASC_MAX_CONSECUTIVE_FAILURES ]]; then
|
|
530
|
-
log_conductor "Max consecutive failures reached: $ASC_CONSECUTIVE_FAILURES"
|
|
555
|
+
log_conductor "$(asc_msg MSG_ASC_MAX_FAILURES "Max consecutive failures reached: {0}" "$ASC_CONSECUTIVE_FAILURES")"
|
|
531
556
|
return 1
|
|
532
557
|
fi
|
|
533
558
|
|
|
@@ -537,7 +562,7 @@ check_continue_conditions() {
|
|
|
537
562
|
local runtime_hours=$(((current_time - ASC_START_TIME) / 3600))
|
|
538
563
|
|
|
539
564
|
if [[ $runtime_hours -ge $ASC_MAX_RUNTIME_HOURS ]]; then
|
|
540
|
-
log_conductor "Max runtime reached:
|
|
565
|
+
log_conductor "$(asc_msg MSG_ASC_MAX_RUNTIME "Max runtime reached: {0}h" "$runtime_hours")"
|
|
541
566
|
return 1
|
|
542
567
|
fi
|
|
543
568
|
|
|
@@ -547,14 +572,14 @@ check_continue_conditions() {
|
|
|
547
572
|
current_hour=$(date +%H:%M)
|
|
548
573
|
|
|
549
574
|
if [[ "$current_hour" > "$ASC_STOP_WINDOW" && "$current_hour" < "12:00" ]]; then
|
|
550
|
-
log_conductor "Stop window reached:
|
|
575
|
+
log_conductor "$(asc_msg MSG_ASC_STOP_WINDOW "Stop window reached: {0} (window: {1})" "$current_hour" "$ASC_STOP_WINDOW")"
|
|
551
576
|
return 1
|
|
552
577
|
fi
|
|
553
578
|
fi
|
|
554
579
|
|
|
555
580
|
# Check for critical escalations
|
|
556
581
|
if type has_critical_pending &>/dev/null && has_critical_pending; then
|
|
557
|
-
log_conductor "Critical escalation pending - pausing"
|
|
582
|
+
log_conductor "$(asc_msg MSG_ASC_CRITICAL_ESCALATION "Critical escalation pending - pausing")"
|
|
558
583
|
|
|
559
584
|
# Wait for resolution or timeout
|
|
560
585
|
sleep 300 # 5 minutes
|
|
@@ -581,7 +606,7 @@ get_next_ready_story() {
|
|
|
581
606
|
fi
|
|
582
607
|
}
|
|
583
608
|
|
|
584
|
-
# Get all ready-for-dev stories (for parallel processing)
|
|
609
|
+
# Get all ready-for-dev stories (for parallel processing), one id per line
|
|
585
610
|
get_all_ready_stories() {
|
|
586
611
|
local bmad_dir="${BMAD_DIR:-.bmad}"
|
|
587
612
|
local status_file="$bmad_dir/sprint-status.yaml"
|
|
@@ -595,16 +620,12 @@ get_all_ready_stories() {
|
|
|
595
620
|
select(.value.status == "ready-for-dev") |
|
|
596
621
|
select(.value.claimed_by == null or .value.claimed_by == "") |
|
|
597
622
|
select(
|
|
598
|
-
(.value.blocked_by // []) |
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
. as $dep |
|
|
602
|
-
($stories[$dep].status == "done" or $stories[$dep].status == "review")
|
|
603
|
-
)
|
|
604
|
-
)
|
|
623
|
+
[(.value.blocked_by // [])[] |
|
|
624
|
+
select($stories[.].status != "done" and $stories[.].status != "review")
|
|
625
|
+
] | length == 0
|
|
605
626
|
) |
|
|
606
627
|
.key
|
|
607
|
-
' "$status_file" 2>/dev/null
|
|
628
|
+
' "$status_file" 2>/dev/null
|
|
608
629
|
fi
|
|
609
630
|
}
|
|
610
631
|
|
|
@@ -621,7 +642,7 @@ get_independent_ready_stories() {
|
|
|
621
642
|
select(.value.claimed_by == null or .value.claimed_by == "") |
|
|
622
643
|
select((.value.blocked_by // []) | length == 0) |
|
|
623
644
|
.key
|
|
624
|
-
' "$status_file" 2>/dev/null
|
|
645
|
+
' "$status_file" 2>/dev/null
|
|
625
646
|
fi
|
|
626
647
|
}
|
|
627
648
|
|
|
@@ -634,11 +655,13 @@ claim_story() {
|
|
|
634
655
|
local timestamp
|
|
635
656
|
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
636
657
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
658
|
+
# Ids and values go through strenv(): never parsed as yq expressions
|
|
659
|
+
STORY_ID="$story_id" OWNER="$ASC_SESSION_ID" TS="$timestamp" yq -i '
|
|
660
|
+
.stories[strenv(STORY_ID)].claimed_by = strenv(OWNER) |
|
|
661
|
+
.stories[strenv(STORY_ID)].claimed_at = strenv(TS) |
|
|
662
|
+
.stories[strenv(STORY_ID)].status = "in-progress"' "$status_file"
|
|
640
663
|
|
|
641
|
-
log_conductor "Claimed story: $story_id"
|
|
664
|
+
log_conductor "$(asc_msg MSG_ASC_CLAIMED "Claimed story: {0}" "$story_id")"
|
|
642
665
|
return 0
|
|
643
666
|
fi
|
|
644
667
|
|
|
@@ -651,10 +674,9 @@ unclaim_story() {
|
|
|
651
674
|
local status_file="$bmad_dir/sprint-status.yaml"
|
|
652
675
|
|
|
653
676
|
if [[ -f "$status_file" ]] && command -v yq &>/dev/null; then
|
|
654
|
-
yq -i
|
|
655
|
-
yq -i ".stories.${story_id}.claimed_at = \"\"" "$status_file"
|
|
677
|
+
STORY_ID="$story_id" yq -i '.stories[strenv(STORY_ID)].claimed_by = "" | .stories[strenv(STORY_ID)].claimed_at = ""' "$status_file"
|
|
656
678
|
|
|
657
|
-
log_conductor "Unclaimed story: $story_id"
|
|
679
|
+
log_conductor "$(asc_msg MSG_ASC_UNCLAIMED "Unclaimed story: {0}" "$story_id")"
|
|
658
680
|
return 0
|
|
659
681
|
fi
|
|
660
682
|
|
|
@@ -678,11 +700,12 @@ transition_story() {
|
|
|
678
700
|
local timestamp
|
|
679
701
|
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
680
702
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
703
|
+
STORY_ID="$story_id" NEW_STATUS="$new_status" TS="$timestamp" yq -i '
|
|
704
|
+
.stories[strenv(STORY_ID)].previous_status = .stories[strenv(STORY_ID)].status |
|
|
705
|
+
.stories[strenv(STORY_ID)].status = strenv(NEW_STATUS) |
|
|
706
|
+
.stories[strenv(STORY_ID)].updated_at = strenv(TS)' "$status_file"
|
|
684
707
|
|
|
685
|
-
log_conductor "Transitioned
|
|
708
|
+
log_conductor "$(asc_msg MSG_ASC_TRANSITIONED "Transitioned {0} to {1}" "$story_id" "$new_status")"
|
|
686
709
|
return 0
|
|
687
710
|
fi
|
|
688
711
|
|
|
@@ -696,16 +719,17 @@ transition_story() {
|
|
|
696
719
|
execute_story_with_ralph() {
|
|
697
720
|
local story_id="$1"
|
|
698
721
|
|
|
699
|
-
log_conductor "Spawning Ralph for story: $story_id"
|
|
722
|
+
log_conductor "$(asc_msg MSG_ASC_SPAWNING_RALPH "Spawning Ralph for story: {0}" "$story_id")"
|
|
700
723
|
|
|
701
724
|
# Build prompt for Ralph
|
|
702
725
|
local prompt
|
|
703
726
|
prompt=$(build_story_prompt "$story_id")
|
|
704
727
|
|
|
705
|
-
# Get story-specific config if available
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
728
|
+
# Get story-specific config if available. An id with `/` (e.g. `../x`)
|
|
729
|
+
# would read a config outside .ralph/stories/: ignored.
|
|
730
|
+
local -a story_config=()
|
|
731
|
+
if [[ "$story_id" != */* && -f ".ralph/stories/${story_id}.yml" ]]; then
|
|
732
|
+
story_config=("--config=.ralph/stories/${story_id}.yml")
|
|
709
733
|
fi
|
|
710
734
|
|
|
711
735
|
# Run Ralph with autonomous profile
|
|
@@ -715,7 +739,7 @@ execute_story_with_ralph() {
|
|
|
715
739
|
local output
|
|
716
740
|
output=$("$ralph_script" \
|
|
717
741
|
--lang="${LANG_ARG:-en}" \
|
|
718
|
-
$story_config \
|
|
742
|
+
"${story_config[@]}" \
|
|
719
743
|
"$prompt" 2>&1)
|
|
720
744
|
local status=$?
|
|
721
745
|
|
|
@@ -733,7 +757,7 @@ execute_story_with_ralph() {
|
|
|
733
757
|
;;
|
|
734
758
|
esac
|
|
735
759
|
else
|
|
736
|
-
log_conductor "Ralph script not found: $ralph_script"
|
|
760
|
+
log_conductor "$(asc_msg MSG_ASC_RALPH_NOT_FOUND "Ralph script not found: {0}" "$ralph_script")"
|
|
737
761
|
return 1
|
|
738
762
|
fi
|
|
739
763
|
}
|
|
@@ -747,9 +771,9 @@ build_story_prompt() {
|
|
|
747
771
|
|
|
748
772
|
if [[ -f "$status_file" ]] && command -v yq &>/dev/null; then
|
|
749
773
|
local title description acceptance_criteria
|
|
750
|
-
title=$(yq
|
|
751
|
-
description=$(yq
|
|
752
|
-
acceptance_criteria=$(yq
|
|
774
|
+
title=$(STORY_ID="$story_id" yq '.stories[strenv(STORY_ID)].title' "$status_file" 2>/dev/null)
|
|
775
|
+
description=$(STORY_ID="$story_id" yq '.stories[strenv(STORY_ID)].description' "$status_file" 2>/dev/null)
|
|
776
|
+
acceptance_criteria=$(STORY_ID="$story_id" yq '.stories[strenv(STORY_ID)].acceptance_criteria[]' "$status_file" 2>/dev/null | tr '\n' '; ') || true
|
|
753
777
|
|
|
754
778
|
prompt="Implement user story: $title
|
|
755
779
|
|
|
@@ -774,10 +798,10 @@ confirm_story_start() {
|
|
|
774
798
|
|
|
775
799
|
echo ""
|
|
776
800
|
echo "════════════════════════════════════════"
|
|
777
|
-
echo " Supervised Mode: Story Ready"
|
|
801
|
+
echo " $(asc_msg MSG_ASC_SUPERVISED_TITLE "Supervised Mode: Story Ready")"
|
|
778
802
|
echo "════════════════════════════════════════"
|
|
779
803
|
echo ""
|
|
780
|
-
echo "Story: $story_id"
|
|
804
|
+
echo "$(asc_msg MSG_ASC_SUPERVISED_STORY "Story: {0}" "$story_id")"
|
|
781
805
|
|
|
782
806
|
if command -v yq &>/dev/null; then
|
|
783
807
|
local bmad_dir="${BMAD_DIR:-.bmad}"
|
|
@@ -785,13 +809,13 @@ confirm_story_start() {
|
|
|
785
809
|
|
|
786
810
|
if [[ -f "$status_file" ]]; then
|
|
787
811
|
local title
|
|
788
|
-
title=$(yq
|
|
789
|
-
echo "Title: $title"
|
|
812
|
+
title=$(STORY_ID="$story_id" yq '.stories[strenv(STORY_ID)].title' "$status_file" 2>/dev/null)
|
|
813
|
+
echo "$(asc_msg MSG_ASC_SUPERVISED_TITLE_LINE "Title: {0}" "$title")"
|
|
790
814
|
fi
|
|
791
815
|
fi
|
|
792
816
|
|
|
793
817
|
echo ""
|
|
794
|
-
read -rp "Start this story? (y/n/s for skip all): " response
|
|
818
|
+
read -rp "$(asc_msg MSG_ASC_SUPERVISED_PROMPT "Start this story? (y/n/s for skip all): ")" response
|
|
795
819
|
|
|
796
820
|
case "$response" in
|
|
797
821
|
y|Y) return 0 ;;
|
|
@@ -814,7 +838,7 @@ update_conductor_state() {
|
|
|
814
838
|
|
|
815
839
|
case "$field" in
|
|
816
840
|
current)
|
|
817
|
-
yq -i
|
|
841
|
+
VALUE="$value" yq -i '.stories.current = strenv(VALUE)' "$ASC_STATE_FILE"
|
|
818
842
|
;;
|
|
819
843
|
stories)
|
|
820
844
|
yq -i ".stories.completed = $ASC_STORIES_COMPLETED" "$ASC_STATE_FILE"
|
|
@@ -822,7 +846,7 @@ update_conductor_state() {
|
|
|
822
846
|
yq -i ".stories.skipped = $ASC_STORIES_SKIPPED" "$ASC_STATE_FILE"
|
|
823
847
|
;;
|
|
824
848
|
status)
|
|
825
|
-
yq -i
|
|
849
|
+
VALUE="$value" yq -i '.status = strenv(VALUE)' "$ASC_STATE_FILE"
|
|
826
850
|
;;
|
|
827
851
|
esac
|
|
828
852
|
}
|
|
@@ -835,9 +859,9 @@ create_conductor_checkpoint() {
|
|
|
835
859
|
local timestamp
|
|
836
860
|
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
837
861
|
|
|
838
|
-
yq -i ".checkpoints += [{
|
|
839
|
-
\"timestamp\":
|
|
840
|
-
\"story\":
|
|
862
|
+
TS="$timestamp" STORY="$ASC_CURRENT_STORY" yq -i ".checkpoints += [{
|
|
863
|
+
\"timestamp\": strenv(TS),
|
|
864
|
+
\"story\": strenv(STORY),
|
|
841
865
|
\"completed\": $ASC_STORIES_COMPLETED,
|
|
842
866
|
\"failed\": $ASC_STORIES_FAILED,
|
|
843
867
|
\"skipped\": $ASC_STORIES_SKIPPED
|
|
@@ -848,6 +872,19 @@ create_conductor_checkpoint() {
|
|
|
848
872
|
# Logging
|
|
849
873
|
# =============================================================================
|
|
850
874
|
|
|
875
|
+
# Leader message in the --lang language: asc_msg <MSG_ var> <English default>
|
|
876
|
+
# [values for {0} {1}...] (MSG_ASC_* strings live in Tools/i18n/ralph/<lang>.sh)
|
|
877
|
+
asc_msg() {
|
|
878
|
+
local msg="${!1:-$2}"
|
|
879
|
+
shift 2
|
|
880
|
+
local i=0 value
|
|
881
|
+
for value in "$@"; do
|
|
882
|
+
msg="${msg//\{$i\}/"$value"}"
|
|
883
|
+
i=$((i + 1))
|
|
884
|
+
done
|
|
885
|
+
printf '%s' "$msg"
|
|
886
|
+
}
|
|
887
|
+
|
|
851
888
|
log_conductor() {
|
|
852
889
|
local message="$1"
|
|
853
890
|
local timestamp
|
|
@@ -866,7 +903,7 @@ print_header_conductor() {
|
|
|
866
903
|
|
|
867
904
|
echo ""
|
|
868
905
|
echo -e "${C_CYAN}╔════════════════════════════════════════════════════════════╗${C_RESET}"
|
|
869
|
-
echo -e "${C_CYAN}║${C_RESET} ${C_BOLD}Autonomous Sprint Conductor (ASC)${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
906
|
+
echo -e "${C_CYAN}║${C_RESET} ${C_BOLD}$(asc_msg MSG_ASC_HEADER "Autonomous Sprint Conductor (ASC)")${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
870
907
|
echo -e "${C_CYAN}║${C_RESET} ${C_DIM}$sprint_name${C_RESET} ${C_CYAN}║${C_RESET}"
|
|
871
908
|
echo -e "${C_CYAN}╚════════════════════════════════════════════════════════════╝${C_RESET}"
|
|
872
909
|
echo ""
|
|
@@ -897,33 +934,33 @@ finalize_sprint_conductor() {
|
|
|
897
934
|
# Print summary
|
|
898
935
|
echo ""
|
|
899
936
|
echo "════════════════════════════════════════"
|
|
900
|
-
echo " Sprint Conductor Summary"
|
|
937
|
+
echo " $(asc_msg MSG_ASC_SUMMARY "Sprint Conductor Summary")"
|
|
901
938
|
echo "════════════════════════════════════════"
|
|
902
939
|
echo ""
|
|
903
|
-
echo "Session: $ASC_SESSION_ID"
|
|
904
|
-
echo "Duration:
|
|
940
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_SESSION "Session: {0}" "$ASC_SESSION_ID")"
|
|
941
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_DURATION "Duration: {0}h {1}m" "$duration_hours" "$duration_mins")"
|
|
905
942
|
echo ""
|
|
906
|
-
echo "Stories:"
|
|
907
|
-
echo " Completed: $ASC_STORIES_COMPLETED"
|
|
908
|
-
echo " Failed: $ASC_STORIES_FAILED"
|
|
909
|
-
echo " Skipped: $ASC_STORIES_SKIPPED"
|
|
943
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_STORIES "Stories:")"
|
|
944
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_COMPLETED " Completed: {0}" "$ASC_STORIES_COMPLETED")"
|
|
945
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_FAILED " Failed: {0}" "$ASC_STORIES_FAILED")"
|
|
946
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_SKIPPED " Skipped: {0}" "$ASC_STORIES_SKIPPED")"
|
|
910
947
|
echo ""
|
|
911
948
|
|
|
912
949
|
# Show escalation stats if available
|
|
913
950
|
if type get_escalation_stats &>/dev/null; then
|
|
914
|
-
echo "Escalations:"
|
|
951
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_ESCALATIONS "Escalations:")"
|
|
915
952
|
get_escalation_stats | jq -r 'to_entries[] | " \(.key): \(.value)"' 2>/dev/null || echo " N/A"
|
|
916
953
|
echo ""
|
|
917
954
|
fi
|
|
918
955
|
|
|
919
956
|
# Show recovery stats if available
|
|
920
957
|
if type get_recovery_stats &>/dev/null; then
|
|
921
|
-
echo "Recovery attempts:"
|
|
958
|
+
echo "$(asc_msg MSG_ASC_SUMMARY_RECOVERY "Recovery attempts:")"
|
|
922
959
|
get_recovery_stats "$ASC_SESSION_ID" | jq -r '.total_attempts // 0' 2>/dev/null || echo " N/A"
|
|
923
960
|
echo ""
|
|
924
961
|
fi
|
|
925
962
|
|
|
926
|
-
log_conductor "Sprint Conductor completed"
|
|
963
|
+
log_conductor "$(asc_msg MSG_ASC_DONE "Sprint Conductor completed")"
|
|
927
964
|
}
|
|
928
965
|
|
|
929
966
|
generate_conductor_metrics() {
|
|
@@ -969,11 +1006,17 @@ cmd_sprint_conductor() {
|
|
|
969
1006
|
--parallel) parallel="$2"; ASC_PARALLEL_ENABLED="true"; ASC_PARALLEL_MAX="$2"; shift 2 ;;
|
|
970
1007
|
--max-stories) max_stories="$2"; shift 2 ;;
|
|
971
1008
|
--timeout) timeout="$2"; shift 2 ;;
|
|
1009
|
+
--lang=*) LANG_ARG="${1#--lang=}"; shift ;;
|
|
972
1010
|
-*) shift ;;
|
|
973
1011
|
*) sprint_name="$1"; shift ;;
|
|
974
1012
|
esac
|
|
975
1013
|
done
|
|
976
1014
|
|
|
1015
|
+
# Messages were loaded before --lang was read: reload them for the leader
|
|
1016
|
+
if type load_messages &>/dev/null; then
|
|
1017
|
+
load_messages
|
|
1018
|
+
fi
|
|
1019
|
+
|
|
977
1020
|
if [[ -z "$sprint_name" ]]; then
|
|
978
1021
|
echo "Usage: sprint-conductor.sh [options] <sprint-name>"
|
|
979
1022
|
echo ""
|