#!/usr/bin/env bash set -euo pipefail # # mission-status.sh — Show mission progress dashboard # # Usage: # mission-status.sh [--project ] [--format table|json|markdown] SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/_lib.sh" # ─── Parse arguments ───────────────────────────────────────────────────────── PROJECT="." FORMAT="table" while [[ $# -gt 0 ]]; do case "$1" in --project) PROJECT="$2"; shift 2 ;; --format) FORMAT="$2"; shift 2 ;; -h|--help) echo "Usage: mission-status.sh [--project ] [--format table|json|markdown]" exit 0 ;; *) echo "Unknown option: $1" >&2; exit 1 ;; esac done _require_jq require_mission "$PROJECT" # ─── Load data ─────────────────────────────────────────────────────────────── mission="$(load_mission "$PROJECT")" mission_name="$(echo "$mission" | jq -r '.name')" mission_id="$(echo "$mission" | jq -r '.mission_id')" mission_status="$(echo "$mission" | jq -r '.status')" version="$(echo "$mission" | jq -r '.milestone_version // "—"')" created_at="$(echo "$mission" | jq -r '.created_at // "—"')" session_count="$(echo "$mission" | jq '.sessions | length')" milestone_count="$(echo "$mission" | jq '.milestones | length')" completed_milestones="$(echo "$mission" | jq '[.milestones[] | select(.status == "completed")] | length')" # Task counts task_counts="$(count_tasks_md "$PROJECT")" tasks_total="$(echo "$task_counts" | jq '.total')" tasks_done="$(echo "$task_counts" | jq '.done')" tasks_inprog="$(echo "$task_counts" | jq '.in_progress')" tasks_pending="$(echo "$task_counts" | jq '.pending')" tasks_blocked="$(echo "$task_counts" | jq '.blocked')" tasks_failed="$(echo "$task_counts" | jq '.failed')" # Next task next_task="$(find_next_task "$PROJECT")" # ─── JSON output ───────────────────────────────────────────────────────────── if [[ "$FORMAT" == "json" ]]; then echo "$mission" | jq \ --argjson tasks "$task_counts" \ --arg next "$next_task" \ '. + {task_counts: $tasks, next_task: $next}' exit 0 fi # ─── Progress bar ──────────────────────────────────────────────────────────── progress_bar() { local done=$1 local total=$2 local width=30 if (( total == 0 )); then printf "[%${width}s]" "" return fi local filled=$(( (done * width) / total )) local empty=$(( width - filled )) local bar="" for (( i=0; i 0 && filled > 0 )); then bar+=">" empty=$(( empty - 1 )) fi for (( i=0; i 0 )) && pct=$(( (tasks_done * 100) / tasks_total )) echo -e "${C_BOLD}Tasks:${C_RESET} $(progress_bar "$tasks_done" "$tasks_total") ${tasks_done}/${tasks_total} (${pct}%)" echo -e " done: ${C_GREEN}$tasks_done${C_RESET} in-progress: ${C_YELLOW}$tasks_inprog${C_RESET} pending: $tasks_pending blocked: ${C_RED}$tasks_blocked${C_RESET} failed: ${C_RED}$tasks_failed${C_RESET}" echo "" # Session history (last 5) if (( session_count > 0 )); then echo -e "${C_BOLD}Recent Sessions:${C_RESET}" start_idx=$(( session_count > 5 ? session_count - 5 : 0 )) for i in $(seq "$start_idx" $(( session_count - 1 ))); do s_id="$(echo "$mission" | jq -r ".sessions[$i].session_id")" s_rt="$(echo "$mission" | jq -r ".sessions[$i].runtime // \"—\"")" s_start="$(echo "$mission" | jq -r ".sessions[$i].started_at // \"\"")" s_end="$(echo "$mission" | jq -r ".sessions[$i].ended_at // \"\"")" s_reason="$(echo "$mission" | jq -r ".sessions[$i].ended_reason // \"—\"")" s_last="$(echo "$mission" | jq -r ".sessions[$i].last_task_id // \"—\"")" duration_str="—" if [[ -n "$s_start" && -n "$s_end" && "$s_end" != "" ]]; then s_epoch="$(iso_to_epoch "$s_start")" e_epoch="$(iso_to_epoch "$s_end")" if (( e_epoch > 0 && s_epoch > 0 )); then duration_str="$(format_duration $(( e_epoch - s_epoch )))" fi fi printf " %-10s %-8s %-10s %-18s → %s\n" "$s_id" "$s_rt" "$duration_str" "$s_reason" "$s_last" done echo "" fi # Current session check lock_data="" if lock_data="$(session_lock_read "$PROJECT" 2>/dev/null)"; then lock_pid="$(echo "$lock_data" | jq -r '.pid // 0')" lock_rt="$(echo "$lock_data" | jq -r '.runtime // "unknown"')" lock_start="$(echo "$lock_data" | jq -r '.started_at // ""')" if is_pid_alive "$lock_pid"; then dur=0 if [[ -n "$lock_start" ]]; then dur=$(( $(epoch_now) - $(iso_to_epoch "$lock_start") )) fi echo -e "${C_GREEN}Current: running ($lock_rt, PID $lock_pid, $(format_duration "$dur"))${C_RESET}" else echo -e "${C_RED}Stale session lock: $lock_rt (PID $lock_pid, not running)${C_RESET}" echo " Run: mosaic coord resume --clean-lock" fi else echo -e "${C_DIM}No active session.${C_RESET}" fi [[ -n "$next_task" ]] && echo -e "Next unblocked task: ${C_CYAN}$next_task${C_RESET}" echo ""