- coord/prdy subcommands now accept --claude/--codex runtime flags - New `mosaic coord run` generates continuation context and launches selected runtime, replacing manual copy/paste workflow - Next-task capsule (.mosaic/orchestrator/next-task.json) provides machine-readable execution context for deterministic session launches - Codex strict orchestrator profile added to runtime/codex/RUNTIME.md - Orchestrator protocol updated with between-session run flow - New smoke-test.sh for orchestration behavior verification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
242 lines
8.2 KiB
Bash
Executable File
242 lines
8.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
#
|
|
# session-status.sh — Check agent session health
|
|
#
|
|
# Usage:
|
|
# session-status.sh [--project <path>] [--format table|json]
|
|
#
|
|
# Exit codes:
|
|
# 0 = running
|
|
# 2 = stale (recently died)
|
|
# 3 = dead (no longer running)
|
|
# 4 = no session
|
|
|
|
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: session-status.sh [--project <path>] [--format table|json]"
|
|
exit 0
|
|
;;
|
|
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
_require_jq
|
|
runtime_cmd="$(coord_launch_command)"
|
|
run_cmd="$(coord_run_command)"
|
|
|
|
# ─── Check session lock ─────────────────────────────────────────────────────
|
|
|
|
lock_data=""
|
|
if ! lock_data="$(session_lock_read "$PROJECT")"; then
|
|
# No active session — but check if a mission exists
|
|
mp="$(mission_path "$PROJECT")"
|
|
if [[ -f "$mp" ]]; then
|
|
m_status="$(jq -r '.status // "inactive"' "$mp")"
|
|
m_name="$(jq -r '.name // "unnamed"' "$mp")"
|
|
m_id="$(jq -r '.mission_id // ""' "$mp")"
|
|
m_total="$(jq '.milestones | length' "$mp")"
|
|
m_done="$(jq '[.milestones[] | select(.status == "completed")] | length' "$mp")"
|
|
m_current="$(jq -r '[.milestones[] | select(.status == "active" or .status == "pending")][0].name // "none"' "$mp")"
|
|
|
|
# Task counts if TASKS.md exists
|
|
task_json="$(count_tasks_md "$PROJECT")"
|
|
t_total="$(echo "$task_json" | jq '.total')"
|
|
t_done="$(echo "$task_json" | jq '.done')"
|
|
t_pending="$(echo "$task_json" | jq '.pending')"
|
|
t_inprog="$(echo "$task_json" | jq '.in_progress')"
|
|
|
|
if [[ "$FORMAT" == "json" ]]; then
|
|
jq -n \
|
|
--arg status "no-session" \
|
|
--arg mission_status "$m_status" \
|
|
--arg mission_name "$m_name" \
|
|
--arg mission_id "$m_id" \
|
|
--argjson milestones_total "$m_total" \
|
|
--argjson milestones_done "$m_done" \
|
|
--argjson tasks_total "$t_total" \
|
|
--argjson tasks_done "$t_done" \
|
|
'{
|
|
status: $status,
|
|
mission: {
|
|
status: $mission_status,
|
|
name: $mission_name,
|
|
id: $mission_id,
|
|
milestones_total: $milestones_total,
|
|
milestones_done: $milestones_done,
|
|
tasks_total: $tasks_total,
|
|
tasks_done: $tasks_done
|
|
}
|
|
}'
|
|
else
|
|
echo ""
|
|
echo -e " ${C_DIM}No active agent session.${C_RESET}"
|
|
echo ""
|
|
|
|
# Mission info
|
|
case "$m_status" in
|
|
active) ms_color="${C_GREEN}ACTIVE${C_RESET}" ;;
|
|
paused) ms_color="${C_YELLOW}PAUSED${C_RESET}" ;;
|
|
completed) ms_color="${C_CYAN}COMPLETED${C_RESET}" ;;
|
|
*) ms_color="${C_DIM}${m_status}${C_RESET}" ;;
|
|
esac
|
|
|
|
echo -e " ${C_BOLD}Mission:${C_RESET} $m_name"
|
|
echo -e " ${C_CYAN}Status:${C_RESET} $ms_color"
|
|
echo -e " ${C_CYAN}ID:${C_RESET} $m_id"
|
|
echo -e " ${C_CYAN}Milestones:${C_RESET} $m_done / $m_total completed"
|
|
[[ "$m_current" != "none" ]] && echo -e " ${C_CYAN}Current:${C_RESET} $m_current"
|
|
|
|
if (( t_total > 0 )); then
|
|
echo -e " ${C_CYAN}Tasks:${C_RESET} $t_done / $t_total done ($t_pending pending, $t_inprog in-progress)"
|
|
fi
|
|
echo ""
|
|
|
|
if [[ "$m_status" == "active" || "$m_status" == "paused" ]]; then
|
|
echo -e " ${C_BOLD}Next steps:${C_RESET}"
|
|
echo " $run_cmd Auto-generate context and launch"
|
|
echo " mosaic coord continue Generate continuation prompt"
|
|
echo " $runtime_cmd Launch agent session"
|
|
elif [[ "$m_status" == "completed" ]]; then
|
|
echo -e " ${C_DIM}Mission completed. Start a new one with: mosaic coord init${C_RESET}"
|
|
else
|
|
echo -e " ${C_DIM}Initialize with: mosaic coord init --name \"Mission Name\"${C_RESET}"
|
|
fi
|
|
echo ""
|
|
fi
|
|
else
|
|
if [[ "$FORMAT" == "json" ]]; then
|
|
echo '{"status":"no-session","mission":null}'
|
|
else
|
|
echo ""
|
|
echo -e " ${C_DIM}No active session.${C_RESET}"
|
|
echo -e " ${C_DIM}No mission found.${C_RESET}"
|
|
echo ""
|
|
echo " Initialize with: mosaic coord init --name \"Mission Name\""
|
|
echo ""
|
|
fi
|
|
fi
|
|
exit 4
|
|
fi
|
|
|
|
# Parse lock
|
|
session_id="$(echo "$lock_data" | jq -r '.session_id // "unknown"')"
|
|
runtime="$(echo "$lock_data" | jq -r '.runtime // "unknown"')"
|
|
pid="$(echo "$lock_data" | jq -r '.pid // 0')"
|
|
started_at="$(echo "$lock_data" | jq -r '.started_at // ""')"
|
|
milestone_id="$(echo "$lock_data" | jq -r '.milestone_id // ""')"
|
|
|
|
# ─── Determine status ───────────────────────────────────────────────────────
|
|
|
|
status="unknown"
|
|
exit_code=1
|
|
|
|
if is_pid_alive "$pid"; then
|
|
status="running"
|
|
exit_code=0
|
|
else
|
|
# PID is dead — check how recently
|
|
last_act="$(last_activity_time "$PROJECT")"
|
|
now="$(epoch_now)"
|
|
age=$(( now - last_act ))
|
|
|
|
if (( age < STALE_THRESHOLD )); then
|
|
status="stale"
|
|
exit_code=2
|
|
elif (( age < DEAD_THRESHOLD )); then
|
|
status="stale"
|
|
exit_code=2
|
|
else
|
|
status="dead"
|
|
exit_code=3
|
|
fi
|
|
fi
|
|
|
|
# ─── Gather supplementary info ──────────────────────────────────────────────
|
|
|
|
duration_secs=0
|
|
if [[ -n "$started_at" ]]; then
|
|
start_epoch="$(iso_to_epoch "$started_at")"
|
|
now="$(epoch_now)"
|
|
duration_secs=$(( now - start_epoch ))
|
|
fi
|
|
|
|
last_act="$(last_activity_time "$PROJECT")"
|
|
|
|
# Current milestone from mission.json
|
|
current_ms=""
|
|
if [[ -f "$(mission_path "$PROJECT")" ]]; then
|
|
current_ms="$(current_milestone_id "$PROJECT")"
|
|
if [[ -n "$current_ms" ]]; then
|
|
ms_name="$(milestone_name "$PROJECT" "$current_ms")"
|
|
[[ -n "$ms_name" ]] && current_ms="$current_ms ($ms_name)"
|
|
fi
|
|
fi
|
|
|
|
# Next task from TASKS.md
|
|
next_task="$(find_next_task "$PROJECT")"
|
|
|
|
# ─── Output ──────────────────────────────────────────────────────────────────
|
|
|
|
if [[ "$FORMAT" == "json" ]]; then
|
|
jq -n \
|
|
--arg status "$status" \
|
|
--arg session_id "$session_id" \
|
|
--arg runtime "$runtime" \
|
|
--arg pid "$pid" \
|
|
--arg started_at "$started_at" \
|
|
--arg duration "$duration_secs" \
|
|
--arg milestone "$current_ms" \
|
|
--arg next_task "$next_task" \
|
|
--arg last_activity "$last_act" \
|
|
'{
|
|
status: $status,
|
|
session_id: $session_id,
|
|
runtime: $runtime,
|
|
pid: ($pid | tonumber),
|
|
started_at: $started_at,
|
|
duration_seconds: ($duration | tonumber),
|
|
milestone: $milestone,
|
|
next_task: $next_task,
|
|
last_activity_epoch: ($last_activity | tonumber)
|
|
}'
|
|
else
|
|
# Color the status
|
|
case "$status" in
|
|
running) status_color="${C_GREEN}RUNNING${C_RESET}" ;;
|
|
stale) status_color="${C_YELLOW}STALE${C_RESET}" ;;
|
|
dead) status_color="${C_RED}DEAD${C_RESET}" ;;
|
|
*) status_color="$status" ;;
|
|
esac
|
|
|
|
echo ""
|
|
echo -e " Session Status: $status_color ($runtime)"
|
|
echo -e " ${C_CYAN}Session ID:${C_RESET} $session_id"
|
|
echo -e " ${C_CYAN}Started:${C_RESET} $started_at ($(format_duration "$duration_secs"))"
|
|
echo -e " ${C_CYAN}PID:${C_RESET} $pid"
|
|
[[ -n "$current_ms" ]] && echo -e " ${C_CYAN}Milestone:${C_RESET} $current_ms"
|
|
[[ -n "$next_task" ]] && echo -e " ${C_CYAN}Next task:${C_RESET} $next_task"
|
|
echo -e " ${C_CYAN}Last activity:${C_RESET} $(format_ago "$last_act")"
|
|
echo ""
|
|
|
|
if [[ "$status" == "stale" || "$status" == "dead" ]]; then
|
|
echo -e " ${C_YELLOW}Session is no longer running.${C_RESET}"
|
|
echo " Recovery: mosaic coord resume"
|
|
echo " Continue: mosaic coord continue"
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
exit "$exit_code"
|