forge-pipeline 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/forge +166 -11
- package/lib/utils.sh +1 -0
- package/package.json +1 -1
package/forge
CHANGED
|
@@ -56,6 +56,7 @@ Usage:
|
|
|
56
56
|
forge start <task description> Run the full pipeline
|
|
57
57
|
forge run <task description> Alias for start
|
|
58
58
|
forge status Show current phase and active agents
|
|
59
|
+
forge dashboard Live-updating agent dashboard
|
|
59
60
|
forge logs [agent-name] Tail an agent's log
|
|
60
61
|
forge abort Kill all agents and cleanup
|
|
61
62
|
forge clean Remove .forge/ directory and branches
|
|
@@ -245,16 +246,16 @@ show_plan_summary() {
|
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
wait_for_approval() {
|
|
248
|
-
printf "${BOLD}${YELLOW}Approve
|
|
249
|
+
printf "${BOLD}${YELLOW}Approve and continue? [Y/n] ${RESET}"
|
|
249
250
|
local answer
|
|
250
251
|
read -r answer </dev/tty
|
|
251
252
|
case "$answer" in
|
|
252
253
|
n|N|no|No|NO)
|
|
253
|
-
log_info "Aborted. Edit .forge/spec/spec.md
|
|
254
|
+
log_info "Aborted. Edit .forge/spec/spec.md, then run 'forge start' again."
|
|
254
255
|
exit 0
|
|
255
256
|
;;
|
|
256
257
|
*)
|
|
257
|
-
log_success "
|
|
258
|
+
log_success "Approved. Continuing..."
|
|
258
259
|
echo ""
|
|
259
260
|
;;
|
|
260
261
|
esac
|
|
@@ -314,6 +315,145 @@ forge_status() {
|
|
|
314
315
|
echo ""
|
|
315
316
|
}
|
|
316
317
|
|
|
318
|
+
###############################################################################
|
|
319
|
+
# Dashboard command — live-updating agent overview
|
|
320
|
+
###############################################################################
|
|
321
|
+
forge_dashboard() {
|
|
322
|
+
local forge_root
|
|
323
|
+
forge_root="$(get_forge_root)"
|
|
324
|
+
local refresh="${1:-2}"
|
|
325
|
+
|
|
326
|
+
trap 'tput cnorm 2>/dev/null; exit 0' INT TERM
|
|
327
|
+
tput civis 2>/dev/null # hide cursor
|
|
328
|
+
|
|
329
|
+
while true; do
|
|
330
|
+
clear
|
|
331
|
+
|
|
332
|
+
# ── Header ──
|
|
333
|
+
printf "${BOLD}${CYAN}╔═══════════════════════════════════════════════════════════════╗${RESET}\n"
|
|
334
|
+
printf "${BOLD}${CYAN}║ FORGE DASHBOARD $(date '+%H:%M:%S') ║${RESET}\n"
|
|
335
|
+
printf "${BOLD}${CYAN}╚═══════════════════════════════════════════════════════════════╝${RESET}\n"
|
|
336
|
+
echo ""
|
|
337
|
+
|
|
338
|
+
# ── Phase ──
|
|
339
|
+
local phase="unknown"
|
|
340
|
+
if [ -f "$forge_root/.forge/status/finalize.done" ]; then
|
|
341
|
+
phase="${GREEN}${BOLD}COMPLETE${RESET}"
|
|
342
|
+
elif [ -f "$forge_root/.forge/status/fix.done" ]; then
|
|
343
|
+
phase="${YELLOW}Fix cycle${RESET}"
|
|
344
|
+
elif [ -f "$forge_root/.forge/status/audit.done" ]; then
|
|
345
|
+
phase="${YELLOW}Audit${RESET}"
|
|
346
|
+
elif [ -f "$forge_root/.forge/status/integrate.done" ]; then
|
|
347
|
+
phase="${YELLOW}Integration${RESET}"
|
|
348
|
+
elif [ -f "$forge_root/.forge/status/implement.done" ]; then
|
|
349
|
+
phase="${YELLOW}Implementation done${RESET}"
|
|
350
|
+
elif [ -f "$forge_root/.forge/status/plan.done" ]; then
|
|
351
|
+
phase="${YELLOW}Planning done${RESET}"
|
|
352
|
+
elif [ -f "$forge_root/.forge/status/spec.done" ]; then
|
|
353
|
+
phase="${YELLOW}Spec done${RESET}"
|
|
354
|
+
else
|
|
355
|
+
phase="${CYAN}In progress...${RESET}"
|
|
356
|
+
fi
|
|
357
|
+
printf " ${BOLD}Phase:${RESET} %b\n" "$phase"
|
|
358
|
+
|
|
359
|
+
# ── Elapsed time ──
|
|
360
|
+
if [ -f "$forge_root/.forge/config.json" ]; then
|
|
361
|
+
local started_at
|
|
362
|
+
started_at="$(jq -r '.started_at // empty' "$forge_root/.forge/config.json" 2>/dev/null || true)"
|
|
363
|
+
if [ -n "$started_at" ]; then
|
|
364
|
+
local now elapsed_s elapsed_m elapsed_sec
|
|
365
|
+
now=$(date +%s)
|
|
366
|
+
elapsed_s=$((now - started_at))
|
|
367
|
+
elapsed_m=$((elapsed_s / 60))
|
|
368
|
+
elapsed_sec=$((elapsed_s % 60))
|
|
369
|
+
printf " ${BOLD}Elapsed:${RESET} %dm %ds\n" "$elapsed_m" "$elapsed_sec"
|
|
370
|
+
fi
|
|
371
|
+
fi
|
|
372
|
+
echo ""
|
|
373
|
+
|
|
374
|
+
# ── Active agents ──
|
|
375
|
+
printf "${BOLD} %-28s %-10s %s${RESET}\n" "AGENT" "STATUS" "LAST ACTIVITY"
|
|
376
|
+
printf " %-28s %-10s %s\n" "────────────────────────────" "──────────" "──────────────────────────────"
|
|
377
|
+
|
|
378
|
+
local sessions
|
|
379
|
+
sessions="$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep "^forge-" || true)"
|
|
380
|
+
|
|
381
|
+
if [ -n "$sessions" ]; then
|
|
382
|
+
while IFS= read -r session; do
|
|
383
|
+
local agent_name="${session#forge-}"
|
|
384
|
+
local status_icon="${GREEN}● running${RESET}"
|
|
385
|
+
local last_line=""
|
|
386
|
+
|
|
387
|
+
# Check for log file
|
|
388
|
+
local log_file="$forge_root/.forge/logs/${agent_name}.log"
|
|
389
|
+
if [ -f "$log_file" ]; then
|
|
390
|
+
# Get last non-empty line, strip ANSI codes, truncate
|
|
391
|
+
last_line="$(tail -5 "$log_file" 2>/dev/null | grep -v '^$' | tail -1 | sed 's/\x1b\[[0-9;]*m//g' | head -c 50 || true)"
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
printf " %-28s %b %s\n" "$agent_name" "$status_icon" "$last_line"
|
|
395
|
+
done <<< "$sessions"
|
|
396
|
+
fi
|
|
397
|
+
|
|
398
|
+
# ── Completed agents ──
|
|
399
|
+
local done_files
|
|
400
|
+
done_files="$(find "$forge_root/.forge/status" -name "*.done" -not -name "spec.done" -not -name "plan.done" -not -name "implement.done" -not -name "integrate.done" -not -name "audit.done" -not -name "fix.done" -not -name "finalize.done" 2>/dev/null || true)"
|
|
401
|
+
|
|
402
|
+
if [ -n "$done_files" ]; then
|
|
403
|
+
while IFS= read -r done_file; do
|
|
404
|
+
local agent_name
|
|
405
|
+
agent_name="$(basename "$done_file" .done)"
|
|
406
|
+
|
|
407
|
+
# Skip if still running in tmux
|
|
408
|
+
if tmux has-session -t "forge-${agent_name}" 2>/dev/null; then
|
|
409
|
+
continue
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
printf " %-28s ${DIM}✓ done${RESET}\n" "$agent_name"
|
|
413
|
+
done <<< "$done_files"
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
if [ -z "$sessions" ] && [ -z "$done_files" ]; then
|
|
417
|
+
printf " ${DIM}(no agents yet)${RESET}\n"
|
|
418
|
+
fi
|
|
419
|
+
|
|
420
|
+
echo ""
|
|
421
|
+
|
|
422
|
+
# ── Progress bar ──
|
|
423
|
+
local total_done total_expected
|
|
424
|
+
total_done=$(find "$forge_root/.forge/status" -name "*.done" 2>/dev/null | wc -l | tr -d ' ')
|
|
425
|
+
total_expected=$(find "$forge_root/.forge/status" -name "*.expected" 2>/dev/null | wc -l | tr -d ' ')
|
|
426
|
+
local running_count=0
|
|
427
|
+
[ -n "$sessions" ] && running_count=$(echo "$sessions" | wc -l | tr -d ' ')
|
|
428
|
+
|
|
429
|
+
printf " ${BOLD}Running:${RESET} %d ${BOLD}Done:${RESET} %d" "$running_count" "$total_done"
|
|
430
|
+
if [ "$total_expected" -gt 0 ]; then
|
|
431
|
+
printf " / %d" "$total_expected"
|
|
432
|
+
fi
|
|
433
|
+
echo ""
|
|
434
|
+
|
|
435
|
+
# ── Progress bar visual ──
|
|
436
|
+
if [ "$total_expected" -gt 0 ]; then
|
|
437
|
+
local pct=$((total_done * 100 / total_expected))
|
|
438
|
+
local bar_width=40
|
|
439
|
+
local filled=$((pct * bar_width / 100))
|
|
440
|
+
local empty=$((bar_width - filled))
|
|
441
|
+
printf " ["
|
|
442
|
+
printf "${GREEN}"
|
|
443
|
+
for ((b=0; b<filled; b++)); do printf "█"; done
|
|
444
|
+
printf "${RESET}${DIM}"
|
|
445
|
+
for ((b=0; b<empty; b++)); do printf "░"; done
|
|
446
|
+
printf "${RESET}"
|
|
447
|
+
printf "] %d%%\n" "$pct"
|
|
448
|
+
fi
|
|
449
|
+
|
|
450
|
+
echo ""
|
|
451
|
+
printf "${DIM} Refreshing every %ds. Press Ctrl+C to exit.${RESET}\n" "$refresh"
|
|
452
|
+
|
|
453
|
+
sleep "$refresh"
|
|
454
|
+
done
|
|
455
|
+
}
|
|
456
|
+
|
|
317
457
|
###############################################################################
|
|
318
458
|
# Logs command
|
|
319
459
|
###############################################################################
|
|
@@ -440,6 +580,8 @@ while [[ $# -gt 0 ]]; do
|
|
|
440
580
|
;;
|
|
441
581
|
status)
|
|
442
582
|
SUBCOMMAND="status"; shift; break ;;
|
|
583
|
+
dashboard)
|
|
584
|
+
SUBCOMMAND="dashboard"; shift; break ;;
|
|
443
585
|
logs)
|
|
444
586
|
SUBCOMMAND="logs"; shift
|
|
445
587
|
LOGS_AGENT="${1:-}"
|
|
@@ -498,6 +640,24 @@ run_pipeline() {
|
|
|
498
640
|
run_phase_spec "$user_prompt" || { log_error "Phase 0 failed"; exit 1; }
|
|
499
641
|
check_global_timeout
|
|
500
642
|
|
|
643
|
+
# ── Approval gate (after spec, before planning + execution) ──
|
|
644
|
+
if [ "$AUTO_APPROVE" = true ]; then
|
|
645
|
+
log_info "Auto-approve enabled, skipping review."
|
|
646
|
+
else
|
|
647
|
+
echo ""
|
|
648
|
+
printf "${BOLD}${CYAN}═══════════════════════════════════════${RESET}\n"
|
|
649
|
+
printf "${BOLD}${CYAN} SPEC REVIEW${RESET}\n"
|
|
650
|
+
printf "${BOLD}${CYAN}═══════════════════════════════════════${RESET}\n"
|
|
651
|
+
echo ""
|
|
652
|
+
echo " The spec has been written to:"
|
|
653
|
+
echo " ${BOLD}.forge/spec/spec.md${RESET}"
|
|
654
|
+
echo ""
|
|
655
|
+
echo " Review it, then approve to continue."
|
|
656
|
+
echo " If you edit the spec, changes will be used as-is."
|
|
657
|
+
echo ""
|
|
658
|
+
wait_for_approval
|
|
659
|
+
fi
|
|
660
|
+
|
|
501
661
|
# Phase 1: Planning
|
|
502
662
|
run_phase_plan || { log_error "Phase 1 failed"; exit 1; }
|
|
503
663
|
check_global_timeout
|
|
@@ -508,14 +668,6 @@ run_pipeline() {
|
|
|
508
668
|
exit 0
|
|
509
669
|
fi
|
|
510
670
|
|
|
511
|
-
# ── Approval gate ─────────────────────────────────────────────
|
|
512
|
-
if [ "$AUTO_APPROVE" = true ]; then
|
|
513
|
-
log_info "Auto-approve enabled, skipping review."
|
|
514
|
-
else
|
|
515
|
-
show_plan_summary "$FORGE_ROOT"
|
|
516
|
-
wait_for_approval
|
|
517
|
-
fi
|
|
518
|
-
|
|
519
671
|
# ── From here on, fully autonomous ────────────────────────────
|
|
520
672
|
|
|
521
673
|
# Phase 2: Implementation
|
|
@@ -570,6 +722,9 @@ case "${SUBCOMMAND:-}" in
|
|
|
570
722
|
status)
|
|
571
723
|
forge_status
|
|
572
724
|
;;
|
|
725
|
+
dashboard)
|
|
726
|
+
forge_dashboard
|
|
727
|
+
;;
|
|
573
728
|
logs)
|
|
574
729
|
forge_logs "${LOGS_AGENT:-}"
|
|
575
730
|
;;
|
package/lib/utils.sh
CHANGED