opencode-builder.sh: major reliability and correctness fixes:
- Parallel pre-fetch per pool: ALL list_prs_*.ts scripts for a pool now
launch in parallel (background jobs), results cached to temp files. Each
pool iteration fetches all work-group data in ONE parallel batch (~90s)
instead of 11 sequential ~90s calls (~990s). The bottleneck is Forgejo
API speed, not sequential script execution.
- Timeouts everywhere: SCRIPT_TIMEOUT_SEC raised 60s→300s (Forgejo is slow).
find_sessions_by_prefix and other session_* scripts get 30s timeout via
the timeout(1) utility. fetch_list_script catches timeout exit codes
(124, 137, 139, 143) and returns [] gracefully.
- Prompt builders fixed: build_impl_prompt, build_merge_prompt,
build_review_prompt now collapse newlines in title/body via tr+sed so
the prompt file stays valid as plain text. Full item JSON embedded as
compact single-line (jq -c .) at end of prompt.
- Verbose step logging: [step2], [pool:NAME] prefixes throughout main
loop show exactly which stage is running and where any hang occurs.
- BUILDER_DEBUG=1 env var enables bash -x tracing for deep debugging.
Note: find_sessions_by_prefix --status busy returns empty (OpenCode
/session/status only reports the supervisor session). busy_count=0 when
all session status fields are empty, making all slots available. The
total session count is logged alongside active count for visibility.
The OpenCode /session/status endpoint reports all async workers as
"idle" even while they are actively processing — making the previous
--status busy filter always return empty and workers count as 0.
Fixes across the board:
- get_active_worker_tags() and count_active_workers(): new functions
that filter by last_active >= (now - 2 min) instead of status field.
- Pool launcher: use count_active_workers() for the busy count, and
extract exclude_numbers from active sessions' tags.
- Health cycle idle check: was using --status idle (returns all sessions
since everything is "idle"). Now uses --status all + last_active
threshold to find genuinely idle workers.
- Doom loop check: was using --status busy (returns nothing). Now uses
--status all + last_active < (now - 30 min) to find abandoned sessions.
- fetch_list_script: guard against corrupted JSON when stderr messages
from the script contaminate stdout — only accept output starting with
"[" as valid JSON.
- Worker launch: add --restart so stale sessions are always replaced
with fresh workers.
- Add IDLE_THRESHOLD_MS (3 min) constant for the health cycle.
Previously workers were launched sequentially (2-3s each), causing
30+ second delays per pool in iteration #1 and making the health
check cycle stall. Now:
- Collect all work items for a pool into an array first
- Launch all workers in parallel with background jobs (&)
- Wait for each job in sequence, tracking results
Also removed dead code: launch_worker() and launch_pool_workers()
functions (replaced by inline parallel launch), and get_work_number()
and get_work_type() helpers (no longer needed).
- resolve_forgejo_config: fall back to git remote origin when
FORGEJO_OWNER/FORGEJO_REPO are not set in env vars
- busy_count: count directly in the tag loop instead of a broken
grep-pipeline that caused '0: syntax error' when count was zero
- Remove the now-dead launch_supervisor function and SUPERVISOR_TIMEOUT
(already removed from loop in prior commit)
- Add check_opencode_running() function to detect existing OpenCode server
- Skip server startup if OpenCode already running on target port
- Display prominent warning when connecting to existing server
- Only manage server lifecycle when script starts its own server
- Add OWN_SERVER flag to track server ownership
- Update cleanup logic to leave existing servers running
This enables multiple developers and automation scripts to safely
run in parallel without conflicting server management.