diff --git a/.agents/scripts/supervisor-helper.sh b/.agents/scripts/supervisor-helper.sh index 8a6e1a47b..7eebd0856 100755 --- a/.agents/scripts/supervisor-helper.sh +++ b/.agents/scripts/supervisor-helper.sh @@ -28,6 +28,7 @@ # supervisor-helper.sh auto-pickup [--repo path] Scan TODO.md for #auto-dispatch tasks # supervisor-helper.sh cron [install|uninstall|status] Manage cron-based pulse scheduling # supervisor-helper.sh watch [--repo path] Watch TODO.md for changes (fswatch) +# supervisor-helper.sh dashboard [--batch id] [--interval N] Live TUI dashboard (t068.8) # supervisor-helper.sh pr-lifecycle [--dry-run] Handle post-PR merge/deploy lifecycle # supervisor-helper.sh pr-check Check PR CI/review status # supervisor-helper.sh pr-merge [--dry-run] Merge PR (squash) @@ -5669,6 +5670,522 @@ cmd_watch() { return 0 } +####################################### +# TUI Dashboard - live-updating terminal UI for supervisor monitoring (t068.8) +# +# Renders a full-screen dashboard with: +# - Header: batch name, uptime, refresh interval +# - Task table: ID, status (color-coded), description, retries, PR URL +# - Batch progress bar +# - System resources: load, memory, worker processes +# - Keyboard controls: q=quit, p=pause/resume, r=refresh, j/k=scroll +# +# Zero dependencies beyond bash + sqlite3 + tput (standard on macOS/Linux). +# Refreshes every N seconds (default 2). Reads from supervisor.db. +####################################### +cmd_dashboard() { + local refresh_interval=2 + local batch_filter="" + + while [[ $# -gt 0 ]]; do + case "$1" in + --interval) [[ $# -lt 2 ]] && { log_error "--interval requires a value"; return 1; }; refresh_interval="$2"; shift 2 ;; + --batch) [[ $# -lt 2 ]] && { log_error "--batch requires a value"; return 1; }; batch_filter="$2"; shift 2 ;; + *) log_error "Unknown option: $1"; return 1 ;; + esac + done + + ensure_db + + # Terminal setup + local term_cols term_rows + term_cols=$(tput cols 2>/dev/null || echo 120) + term_rows=$(tput lines 2>/dev/null || echo 40) + + # State + local paused=false + local scroll_offset=0 + local start_time + start_time=$(date +%s) + + # Save terminal state and hide cursor + tput smcup 2>/dev/null || true + tput civis 2>/dev/null || true + stty -echo -icanon min 0 time 0 2>/dev/null || true + + # Cleanup on exit + _dashboard_cleanup() { + tput rmcup 2>/dev/null || true + tput cnorm 2>/dev/null || true + stty echo icanon 2>/dev/null || true + } + trap _dashboard_cleanup EXIT INT TERM + + # Color helpers using tput for portability + local c_reset c_bold c_dim c_red c_green c_yellow c_blue c_cyan c_magenta c_white c_bg_black + c_reset=$(tput sgr0 2>/dev/null || printf '\033[0m') + c_bold=$(tput bold 2>/dev/null || printf '\033[1m') + c_dim=$(tput dim 2>/dev/null || printf '\033[2m') + c_red=$(tput setaf 1 2>/dev/null || printf '\033[31m') + c_green=$(tput setaf 2 2>/dev/null || printf '\033[32m') + c_yellow=$(tput setaf 3 2>/dev/null || printf '\033[33m') + c_blue=$(tput setaf 4 2>/dev/null || printf '\033[34m') + c_cyan=$(tput setaf 6 2>/dev/null || printf '\033[36m') + c_white=$(tput setaf 7 2>/dev/null || printf '\033[37m') + + # Format elapsed time as Xh Xm Xs + _fmt_elapsed() { + local secs="$1" + local h=$((secs / 3600)) + local m=$(( (secs % 3600) / 60 )) + local s=$((secs % 60)) + if [[ "$h" -gt 0 ]]; then + printf '%dh %dm %ds' "$h" "$m" "$s" + elif [[ "$m" -gt 0 ]]; then + printf '%dm %ds' "$m" "$s" + else + printf '%ds' "$s" + fi + } + + # Render a progress bar: _render_bar + _render_bar() { + local current="$1" total="$2" width="${3:-30}" + local filled=0 + if [[ "$total" -gt 0 ]]; then + filled=$(( (current * width) / total )) + fi + local empty=$((width - filled)) + local pct=0 + if [[ "$total" -gt 0 ]]; then + pct=$(( (current * 100) / total )) + fi + printf '%s' "${c_green}" + local i + for ((i = 0; i < filled; i++)); do printf '%s' "█"; done + printf '%s' "${c_dim}" + for ((i = 0; i < empty; i++)); do printf '%s' "░"; done + printf '%s %3d%%' "${c_reset}" "$pct" + } + + # Color for a task status + _status_color() { + local status="$1" + case "$status" in + running|dispatched) printf '%s' "${c_green}" ;; + evaluating|retrying|pr_review|merging|deploying) printf '%s' "${c_yellow}" ;; + blocked|failed) printf '%s' "${c_red}" ;; + complete|merged) printf '%s' "${c_cyan}" ;; + deployed) printf '%s' "${c_green}${c_bold}" ;; + queued) printf '%s' "${c_white}" ;; + cancelled) printf '%s' "${c_dim}" ;; + *) printf '%s' "${c_reset}" ;; + esac + } + + # Status icon + _status_icon() { + local status="$1" + case "$status" in + running) printf '%s' ">" ;; + dispatched) printf '%s' "~" ;; + evaluating) printf '%s' "?" ;; + retrying) printf '%s' "!" ;; + complete) printf '%s' "+" ;; + pr_review) printf '%s' "R" ;; + merging) printf '%s' "M" ;; + merged) printf '%s' "=" ;; + deploying) printf '%s' "D" ;; + deployed) printf '%s' "*" ;; + blocked) printf '%s' "X" ;; + failed) printf '%s' "x" ;; + queued) printf '%s' "." ;; + cancelled) printf '%s' "-" ;; + *) printf '%s' " " ;; + esac + } + + # Truncate string to width + _trunc() { + local str="$1" max="$2" + if [[ "${#str}" -gt "$max" ]]; then + printf '%s' "${str:0:$((max - 1))}…" + else + printf '%-*s' "$max" "$str" + fi + } + + # Render one frame + _render_frame() { + # Refresh terminal size + term_cols=$(tput cols 2>/dev/null || echo 120) + term_rows=$(tput lines 2>/dev/null || echo 40) + + local now + now=$(date +%s) + local elapsed=$((now - start_time)) + + # Move cursor to top-left, clear screen + tput home 2>/dev/null || printf '\033[H' + tput ed 2>/dev/null || printf '\033[J' + + local line=0 + local max_lines=$((term_rows - 1)) + + # === HEADER === + local header_left="SUPERVISOR DASHBOARD" + local header_right + if [[ "$paused" == "true" ]]; then + header_right="[PAUSED] $(date '+%H:%M:%S') | up $(_fmt_elapsed "$elapsed")" + else + header_right="$(date '+%H:%M:%S') | up $(_fmt_elapsed "$elapsed") | refresh ${refresh_interval}s" + fi + local header_pad=$((term_cols - ${#header_left} - ${#header_right})) + [[ "$header_pad" -lt 1 ]] && header_pad=1 + printf '%s%s%s%*s%s%s\n' "${c_bold}${c_cyan}" "$header_left" "${c_reset}" "$header_pad" "" "${c_dim}" "$header_right${c_reset}" + line=$((line + 1)) + + # Separator + printf '%s' "${c_dim}" + printf '%*s' "$term_cols" '' | tr ' ' '─' + printf '%s\n' "${c_reset}" + line=$((line + 1)) + + # === BATCH SUMMARY === + local batch_where="" + if [[ -n "$batch_filter" ]]; then + batch_where="AND EXISTS (SELECT 1 FROM batch_tasks bt WHERE bt.task_id = t.id AND bt.batch_id = '$(sql_escape "$batch_filter")')" + fi + + local counts + counts=$(db "$SUPERVISOR_DB" " + SELECT + count(*) as total, + sum(CASE WHEN t.status = 'queued' THEN 1 ELSE 0 END), + sum(CASE WHEN t.status IN ('dispatched','running') THEN 1 ELSE 0 END), + sum(CASE WHEN t.status = 'evaluating' THEN 1 ELSE 0 END), + sum(CASE WHEN t.status = 'retrying' THEN 1 ELSE 0 END), + sum(CASE WHEN t.status IN ('complete','pr_review','merging','merged','deploying','deployed') THEN 1 ELSE 0 END), + sum(CASE WHEN t.status IN ('blocked','failed') THEN 1 ELSE 0 END), + sum(CASE WHEN t.status = 'cancelled' THEN 1 ELSE 0 END) + FROM tasks t WHERE 1=1 $batch_where; + " 2>/dev/null) + + local total queued active evaluating retrying finished errored cancelled + IFS='|' read -r total queued active evaluating retrying finished errored cancelled <<< "$counts" + total=${total:-0}; queued=${queued:-0}; active=${active:-0} + evaluating=${evaluating:-0}; retrying=${retrying:-0} + finished=${finished:-0}; errored=${errored:-0}; cancelled=${cancelled:-0} + + # Batch info line + local batch_label="All Tasks" + if [[ -n "$batch_filter" ]]; then + local batch_name + batch_name=$(db "$SUPERVISOR_DB" "SELECT name FROM batches WHERE id = '$(sql_escape "$batch_filter")';" 2>/dev/null || echo "$batch_filter") + batch_label="Batch: ${batch_name:-$batch_filter}" + fi + + printf ' %s%s%s ' "${c_bold}" "$batch_label" "${c_reset}" + printf '%s%d total%s | ' "${c_white}" "$total" "${c_reset}" + printf '%s%d queued%s | ' "${c_white}" "$queued" "${c_reset}" + printf '%s%d active%s | ' "${c_green}" "$active" "${c_reset}" + printf '%s%d eval%s | ' "${c_yellow}" "$evaluating" "${c_reset}" + printf '%s%d retry%s | ' "${c_yellow}" "$retrying" "${c_reset}" + printf '%s%d done%s | ' "${c_cyan}" "$finished" "${c_reset}" + printf '%s%d err%s' "${c_red}" "$errored" "${c_reset}" + if [[ "$cancelled" -gt 0 ]]; then + printf ' | %s%d cancel%s' "${c_dim}" "$cancelled" "${c_reset}" + fi + printf '\n' + line=$((line + 1)) + + # Progress bar + local completed_for_bar=$((finished + cancelled)) + printf ' Progress: ' + _render_bar "$completed_for_bar" "$total" 40 + printf ' (%d/%d)\n' "$completed_for_bar" "$total" + line=$((line + 1)) + + # Separator + printf '%s' "${c_dim}" + printf '%*s' "$term_cols" '' | tr ' ' '─' + printf '%s\n' "${c_reset}" + line=$((line + 1)) + + # === TASK TABLE === + # Column widths (adaptive to terminal width) + local col_icon=3 col_id=8 col_status=12 col_retry=7 col_pr=0 col_error=0 + local col_desc_min=20 + local remaining=$((term_cols - col_icon - col_id - col_status - col_retry - 8)) + + # Allocate PR column if any tasks have PR URLs + local has_prs + has_prs=$(db "$SUPERVISOR_DB" "SELECT count(*) FROM tasks WHERE pr_url IS NOT NULL AND pr_url != '' $batch_where;" 2>/dev/null || echo 0) + if [[ "$has_prs" -gt 0 ]]; then + col_pr=12 + remaining=$((remaining - col_pr)) + fi + + # Allocate error column if any tasks have errors + local has_errors + has_errors=$(db "$SUPERVISOR_DB" "SELECT count(*) FROM tasks WHERE error IS NOT NULL AND error != '' $batch_where;" 2>/dev/null || echo 0) + if [[ "$has_errors" -gt 0 ]]; then + col_error=25 + remaining=$((remaining - col_error)) + fi + + local col_desc=$remaining + [[ "$col_desc" -lt "$col_desc_min" ]] && col_desc=$col_desc_min + + # Table header + printf ' %s' "${c_bold}${c_dim}" + printf '%-*s' "$col_icon" " " + printf '%-*s' "$col_id" "TASK" + printf '%-*s' "$col_status" "STATUS" + printf '%-*s' "$col_desc" "DESCRIPTION" + printf '%-*s' "$col_retry" "RETRY" + [[ "$col_pr" -gt 0 ]] && printf '%-*s' "$col_pr" "PR" + [[ "$col_error" -gt 0 ]] && printf '%-*s' "$col_error" "ERROR" + printf '%s\n' "${c_reset}" + line=$((line + 1)) + + # Fetch tasks + local tasks + tasks=$(db -separator ' ' "$SUPERVISOR_DB" " + SELECT t.id, t.status, t.description, t.retries, t.max_retries, + COALESCE(t.pr_url, ''), COALESCE(t.error, '') + FROM tasks t + WHERE 1=1 $batch_where + ORDER BY + CASE t.status + WHEN 'running' THEN 1 + WHEN 'dispatched' THEN 2 + WHEN 'evaluating' THEN 3 + WHEN 'retrying' THEN 4 + WHEN 'queued' THEN 5 + WHEN 'pr_review' THEN 6 + WHEN 'merging' THEN 7 + WHEN 'deploying' THEN 8 + WHEN 'blocked' THEN 9 + WHEN 'failed' THEN 10 + WHEN 'complete' THEN 11 + WHEN 'merged' THEN 12 + WHEN 'deployed' THEN 13 + WHEN 'cancelled' THEN 14 + END, t.created_at ASC; + " 2>/dev/null) + + local task_count=0 + local visible_start=$scroll_offset + local visible_rows=$((max_lines - line - 6)) + [[ "$visible_rows" -lt 3 ]] && visible_rows=3 + + if [[ -n "$tasks" ]]; then + local task_idx=0 + while IFS=' ' read -r tid tstatus tdesc tretries tmax tpr terror; do + task_count=$((task_count + 1)) + if [[ "$task_idx" -lt "$visible_start" ]]; then + task_idx=$((task_idx + 1)) + continue + fi + if [[ "$task_idx" -ge $((visible_start + visible_rows)) ]]; then + task_idx=$((task_idx + 1)) + continue + fi + + local sc + sc=$(_status_color "$tstatus") + local si + si=$(_status_icon "$tstatus") + + printf ' %s%s%s ' "$sc" "$si" "${c_reset}" + printf '%-*s' "$col_id" "$tid" + printf '%s%-*s%s' "$sc" "$col_status" "$tstatus" "${c_reset}" + _trunc "${tdesc:-}" "$col_desc" + printf ' ' + if [[ "$tretries" -gt 0 ]]; then + printf '%s%d/%d%s' "${c_yellow}" "$tretries" "$tmax" "${c_reset}" + local pad=$((col_retry - ${#tretries} - ${#tmax} - 1)) + [[ "$pad" -gt 0 ]] && printf '%*s' "$pad" '' + else + printf '%-*s' "$col_retry" "0/$tmax" + fi + if [[ "$col_pr" -gt 0 ]]; then + if [[ -n "$tpr" ]]; then + local pr_num + pr_num=$(echo "$tpr" | grep -oE '[0-9]+$' || echo "$tpr") + printf ' %s#%-*s%s' "${c_blue}" $((col_pr - 2)) "$pr_num" "${c_reset}" + else + printf ' %-*s' "$col_pr" "" + fi + fi + if [[ "$col_error" -gt 0 && -n "$terror" ]]; then + printf ' %s' "${c_red}" + _trunc "$terror" "$col_error" + printf '%s' "${c_reset}" + fi + printf '\n' + line=$((line + 1)) + task_idx=$((task_idx + 1)) + done <<< "$tasks" + else + printf ' %s(no tasks)%s\n' "${c_dim}" "${c_reset}" + line=$((line + 1)) + fi + + # Scroll indicator + if [[ "$task_count" -gt "$visible_rows" ]]; then + local scroll_end=$((scroll_offset + visible_rows)) + [[ "$scroll_end" -gt "$task_count" ]] && scroll_end=$task_count + printf ' %s[%d-%d of %d tasks]%s\n' "${c_dim}" "$((scroll_offset + 1))" "$scroll_end" "$task_count" "${c_reset}" + line=$((line + 1)) + fi + + # === SYSTEM RESOURCES === + # Only show if we have room + if [[ "$line" -lt $((max_lines - 4)) ]]; then + printf '%s' "${c_dim}" + printf '%*s' "$term_cols" '' | tr ' ' '─' + printf '%s\n' "${c_reset}" + line=$((line + 1)) + + local load_output + load_output=$(check_system_load 2>/dev/null || echo "") + + if [[ -n "$load_output" ]]; then + local sys_cores sys_load1 sys_load5 sys_load15 sys_procs sys_sup_procs sys_mem sys_overloaded + sys_cores=$(echo "$load_output" | grep '^cpu_cores=' | cut -d= -f2) + sys_load1=$(echo "$load_output" | grep '^load_1m=' | cut -d= -f2) + sys_load5=$(echo "$load_output" | grep '^load_5m=' | cut -d= -f2) + sys_load15=$(echo "$load_output" | grep '^load_15m=' | cut -d= -f2) + sys_procs=$(echo "$load_output" | grep '^process_count=' | cut -d= -f2) + sys_sup_procs=$(echo "$load_output" | grep '^supervisor_process_count=' | cut -d= -f2) + sys_mem=$(echo "$load_output" | grep '^memory_pressure=' | cut -d= -f2) + sys_overloaded=$(echo "$load_output" | grep '^overloaded=' | cut -d= -f2) + + printf ' %sSYSTEM%s ' "${c_bold}" "${c_reset}" + printf 'Load: %s%s%s %s %s (%s cores) ' \ + "$([[ "$sys_overloaded" == "true" ]] && printf '%s' "${c_red}${c_bold}" || printf '%s' "${c_green}")" \ + "$sys_load1" "${c_reset}" "$sys_load5" "$sys_load15" "$sys_cores" + printf 'Procs: %s (%s supervisor) ' "$sys_procs" "$sys_sup_procs" + printf 'Mem: %s%s%s' \ + "$([[ "$sys_mem" == "high" ]] && printf '%s' "${c_red}" || ([[ "$sys_mem" == "medium" ]] && printf '%s' "${c_yellow}" || printf '%s' "${c_green}"))" \ + "$sys_mem" "${c_reset}" + if [[ "$sys_overloaded" == "true" ]]; then + printf ' %s!! OVERLOADED !!%s' "${c_red}${c_bold}" "${c_reset}" + fi + printf '\n' + line=$((line + 1)) + fi + + # Active workers with PIDs + if [[ -d "$SUPERVISOR_DIR/pids" ]]; then + local worker_info="" + local worker_count=0 + for pid_file in "$SUPERVISOR_DIR/pids"/*.pid; do + [[ -f "$pid_file" ]] || continue + local wpid wtask_id + wpid=$(cat "$pid_file") + wtask_id=$(basename "$pid_file" .pid) + if kill -0 "$wpid" 2>/dev/null; then + worker_count=$((worker_count + 1)) + if [[ -n "$worker_info" ]]; then + worker_info="$worker_info, " + fi + worker_info="${worker_info}${wtask_id}(pid:${wpid})" + fi + done + if [[ "$worker_count" -gt 0 ]]; then + printf ' %sWORKERS%s %d active: %s\n' "${c_bold}" "${c_reset}" "$worker_count" "$worker_info" + line=$((line + 1)) + fi + fi + fi + + # === FOOTER === + # Move to last line + local footer_line=$((max_lines)) + tput cup "$footer_line" 0 2>/dev/null || printf '\033[%d;0H' "$footer_line" + printf '%s q%s=quit %sp%s=pause %sr%s=refresh %sj/k%s=scroll %s?%s=help' \ + "${c_bold}" "${c_reset}" "${c_bold}" "${c_reset}" "${c_bold}" "${c_reset}" \ + "${c_bold}" "${c_reset}" "${c_bold}" "${c_reset}" + } + + # Main loop + while true; do + if [[ "$paused" != "true" ]]; then + _render_frame + fi + + # Read keyboard input (non-blocking) + local key="" + local wait_count=0 + local wait_max=$((refresh_interval * 10)) + + while [[ "$wait_count" -lt "$wait_max" ]]; do + key="" + read -rsn1 -t 0.1 key 2>/dev/null || true + + case "$key" in + q|Q) + return 0 + ;; + p|P) + if [[ "$paused" == "true" ]]; then + paused=false + else + paused=true + # Show paused indicator + tput cup 0 $((term_cols - 10)) 2>/dev/null || true + printf '%s[PAUSED]%s' "${c_yellow}${c_bold}" "${c_reset}" + fi + ;; + r|R) + _render_frame + wait_count=0 + ;; + j|J) + local max_task_count + max_task_count=$(db "$SUPERVISOR_DB" "SELECT count(*) FROM tasks;" 2>/dev/null || echo 0) + if [[ "$scroll_offset" -lt $((max_task_count - 1)) ]]; then + scroll_offset=$((scroll_offset + 1)) + _render_frame + fi + ;; + k|K) + if [[ "$scroll_offset" -gt 0 ]]; then + scroll_offset=$((scroll_offset - 1)) + _render_frame + fi + ;; + '?') + tput home 2>/dev/null || printf '\033[H' + tput ed 2>/dev/null || printf '\033[J' + printf '%s%sSupervisor Dashboard Help%s\n\n' "${c_bold}" "${c_cyan}" "${c_reset}" + printf ' %sq%s Quit dashboard\n' "${c_bold}" "${c_reset}" + printf ' %sp%s Pause/resume auto-refresh\n' "${c_bold}" "${c_reset}" + printf ' %sr%s Force refresh now\n' "${c_bold}" "${c_reset}" + printf ' %sj/k%s Scroll task list down/up\n' "${c_bold}" "${c_reset}" + printf ' %s?%s Show this help\n\n' "${c_bold}" "${c_reset}" + printf '%sStatus Icons:%s\n' "${c_bold}" "${c_reset}" + printf ' %s>%s running %s~%s dispatched %s?%s evaluating %s!%s retrying\n' \ + "${c_green}" "${c_reset}" "${c_green}" "${c_reset}" "${c_yellow}" "${c_reset}" "${c_yellow}" "${c_reset}" + printf ' %s+%s complete %s=%s merged %s*%s deployed %s.%s queued\n' \ + "${c_cyan}" "${c_reset}" "${c_cyan}" "${c_reset}" "${c_green}" "${c_reset}" "${c_white}" "${c_reset}" + printf ' %sX%s blocked %sx%s failed %s-%s cancelled %sR%s pr_review\n\n' \ + "${c_red}" "${c_reset}" "${c_red}" "${c_reset}" "${c_dim}" "${c_reset}" "${c_yellow}" "${c_reset}" + printf 'Press any key to return...' + read -rsn1 _ 2>/dev/null || true + _render_frame + wait_count=0 + ;; + esac + + wait_count=$((wait_count + 1)) + done + done +} + ####################################### # Show usage ####################################### @@ -5705,6 +6222,7 @@ Usage: supervisor-helper.sh auto-pickup [--repo path] Scan TODO.md for auto-dispatch tasks supervisor-helper.sh cron [install|uninstall|status] Manage cron-based pulse scheduling supervisor-helper.sh watch [--repo path] Watch TODO.md for changes (fswatch) + supervisor-helper.sh dashboard [--batch id] [--interval N] Live TUI dashboard supervisor-helper.sh db [sql] Direct SQLite access supervisor-helper.sh help Show this help @@ -5914,6 +6432,22 @@ Options for 'release': --enable Enable release_on_complete for the batch --disable Disable release_on_complete for the batch --dry-run Show what would happen without executing + +TUI Dashboard (t068.8): + Live-updating terminal dashboard for monitoring supervisor tasks. + Shows task states, batch progress, system resources, and active workers. + Zero dependencies beyond bash + sqlite3 + tput. + + Keyboard controls: + q Quit dashboard + p Pause/resume auto-refresh + r Force refresh now + j/k Scroll task list down/up + ? Show help overlay + +Options for 'dashboard': + --batch Filter to a specific batch + --interval Refresh interval in seconds (default: 2) EOF } @@ -5944,6 +6478,7 @@ main() { auto-pickup) cmd_auto_pickup "$@" ;; cron) cmd_cron "$@" ;; watch) cmd_watch "$@" ;; + dashboard) cmd_dashboard "$@" ;; recall) cmd_recall "$@" ;; release) cmd_release "$@" ;; retrospective) cmd_retrospective "$@" ;; diff --git a/.agents/subagent-index.toon b/.agents/subagent-index.toon index 3b26dbb47..75704433b 100644 --- a/.agents/subagent-index.toon +++ b/.agents/subagent-index.toon @@ -116,7 +116,7 @@ cron-helper.sh,Cron job management for scheduled AI agent dispatch cron-dispatch.sh,Execute cron jobs via OpenCode server API runner-helper.sh,Named headless AI agent instances (create run status list edit logs stop destroy) matrix-dispatch-helper.sh,Matrix bot for dispatching messages to AI runners (setup start stop map test) -supervisor-helper.sh,Autonomous supervisor for multi-task orchestration (init add batch dispatch reprompt evaluate pulse worker-status cleanup transition status list next running-count reset cancel db) +supervisor-helper.sh,Autonomous supervisor for multi-task orchestration (init add batch dispatch reprompt evaluate pulse dashboard worker-status cleanup transition status list next running-count reset cancel db) schema-validator-helper.sh,Schema.org structured data validation (validate validate-json status install) speech-to-speech-helper.sh,Voice pipeline management (setup start stop status client config benchmark) voice-helper.sh,Voice bridge - talk to AI agents via speech (talk devices voices status benchmark) diff --git a/TODO.md b/TODO.md index 97224f17d..c6b25c2d7 100644 --- a/TODO.md +++ b/TODO.md @@ -83,8 +83,8 @@ Tasks with no open blockers - ready to work on. Use `/ready` to refresh this lis - Notes: PR #469 merged. create_github_issue() + update_todo_with_issue_ref() + --no-issue flag + SUPERVISOR_AUTO_ISSUE env. - [ ] t146 bug: supervisor no_pr retry counter non-functional (missing $SUPERVISOR_DB) #bugfix #supervisor ~15m (ai:10m test:5m) logged:2026-02-07 ref:GH#439 - Notes: Lines 3165 and 3183 of supervisor-helper.sh missing $SUPERVISOR_DB as first arg to db(). Every other db call (20+) passes it. Retry counter never persists. Also remove unused no_pr_key variable on line 3163. From CodeRabbit review on PR #435. BLOCKED: FAILED: no_log_file -- [x] t145 bug: sed -i '' is macOS-only, breaks on Linux/CI #bugfix #portability ~1h (ai:30m test:30m) logged:2026-02-07 ref:GH#440 completed:2026-02-08 - - Notes: PR #479 merged. Replaced all non-portable sed -i usage across 17 scripts with sed_inplace() wrapper from shared-constants.sh. Added sed_append_after() for portable line insertion. Removed 6 duplicate local definitions. +- [ ] t145 bug: sed -i '' is macOS-only, breaks on Linux/CI #bugfix #portability ~1h (ai:30m test:30m) logged:2026-02-07 ref:GH#440 + - Notes: Multiple scripts use BSD sed -i '' syntax. Need portable wrapper in shared-constants.sh. Audit all scripts for sed -i usage. From reviews on PR #406. - [x] t144 quality: excessive 2>/dev/null suppresses real errors #quality #debugging ~3h actual:1h (ai:1h) logged:2026-02-07 ref:GH#441 completed:2026-02-07 - Notes: PR #463 merged. Replaced excessive 2>/dev/null with log file redirects across supervisor and helper scripts. - [x] t143 quality: test script BRE alternation -> ERE style improvement #quality #tests ~15m (ai:10m test:5m) logged:2026-02-07 ref:GH#442 completed:2026-02-07 @@ -129,8 +129,7 @@ Tasks with no open blockers - ready to work on. Use `/ready` to refresh this lis - [x] t135.5 P1-B: Remove tracked artifacts that should be gitignored ~30m blocked-by:none completed:2026-02-07 - Notes: Already resolved. Neither .scannerwork/ nor .playwright-cli/ are tracked in git (git ls-files --error-unmatch confirms). - [x] t135.6 P1-C: Fix CI workflow code-quality.yml issues ~1h blocked-by:none completed:2026-02-07 - - [x] t135.6.1 Fix Docker test environment path case (git->Git) and workspace paths ~5m completed:2026-02-08 - - Notes: PR #481 merged. Fixed Dockerfile and docker-compose.yml paths. + - [ ] t135.6.1 Fix .agent typo to .agents on line 31 ~5m - [x] t135.6.2 Fix references to non-existent .agents/spec and docs/ ~10m completed:2026-02-07 - [ ] t135.6.3 Add enforcement steps (shellcheck, json validation) that fail the build ~45m blocked-by:t135.6.1,t135.6.2 - [x] t135.7 P2-A: Eliminate eval in 4 remaining scripts (wp-helper, coderabbit-cli, codacy-cli, pandoc-helper) ~3h blocked-by:none completed:2026-02-07 @@ -138,11 +137,10 @@ Tasks with no open blockers - ready to work on. Use `/ready` to refresh this lis - [x] t135.7.1 Read each eval context to understand construction and purpose ~30m completed:2026-02-07 - [x] t135.7.2 Replace with array-based command construction ~2h blocked-by:t135.7.1 completed:2026-02-07 - [x] t135.7.3 Test affected command paths ~30m blocked-by:t135.7.2 completed:2026-02-07 - - [x] t135.8 P2-B: Increase shared-constants.sh adoption from 17% (29/170) to 93% ~4h blocked-by:none completed:2026-02-08 - - Notes: PR #480 merged. 155 files changed, -2704 lines net. Removed duplicate color constants, print functions, and sed_inplace definitions from 150+ scripts by sourcing shared-constants.sh. - - [x] t135.8.1 Audit shared-constants.sh vs what scripts duplicate ~30m completed:2026-02-08 - - [x] t135.8.2 Create migration script to replace inline print_* with source shared-constants.sh ~1.5h blocked-by:t135.8.1 completed:2026-02-08 - - [x] t135.8.3 Run migration in batches, testing each for regressions ~2h blocked-by:t135.8.2 completed:2026-02-08 + - [ ] t135.8 P2-B: Increase shared-constants.sh adoption from 17% (29/170) to 80%+ ~4h blocked-by:none + - Notes: BLOCKED by supervisor: Re-prompt dispatch failed: backend_infrastructure_error - [ ] t135.8.1 Audit shared-constants.sh vs what scripts duplicate ~30m BLOCKED: Max retries exceeded: backend_infrastructure_error + - [ ] t135.8.2 Create migration script to replace inline print_* with source shared-constants.sh ~1.5h blocked-by:t135.8.1 + - [ ] t135.8.3 Run migration in batches, testing each for regressions ~2h blocked-by:t135.8.2 - [x] t135.9 P2-C: Add trap cleanup for temp files in setup.sh and mktemp scripts ~1h blocked-by:none started:2026-02-07 completed:2026-02-07 - [x] t135.9.1 Identify all mktemp usages without trap cleanup ~15m completed:2026-02-07 - Notes: 33 scripts use mktemp, 31 without trap. Critical scripts (secret-helper, version-manager) fixed in PR #436. @@ -241,8 +239,7 @@ Tasks with no open blockers - ready to work on. Use `/ready` to refresh this lis - [x] t068.5 Agent Registry & Worker Mailbox Awareness ~3h blocked-by:t068.4 completed:2026-01-24 - [x] t068.6 Stateless Coordinator (coordinator-helper.sh) ~4h blocked-by:t068.4,t068.5 completed:2026-01-24 - [x] t068.7 Model Routing (subagent YAML frontmatter) ~2h blocked-by:t068.3 completed:2026-01-24 - - [x] t068.8 TUI Dashboard (bash TUI in supervisor-helper.sh) ~1h blocked-by:t068.4,t068.5 started:2026-02-07 ref:GH#442 - - Notes: PR #482 pending. Live-updating terminal dashboard with task table, progress bar, system resources, keyboard controls (q/p/r/j/k/?). Zero deps beyond bash+sqlite3+tput. + - [ ] t068.8 TUI Dashboard (supervisor-helper.sh dashboard) ~1h blocked-by:t068.4,t068.5 started:2026-02-07 - [ ] t009 Claude Code Destructive Command Hooks #plan → [todo/PLANS.md#claude-code-destructive-command-hooks] ~30m (ai:15m test:10m read:5m) logged:2025-12-21 - [ ] t008 aidevops-opencode Plugin #plan → [todo/PLANS.md#aidevops-opencode-plugin] ~1.5h (ai:45m test:30m read:15m) logged:2025-12-21 - [x] t004 Add Ahrefs MCP server integration #seo ~4h (ai:2h test:1h read:1h) logged:2025-12-20 completed:2026-01-25