# Scripts Reference

Helper scripts for interacting with the Forgejo API. All scripts are written
in TypeScript and executed via `npx --yes tsx`. They require Node.js ≥ 18 and
zero external npm dependencies.

**Scripts directory:** [`scripts/`](../../scripts/)


## Available Scripts

### PR Listing Scripts

Six scripts that classify every open PR into one of six mutually exclusive
buckets. Together they cover the complete PR pipeline used by
`pr-merge-pool-supervisor` and `pr-review-pool-supervisor`.

| Script | One-liner |
|--------|-----------|
| [`list_prs`](./list_prs/) | General-purpose PR lister — all filter options (`--stale`, `--ci-status`, `--min-approvals`, `--has-request-changes`, …), importable as a module by the wrappers below |
| [`list_prs_ready_to_merge`](./list_prs_ready_to_merge/) | Open PRs with ≥ 1 approval, already current with their base branch, **and CI passing** — merge immediately |
| [`list_prs_stale_clean`](./list_prs_stale_clean/) | Open PRs with ≥ 1 approval, behind their base branch, no conflicts, any CI status — server-side rebase then merge |
| [`list_prs_stale_conflicts`](./list_prs_stale_conflicts/) | Open PRs with ≥ 1 approval, behind their base branch, merge conflicts present, any CI status — local clone, resolve, force-push, then merge |
| [`list_prs_needs_review_not_stale`](./list_prs_needs_review_not_stale/) | Open PRs with zero approvals, current with their base branch, any CI status — review only needed |
| [`list_prs_needs_review_stale_clean`](./list_prs_needs_review_stale_clean/) | Open PRs with zero approvals, stale but conflict-free, any CI status — review + server-side rebase needed |
| [`list_prs_needs_review_stale_conflicts`](./list_prs_needs_review_stale_conflicts/) | Open PRs with zero approvals, stale with conflicts, any CI status — review + local conflict resolution needed |

### Review Pipeline PR Listing Scripts

Five scripts that classify every open PR with zero approvals into one of five
mutually exclusive review buckets (excluding unaddressed `REQUEST_CHANGES` and
CI-pending PRs). Together they cover the complete peer review pipeline used by
`pr-review-supervisor`.

| Script | One-liner |
|--------|-----------|
| [`list_prs_addressed_changes_ci_passing`](./list_prs_addressed_changes_ci_passing/) | Open PRs with **passing CI**, zero approvals, active `REQUEST_CHANGES`, and **addressed** feedback (author pushed commits since review) — highest-priority re-review |
| [`list_prs_no_active_review_ci_passing`](./list_prs_no_active_review_ci_passing/) | Open PRs with **passing CI**, zero approvals, and **no active `REQUEST_CHANGES`** — ready for a fresh first review |
| [`list_prs_addressed_changes_ci_failing`](./list_prs_addressed_changes_ci_failing/) | Open PRs with **failing CI**, zero approvals, active `REQUEST_CHANGES`, and **addressed** feedback — re-review with CI failure noted |
| [`list_prs_no_active_review_ci_failing`](./list_prs_no_active_review_ci_failing/) | Open PRs with **failing CI**, zero approvals, and **no active `REQUEST_CHANGES`** — first review with CI failure noted |
| [`list_prs_missing_ci_checks`](./list_prs_missing_ci_checks/) | Open PRs with zero approvals and **no CI checks reported at all** — lightweight review flagging missing CI |

### Cross-Cutting PR Listing Scripts

Two additional scripts that cut across the six-bucket pipeline to surface
specific actionable states regardless of approval/staleness classification.

| Script | One-liner |
|--------|-----------|
| [`list_prs_ci_failing`](./list_prs_ci_failing/) | Open PRs with failing CI, **any review or staleness status** — CI must be fixed before any downstream step can proceed |
| [`list_prs_changes_requested`](./list_prs_changes_requested/) | Open PRs with **passing CI**, zero approvals, and at least one active `REQUEST_CHANGES` review — author must address reviewer feedback |

### Issue Listing Scripts

| Script | One-liner |
|--------|-----------|
| [`list_issues`](./list_issues/) | Open issues excluding `State/In Progress`, sorted by milestone due date (oldest first) then priority (highest first) within each milestone tier |

### PR Action Scripts

| Script | One-liner |
|--------|-----------|
| [`rebase_pr`](./rebase_pr/) | Triggers a Forgejo server-side rebase on a single stale, conflict-free PR — no local clone required |
| [`merge_pr`](./merge_pr/) | Initiates a rebase-style merge (with automerge scheduling) on a single PR, handling open issue dependencies before calling the merge endpoint |


## OpenCode Session Scripts

These scripts wrap the `localhost:4096` OpenCode Server API. They are used
exclusively by the `async-agent-util` agent. No other agent may call these
scripts directly or interact with localhost:4096.

### Shared Module

| Script | One-liner |
|--------|-----------|
| [`session_api`](./session_api/) | Shared types and API client — importable module only, not a standalone CLI |

### Session Management Scripts

| Script | One-liner |
|--------|-----------|
| [`session_list`](./session_list/) | List all sessions with current status and last-activity timestamps |
| [`session_start`](./session_start/) | Start an async agent in a new session; handles existing-session detection and restart |
| [`session_find_by_tag`](./session_find_by_tag/) | Find sessions whose `[TAG]` exactly matches the given string |
| [`session_find_by_prefix`](./session_find_by_prefix/) | Find sessions whose tag starts with a prefix; optional `-SUP` exclusion |
| [`session_messages`](./session_messages/) | Retrieve and format messages from a single session |
| [`session_stop`](./session_stop/) | Stop (and delete) sessions by ID or tag-prefix pattern |
| [`session_delete`](./session_delete/) | Delete a specific session by ID; guards against deleting busy sessions |
| [`session_health_data`](./session_health_data/) | Collect raw health signals for all sessions — the caller classifies health states |
| [`session_prompt`](./session_prompt/) | Send a prompt to an **existing** session (fire-and-forget) — the canonical "send continue" / nudge script |

### Session Wait / Blocking Scripts

| Script | One-liner |
|--------|-----------|
| [`session_wait_till_idle`](./session_wait_till_idle/) | Core blocking script — polls sessions and blocks while busy count >= threshold; supports both supervisor and worker modes |
| [`session_wait_till_supervisor_idle`](./session_wait_till_supervisor_idle/) | Wrapper — blocks until busy supervisor count (tags ending in `-SUP`) drops below expected count |
| [`session_wait_till_worker_idle`](./session_wait_till_worker_idle/) | Wrapper — blocks until busy worker count in a specific pool drops below pool size |

### Session Script Quick Reference

All session scripts accept an optional `--server URL` to override the default
`http://localhost:4096`.

```bash
# Start format common to all session scripts:
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/<script>.ts [FLAGS]
```

| Operation | Script | Key Flags |
|-----------|--------|-----------|
| List all sessions | `session_list.ts` | (none) |
| Start async agent | `session_start.ts` | `--tag` `--agent` (`--prompt` \| `--prompt-file`) `[--restart]` |
| Send prompt to existing session | `session_prompt.ts` | `--session-id` `--agent` (`--prompt` \| `--prompt-file`) |
| Find by exact tag | `session_find_by_tag.ts` | `--tag` |
| Find by tag prefix | `session_find_by_prefix.ts` | `--prefix` `[--exclude-supervisor]` |
| Get messages | `session_messages.ts` | `--session-id` `[--limit]` |
| Stop sessions | `session_stop.ts` | `--session-id` or `--tag-pattern` `[--no-delete]` |
| Delete session | `session_delete.ts` | `--session-id` `[--force]` |
| Get health data | `session_health_data.ts` | `[--message-limit]` |
| Wait (supervisors or workers) | `session_wait_till_idle.ts` | `--mode` `--max-pool-size` `--timeout` `[--tag-prefix]` |
| Wait for supervisor slot | `session_wait_till_supervisor_idle.ts` | `--expected-supervisors` `--timeout` |
| Wait for worker slot | `session_wait_till_worker_idle.ts` | `--tag-prefix` `--pool-size` `--timeout` |


## The Six-Bucket Pipeline

The six listing scripts define a complete, non-overlapping classification of
open PRs. The two approval states (approved vs needs review) are each split
by three staleness states, giving six buckets in total. **Bucket 1 additionally
requires CI to be passing**; approved + not-stale PRs with failing or pending CI
are held out of all buckets until their CI resolves.

```
Every open PR belongs to exactly one bucket at any moment
(or is temporarily absent if CI is blocking it from Bucket 1):

  ── Approved (≥ 1 non-dismissed approval) ──────────────────────────────────
  Bucket 1 — list_prs_ready_to_merge               (approved + not stale + CI passing)
  Bucket 2 — list_prs_stale_clean                   (approved + stale, no conflicts, any CI)
  Bucket 3 — list_prs_stale_conflicts               (approved + stale, has conflicts, any CI)

  ── Needs Review (0 approvals) ─────────────────────────────────────────────
  Bucket 4 — list_prs_needs_review_not_stale        (no approvals + not stale, any CI)
  Bucket 5 — list_prs_needs_review_stale_clean      (no approvals + stale, no conflicts, any CI)
  Bucket 6 — list_prs_needs_review_stale_conflicts  (no approvals + stale, has conflicts, any CI)

  ── Temporarily absent (not in any bucket) ─────────────────────────────────
  • stale_state == stale_unknown   → Forgejo still computing conflict status; appears shortly
  • approved + not stale + CI failing/pending/unknown → held out of Bucket 1 until CI passes
```

Typical action sequence per bucket:

```
Bucket 1:  merge_pr                  (CI already green — safe to merge immediately)
Bucket 2:  rebase_pr → merge_pr
Bucket 3:  clone → rebase locally → resolve conflicts → force-push → merge_pr
Bucket 4:  (dispatch reviewer → on approval, moves to Bucket 1 if CI passes)
Bucket 5:  (dispatch reviewer → on approval, moves to Bucket 2)
Bucket 6:  (dispatch reviewer → on approval, moves to Bucket 3)
```


## The Five-Bucket Review Pipeline

The five review pipeline scripts define a complete, non-overlapping
classification of open PRs with zero approvals that are candidates for peer
review. The two review states (addressed `REQUEST_CHANGES` vs no active
`REQUEST_CHANGES`) are each split by CI status, plus a catch-all for missing CI.

PRs with **unaddressed `REQUEST_CHANGES`** (author has not pushed commits since
the review) and PRs with **CI pending** are intentionally excluded — unaddressed
feedback is the implementation supervisor's domain, and CI-pending PRs should
wait for CI to resolve before review.

```
Every open PR with zero approvals belongs to exactly one review bucket
(or is excluded as noted below):

  ── Addressed REQUEST_CHANGES (author pushed since review) ─────────────────
  Bucket 1 — list_prs_addressed_changes_ci_passing    (addressed + CI passing)
  Bucket 3 — list_prs_addressed_changes_ci_failing    (addressed + CI failing)

  ── No Active REQUEST_CHANGES ──────────────────────────────────────────────
  Bucket 2 — list_prs_no_active_review_ci_passing     (no review + CI passing)
  Bucket 4 — list_prs_no_active_review_ci_failing     (no review + CI failing)

  ── Missing CI ─────────────────────────────────────────────────────────────
  Bucket 5 — list_prs_missing_ci_checks               (no CI checks reported)

  ── Excluded (not in any review bucket) ────────────────────────────────────
  • hasUnaddressedRequestChanges == true → implementation supervisor handles
  • ci_status == 'pending'              → wait for CI to resolve
```

Typical action per review bucket:

```
Bucket 1:  full re-review (verify addressed feedback) → approve or request changes
Bucket 2:  full first review (fresh evaluation) → approve or request changes
Bucket 3:  re-review + flag CI failures → request changes
Bucket 4:  first review + flag CI failures → request changes
Bucket 5:  lightweight review flagging missing CI → request changes
```


## Quick Invocation Reference

All scripts share the same four connection flags:

```bash
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/<script>.ts \
  --url  <forgejo-base-url>   \   # e.g. https://git.example.com
  --pat  <personal-access-token>  \
  --owner <repo-owner-or-org>     \
  --repo  <repo-name>
```

`merge_pr` and `rebase_pr` additionally require `--pr <number>`.
`merge_pr` has an optional `--dep error|delete|reverse` flag.
All `list_prs_*` wrappers accept **only** the four connection flags —
their filter parameters are hard-coded and cannot be overridden on the CLI.
`list_prs` itself accepts optional filter flags: `--state`, `--min-approvals`,
`--max-approvals`, `--mergeable`, `--stale`, `--ci-status`, and
`--has-request-changes`.

**`--ci-status`** accepts a comma-separated whitelist of CI states to include:
`passing`, `failing`, `pending`, `unknown` (any combination). Omit to include
all CI states. Example: `--ci-status passing,pending`

**`--has-request-changes`** accepts `true` or `false`. `true` restricts results
to PRs where at least one reviewer's latest non-dismissed review is
`REQUEST_CHANGES`. `false` restricts to PRs with no such active review. Omit
to include all PRs regardless of request-changes status.

Each PR object in all outputs includes a `ci_status` field
(`passing` | `failing` | `pending` | `unknown`) derived from the Forgejo
combined commit-status endpoint for the PR's head SHA.

All scripts write JSON to **stdout** and progress/diagnostics to **stderr**.
Exit code `0` = success, `1` = error.
