-
Notifications
You must be signed in to change notification settings - Fork 1
Pipeline Design 4
The shipwright status command (scripts/sw-status.sh, ~605 lines) renders a human-readable dashboard showing tmux windows, team configs, task lists, daemon/pipeline state, issue tracker info, heartbeats, remote machines, and connected developers. It currently interleaves data collection (tmux queries, JSON file reads, curl calls) with ANSI-colored echo output, making it impossible to consume programmatically.
Other shipwright commands already support --json output: sw-pipeline-vitals.sh, sw-cost.sh, and sw-fleet.sh all follow a pattern of flag parsing at the top, data collection into variables, and conditional rendering. The project requires Bash 3.2 compatibility (no associative arrays, no readarray, no ${var,,}), set -euo pipefail, and jq --arg for JSON construction (never string interpolation).
Refactor sw-status.sh into collect/render pairs, gated by a --json flag.
Data flow:
- Parse
--json/--helpflags at script top (aftersource compat.sh) - Eight
collect_*functions each populate a*_JSONshell variable with a jq-constructed JSON fragment (array or object). These functions perform no stdout output. - When
JSON_OUTPUT=false: eightrender_*functions reproduce the existing human-readable output verbatim using the collected data. - When
JSON_OUTPUT=true: a singlejq -ncall assembles all eight fragments plusversionandtimestampinto one JSON object written to stdout, then exits.
JSON schema (top-level keys):
{
"version": "string",
"timestamp": "ISO-8601 UTC",
"tmux_windows": [{"name", "session_window", "pane_count", "active"}],
"teams": [{"name", "members", "member_names"}],
"tasks": [{"team", "total", "completed", "in_progress", "pending", "percent_complete"}],
"daemon": {"running", "pid", "uptime_seconds", "active_jobs", "queued", "completed", "recent_activity"},
"tracker": {"provider", "url"},
"heartbeats": [{"job_id", "pid", "alive", "stage", "issue", "iteration", "activity", "updated_at", "age_seconds", "memory_mb"}],
"remote_machines": [{"name", "host", "cores", "memory_gb", "max_workers"}],
"connected_developers": {"reachable", "dashboard_url", "total_online", "developers"}
}Error handling: Each collect_* function initializes its variable to [] or {} before attempting data reads. Missing files, unreachable daemons, or failed tmux queries result in empty collections — never missing keys. All jq calls use --arg / --argjson for safe escaping. ANSI escape codes are never written when JSON_OUTPUT=true (color helpers short-circuit or are bypassed entirely).
Pattern alignment: Follows the same flag-parsing and jq -n assembly pattern used in sw-pipeline-vitals.sh (which the user's supermemory confirms has a --json flag) and sw-cost.sh.
-
Emit JSON per-section (streaming NDJSON) — Pros: simpler implementation, each section independently parseable. Cons: breaks
jq .on the full output, inconsistent withsw-pipeline-vitals.shandsw-cost.shwhich emit a single JSON object. Users expect| jq .fieldto work on a single document. -
Separate
sw-status-json.shscript — Pros: zero risk of regressing human-readable output. Cons: duplicates all data-collection logic, doubles maintenance surface, diverges from the--jsonflag convention established by other sw scripts. -
Template-based rendering (shared data, pluggable formatters) — Pros: cleanest separation of concerns. Cons: over-engineered for a bash script; adds abstraction layers that make the code harder to read and maintain. The collect/render pair approach achieves adequate separation without framework overhead.
Files to create:
-
scripts/sw-status-test.sh— test suite following existing harness pattern (mock binaries, PASS/FAIL counters, ERR trap, temp directory fixtures)
Files to modify:
-
scripts/sw-status.sh— add flag parsing, refactor into 8 collect/render pairs, add JSON assembly -
scripts/sw— update help text forstatussubcommand to show[--json] -
package.json— append&& bash scripts/sw-status-test.shto the npm test script
Dependencies: None new. jq is already a project dependency used throughout.
Risk areas:
- Regression in human-readable output. The render functions must reproduce the exact current output including ANSI codes, box-drawing characters, and conditional sections. Mitigation: capture a baseline snapshot of current output before refactoring; compare after.
-
set -euo pipefailinteractions. Commands liketmux list-windowsorcurlthat may fail (no tmux session, daemon not running) must be guarded with|| trueor checked via return code, not allowed to exit the script. The current code already handles some of these; refactoring must preserve all guards. -
Large JSON assembly. If a user has many heartbeats or team configs, the
jq -ncall receives many--argjsonarguments. This is fine for practical team sizes but worth noting. No mitigation needed. -
Bash 3.2
$()nesting. Complex jq command substitutions must avoid nested$()where possible, using temp variables instead.
-
shipwright status(no flag) produces byte-identical output to the pre-change version in all states (active daemon, no daemon, empty teams, populated teams) -
shipwright status --jsonoutputs valid JSON:shipwright status --json | jq emptyexits 0 - JSON output contains zero ANSI escape codes:
shipwright status --json | grep -P '\x1b\[' | wc -lreturns 0 - All 10 top-level keys present in JSON output:
version,timestamp,tmux_windows,teams,tasks,daemon,tracker,heartbeats,remote_machines,connected_developers - Empty state (no daemon, no teams, no tmux) produces empty arrays/objects for all collection keys — no
nullvalues, no missing keys -
shipwright status --helpprints usage including--jsondocumentation -
shipwright help/swhelp text shows[--json]for the status subcommand -
sw-status-test.shpasses all tests (valid JSON structure, key presence, empty-state handling, human-readable section headers, help output) - Test suite registered in
package.jsonand runs vianpm test - No Bash 3.2 incompatibilities: no
declare -A, noreadarray, no${var,,}, no${var^^} -
set -euo pipefailmaintained; no unguarded commands that could exit on expected failures