#!/bin/sh # opencode turn-boundary/completion poller — same rationale as # orchestra-codex-poll.sh: opencode has no native Stop hook, so this runs as # a background loop in the pane, polling /v1/harness/turn and watching for # the .orchestra-report.md completion marker. # # opencode's own SSE session-status stream (OpenCodeStatus in # internal/herdr/occupancy.go) is a fast path this script does not use — it # would need the pane's session id, which isn't reliably known outside the # opencode process. Instead this falls back to the same # most-recently-written message file under opencode's storage dir that # OpenCodeUsage already reads as its backstop (per AUDIT.md's "Real harness # quota sources": "the SSE stream is not rock-solid"). # # Requires: ORCHESTRA_TASK_ID, ORCHESTRA_URL, ORCHESTRA_WORKTREE set in the # pane's env. Optional: ORCHESTRA_HARNESS_TOKEN, # ORCHESTRA_POLL_INTERVAL (seconds, default 60). # Needs: jq, find, curl. set -u : "${ORCHESTRA_POLL_INTERVAL:=60}" : "${ORCHESTRA_WORKTREE:=$PWD}" [ -z "${ORCHESTRA_TASK_ID:-}" ] && { echo "orchestra-opencode-poll: ORCHESTRA_TASK_ID not set" >&2; exit 1; } [ -z "${ORCHESTRA_URL:-}" ] && { echo "orchestra-opencode-poll: ORCHESTRA_URL not set" >&2; exit 1; } auth_header="" if [ -n "${ORCHESTRA_HARNESS_TOKEN:-}" ]; then auth_header="Authorization: Bearer ${ORCHESTRA_HARNESS_TOKEN}" fi latest_message() { find "$HOME/.local/share/opencode/storage/message" -type f -name '*.json' -printf '%T@ %p\n' 2>/dev/null \ | sort -rn | head -n1 | cut -d' ' -f2- } report_file="${ORCHESTRA_WORKTREE%/}/.orchestra-report.md" while true; do sleep "$ORCHESTRA_POLL_INTERVAL" msg="$(latest_message)" [ -z "$msg" ] && continue if [ -f "$report_file" ]; then report="$(cat "$report_file")" body="$(jq -n \ --arg task_id "$ORCHESTRA_TASK_ID" \ --arg transcript_path "$msg" \ --arg report "$report" \ '{task_id: $task_id, harness: "opencode", transcript_path: $transcript_path, report: $report}')" if curl -fsS -X POST "${ORCHESTRA_URL%/}/v1/harness/complete" \ -H "Content-Type: application/json" \ ${auth_header:+-H "$auth_header"} \ -d "$body" >/dev/null 2>&1; then rm -f "$report_file" exit 0 else echo "orchestra-opencode-poll: failed to report completion" >&2 fi continue fi body="$(jq -n --arg task_id "$ORCHESTRA_TASK_ID" '{task_id: $task_id}')" response="$(curl -fsS -X POST "${ORCHESTRA_URL%/}/v1/harness/turn" \ -H "Content-Type: application/json" \ ${auth_header:+-H "$auth_header"} \ -d "$body" 2>/dev/null)" || { echo "orchestra-opencode-poll: failed to reach turn-decision endpoint" >&2 continue } decision="$(printf '%s' "$response" | jq -r '.decision // empty')" if [ "$decision" = "refuse" ] || [ "$decision" = "rotate_now" ]; then echo "orchestra-opencode-poll: turn decision is $decision" >&2 fi done