Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
and submodules without requiring directory changes. Commands,
configuration, drivers, dashboard behavior, runtime resource naming,
and `Tools: swarm` commit trailers are unchanged.
- **Fix: dashboard `p` restarts an exited post-process.** The
dashboard blocked `p` whenever a post-process container existed,
so an exited one stranded the restart path even after `s`. It now
blocks only a running container and notes that an exited one will
be replaced. `p` also passes the dashboard's `SWARM_CONFIG` to
`launch.sh post-process`, so non-default configs are honoured.

## 0.22.0 — 2026-06-08

Expand Down
4 changes: 2 additions & 2 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ do not count toward numbered-agent completion.
| `P` | Post-process logs (the `P` row), if it exists. |
| `h` | Harvest results. |
| `s` | Stop numbered agents and post-process. |
| `p` | Start post-process after confirmation. |
| `p` | Start post-process after confirmation; replaces an exited run. |

The Model column appends the agent's reasoning effort as a
parenthesised letter: `(h)` high, `(m)` medium, `(l)` low,
Expand Down Expand Up @@ -472,7 +472,7 @@ Add to `swarm.json`:
}
```

Trigger via `[P]` in the dashboard, `./launch.sh post-process`,
Trigger via `[p]` in the dashboard, `./launch.sh post-process`,
Comment thread
moodmosaic marked this conversation as resolved.
or automatically via `./launch.sh wait` after numbered agents have
already been started. `./launch.sh wait` does not launch numbered
agents.
Expand Down
16 changes: 13 additions & 3 deletions dashboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,12 @@ post_process_container_exists() {
[ "$_pp_state" != "not found" ] && [ "$_pp_state" != "none" ]
}

post_process_container_running() {
local _pp_state
_pp_state=$(container_state "${IMAGE_NAME}-post")
[ "$_pp_state" = "running" ]
}

interactive_container_names() {
docker ps -a --format '{{.Names}}' 2>/dev/null \
| grep -E "^${IMAGE_NAME}-interactive-" \
Expand Down Expand Up @@ -770,7 +776,7 @@ draw() {
printf " ${DIM}[h]${RESET} harvest"
# shellcheck disable=SC2059
printf " ${DIM}[s]${RESET} stop all"
if post_process_configured && ! post_process_container_exists; then
if post_process_configured && ! post_process_container_running; then
# shellcheck disable=SC2059
printf " ${DIM}[p]${RESET} post-process"
fi
Expand Down Expand Up @@ -838,14 +844,17 @@ while true; do
continue
fi
_pp_name="${IMAGE_NAME}-post"
if post_process_container_exists; then
if post_process_container_running; then
echo "(post-processing is already running -- press P for logs)"
echo "Stop it first with s before starting a new run."
echo ""
read -rp "Press Enter to return to dashboard..." _
enter_alt_screen
continue
fi
if post_process_container_exists; then
echo "(previous post-process container will be replaced)"
fi
_pp_prompt="Start post-processing now? [y/N] "
read -r -p "$_pp_prompt" _pp_confirm || _pp_confirm=""
case "$_pp_confirm" in
Expand All @@ -863,7 +872,8 @@ while true; do
docker stop "${IMAGE_NAME}-${i}" 2>/dev/null || true
done
echo "--- Starting post-processing ---"
"$SWARM_DIR/launch.sh" post-process || \
SWARM_CONFIG="$CONFIG_FILE" \
"$SWARM_DIR/launch.sh" post-process || \
echo "(post-processing failed)"
echo ""
read -rp "Press Enter to return to dashboard..." _
Expand Down
42 changes: 39 additions & 3 deletions tests/test_dashboard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -692,9 +692,31 @@ assert_eq "leading blank inspect fallback becomes not found" "not found" \
"$(normalize_docker_state $'\nnot found')"
assert_eq "leading blank inspect state keeps real state" "running" \
"$(normalize_docker_state $'\nrunning')"
assert_eq "dashboard uses normalized container state" "4" \
assert_eq "dashboard uses normalized container state" "5" \
"$(grep -cF 'container_state "' "$DASHBOARD_FILE")"

# Post-process container predicates, loaded from dashboard.sh with
# container_state stubbed. Only a running container blocks p.
eval "$(sed -n '/^post_process_container_exists()/,/^}/p;
/^post_process_container_running()/,/^}/p' "$DASHBOARD_FILE")"
# Invoked by the eval'd predicates above.
# shellcheck disable=SC2329
container_state() { printf '%s' "$_stub_state"; }
IMAGE_NAME="test-swarm"
for _stub_state in running exited created paused "not found" none; do
_want_exists=true
case "$_stub_state" in
"not found"|none) _want_exists=false ;;
esac
_want_running=false
[ "$_stub_state" = "running" ] && _want_running=true
assert_eq "post-process exists when ${_stub_state}" "$_want_exists" \
"$(post_process_container_exists && echo true || echo false)"
assert_eq "post-process running when ${_stub_state}" "$_want_running" \
"$(post_process_container_running && echo true || echo false)"
done
unset -f container_state

pp_lower_case=$(awk '
/^[[:space:]]*p\)/ { p = 1 }
p { print }
Expand Down Expand Up @@ -733,12 +755,22 @@ assert_eq "lowercase p asks for confirmation" "true" \
assert_eq "lowercase p can launch post-process" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF '"$SWARM_DIR/launch.sh" post-process' || true)"
assert_eq "lowercase p preserves dashboard config" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'SWARM_CONFIG="$CONFIG_FILE"' || true)"
assert_eq "lowercase p has cancellation path" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'post-processing not started' || true)"
assert_eq "lowercase p refuses to replace running post-process" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'post-processing is already running' || true)"
assert_eq "lowercase p blocks only running post-process" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'if post_process_container_running; then' || true)"
assert_eq "lowercase p allows exited post-process replacement" "1" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'previous post-process container will be replaced' \
|| true)"
assert_eq "lowercase p has no replacement prompt" "0" \
"$(printf '%s\n' "$pp_lower_case" \
| grep -cF 'Replace existing' || true)"
Expand All @@ -751,10 +783,14 @@ assert_eq "footer merges P into the logs hint" "1" \
assert_eq "footer offers lowercase p to start post-process" "1" \
"$(printf '%s\n' "$help_bar" \
| grep -cF '[p]' || true)"
assert_eq "footer guards start hint on missing container" "1" \
assert_eq "footer guards start hint on running container" "1" \
"$(printf '%s\n' "$help_bar" \
| grep -cF 'post_process_configured && ! post_process_container_exists' \
| grep -cF \
'post_process_configured && ! post_process_container_running' \
|| true)"
assert_eq "footer keeps logs hint for exited container" "1" \
"$(printf '%s\n' "$help_bar" \
| grep -cF 'if post_process_container_exists; then' || true)"
assert_eq "s stops post-process container" "1" \
"$(printf '%s\n' "$s_case" \
| grep -cF 'docker stop "${IMAGE_NAME}-post"' || true)"
Expand Down
Loading