# session_wait_till_idle — Block Until Busy Session Count Drops Below a Threshold

**Script name:** `session_wait_till_idle`

**Script location:** [`scripts/session_wait_till_idle.ts`](../../../scripts/session_wait_till_idle.ts)

**Invoke:**
```bash
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/session_wait_till_idle.ts \
  --mode (supervisors|workers) --max-pool-size N --timeout SECONDS \
  [--tag-prefix PREFIX] [--server URL]
```

**CRITICAL:** Always invoke the script using bash and the format noted above. **Never** try to use the skill as a task, or invoke it through any other method than by directly calling bash with a command of the form listed above under "Invoke:".

## Synopsis

```
session_wait_till_idle.ts --mode (supervisors|workers) \
  --max-pool-size N --timeout SECONDS \
  [--tag-prefix PREFIX] [--server URL]
```

Polls the OpenCode Server and counts busy sessions matching the specified mode.
Blocks (sleeps + re-polls every ~5 seconds) while the busy count is >= the
max pool size.  Unblocks when the count drops below the threshold OR the
timeout is reached, whichever comes first.

This is the core implementation script. For most use cases, prefer the
purpose-specific wrappers:
- [`session_wait_till_supervisor_idle`](../session_wait_till_supervisor_idle/) — supervisor-oriented interface
- [`session_wait_till_worker_idle`](../session_wait_till_worker_idle/) — worker-oriented interface

## Arguments

| Flag | Type | Required | Description |
|------|------|----------|-------------|
| `--mode MODE` | string | yes | `"supervisors"` or `"workers"` |
| `--max-pool-size N` | integer | yes | Positive integer; block while `busy_count >= N` |
| `--timeout SECONDS` | integer | yes | Positive integer; maximum seconds to block |
| `--tag-prefix PREFIX` | string | workers only | Tag prefix for worker matching; ignored for supervisors |
| `--server URL` | string | no | OpenCode Server base URL (default: `http://localhost:4096`) |
| `-h`, `--help` | — | — | Print usage to stderr and exit 0 |

## Matching Rules

### Supervisors Mode

A session is counted as a **busy supervisor** when:
1. Its status is `busy`
2. Its extracted tag (from `[TAG] title`) ends with `-SUP`

The `--tag-prefix` argument is **ignored** in this mode because all supervisors
share the `-SUP` suffix convention. All supervisor sessions across the entire
system are counted.

### Workers Mode

A session is counted as a **busy worker** when:
1. Its status is `busy`
2. Its extracted tag starts with `{PREFIX}-` (strict prefix-dash matching)
3. Its tag does **NOT** end with `-SUP`

Examples with `--tag-prefix AUTO-IMP`:
- `[AUTO-IMP-ISSUE-42] impl-worker` — **matches** (starts with `AUTO-IMP-`, not `-SUP`)
- `[AUTO-IMP-PR-7] impl-worker` — **matches**
- `[AUTO-IMP-SUP] impl-supervisor` — **excluded** (ends in `-SUP`)
- `[AUTO-PRMRG-ISSUE-1] merge-worker` — **excluded** (wrong prefix)
- `[AUTO-IMP] some-agent` — **excluded** (no dash after prefix)

## Output

Written to **stdout** as a JSON object:

| Field | Type | Description |
|-------|------|-------------|
| `waited` | boolean | `true` if the script had to block at least once |
| `timed_out` | boolean | `true` if the timeout was reached before the condition was met |
| `elapsed_seconds` | number | Wall-clock seconds spent waiting (1 decimal precision) |
| `busy_count` | number | Final busy count at the moment the script returned |
| `max_pool_size` | number | The threshold that was used |
| `mode` | string | `"supervisors"` or `"workers"` |
| `tag_prefix` | string \| null | The tag prefix used (`null` for supervisors) |

Example:
```json
{
  "waited": true,
  "timed_out": false,
  "elapsed_seconds": 15.2,
  "busy_count": 2,
  "max_pool_size": 3,
  "mode": "workers",
  "tag_prefix": "AUTO-IMP"
}
```

## Diagnostics / stderr

```
Waiting for workers pool to have fewer than 3 busy session(s) (prefix: AUTO-IMP) — timeout: 60s
[0.0s] Busy worker sessions (tag starts with AUTO-IMP-, excludes -SUP): 3 / max 3
[5.1s] Busy worker sessions (tag starts with AUTO-IMP-, excludes -SUP): 3 / max 3
[10.2s] Busy worker sessions (tag starts with AUTO-IMP-, excludes -SUP): 2 / max 3
Condition met after 10.2s — busy count: 2 < max pool size: 3
```

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Always — check the `timed_out` field in JSON output to distinguish condition-met from timeout |
| 1 | Fatal error (missing args, invalid values, API unreachable after retries) |

## When to Use This Script

- **Supervisor waiting for a worker slot:** use `--mode workers` to block until
  there is room in the worker pool before dispatching a new worker.
- **Orchestrator waiting for a supervisor slot:** use `--mode supervisors` to
  block until a supervisor finishes before launching a replacement.
- **Rate limiting:** prevent over-saturation of the session pool by gating
  new launches on current busy counts.

## Usage Examples

```bash
# Wait for the AUTO-IMP worker pool (max 4 workers) to have an opening, 60s timeout
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/session_wait_till_idle.ts \
  --mode workers --tag-prefix "AUTO-IMP" --max-pool-size 4 --timeout 60

# Wait for fewer than 2 supervisors to be busy, 120s timeout
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/session_wait_till_idle.ts \
  --mode supervisors --max-pool-size 2 --timeout 120

# Quick check with 1s timeout (effectively: are all slots full right now?)
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/session_wait_till_idle.ts \
  --mode workers --tag-prefix "AUTO-PRMRG" --max-pool-size 3 --timeout 1
```

## Dependencies

- Node.js >= 18 (native `fetch` API)
- `npx tsx` for TypeScript execution
- Zero external npm packages
