Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f5d187086c | |||
| 9a5ccc6b01 | |||
| f167098541 | |||
| 072f470212 | |||
| 1f95ea0c2a | |||
| 832d0b26ae | |||
| 89baa0a525 | |||
|
435e409df9
|
|||
|
59a2a83328
|
|||
|
bcf58f0703
|
|||
|
37402e83c2
|
|||
|
7c13643441
|
|||
|
4e7bb5ae4e
|
|||
|
47d630599a
|
|||
|
6153da8deb
|
|||
|
e8f06fa433
|
|||
|
17bbe20376
|
|||
|
5c8b5a84d2
|
|||
|
fe95acb856
|
|||
|
6ed9dbc2e7
|
|||
|
555509c609
|
|||
|
aaeecd1616
|
|||
|
868fdeff8a
|
|||
| 66850665b7 | |||
| beceb183d0 | |||
|
d6fca18c01
|
|||
| 0c5b140d29 | |||
|
11ba77cf73
|
|||
|
5762f92583
|
|||
|
afa4ebd19b
|
|||
| 1663750b78 | |||
| bdd1ea4f3a | |||
|
e2b127b7e5
|
|||
|
80c8636c4a
|
|||
|
8a89a5d5a6
|
|||
| ed7276773e | |||
| 1fda56b778 | |||
|
8953449dc2
|
|||
| 449c33b752 | |||
| 4fc4d7863c |
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#E74C3C"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -10,6 +10,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: warning
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: primary
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: success
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#DC2626"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#DC2626"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -8,6 +8,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#DC2626"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#DC2626"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: error
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#6B7280"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#9B59B6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: accent
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -4,7 +4,8 @@ description: >
|
||||
CI failure resolution and review feedback handling. User-facing.
|
||||
mode: primary
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#059669"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#9B59B6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#6B7280"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#10B981"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
---
|
||||
description: >
|
||||
Git rebase helper. Rebases a branch onto a target branch (usually master)
|
||||
and resolves any merge conflicts that arise. Ensures the rebase completes
|
||||
fully by running git rebase --continue for every conflicting commit. Does
|
||||
NOT push — the caller is responsible for pushing after this agent exits.
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#F59E0B"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
question: deny
|
||||
"sequential-thinking*": allow
|
||||
read: "allow"
|
||||
grep: "allow"
|
||||
glob: "allow"
|
||||
edit:
|
||||
"*": deny
|
||||
"/tmp/**": allow
|
||||
external_directory:
|
||||
"/tmp/**": allow
|
||||
webfetch: allow
|
||||
websearch: allow
|
||||
codesearch: allow
|
||||
bash:
|
||||
"*": deny
|
||||
"git *": allow
|
||||
"git push *": deny
|
||||
"git * --force *": deny
|
||||
"ls *": allow
|
||||
"cat *": allow
|
||||
"find *": allow
|
||||
"grep *": allow
|
||||
# Block ALL commands that could hit the label creation endpoints
|
||||
"*api/v1/orgs/*/labels*": deny
|
||||
"*api/v1/repos/*/labels*": deny
|
||||
"*https://git.cleverthis.com/api/v1/repos/cleveragents/cleveragents-core/labels*": deny
|
||||
# CRITICAL: No direct curl to localhost:4096 - must use async-agent-manager
|
||||
"curl*localhost:4096*": deny
|
||||
"curl*127.0.0.1:4096*": deny
|
||||
task:
|
||||
"*": deny
|
||||
---
|
||||
|
||||
# Git Rebase Helper
|
||||
|
||||
You rebase a branch onto a target branch and resolve any merge conflicts that arise. You do not push — your caller handles that after you exit.
|
||||
|
||||
## What You Receive
|
||||
|
||||
Your prompt includes:
|
||||
- **working_directory** — absolute path to the git clone
|
||||
- **branch** — the feature branch to rebase (the branch whose history is rewritten)
|
||||
- **base_branch** — the branch to rebase onto (usually `master` or `origin/master`)
|
||||
- **git email** and **git name** — git author identity (optional; configure if provided)
|
||||
|
||||
## Rebase Procedure
|
||||
|
||||
Follow these steps exactly:
|
||||
|
||||
### 1. Prepare
|
||||
|
||||
```bash
|
||||
# Optionally configure identity if provided
|
||||
git -C "$WORK_DIR" config user.name "$GIT_USER_NAME"
|
||||
git -C "$WORK_DIR" config user.email "$GIT_USER_EMAIL"
|
||||
|
||||
# Fetch the latest state of all branches
|
||||
git -C "$WORK_DIR" fetch origin
|
||||
|
||||
# Switch to the feature branch
|
||||
git -C "$WORK_DIR" checkout "$BRANCH"
|
||||
|
||||
# Confirm current state before starting
|
||||
git -C "$WORK_DIR" log --oneline -5
|
||||
git -C "$WORK_DIR" status
|
||||
```
|
||||
|
||||
### 2. Start the rebase
|
||||
|
||||
```bash
|
||||
git -C "$WORK_DIR" rebase "origin/$BASE_BRANCH"
|
||||
```
|
||||
|
||||
If the rebase exits cleanly with no conflicts, skip to step 5 (Verify).
|
||||
|
||||
### 3. Resolve conflicts (repeat for every conflicting commit)
|
||||
|
||||
When the rebase pauses due to conflicts:
|
||||
|
||||
**a. Identify all conflicted files:**
|
||||
|
||||
```bash
|
||||
git -C "$WORK_DIR" diff --name-only --diff-filter=U
|
||||
```
|
||||
|
||||
**b. For each conflicted file:**
|
||||
|
||||
Read the file to understand what both sides changed:
|
||||
|
||||
```bash
|
||||
cat "$WORK_DIR/$FILE"
|
||||
```
|
||||
|
||||
The conflict markers look like:
|
||||
```
|
||||
<<<<<<< HEAD
|
||||
(incoming from base_branch)
|
||||
=======
|
||||
(original from the rebased commit)
|
||||
>>>>>>> <commit-sha> (<commit message>)
|
||||
```
|
||||
|
||||
Study the recent git history on both sides to understand the intent:
|
||||
|
||||
```bash
|
||||
# What changed on the base branch around this file
|
||||
git -C "$WORK_DIR" log --oneline "HEAD..origin/$BASE_BRANCH" -- "$FILE"
|
||||
git -C "$WORK_DIR" show "origin/$BASE_BRANCH" -- "$FILE"
|
||||
|
||||
# What this rebased commit intended to change
|
||||
git -C "$WORK_DIR" show ORIG_HEAD -- "$FILE"
|
||||
```
|
||||
|
||||
Use the `edit` tool to resolve the conflict. Remove all `<<<<<<<`, `=======`, and `>>>>>>>` markers. Produce a result that correctly incorporates both sets of changes, preserving the intent of the rebased commit against the current state of `base_branch`.
|
||||
|
||||
**c. Stage the resolved file:**
|
||||
|
||||
```bash
|
||||
git -C "$WORK_DIR" add "$WORK_DIR/$FILE"
|
||||
```
|
||||
|
||||
Repeat (b)–(c) for every conflicted file in this commit.
|
||||
|
||||
**d. Continue the rebase:**
|
||||
|
||||
```bash
|
||||
GIT_EDITOR=true git -C "$WORK_DIR" rebase --continue
|
||||
```
|
||||
|
||||
`GIT_EDITOR=true` prevents git from opening an interactive editor for the commit message — the original commit message is preserved as-is.
|
||||
|
||||
**e. Check if more conflicts remain:**
|
||||
|
||||
If the rebase pauses again, return to step (a). Repeat until `git rebase --continue` completes without error.
|
||||
|
||||
**CRITICAL:** If a conflict cannot be resolved safely (e.g. a file was deleted on one side and heavily modified on the other, and the correct resolution is ambiguous), never abort the rebase, make a best effort and report accordingly when done.
|
||||
|
||||
### 4. Verify completion
|
||||
|
||||
After the rebase finishes cleanly:
|
||||
|
||||
```bash
|
||||
# Confirm clean working tree (no conflict markers, nothing unstaged)
|
||||
git -C "$WORK_DIR" status
|
||||
|
||||
# Show the rebased commits relative to base
|
||||
git -C "$WORK_DIR" log --oneline "origin/$BASE_BRANCH..HEAD"
|
||||
|
||||
# Confirm no conflict markers remain in any file
|
||||
git -C "$WORK_DIR" diff --check
|
||||
```
|
||||
|
||||
If `git diff --check` reports any remaining conflict markers, find and fix them before returning.
|
||||
|
||||
## Return Value
|
||||
|
||||
Always return a structured summary to your caller:
|
||||
- Final status of `git status`
|
||||
- Short log of commits that were rebased (`git log --oneline origin/$BASE_BRANCH..HEAD`)
|
||||
- List of files where conflicts were resolved (and a brief description of how each was resolved)
|
||||
- Confirmation that the branch is ready to push
|
||||
|
||||
## **CRITICAL** Rules
|
||||
|
||||
1. **Never push.** Your job ends when the rebase is complete and verified. Pushing is the caller's responsibility.
|
||||
2. **Never use `git rebase --skip`.** Skipping a commit silently discards its changes. If a commit cannot be applied, make a best effort.
|
||||
3. **Never use `--force` git operations.** You are not pushing, so this does not apply, but do not run any destructive git commands not required by the rebase procedure.
|
||||
4. **Always remove all conflict markers.** A file containing `<<<<<<<`, `=======`, or `>>>>>>>` that was staged would corrupt the commit. Run `git diff --check` to confirm all markers are gone.
|
||||
5. **Preserve the intent of both sides.** When resolving a conflict, do not silently drop either side's changes without justification. If you cannot safely combine them, abort.
|
||||
6. **Never work in `/app`.** The working directory provided by your caller must be inside `/tmp/`. Refuse and report an error if it is not.
|
||||
7. **One task, then exit.** Do not look for more work, do not loop, do not sleep.
|
||||
8. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
|
||||
9. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* `git diff --name-only --diff-filter=U` listing conflicted files must be fully processed — do not stop at an assumed cutoff; `git log` output during history inspection may be long — use `--no-pager` or explicit `--max-count` limits and be aware the output may be truncated; any future REST/curl calls returning JSON arrays must be paginated.
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#95A5A6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#3498DB"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#8B5CF6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: warning
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#9B59B6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: warning
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#9B59B6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: secondary
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#10B981"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
agents for specific operations. User-facing.
|
||||
mode: all
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#6366F1"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: openai/gpt-5-nano
|
||||
reasoningEffort: "high"
|
||||
color: "#059669"
|
||||
permission:
|
||||
"*": deny
|
||||
@@ -20,11 +21,13 @@ permission:
|
||||
external_directory:
|
||||
"/tmp/**": allow
|
||||
webfetch: deny
|
||||
websearch: deny
|
||||
codesearch: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"sleep *": allow
|
||||
"jq *": allow
|
||||
"npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/*": allow
|
||||
"npx --yes tsx *.opencode/skills/auto-agents-system/scripts/*": allow
|
||||
# Block ALL commands that could hit the label creation endpoints
|
||||
"*api/v1/orgs/*/labels*": deny
|
||||
"*api/v1/repos/*/labels*": deny
|
||||
@@ -48,6 +51,12 @@ permission:
|
||||
|
||||
You are a supervisor that monitors open PRs for merge readiness, verifies all criteria are met, rebases stale PRs, resolves conflicts, and merges them. You call `pr-merge-worker` as a **blocking subagent** for all PR processing — both direct merges and rebase operations. Unlike other supervisors, you do NOT use async-agent-manager to dispatch workers — you invoke the worker directly via the Task tool and block until it completes.
|
||||
|
||||
## Do first
|
||||
|
||||
**Always** do the following things first before anything else:
|
||||
|
||||
- Load the `auto-agents-system` skill and from it learn how to use the scripts with the following names: `list_prs_ready_to_merge`, `list_prs_stale_clean`, `list_prs_stale_conflicts`, `list_prs_needs_review_stale_clean`, and `list_prs_needs_review_stale_conflicts`. Once you have queried the skill to fully understand these scripts you should understand what arguments it takes, what arguments are valid, how to call it, and what output you expect in return.
|
||||
|
||||
## What You Receive
|
||||
|
||||
Your prompt will include:
|
||||
@@ -67,21 +76,23 @@ Every worker prompt must include:
|
||||
- Whether the PR is stale (merge_base != base.sha)
|
||||
- Current review status (any approvals? any unresolved REQUEST_CHANGES?)
|
||||
- Current CI status if known
|
||||
- If the PR has conflicts.
|
||||
- Repository info, Forgejo PAT, git identity
|
||||
- Credentials: PAT, username, password, git name, git email
|
||||
|
||||
## Main Loop
|
||||
|
||||
Before starting the main loop below be sure to create your status tracking ticket (see the tracking section below). Also, before starting the below main loop ensure you have enabled the `auto-agents-system` skill.
|
||||
Before starting the main loop below be sure to create your status tracking ticket (see the tracking section below). Also, before starting the below main loop ensure you have loaded the `auto-agents-system` skill.
|
||||
|
||||
In an infinite loop do the following each cycle:
|
||||
1. If at least 10 minutes has passed since the last time you updated your automation tracking status ticket, or if you never created/updated one, (see tracking section below) then update your tracking ticket using the `automation-tracking-manager` subagent according to the details provided in the section labeled "tracking" below.
|
||||
2. Use the script `list_prs_ready_to_merge` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
3. Use the script `list_prs_stale_clean` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
4. Use the script `list_prs_stale_conflicts` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
5. Use the script `list_prs_needs_review` from the `auto-agents-system` skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
6. Sleep for 5 minutes using `bash("sleep 300", timeout=360000)`.
|
||||
7. Loop through the cycle indefinately by starting at step 1 above again.
|
||||
2. Run via bash tool the script named `list_prs_ready_to_merge` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
3. Run via bash tool the script named `list_prs_stale_clean` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
4. Run via bash tool the script named `list_prs_stale_conflicts` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
5. Run via bash tool the script named `list_prs_needs_review_stale_clean` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
6. Run via bash tool the script named `list_prs_needs_review_stale_conflicts` from the `auto-agents-system` skill which you must load and query how to use the mentioned skill, if the list is empty skip to the next step, however, if it has one or more PR in it then sequentially dispatch a single `pr-merge-worker` subagent for each PR in the group and then start the cycle over at #1 (skipping the rest of the steps in this cycle)
|
||||
7. Sleep for 5 minutes using `bash("sleep 300", timeout=360000)`.
|
||||
8. Loop through the cycle indefinately by starting at step 1 above again.
|
||||
|
||||
## Tracking
|
||||
|
||||
@@ -106,3 +117,5 @@ Supervisor: PR Merge Pool | Agent: pr-merge-pool-supervisor
|
||||
3. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
|
||||
4. **Exhaustive pagination for all list results.** Every tool call that returns a list must be treated as potentially paginated. Always set `limit=50` for Forgejo MCP tools. After each list response, check whether the number of returned items equals the page size — if so, fetch the next page. Never assume the first response is the complete result. This applies to: `forgejo_list_repo_pull_requests` (must paginate ALL pages — missing a page means a ready PR never gets merged), `forgejo_list_pull_reviews` (paginate to see all review rounds), `forgejo_list_issue_comments` (paginate when updating linked issues post-merge).
|
||||
5. **Never close or change the label of a PR's issue** The issue for a PR will automatically be closed and the grooming agent will update its labels. Never close the originating issue directly or change its state.
|
||||
6. **Never try to access Forgejo directly** All access to forgejo will occur through the scripts provided by the `auto-agents-system` skill and provide all the access to Forgejo you need, **never** try to call the Forgejo API directly.
|
||||
7. **Never ask questions or give up** Under no circumstances should you ask questions for clarification, you must operate fully autonomously. You have all the resources you need to succeed at your task, do not give up and give it your best possible effort, any questions you may have just use your best judgement.
|
||||
|
||||
@@ -6,7 +6,7 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: openai/gpt-5-nano
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
@@ -18,9 +18,11 @@ permission:
|
||||
"external_directory":
|
||||
"/tmp/**": allow
|
||||
webfetch: deny
|
||||
websearch: deny
|
||||
codesearch: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"git *": allow
|
||||
"git status *": allow
|
||||
"mkdir *": allow
|
||||
"rm -rf *": allow
|
||||
"sleep *": allow
|
||||
@@ -36,7 +38,7 @@ permission:
|
||||
"*": deny
|
||||
"repo-isolator": allow
|
||||
"git-commit-helper": allow
|
||||
"forgejo-label-manager": allow
|
||||
"git-rebase-helped": allow
|
||||
skill:
|
||||
"*": deny
|
||||
"auto-agents-system": allow
|
||||
@@ -46,30 +48,35 @@ permission:
|
||||
|
||||
You perform a single rebase operation on a PR branch, resolve any conflicts, and then exit. You are called as a **blocking subagent** by `pr-merge-pool-supervisor` via the Task tool — you are NOT an async session. The supervisor blocks until you finish and return your results.
|
||||
|
||||
## **CRITICAL** Running scripts from skills
|
||||
## Do First
|
||||
|
||||
When running any scripts from skills use `npx --yes tsx <script_path> <args>` for example `npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/foo.ts --arg value`.
|
||||
**Always** do the following things first before anything else:
|
||||
|
||||
- Load the `auto-agents-system` skill and from it learn how to use the scripts with the following names: `merge_pr`, and `rebase_pr`.
|
||||
|
||||
## Procedure
|
||||
|
||||
Your prompt tells you which PR to rebase. First you must determine if the PR has conflicts.
|
||||
**CRITICAL**: Always follow this procedure exactly unless explicitly stated otherwise. You need to strictly adhere to these steps exactly as laid out whenever called except when clearly and explicitly stated in your prompt to deviate.
|
||||
|
||||
Before starting the below main loop ensure you have loaded the `auto-agents-system` skill.
|
||||
|
||||
Your prompt tells you which PR to rebase. Your prompt will tell you all the information you need, no need to investigate the PR for more information.
|
||||
|
||||
If the PR is stale and has conflicts then do the following:
|
||||
1. Create an isolated clone using the `repo-isolator` subagent ensuring you pass it the branch used by the PR. Make sure all work is done within this clone's directory.
|
||||
2. Rebase it onto the base branch (usually `master`).
|
||||
3. Resolve any conflicts that arise by reviewing the recent git history and using that to fix the conflicts
|
||||
4. Force-push with lease using `git-commit-helper`
|
||||
5. Clean up the clone.
|
||||
6. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
|
||||
7. Report back with any relevant details.
|
||||
2. Call the `git-rebase-helper` subagent and pass it the directory of the isolated and cloned repo, the base branch as master, and the name of the branch to be rebased, instruct it to conduct the rebase and conflict resolution, and finish any rebase operation, but not to push.
|
||||
3. Pass the correct branch, and repo directory in the prompt, and instruct `git-commit-helper` subagent to force-push the branch with lease
|
||||
4. Clean up the clone.
|
||||
5. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` from the skill to initiate the merge (or at least auto-schedule it).
|
||||
6. Report back with any relevant details.
|
||||
|
||||
If the PR does **not** have any conflicts but is stale:
|
||||
1. Load the skill `auto-agents-system` and run the script `rebase_pr` to initiate an on-server rebase.
|
||||
2. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
|
||||
1. Load the skill `auto-agents-system` and run, via the bash tool, the script named `rebase_pr` from the skill to initiate an on-server rebase.
|
||||
2. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` from the skill to initiate the merge (or at least auto-schedule it).
|
||||
3. Report back with any relevant details.
|
||||
|
||||
If the PR is **not** stale (and therefore wouldnt have any conflicts either):
|
||||
1. load the skill `auto-agents-system` and run the script `merge_pr` to initiate the merge (or at least auto-schedule it).
|
||||
1. load the skill `auto-agents-system` and run, via the bash tool, the script named `merge_pr` to initiate the merge (or at least auto-schedule it).
|
||||
2. Report back with any relevant details.
|
||||
|
||||
## **CRITICAL** Rules
|
||||
@@ -80,4 +87,6 @@ If the PR is **not** stale (and therefore wouldnt have any conflicts either):
|
||||
4. **Apply labels via `forgejo-label-manager`.** Never apply labels directly or using the Forgejo MCP/task. All label operations must go through `forgejo-label-manager`.
|
||||
5. **Exhaustive pagination for all list results.** Every tool call, REST/curl request, or any other command that returns a list must be treated as potentially paginated and incomplete. Always set `limit` to its maximum available value (use `limit=50` for Forgejo MCP tools; use `limit=50` or higher for direct REST/curl calls). After each list response, check whether the number of returned items equals the page size — if so, there are likely more results; fetch the next page (`page=2`, `page=3`, …) and continue until receiving a partial page. Never assume the first response is the complete result. This rule applies to every list-returning call without exception. *Examples specific to this agent (not exhaustive):* `git log` listing commits during conflict resolution must be fully read; any future REST/curl calls returning JSON arrays must be paginated.
|
||||
6. **Never close or change the label of a PR's issue** The issue for a PR will automatically be closed and the grooming agent will update its labels. Never close the originating issue directly or change its state.
|
||||
7. **CRITICAL** Never wait for CI quality gates or merges to finish, merge, when set, will be scheduled to occur automatically when tests complete.
|
||||
7. **CRITICAL** Never wait for CI quality gates or merges to finish, merge, when set, will be scheduled to occur automatically when tests complete.
|
||||
8. **Never try to access Forgejo directly** All access to forgejo will occur through the scripts provided by the `auto-agents-system` skill and provide all the access to Forgejo you need, **never** try to call the Forgejo API directly.
|
||||
9. **Never ask questions or give up** Under no circumstances should you ask questions for clarification, you must operate fully autonomously. You have all the resources you need to succeed at your task, do not give up and give it your best possible effort, any questions you may have just use your best judgement.
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
edit: deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: warning
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#3B82F6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
and reports status. Never does implementation work itself.
|
||||
mode: primary
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: primary
|
||||
permission:
|
||||
"*": deny
|
||||
@@ -14,6 +15,8 @@ permission:
|
||||
"sequential-thinking*": allow
|
||||
edit: deny
|
||||
webfetch: deny
|
||||
websearch: deny
|
||||
codesearch: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"echo $*": allow
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: primary
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#8E44AD"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: error
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#6B7280"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,6 +7,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#6B7280"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: info
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#9B59B6"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -5,7 +5,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: warning
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -9,6 +9,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: accent
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#E74C3C"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#2ECC71"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.2
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,6 +6,7 @@ mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.0
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: "#2ECC71"
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.1
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -7,7 +7,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
color: success
|
||||
permission:
|
||||
"*": deny
|
||||
|
||||
@@ -6,7 +6,8 @@ description: >
|
||||
mode: subagent
|
||||
hidden: true
|
||||
temperature: 0.3
|
||||
model: anthropic/claude-sonnet-4-6
|
||||
model: anthropic/claude-haiku-4-5
|
||||
reasoningEffort: "max"
|
||||
permission:
|
||||
"*": deny
|
||||
"doom_loop": deny
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# Async Agent Manager Migration Summary
|
||||
|
||||
## Problem Identified
|
||||
The `async-agent-starter` subagent was failing because it tried to use bash with curl commands, but the environment was restricting these operations. The error message showed:
|
||||
> "I don't currently have the ability to run the required shell or HTTP commands from this environment"
|
||||
|
||||
## Solution Implemented
|
||||
|
||||
### 1. Created New `async-agent-manager.md`
|
||||
- Renamed from `async-agent-starter` to better reflect its expanded responsibilities
|
||||
- Enhanced to handle all async agent operations:
|
||||
- Starting async agents
|
||||
- Getting session status
|
||||
- Retrieving session messages
|
||||
- Searching sessions by tag
|
||||
- Closing/cleanup sessions
|
||||
- Monitoring session health
|
||||
- Properly configured with explicit curl permissions to localhost:4096
|
||||
- Includes detailed curl command examples that have been tested and verified to work
|
||||
|
||||
### 2. Updated All Agents Using Async Operations
|
||||
|
||||
#### Primary Agent Updated:
|
||||
- **product-builder.md**:
|
||||
- Removed direct curl permissions to localhost:4096
|
||||
- Added permission to use `async-agent-manager` subagent
|
||||
- Updated `launch_supervisor` function to use async-agent-manager instead of direct curl
|
||||
- Updated all session status queries to use async-agent-manager
|
||||
- Updated session conversation retrieval to use async-agent-manager
|
||||
|
||||
#### Pool Supervisors Updated:
|
||||
- **implementation-orchestrator.md**: Updated all references from async-agent-starter to async-agent-manager
|
||||
- **uat-tester.md**: Added async-agent-manager permission and updated worker launch code
|
||||
- **test-infra-improver.md**: Added async-agent-manager permission and updated worker launch code
|
||||
- **continuous-pr-reviewer.md**: Added async-agent-manager permission and updated reviewer dispatch code
|
||||
- **bug-hunter.md**: Added async-agent-manager permission (already structured for worker dispatch)
|
||||
|
||||
#### Other Agents Updated:
|
||||
- **subtask-loop.md**: Updated all references from async-agent-starter to async-agent-manager
|
||||
- **async-agent-monitor.md**: Updated to use async-agent-manager for restart operations
|
||||
- **system-watchdog.md**: Added async-agent-manager permission and updated dispatch_one_off function
|
||||
- **async-agent-cleanup.md**: Removed direct curl permissions, added async-agent-manager permission
|
||||
- **async-agent-cleanup-all.md**: Removed direct curl permissions, added async-agent-manager permission
|
||||
|
||||
### 3. Key Design Principles
|
||||
|
||||
1. **Single Point of Control**: Only `async-agent-manager` has permission to curl to localhost:4096
|
||||
2. **Consistent Interface**: All agents use the same Task tool interface to interact with async operations
|
||||
3. **Proper Error Handling**: The manager returns structured JSON responses for all operations
|
||||
4. **Security**: Properly escapes all inputs to prevent injection attacks
|
||||
5. **Comprehensive Operations**: Handles the full lifecycle of async sessions
|
||||
|
||||
### 4. Testing
|
||||
Created and ran a test script that verified:
|
||||
- Session listing works correctly
|
||||
- Session status retrieval works correctly
|
||||
- Session creation returns proper session IDs
|
||||
- Async agent launch returns HTTP 204 (success)
|
||||
- Session deletion works correctly
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Centralized Management**: All async operations go through a single, well-tested agent
|
||||
2. **Better Error Handling**: Structured responses make it easier to handle failures
|
||||
3. **Improved Security**: Only one agent needs curl permissions to the API
|
||||
4. **Easier Maintenance**: Changes to the API only need to be updated in one place
|
||||
5. **Consistent Patterns**: All agents use the same interface for async operations
|
||||
|
||||
## Migration Complete
|
||||
All agents that previously used direct curl commands or async-agent-starter have been updated to use the new async-agent-manager. The old async-agent-starter.md file has been removed.
|
||||
Generated
+283
-10
@@ -5,21 +5,100 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@opencode-ai/plugin": "1.3.17"
|
||||
"@opencode-ai/plugin": "1.4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
|
||||
"integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@opencode-ai/plugin": {
|
||||
"version": "1.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.3.17.tgz",
|
||||
"integrity": "sha512-N5lckFtYvEu2R8K1um//MIOTHsJHniF2kHoPIWPCrxKG5Jpismt1ISGzIiU3aKI2ht/9VgcqKPC5oZFLdmpxPw==",
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.4.8.tgz",
|
||||
"integrity": "sha512-arbggGAwR7vE6d5a/Ra8A7yECXYcOAPyRbJHzkofLLiVzyclsThFaL2SSCZw/UNJJTtt3L7JGl95phFodJq8tQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "1.3.17",
|
||||
"@opencode-ai/sdk": "1.4.8",
|
||||
"effect": "4.0.0-beta.48",
|
||||
"zod": "4.1.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentui/core": ">=0.1.96",
|
||||
"@opentui/solid": ">=0.1.96"
|
||||
"@opentui/core": ">=0.1.100",
|
||||
"@opentui/solid": ">=0.1.100"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@opentui/core": {
|
||||
@@ -31,16 +110,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@opencode-ai/sdk": {
|
||||
"version": "1.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.3.17.tgz",
|
||||
"integrity": "sha512-2+MGgu7wynqTBwxezR01VAGhILXlpcHDY/pF7SWB87WOgLt3kD55HjKHNj6PWxyY8n575AZolR95VUC3gtwfmA==",
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.4.8.tgz",
|
||||
"integrity": "sha512-DTN0TwRxuBxdm2JvJO3Dg7Vp9/j8PFpTS/26qD6Mzi6UPI5+NBxgcDVkozKygi55Goj3AAQGJPp63qzbdc+8ag==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "7.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
@@ -51,19 +138,164 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/effect": {
|
||||
"version": "4.0.0-beta.48",
|
||||
"resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz",
|
||||
"integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"fast-check": "^4.6.0",
|
||||
"find-my-way-ts": "^0.1.6",
|
||||
"ini": "^6.0.0",
|
||||
"kubernetes-types": "^1.30.0",
|
||||
"msgpackr": "^1.11.9",
|
||||
"multipasta": "^0.2.7",
|
||||
"toml": "^4.1.1",
|
||||
"uuid": "^13.0.0",
|
||||
"yaml": "^2.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-check": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.6.0.tgz",
|
||||
"integrity": "sha512-h7H6Dm0Fy+H4ciQYFxFjXnXkzR2kr9Fb22c0UBpHnm59K2zpr2t13aPTHlltFiNT6zuxp6HMPAVVvgur4BLdpA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/dubzzz"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fast-check"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pure-rand": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/find-my-way-ts": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz",
|
||||
"integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
|
||||
"integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/kubernetes-types": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz",
|
||||
"integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/msgpackr": {
|
||||
"version": "1.11.9",
|
||||
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.9.tgz",
|
||||
"integrity": "sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"msgpackr-extract": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/msgpackr-extract": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
|
||||
"integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build-optional-packages": "5.2.2"
|
||||
},
|
||||
"bin": {
|
||||
"download-msgpackr-prebuilds": "bin/download-prebuilds.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/multipasta": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz",
|
||||
"integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-gyp-build-optional-packages": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
|
||||
"integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"node-gyp-build-optional-packages": "bin.js",
|
||||
"node-gyp-build-optional-packages-optional": "optional.js",
|
||||
"node-gyp-build-optional-packages-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pure-rand": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz",
|
||||
"integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/dubzzz"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fast-check"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
@@ -74,13 +306,39 @@
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/toml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz",
|
||||
"integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
@@ -92,6 +350,21 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.1.8",
|
||||
"license": "MIT",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
└── system-watchdog-worker ← dispatched by AUTO-WDOG
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pool Supervisor Detailed Reference
|
||||
|
||||
@@ -66,7 +65,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Never dispatches to**: PRs that are already in mergeable state (passing CI + approval)
|
||||
|
||||
---
|
||||
|
||||
### 2. PR Review Pool (`AUTO-REV-SUP`)
|
||||
|
||||
@@ -80,7 +78,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Special**: Receives `FORGEJO_REVIEWER_PAT/USERNAME/PASSWORD` instead of primary credentials.
|
||||
|
||||
---
|
||||
|
||||
### 3. PR Merge Pool (`AUTO-PRMRG-SUP`)
|
||||
|
||||
@@ -90,11 +87,10 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
**Workers**: `pr-merge-worker` via **blocking Task tool call** (not async)
|
||||
**Worker tag pattern**: NONE — no `[AUTO-PRMRG-N]` sessions ever exist
|
||||
|
||||
**Role**: Merges approved PRs. Verifies seven merge criteria. Handles pre-merge rebasing.
|
||||
**Role**: Merges approved PRs. Verifies merge criteria. Handles pre-merge rebasing.
|
||||
|
||||
**⚠️ Special**: Does NOT use async-agent-manager. Calls `pr-merge-worker` directly as a Task subagent and blocks until it completes. When the supervisor is busy executing its worker, it appears as a normal busy session — this is correct behavior. Product-builder and system-watchdog must NOT flag the absence of `[AUTO-PRMRG-N]` sessions as a problem.
|
||||
|
||||
---
|
||||
|
||||
### 4. UAT Test Pool (`AUTO-UAT-SUP`)
|
||||
|
||||
@@ -106,31 +102,28 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Specification-driven user acceptance testing. Discovers testable feature areas from the spec, dispatches workers to test each area, files bug issues for gaps. Only assigns Priority/Critical bugs to the active milestone (scope guard).
|
||||
|
||||
---
|
||||
|
||||
### 5. Bug Hunt Pool (`AUTO-BUG-SUP`)
|
||||
|
||||
**Definition**: `bug-hunt-pool-supervisor`
|
||||
**Worker count**: N_QUARTER
|
||||
**Sleep**: 900 seconds (15 minutes)
|
||||
**Workers**: `bug-hunt-worker` (async sessions, use Gemini 2.5 Pro for large context)
|
||||
**Workers**: `bug-hunt-worker` (async sessions)
|
||||
**Worker tag pattern**: `[AUTO-BUG-N]`
|
||||
|
||||
**Role**: Proactive bug detection. Maps source modules, dispatches workers for deep code analysis combined with specification comparison.
|
||||
|
||||
---
|
||||
|
||||
### 6. Test Infrastructure Pool (`AUTO-INF-SUP`)
|
||||
|
||||
**Definition**: `test-infra-pool-supervisor`
|
||||
**Worker count**: N_QUARTER
|
||||
**Sleep**: 900 seconds (15 minutes)
|
||||
**Workers**: `test-infra-worker` (async sessions, use Gemini 2.5 Pro)
|
||||
**Workers**: `test-infra-worker` (async sessions)
|
||||
**Worker tag pattern**: `[AUTO-INF-N]`
|
||||
|
||||
**Role**: Testing infrastructure improvement. Analyzes CI timing, coverage gaps, test architecture. Never disables or weakens existing checks — only proposes additions and optimizations.
|
||||
|
||||
---
|
||||
|
||||
### 7. Architecture (`AUTO-ARCH`)
|
||||
|
||||
@@ -142,7 +135,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Specification authoring and module boundary definition. **The most consequential agent** — bad architecture cascades everywhere. Major changes go through PRs with `needs feedback` label for human approval.
|
||||
|
||||
---
|
||||
|
||||
### 8. Epic Planning (`AUTO-EPIC`)
|
||||
|
||||
@@ -154,7 +146,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Decomposes architecture into Forgejo Epics and Issues. Monitors for milestones without issues, epics without children. Creates dependency chains and metadata.
|
||||
|
||||
---
|
||||
|
||||
### 9. Human Liaison (`AUTO-HUMAN`)
|
||||
|
||||
@@ -166,7 +157,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Bridge to humans. Monitors all human activity on Forgejo. Has full triage authority. Responds to new issues, comments, PR reviews, and label changes.
|
||||
|
||||
---
|
||||
|
||||
### 10. Agent Evolution (`AUTO-EVLV`)
|
||||
|
||||
@@ -178,7 +168,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Monitors agent effectiveness. Identifies failure patterns. Proposes agent definition modifications in `.opencode/agents/`. All changes require human-approved PRs with `needs feedback` label.
|
||||
|
||||
---
|
||||
|
||||
### 11. Architecture Guard (`AUTO-GUARD`)
|
||||
|
||||
@@ -190,7 +179,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Aggressive codebase coherence checking. Scans for pattern drift, duplicate code, module coupling, API inconsistencies, and technical debt.
|
||||
|
||||
---
|
||||
|
||||
### 12. Spec Update (`AUTO-SPEC`)
|
||||
|
||||
@@ -202,7 +190,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Compares implementation against spec after merges. Updates spec where implementation found a better approach. Creates issues where implementation deviates incorrectly.
|
||||
|
||||
---
|
||||
|
||||
### 13. Backlog Grooming (`AUTO-GROOM`)
|
||||
|
||||
@@ -214,7 +201,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Continuously scans all open Forgejo issues and PRs for quality problems. Detects duplicates, orphans, stale issues, missing labels, priority mismatches. Works entirely via Forgejo API — no clone needed.
|
||||
|
||||
---
|
||||
|
||||
### 14. Documentation (`AUTO-DOCS`)
|
||||
|
||||
@@ -226,7 +212,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Documentation generation at milestone boundaries. Generates API docs, architecture overviews, README updates, changelogs.
|
||||
|
||||
---
|
||||
|
||||
### 15. Timeline Update (`AUTO-TIME`)
|
||||
|
||||
@@ -238,7 +223,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Monitors project progress and updates `docs/timeline.md` with milestone status, schedule adherence, and PlantUML gantt chart entries.
|
||||
|
||||
---
|
||||
|
||||
### 16. Project Owner (`AUTO-OWNR`)
|
||||
|
||||
@@ -250,7 +234,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Role**: Autonomous strategic decision-maker. Triages unverified issues, assigns priority and scope labels, makes strategic decisions, and engages with developers. For the label system and ticket lifecycle this agent uses, see `cleveragents-contributing` and `cleverthis-guidelines` skills.
|
||||
|
||||
---
|
||||
|
||||
### 17. System Watchdog (`AUTO-WDOG`)
|
||||
|
||||
@@ -265,7 +248,6 @@ product-builder (AUTO-PROD-BLDR) ← process supervisor (like systemd)
|
||||
|
||||
**Special**: Has the broadest view — monitors ALL other agents and their tracking issues.
|
||||
|
||||
---
|
||||
|
||||
## Utility Subagents (No Session Tags)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ The CleverAgents system runs as an OpenCode session (using `@opencode-ai/plugin`
|
||||
|
||||
**Critical rule**: Only `async-agent-manager` is permitted to make HTTP calls to `localhost:4096`. All other agents have this explicitly denied in their permissions. This centralises all async operations through a single, well-tested gateway.
|
||||
|
||||
---
|
||||
|
||||
## Why prompt_async Exists
|
||||
|
||||
@@ -25,7 +24,6 @@ Pool supervisors cannot use synchronous calls for workers because:
|
||||
|
||||
`prompt_async` solves this: the supervisor dispatches a worker, gets a 204 response immediately, and continues its main loop. Workers signal completion through Forgejo activity (comments, PRs, issue state changes) — the supervisor detects this by checking session status and Forgejo state on subsequent cycles.
|
||||
|
||||
---
|
||||
|
||||
## OpenCode Server API Reference
|
||||
|
||||
@@ -139,7 +137,6 @@ curl -s -X DELETE "http://localhost:4096/session/${SESSION_ID}"
|
||||
|
||||
Returns `true` with HTTP 200 on success.
|
||||
|
||||
---
|
||||
|
||||
## Session Naming Convention
|
||||
|
||||
@@ -194,7 +191,6 @@ All sessions follow the format: `[TAG] display-name`
|
||||
| `AUTO-OWNR` | `[AUTO-OWNR-N]` | `[AUTO-OWNR-8]` |
|
||||
| `AUTO-WDOG` | `[AUTO-WDOG-N]` | `[AUTO-WDOG-2]` |
|
||||
|
||||
---
|
||||
|
||||
## Common Operations (via async-agent-manager)
|
||||
|
||||
@@ -229,7 +225,6 @@ Workers completing normally is expected — they do their task and exit. The sup
|
||||
|
||||
Supervisors periodically prune completed worker sessions using async-agent-cleanup.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
Multiple agents may discover the same work item simultaneously. Without coordination, two agents might work on the same issue/PR concurrently, leading to conflicts. The system uses a **comment-based claiming protocol** on Forgejo issues and PRs to prevent this.
|
||||
|
||||
---
|
||||
|
||||
## Claim Protocol
|
||||
|
||||
@@ -85,7 +84,6 @@ Reason: completed | failed | timeout | error
|
||||
**Automated by CleverAgents Bot**
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PR Work Coordination
|
||||
|
||||
@@ -102,7 +100,6 @@ When multiple agents may work on the same PR (e.g., implementation pool fixes a
|
||||
|
||||
**Wait policy**: If another agent has been working < 15 minutes → wait 5 minutes and retry. If > 15 minutes → they may be stuck; proceed anyway.
|
||||
|
||||
---
|
||||
|
||||
## Session-Level Deduplication (Supervisor Responsibility)
|
||||
|
||||
@@ -114,7 +111,6 @@ Beyond claim-level coordination, supervisors prevent duplicate dispatch by check
|
||||
|
||||
This tag-based deduplication is the PRIMARY mechanism. The claim protocol is a secondary safeguard for cases where the tag search might miss something.
|
||||
|
||||
---
|
||||
|
||||
## System Watchdog Monitoring of Coordination
|
||||
|
||||
@@ -127,7 +123,6 @@ The system-watchdog monitors for coordination violations:
|
||||
|
||||
When violations are detected, the watchdog dispatches a `system-watchdog-worker` to clean up and may create an announcement.
|
||||
|
||||
---
|
||||
|
||||
## Startup Deduplication
|
||||
|
||||
@@ -138,7 +133,6 @@ Product-builder prevents duplicate supervisors:
|
||||
|
||||
This prevents supervisor accumulation across restarts. Supervisors recover their state from Forgejo tracking issues, so stopping them causes no data loss.
|
||||
|
||||
---
|
||||
|
||||
## Bot Signatures
|
||||
|
||||
@@ -159,13 +153,12 @@ Agent: implementation-worker
|
||||
|
||||
This identifies automated content, helps humans understand which agent made a change, and is used by the coordination protocols to distinguish automated from human comments.
|
||||
|
||||
---
|
||||
|
||||
## Announcement Relevancy Matrix
|
||||
|
||||
The full canonical cross-agent attention table is in **SKILL.md** under the
|
||||
"Which announcements should I consume?" decision tree. It lists every supervisor
|
||||
prefix with its complete source-and-minimum-priority matrix.
|
||||
The full canonical cross-agent attention table lives in
|
||||
[`../tracking-system/announcement-matrix/`](../tracking-system/announcement-matrix/).
|
||||
It lists every supervisor prefix with its complete source-and-minimum-priority matrix.
|
||||
|
||||
For dynamic lookup: use `agent-prefix-info` with `GET_RELEVANCY_MATRIX` to get
|
||||
the table for any specific prefix programmatically.
|
||||
|
||||
@@ -31,7 +31,6 @@ git remote get-url origin
|
||||
# → FORGEJO_REPO = cleveragents-core
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Credential Hierarchy
|
||||
|
||||
@@ -49,7 +48,6 @@ git commits, Forgejo API calls, etc.
|
||||
|
||||
**Key principle**: Every level explicitly passes ALL needed credentials to the next level. Nothing is inferred from environment variables after product-builder's initial read.
|
||||
|
||||
---
|
||||
|
||||
## The Two Bot Accounts
|
||||
|
||||
@@ -73,7 +71,6 @@ Credentials: `FORGEJO_REVIEWER_PAT`, `FORGEJO_REVIEWER_USERNAME`, `FORGEJO_REVIE
|
||||
|
||||
**Note**: product-builder detects this special case and passes reviewer credentials to `pr-review-pool-supervisor` instead of the primary credentials.
|
||||
|
||||
---
|
||||
|
||||
## Worker Credential Rules
|
||||
|
||||
@@ -101,7 +98,6 @@ The supervisor's prompt to the worker must include:
|
||||
|
||||
If a supervisor omits any of these, the worker cannot proceed. Supervisors are responsible for passing everything explicitly.
|
||||
|
||||
---
|
||||
|
||||
## Worker Count Configuration
|
||||
|
||||
@@ -121,7 +117,6 @@ Product-builder computes these values at startup and passes the appropriate coun
|
||||
| If N = 16: | N_FULL=16, N_HALF=8, N_QUARTER=4 |
|
||||
| If N = 1: | N_FULL=1, N_HALF=1, N_QUARTER=1 (minimums enforced) |
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# Operational Parameters — Key Numbers and Thresholds
|
||||
|
||||
All timing, sizing, and threshold values used across the autonomous agent system.
|
||||
|
||||
For the *complete* supervisor details (role descriptions, worker types, worker tag
|
||||
patterns) see [`../agent-registry/`](../agent-registry/).
|
||||
|
||||
|
||||
## Supervisor Registry — Quick Lookup Table
|
||||
|
||||
| # | Prefix | Agent Definition | Workers | Sleep | Tracking Prefix |
|
||||
|---|--------|-----------------|---------|-------|-----------------|
|
||||
| 0 | `AUTO-PROD-BLDR` | product-builder | N/A (monitors, not a pool) | 60 s | `AUTO-PROD-BLDR` |
|
||||
| 1 | `AUTO-IMP-SUP` | implementation-pool-supervisor | N_FULL | 120 s | `AUTO-IMP-POOL` |
|
||||
| 2 | `AUTO-REV-SUP` | pr-review-pool-supervisor | N_HALF | 30 s | `AUTO-REV-SUP` |
|
||||
| 3 | `AUTO-PRMRG-SUP` | pr-merge-pool-supervisor | 0 (blocking subagent) | 300 s | `AUTO-PRMRG-SUP` |
|
||||
| 4 | `AUTO-UAT-SUP` | uat-test-pool-supervisor | N_QUARTER | 600 s | `AUTO-UAT-SUP` |
|
||||
| 5 | `AUTO-BUG-SUP` | bug-hunt-pool-supervisor | N_QUARTER | 900 s | `AUTO-BUG-SUP` |
|
||||
| 6 | `AUTO-INF-SUP` | test-infra-pool-supervisor | N_QUARTER | 900 s | `AUTO-INF-SUP` |
|
||||
| 7 | `AUTO-ARCH` | architecture-pool-supervisor | 1 | 1800 s | `AUTO-ARCH` |
|
||||
| 8 | `AUTO-EPIC` | epic-planning-pool-supervisor | 1 | 600 s | `AUTO-EPIC` |
|
||||
| 9 | `AUTO-HUMAN` | human-liaison-pool-supervisor | 1 | 120 s | `AUTO-HUMAN` |
|
||||
| 10 | `AUTO-EVLV` | agent-evolution-pool-supervisor | 1 | 1800 s | `AUTO-EVLV` |
|
||||
| 11 | `AUTO-GUARD` | architecture-guard-pool-supervisor | 1 | 600 s | `AUTO-GUARD` |
|
||||
| 12 | `AUTO-SPEC` | spec-update-pool-supervisor | 1 | 900 s | `AUTO-SPEC` |
|
||||
| 13 | `AUTO-GROOM` | grooming-pool-supervisor | 1 | 300 s | `AUTO-GROOM` |
|
||||
| 14 | `AUTO-DOCS` | documentation-pool-supervisor | 1 | 1800 s | `AUTO-DOCS` |
|
||||
| 15 | `AUTO-TIME` | timeline-update-pool-supervisor | 1 | 3600 s | `AUTO-TIME` |
|
||||
| 16 | `AUTO-OWNR` | project-owner-pool-supervisor | 1 | 300 s | `AUTO-OWNR` |
|
||||
| 17 | `AUTO-WDOG` | system-watchdog-pool-supervisor | 1 | 300 s | `AUTO-WATCHDOG` |
|
||||
|
||||
> **⚠️ `AUTO-WDOG` tracking prefix exception:** The session tag is `[AUTO-WDOG]` but
|
||||
> the tracking issue prefix is `AUTO-WATCHDOG`. Don't confuse the two.
|
||||
|
||||
> **⚠️ `AUTO-PRMRG-SUP` worker count exception:** This supervisor calls
|
||||
> `pr-merge-worker` as a **blocking Task subagent** — there are no `[AUTO-PRMRG-N]`
|
||||
> async sessions. Worker count = 0 means "no async worker sessions", not "no work".
|
||||
|
||||
### Sleep Timeout Rule
|
||||
|
||||
Always set bash timeout to `sleep_duration × 1.5` minimum:
|
||||
```bash
|
||||
bash("sleep 300", timeout=450000) # 5 min sleep → 7.5 min timeout
|
||||
bash("sleep 120", timeout=180000) # 2 min sleep → 3 min timeout
|
||||
```
|
||||
Never let the bash timeout be less than the sleep duration — the call will be
|
||||
killed before the sleep completes.
|
||||
|
||||
|
||||
## Worker Count Formula
|
||||
|
||||
Controlled by the `CA_MAX_PARALLEL_WORKERS` environment variable (default: 4).
|
||||
Product-builder reads this at startup and passes the computed values to each supervisor.
|
||||
|
||||
```
|
||||
N = CA_MAX_PARALLEL_WORKERS
|
||||
N_FULL = N
|
||||
N_HALF = max(1, N ÷ 2) # integer division; minimum 1
|
||||
N_QUARTER = max(1, N ÷ 4) # integer division; minimum 1
|
||||
```
|
||||
|
||||
| If N = 1 | N_FULL=1, N_HALF=1, N_QUARTER=1 | (minimums enforced) |
|
||||
|----------|----------------------------------|---------------------|
|
||||
| If N = 4 | N_FULL=4, N_HALF=2, N_QUARTER=1 | |
|
||||
| If N = 8 | N_FULL=8, N_HALF=4, N_QUARTER=2 | |
|
||||
| If N = 16 | N_FULL=16, N_HALF=8, N_QUARTER=4 | |
|
||||
|
||||
|
||||
## Key Numbers — All Thresholds and Timings
|
||||
|
||||
| Parameter | Value | Context |
|
||||
|-----------|-------|---------|
|
||||
| `CA_MAX_PARALLEL_WORKERS` default | 4 | Set via environment variable |
|
||||
| N_FULL | N | Implementation pool only |
|
||||
| N_HALF | max(1, N ÷ 2) | PR review pool only |
|
||||
| N_QUARTER | max(1, N ÷ 4) | UAT, Bug Hunt, Test Infra |
|
||||
| Work claim expiry | 2 hours | Without heartbeat — see `references/coordination/` |
|
||||
| Heartbeat interval | 10 minutes | Must send to maintain a claim |
|
||||
| Rolling average formula | 0.90 × old + 0.10 × actual | Cycle interval smoothing |
|
||||
| Status issue limit | 1 per prefix at a time | Older ones closed when new one created |
|
||||
| Human escalation trigger | Opus tier × 3 same-problem failures | Apply `needs feedback` label |
|
||||
| Forgejo API timeout | 30 seconds | Per individual HTTP request |
|
||||
| Git operation timeout | 5 minutes | Local git commands |
|
||||
| Test execution timeout | 15 minutes | Full test suite runs |
|
||||
| Worker stuck threshold | 15 minutes idle | No new messages → classified as `stuck` |
|
||||
| Product-builder fast cycle | 60 seconds | Liveness check + question-answering |
|
||||
| Product-builder deep inspection | Every 5 fast cycles (~5 min) | Message reading, anti-pattern detection |
|
||||
| Product-builder worker health check | Every 5 fast cycles (~5 min) | Pool count vs expected |
|
||||
| Product-builder hourly cycle | Every ~60 fast cycles | Full verification + status ticket |
|
||||
| Watchdog staleness threshold | 2 × estimated_cycle_interval | If tracking issue older → supervisor frozen |
|
||||
| Supervisor max downtime | ≤ 60 seconds | product-builder fast cycle detects crash |
|
||||
| Worker max downtime before re-dispatch | Supervisor's sleep interval | 2 min (IMP) to 60 min (TIME) |
|
||||
| Max temp dir age | 24 hours | Cleaned automatically by repo-isolator |
|
||||
| Forgejo MCP page limit | 50 per page | Always paginate exhaustively |
|
||||
| Supervisor crash offline thresholds | < 30 min → light recovery | Resume from state |
|
||||
| | 30–120 min → moderate recovery | Re-verify key Forgejo state |
|
||||
| | > 120 min → full re-scan | Treat as fresh start with hints |
|
||||
@@ -12,7 +12,6 @@ Layer 3 — each supervisor monitors its own workers (every cycle)
|
||||
|
||||
No layer depends on another to detect problems — if product-builder is distracted or slow, system-watchdog independently detects frozen supervisors via Forgejo. If a supervisor's pool drains, product-builder notices the undercount before system-watchdog checks in.
|
||||
|
||||
---
|
||||
|
||||
## Layer 1: Product-Builder Monitoring
|
||||
|
||||
@@ -73,7 +72,6 @@ Product-builder manages its own context window explicitly:
|
||||
|
||||
**Critical limit**: product-builder itself has no external watcher. If it crashes or exhausts its context, a human must restart it. This is the only single point of failure in the system. All supervisor-level crashes self-heal; product-builder-level crashes require human intervention.
|
||||
|
||||
---
|
||||
|
||||
## Layer 2: System Watchdog
|
||||
|
||||
@@ -119,7 +117,6 @@ System-watchdog monitors supervisors but does NOT restart them. It creates:
|
||||
|
||||
Product-builder is responsible for actually relaunching failed supervisors.
|
||||
|
||||
---
|
||||
|
||||
## Layer 3: Supervisor Self-Monitoring of Workers
|
||||
|
||||
@@ -165,7 +162,6 @@ Each pool supervisor maintains a sliding window of active workers:
|
||||
- The pool is continuously filled, not batch-dispatched
|
||||
- A supervisor that stops filling its pool triggers product-builder's worker health check and gets relaunched
|
||||
|
||||
---
|
||||
|
||||
## State Persistence: The Foundation of Self-Healing
|
||||
|
||||
@@ -219,7 +215,6 @@ Self-healing only works because all state is externalized to Forgejo. No state l
|
||||
8. New worker starts from the appropriate resumption point
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Two Independent Health Signals
|
||||
|
||||
@@ -232,7 +227,6 @@ Understanding which signal catches which failure:
|
||||
|
||||
Together they provide complete coverage. A session can appear `busy` in OpenCode while being completely stuck (no Forgejo output) — only the staleness check catches this. A session can stop posting to Forgejo because it crashed — only the OpenCode check catches this.
|
||||
|
||||
---
|
||||
|
||||
## Detecting Specific Failure Modes
|
||||
|
||||
@@ -249,7 +243,6 @@ Together they provide complete coverage. A session can appear `busy` in OpenCode
|
||||
| Multiple supervisors down | product-builder: repeated relaunch failures; system-watchdog: multiple stale tracking issues | product-builder: Priority/Critical announcement; human intervention |
|
||||
| product-builder itself crashed | No automatic detection | Human must restart |
|
||||
|
||||
---
|
||||
|
||||
## The async-agent-monitor Subagent
|
||||
|
||||
@@ -267,7 +260,6 @@ Classifies sessions as:
|
||||
|
||||
The 15-minute threshold is configurable by the caller via `idle_threshold_minutes`. For short-cycle supervisors (120s sleep) this may be set lower; for long-cycle supervisors (1800s sleep) the default may be appropriate.
|
||||
|
||||
---
|
||||
|
||||
## Redundancy Gaps and Limitations
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
# 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`, …), importable as a module by the six 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 |
|
||||
|
||||
### 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 |
|
||||
|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||
|
||||
## 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.
|
||||
The six `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`, and `--ci-status`.
|
||||
|
||||
**`--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`
|
||||
|
||||
Each PR object in all outputs now 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.
|
||||
@@ -0,0 +1,310 @@
|
||||
# list_prs — General Forgejo PR Listing Script
|
||||
|
||||
**Script name:** `list_prs`
|
||||
|
||||
**Script location:** [`scripts/list_prs.ts`](../../../scripts/list_prs.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO \
|
||||
[--state open|closed|all] [--min-approvals N] [--max-approvals N] \
|
||||
[--mergeable true|false] [--stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown] \
|
||||
[--ci-status passing|failing|pending|unknown[,...]]
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
|
||||
```
|
||||
|
||||
Fetches all pull requests from a Forgejo repository, enriches each one with a
|
||||
computed approval count, a staleness classification, and a priority rank, then
|
||||
filters and sorts the results before writing a JSON array to stdout.
|
||||
|
||||
`list_prs.ts` is both a standalone CLI tool and the **importable core module**
|
||||
used by the four thin wrapper scripts
|
||||
(`list_prs_needs_review`, `list_prs_ready_to_merge`, `list_prs_stale_clean`,
|
||||
`list_prs_stale_conflicts`). When imported, it exports `listPRs` and
|
||||
`parseConnectionArgs` for use by those wrappers.
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
### Required
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
|
||||
All four required flags must be present. Any missing flag causes an immediate
|
||||
exit with code 1 and an error message to stderr.
|
||||
|
||||
### Optional Filters
|
||||
|
||||
All filter flags default to "no filter" (i.e. all values pass) when omitted.
|
||||
|
||||
| Flag | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `--state open\|closed\|all` | string | `open` | Filter by PR state |
|
||||
| `--min-approvals N` | integer ≥ 0 | (none) | Include only PRs with **≥ N** non-dismissed approvals |
|
||||
| `--max-approvals N` | integer ≥ 0 | (none) | Include only PRs with **≤ N** non-dismissed approvals |
|
||||
| `--mergeable true\|false` | boolean | (none) | Filter by Forgejo's raw `PR.mergeable` field |
|
||||
| `--stale VALUE` | string | (none) | Filter by computed `stale_state` (see Stale States below) |
|
||||
| `--ci-status VALUE[,...]` | string | (none) | Comma-separated whitelist of CI statuses to include (see CI Status below). Omit to include all CI statuses. |
|
||||
| `-h`, `--help` | — | — | Print usage to stderr and exit 0 |
|
||||
|
||||
### Argument Validity Rules
|
||||
|
||||
- `--min-approvals` and `--max-approvals` may be used together; both constraints apply simultaneously (logical AND).
|
||||
- `--min-approvals 1 --max-approvals 0` is logically impossible and will return an empty result set — the script does not reject it, it simply matches nothing.
|
||||
- `--mergeable` filters on the raw API field, not on the computed `stale_state`. Use `--stale` for the semantically richer classification.
|
||||
- `--ci-status` accepts a comma-separated list of values from `passing`, `failing`, `pending`, `unknown`. A PR must match **any one** of the listed values (logical OR within the list). Multiple `--ci-status` flags are not supported — put all desired values in one comma-separated argument.
|
||||
- Any unknown flag causes exit code 1 and a usage message.
|
||||
- `--state` only accepts the three literal values `open`, `closed`, `all`; any other value is passed to the API which may behave unexpectedly (this is not validated client-side).
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array. Each element is the full
|
||||
Forgejo PR object as returned by the API, augmented with four additional fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Count of distinct non-dismissed `APPROVED` reviews. Per-reviewer: only the reviewer's most recent review is counted; if they later submitted `REQUEST_CHANGES`, that supersedes the approval and it is not counted. |
|
||||
| `stale_state` | string | One of five stale states (see below) |
|
||||
| `ci_status` | string | One of four CI status values (see CI Status below) |
|
||||
| `priority_rank` | integer | 0 = `Priority/CI Blocker` (highest), …, 5 = `Priority/Backlog`, 6 = unlabelled |
|
||||
| `priority_label` | string \| null | The matched `Priority/*` label name, or `null` if none present |
|
||||
|
||||
The array is **sorted ascending by `priority_rank`** so the most urgent PRs appear
|
||||
first within the result set.
|
||||
|
||||
### Stale States
|
||||
|
||||
| `stale_state` value | Meaning |
|
||||
|---------------------|---------|
|
||||
| `not_stale` | `PR.merge_base == base branch HEAD` — PR is fully up-to-date |
|
||||
| `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` — clean auto-rebase possible |
|
||||
| `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` — manual resolution required |
|
||||
| `stale_unknown` | Base has advanced AND `PR.mergeable == null` — Forgejo is still computing |
|
||||
| `compute_error` | `PR.merge_base` or base HEAD SHA is missing; classification impossible |
|
||||
|
||||
### CI Status
|
||||
|
||||
Derived from `GET /api/v1/repos/{owner}/{repo}/commits/{head_sha}/status` — the Forgejo combined commit-status endpoint. The `state` field of that response is mapped as follows:
|
||||
|
||||
| `ci_status` value | Forgejo combined state | Meaning |
|
||||
|-------------------|----------------------|---------|
|
||||
| `passing` | `success` | All status checks have reported success |
|
||||
| `failing` | `failure` \| `error` \| `warning` | At least one check has failed or errored |
|
||||
| `pending` | `pending` | Checks are queued or still running |
|
||||
| `unknown` | `""` \| `unknown` | No status checks have been reported for this commit |
|
||||
|
||||
Use `--ci-status passing` to restrict to PRs where all CI has passed. Use `--ci-status passing,pending` to include both passing and still-running PRs. Omit `--ci-status` entirely to return PRs regardless of their CI state.
|
||||
|
||||
### Priority Rank Table
|
||||
|
||||
| `priority_rank` | Label |
|
||||
|----------------|-------|
|
||||
| 0 | `Priority/CI Blocker` |
|
||||
| 1 | `Priority/Critical` |
|
||||
| 2 | `Priority/High` |
|
||||
| 3 | `Priority/Medium` |
|
||||
| 4 | `Priority/Low` |
|
||||
| 5 | `Priority/Backlog` |
|
||||
| 6 | (no `Priority/*` label present) |
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr during execution (not to stdout, so
|
||||
they do not contaminate the JSON output):
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 12/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
Warnings about individual failures (e.g. a branch API error for one PR) are
|
||||
also written to stderr. The script continues processing the remaining PRs
|
||||
rather than aborting.
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be empty `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing required `--url`, `--pat`, `--owner`, or `--repo` | Exit 1 with descriptive message |
|
||||
| Unknown CLI flag | Exit 1 with usage message |
|
||||
| API returns non-2xx for the PR list | Throws; script exits 1 with the HTTP status and body |
|
||||
| API returns non-2xx for a base branch HEAD | Logs a warning to stderr; marks affected PRs as `compute_error`; continues |
|
||||
| API returns non-2xx for a PR's reviews | Logs a warning; treats that PR as having 0 approvals; continues |
|
||||
| Network timeout (30 s per request) | Throws; script exits 1 |
|
||||
|
||||
|
||||
## Performance Notes
|
||||
|
||||
The script uses concurrent fetch chains to minimise wall-clock time:
|
||||
|
||||
- **PR pages** are fetched in parallel batches of 6 pages at a time.
|
||||
- **Base-branch HEAD SHAs** are fetched simultaneously for all unique branches (cached: one call per unique branch regardless of how many PRs share it).
|
||||
- **Reviews** are fetched with up to 20 concurrent in-flight requests at once.
|
||||
|
||||
For a repository with ~326 PRs, this reduces review-fetching from ~230 s
|
||||
(sequential) to ~1.7 s.
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs.ts` directly when you need **custom filter combinations** not
|
||||
served by one of the four wrapper scripts:
|
||||
|
||||
- List all closed PRs: `--state closed`
|
||||
- Find PRs with exactly 2 approvals: `--min-approvals 2 --max-approvals 2`
|
||||
- Find approved PRs that are still pending Forgejo's conflict check: `--min-approvals 1 --stale stale_unknown`
|
||||
- List all PRs regardless of state: `--state all`
|
||||
- Find open PRs ready to merge (approved, not stale, CI passing): `--min-approvals 1 --stale not_stale --ci-status passing`
|
||||
- Find PRs with broken CI: `--ci-status failing`
|
||||
- Find PRs with passing or pending CI: `--ci-status passing,pending`
|
||||
|
||||
For the four standard operating buckets used by `pr-merge-pool-supervisor`,
|
||||
prefer the thin wrappers — they are self-documenting and require fewer flags.
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# List all open PRs (no filters — returns everything)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# List open PRs with at least 1 approval that are not stale
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--min-approvals 1 \
|
||||
--stale not_stale
|
||||
|
||||
# List open PRs awaiting a first review (0 approvals)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--max-approvals 0
|
||||
|
||||
# List all closed PRs (for audit/history purposes)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--state closed
|
||||
|
||||
# Extract just PR numbers from the result using jq
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --min-approvals 1 \
|
||||
| jq '[.[].number]'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor does **not** call `list_prs.ts` directly. It calls the four
|
||||
purpose-built wrapper scripts to populate its four work queues each cycle.
|
||||
It would only call `list_prs.ts` directly if it needed a custom filter
|
||||
combination not covered by those wrappers (e.g. investigating `stale_unknown`
|
||||
PRs to determine if Forgejo is lagging).
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
The worker does **not** call `list_prs.ts`. It receives a specific PR number
|
||||
from the supervisor and operates on that single PR. However, a worker
|
||||
implementing complex decision logic could import `listPRs` programmatically
|
||||
to inspect the state of all PRs before deciding how to proceed.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
The watchdog could use `list_prs.ts` with `--state all` or custom filter
|
||||
combinations to audit the full PR pipeline — for example, to detect PRs
|
||||
that have been open for an unusually long time, or to count approved PRs
|
||||
that are not progressing through the merge pipeline.
|
||||
|
||||
### implementation-pool-supervisor
|
||||
|
||||
The implementation supervisor might use `list_prs.ts` with
|
||||
`--min-approvals 0 --max-approvals 0` (or equivalently `list_prs_needs_review`)
|
||||
to check whether any of its submitted PRs are awaiting a first review, so it
|
||||
can decide whether to dispatch more implementation workers or wait for review
|
||||
capacity to clear.
|
||||
|
||||
|
||||
## Module API (when imported)
|
||||
|
||||
```typescript
|
||||
import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
|
||||
// Config object
|
||||
const config: Config = {
|
||||
url: 'https://git.example.com',
|
||||
pat: 'ghp_XXXX',
|
||||
owner: 'my-org',
|
||||
repo: 'my-repo',
|
||||
};
|
||||
|
||||
// Filters object (all fields optional)
|
||||
const filters: Filters = {
|
||||
state: 'open',
|
||||
minApprovals: 1,
|
||||
stale: 'not_stale',
|
||||
ciStatus: ['passing'], // only PRs with all CI checks passing
|
||||
};
|
||||
|
||||
// ciStatus accepts any combination:
|
||||
// ciStatus: ['passing'] — CI must have passed
|
||||
// ciStatus: ['pending'] — CI still running
|
||||
// ciStatus: ['failing'] — CI has failed
|
||||
// ciStatus: ['passing', 'pending'] — CI passed or still running
|
||||
// (omit ciStatus entirely) — any CI state passes through
|
||||
|
||||
const prs: AugmentedPR[] = await listPRs(config, filters);
|
||||
```
|
||||
|
||||
The exported `parseConnectionArgs(argv)` function parses only the four
|
||||
connection flags (`--url`, `--pat`, `--owner`, `--repo`) and is used by the
|
||||
four wrapper scripts. It rejects any unknown flag with an informative error.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API, stable since v21; available unflagged since v18)
|
||||
- `npx tsx` for TypeScript execution (auto-installed by `npx --yes tsx`)
|
||||
- Zero external npm packages — uses only Node.js built-ins
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
# list_prs_needs_review_not_stale — Open PRs With No Approvals, Up-to-Date
|
||||
|
||||
**Script name:** `list_prs_needs_review_not_stale`
|
||||
|
||||
**Script location:** [`scripts/list_prs_needs_review_not_stale.ts`](../../../scripts/list_prs_needs_review_not_stale.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_needs_review_not_stale.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **zero non-dismissed approvals**
|
||||
and are **not stale** — i.e. the PR's `merge_base` already matches the current
|
||||
HEAD of its base branch. The PR is fully up-to-date and requires no rebase
|
||||
before merging.
|
||||
|
||||
These are the simplest PRs in the "needs review" set: once a reviewer approves
|
||||
them, they can be merged immediately without any additional rebase or conflict
|
||||
resolution step.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
maxApprovals: 0
|
||||
stale: 'not_stale'
|
||||
(no ciStatus filter — all CI states are included)
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1 and an error
|
||||
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
|
||||
and cannot be overridden via CLI flags on this wrapper script.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
There are no valid filter-combination errors since no optional filters exist.
|
||||
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
|
||||
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
|
||||
| `stale` | `not_stale` | `PR.merge_base` equals the current base branch HEAD |
|
||||
|
||||
**"Not stale"** means `PR.merge_base == current base branch HEAD`: the base
|
||||
branch has not advanced since the PR's head was last reconciled, so no rebase
|
||||
is needed.
|
||||
|
||||
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
|
||||
review as their most recent review. A reviewer who approved and then later
|
||||
submitted `REQUEST_CHANGES` is not counted as an approver.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be `0` for results of this script |
|
||||
| `stale_state` | string | Will always be `not_stale` for results of this script |
|
||||
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` is a valid and common result — it means all open
|
||||
up-to-date PRs already have at least one approval.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 8/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_needs_review_not_stale` when you want to identify PRs that are
|
||||
**waiting for a first review and are already current with their base branch**.
|
||||
Typical use cases:
|
||||
|
||||
- **`pr-review-pool-supervisor`** uses this as its highest-priority review
|
||||
bucket: once approved, these PRs merge cleanly with no further action.
|
||||
- A **review dispatcher** agent can prioritise these over stale PRs since
|
||||
reviewing them provides immediate merge readiness.
|
||||
- A **monitoring agent** can track this bucket to detect a backlog of fresh
|
||||
PRs waiting for review.
|
||||
|
||||
### Position in the Six-Bucket System
|
||||
|
||||
```
|
||||
Every open PR belongs to exactly one bucket at any moment:
|
||||
|
||||
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
|
||||
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
|
||||
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
|
||||
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale) ← THIS SCRIPT
|
||||
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts)
|
||||
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts)
|
||||
|
||||
Exception: PRs with stale_state == stale_unknown are transiently absent from
|
||||
all buckets while Forgejo computes conflict status. They appear shortly.
|
||||
```
|
||||
|
||||
Workflow for a PR in this bucket once approved:
|
||||
```
|
||||
Reviewer approves → PR moves to list_prs_ready_to_merge → merge_pr
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count how many fresh PRs are waiting for a first review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Get just the PR numbers and titles
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[] | {number, title}]'
|
||||
|
||||
# Get only the highest-priority PR needing review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-review-pool-supervisor
|
||||
|
||||
The supervisor can call this script to find its highest-priority review
|
||||
targets — PRs that will merge immediately after approval. It dispatches
|
||||
`pr-reviewer` workers for each result.
|
||||
|
||||
```bash
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_not_stale.ts \
|
||||
--url $FORGEJO_URL \
|
||||
--pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER \
|
||||
--repo $REPO_NAME
|
||||
```
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The merge supervisor uses this to surface PRs waiting for review that will
|
||||
have the simplest post-approval workflow. An empty result here (combined with
|
||||
non-empty stale buckets) suggests review bandwidth is being absorbed by PRs
|
||||
that still have pending rebase work.
|
||||
|
||||
### human-liaison-pool-supervisor
|
||||
|
||||
The human liaison can filter by `created_at` to identify PRs that have been
|
||||
waiting for a first review for too long, then post reminder comments or alert
|
||||
human reviewers.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
# list_prs_needs_review_stale_clean — Open PRs With No Approvals, Stale, No Conflicts
|
||||
|
||||
**Script name:** `list_prs_needs_review_stale_clean`
|
||||
|
||||
**Script location:** [`scripts/list_prs_needs_review_stale_clean.ts`](../../../scripts/list_prs_needs_review_stale_clean.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_needs_review_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **zero non-dismissed approvals**,
|
||||
are **stale** (the base branch has advanced since the PR was last synced), and
|
||||
have **no merge conflicts** (`PR.mergeable == true`). These PRs need a first
|
||||
review AND will require a server-side rebase before or after approval — but no
|
||||
conflict resolution will be required.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
maxApprovals: 0
|
||||
stale: 'stale_no_conflicts'
|
||||
(no ciStatus filter — all CI states are included)
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1 and an error
|
||||
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
|
||||
and cannot be overridden via CLI flags on this wrapper script.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
There are no valid filter-combination errors since no optional filters exist.
|
||||
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
|
||||
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
|
||||
| `stale` | `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` |
|
||||
|
||||
**"Stale no conflicts"** means two things are simultaneously true:
|
||||
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
|
||||
2. `PR.mergeable == true` — Forgejo has determined that rebasing the PR's commits onto the new base would succeed without any merge conflicts.
|
||||
|
||||
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
|
||||
review as their most recent review.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be `0` for results of this script |
|
||||
| `stale_state` | string | Will always be `stale_no_conflicts` for results of this script |
|
||||
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` is a valid and common result — it means no open
|
||||
stale-but-clean PRs are currently awaiting a first review.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 5/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_needs_review_stale_clean` when you want to identify PRs that are
|
||||
**waiting for a first review and will need a server-side rebase before
|
||||
merging** (but no conflict resolution). Typical use cases:
|
||||
|
||||
- **`pr-review-pool-supervisor`** uses this as a medium-priority review
|
||||
bucket. After approving one of these PRs, the merge workflow is:
|
||||
`rebase_pr` then `merge_pr` — no local clone required.
|
||||
- A **review dispatcher** can distinguish these from `not_stale` PRs to
|
||||
inform the review prioritisation strategy.
|
||||
- A **monitoring agent** can track a growing bucket here as a signal that
|
||||
the base branch is advancing faster than reviewers are approving PRs.
|
||||
|
||||
### Position in the Six-Bucket System
|
||||
|
||||
```
|
||||
Every open PR belongs to exactly one bucket at any moment:
|
||||
|
||||
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
|
||||
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
|
||||
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
|
||||
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale)
|
||||
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts) ← THIS SCRIPT
|
||||
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts)
|
||||
|
||||
Exception: PRs with stale_state == stale_unknown are transiently absent from
|
||||
all buckets while Forgejo computes conflict status. They appear shortly.
|
||||
```
|
||||
|
||||
Workflow for a PR in this bucket once approved:
|
||||
```
|
||||
Reviewer approves → PR moves to list_prs_stale_clean → rebase_pr → merge_pr
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count stale-clean PRs awaiting first review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Get PR numbers, titles, and their base branches
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[] | {number, title, base: .base.ref}]'
|
||||
|
||||
# Get the highest-priority stale-clean PR awaiting review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-review-pool-supervisor
|
||||
|
||||
The supervisor dispatches `pr-reviewer` workers for PRs found in this bucket.
|
||||
After approval, the merge supervisor's `list_prs_stale_clean` script will pick
|
||||
them up for server-side rebase and merge.
|
||||
|
||||
```bash
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_clean.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
|
||||
# If non-empty → dispatch pr-reviewer for each PR
|
||||
```
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The merge supervisor can use the combined sizes of this bucket and
|
||||
`list_prs_needs_review_not_stale` to understand total review demand. A large
|
||||
combined backlog relative to approved buckets signals under-capacity in the
|
||||
review pool.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
A growing `list_prs_needs_review_stale_clean` bucket over consecutive watchdog
|
||||
cycles — while PRs in `list_prs_stale_clean` (approved) are being processed
|
||||
normally — suggests that review capacity is insufficient to keep pace with
|
||||
incoming PRs.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
# list_prs_needs_review_stale_conflicts — Open PRs With No Approvals, Stale, With Conflicts
|
||||
|
||||
**Script name:** `list_prs_needs_review_stale_conflicts`
|
||||
|
||||
**Script location:** [`scripts/list_prs_needs_review_stale_conflicts.ts`](../../../scripts/list_prs_needs_review_stale_conflicts.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_needs_review_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **zero non-dismissed approvals**,
|
||||
are **stale** (the base branch has advanced since the PR was last synced), and
|
||||
**have merge conflicts** (`PR.mergeable == false`). These PRs need a first
|
||||
review AND require manual conflict resolution — they have the most complex
|
||||
path to merge of any PR awaiting review.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
maxApprovals: 0
|
||||
stale: 'stale_with_conflicts'
|
||||
(no ciStatus filter — all CI states are included)
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1 and an error
|
||||
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
|
||||
and cannot be overridden via CLI flags on this wrapper script.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
There are no valid filter-combination errors since no optional filters exist.
|
||||
However, passing any filter-style flag (e.g. `--min-approvals`, `--stale`, etc.)
|
||||
will cause an immediate exit 1 — those flags are not accepted by this wrapper.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `maxApprovals` | `0` | PRs with zero non-dismissed `APPROVED` reviews |
|
||||
| `stale` | `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` |
|
||||
|
||||
**"Stale with conflicts"** means two things are simultaneously true:
|
||||
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
|
||||
2. `PR.mergeable == false` — Forgejo has determined that rebasing the PR's commits onto the new base would produce merge conflicts that cannot be resolved automatically.
|
||||
|
||||
**"Zero approvals"** means: no reviewer has an active (non-dismissed) `APPROVED`
|
||||
review as their most recent review.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be `0` for results of this script |
|
||||
| `stale_state` | string | Will always be `stale_with_conflicts` for results of this script |
|
||||
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` is a valid and common result — it means no open
|
||||
conflicted PRs are currently awaiting a first review.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 2/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_needs_review_stale_conflicts` when you want to identify the
|
||||
**highest-complexity PRs awaiting review** — those that need both a reviewer
|
||||
AND conflict resolution before they can merge. Typical use cases:
|
||||
|
||||
- **`pr-review-pool-supervisor`** uses this as its lowest-priority review
|
||||
bucket (these PRs have the most work remaining after review).
|
||||
- A **human-liaison agent** can use this to surface a conflict-backlog report:
|
||||
"These N PRs are not yet reviewed AND already have conflicts — they need
|
||||
author attention to resolve the conflicts first."
|
||||
- A **monitoring agent** can track a growing bucket here as a compound health
|
||||
signal: both review bandwidth AND code divergence are problems.
|
||||
|
||||
### Position in the Six-Bucket System
|
||||
|
||||
```
|
||||
Every open PR belongs to exactly one bucket at any moment:
|
||||
|
||||
Bucket 1 — list_prs_ready_to_merge (approved + not stale)
|
||||
Bucket 2 — list_prs_stale_clean (approved + stale, no conflicts)
|
||||
Bucket 3 — list_prs_stale_conflicts (approved + stale, has conflicts)
|
||||
Bucket 4 — list_prs_needs_review_not_stale (no approvals + not stale)
|
||||
Bucket 5 — list_prs_needs_review_stale_clean (no approvals + stale, no conflicts)
|
||||
Bucket 6 — list_prs_needs_review_stale_conflicts (no approvals + stale, has conflicts) ← THIS SCRIPT
|
||||
|
||||
Exception: PRs with stale_state == stale_unknown are transiently absent from
|
||||
all buckets while Forgejo computes conflict status. They appear shortly.
|
||||
```
|
||||
|
||||
Workflow for a PR in this bucket once approved:
|
||||
```
|
||||
Reviewer approves → PR moves to list_prs_stale_conflicts
|
||||
→ clone repo → rebase locally → resolve conflicts → force-push → merge_pr
|
||||
```
|
||||
|
||||
Note: Conflict resolution may need to happen **before** review if the PR
|
||||
author is asked to fix their branch first. Whether review comes before or after
|
||||
conflict resolution is a project workflow decision — this script surfaces the
|
||||
set of PRs where both are pending.
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count conflicted PRs awaiting first review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Get PR numbers, titles, and head/base branches (useful for conflict resolution planning)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[] | {number, title, head_branch: .head.ref, base_branch: .base.ref}]'
|
||||
|
||||
# Get the highest-priority conflicted PR awaiting review
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-review-pool-supervisor
|
||||
|
||||
The supervisor dispatches `pr-reviewer` workers for PRs in this bucket as
|
||||
lowest priority. The reviewer is informed that conflicts also exist and may
|
||||
note this in their review feedback.
|
||||
|
||||
```bash
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_needs_review_stale_conflicts.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
|
||||
# If non-empty → dispatch pr-reviewer for each PR (note conflict state in prompt)
|
||||
```
|
||||
|
||||
### human-liaison-pool-supervisor
|
||||
|
||||
The liaison can filter results by `created_at` to identify PRs stuck in this
|
||||
worst-case state for an extended period — no review AND conflicts — and post
|
||||
a comment pinging the PR author to fix the conflicts first, making the PR
|
||||
easier to review.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
A growing `list_prs_needs_review_stale_conflicts` bucket is a compound health
|
||||
signal: it indicates that neither the review pipeline nor the conflict
|
||||
resolution pipeline is keeping pace with incoming work. The watchdog should
|
||||
create a `Priority/High` announcement if this bucket exceeds a threshold.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
# list_prs_ready_to_merge — Open PRs Approved, Up-to-Date, and CI Passing
|
||||
|
||||
**Script name:** `list_prs_ready_to_merge`
|
||||
|
||||
**Script location:** [`scripts/list_prs_ready_to_merge.ts`](../../../scripts/list_prs_ready_to_merge.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_ready_to_merge.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **at least 1 non-dismissed
|
||||
approval**, are **not stale** (the PR's head branch is already current with
|
||||
its base branch), and have **passing CI** (all commit status checks have
|
||||
succeeded). These PRs are ready to be merged immediately — no rebase,
|
||||
conflict resolution, or CI wait is required.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
minApprovals: 1
|
||||
stale: 'not_stale'
|
||||
ciStatus: ['passing']
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1 and an error
|
||||
message: `ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded
|
||||
and cannot be overridden via CLI flags on this wrapper.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
No optional filter arguments are accepted on this script. Passing any
|
||||
filter-style flag (e.g. `--min-approvals`, `--stale`, `--state`, etc.) causes
|
||||
immediate exit 1 — those flags are not accepted by this wrapper.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
|
||||
| `stale` | `not_stale` | `PR.merge_base == current base branch HEAD` |
|
||||
| `ciStatus` | `['passing']` | All CI checks must have succeeded (`ci_status == 'passing'`) |
|
||||
|
||||
**"Not stale"** means `PR.merge_base` (the common ancestor SHA between the PR
|
||||
head and the base) equals the current HEAD of the base branch. In other words,
|
||||
the base branch has not advanced since the PR was last synced — the PR can be
|
||||
merged into the base branch without a rebase.
|
||||
|
||||
**"At least 1 approval"** means at least one reviewer has their most recent
|
||||
review in `APPROVED` state (non-dismissed). A reviewer who approved then later
|
||||
submitted `REQUEST_CHANGES` is not counted.
|
||||
|
||||
**"CI passing"** means the Forgejo combined commit-status for the PR's head
|
||||
SHA returned `state == 'success'`. PRs with `pending` CI (still running),
|
||||
`failing` CI (at least one check failed), or `unknown` CI (no checks reported)
|
||||
are excluded. This prevents merging code before the full test suite has
|
||||
confirmed it is safe.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
|
||||
| `stale_state` | string | Will always be `not_stale` for results of this script |
|
||||
| `ci_status` | string | Will always be `passing` for results of this script |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` means no open PR currently satisfies both conditions.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 5/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_ready_to_merge` when you need a list of PRs that can be merged
|
||||
**right now** without any intermediate steps. Typical use cases:
|
||||
|
||||
- **`pr-merge-pool-supervisor`** calls this as the **first and highest-priority
|
||||
step** in its cycle. Processing these PRs first ensures that already-approved,
|
||||
current PRs are never delayed while rebase or review work is happening.
|
||||
- A **monitoring agent** can use this as a health indicator: a consistently
|
||||
non-empty result that never shrinks suggests the merge process is blocked.
|
||||
- A **deployment pipeline** trigger could use this to determine whether any
|
||||
code is ready for release.
|
||||
|
||||
### Priority in the Four-Bucket System
|
||||
|
||||
```
|
||||
pr-merge-pool-supervisor processes buckets in this order:
|
||||
1. list_prs_ready_to_merge ← THIS SCRIPT (highest priority)
|
||||
2. list_prs_stale_clean
|
||||
3. list_prs_stale_conflicts
|
||||
4. list_prs_needs_review
|
||||
|
||||
When this bucket is non-empty, the supervisor dispatches workers for
|
||||
ALL PRs in it and then restarts the cycle at step 1.
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count ready-to-merge PRs
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Extract PR numbers for iteration
|
||||
READY_PRS=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[].number]')
|
||||
|
||||
# Get only the top-priority ready PR
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor calls this script as **step 2** (the first work step) of its
|
||||
main cycle. If the list is non-empty, it dispatches `pr-merge-worker`
|
||||
sequentially for each PR and then restarts the cycle from step 1.
|
||||
|
||||
```bash
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_ready_to_merge.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
|
||||
# If non-empty → iterate and dispatch pr-merge-worker for each PR number
|
||||
```
|
||||
|
||||
The supervisor passes each PR's full JSON object (number, title, head SHA,
|
||||
base branch, staleness, approval count, etc.) in the `pr-merge-worker` prompt.
|
||||
Since results come from this script, the worker knows the PR is already
|
||||
approved and not stale — it calls [`merge_pr`](../merge_pr/) directly without
|
||||
needing to rebase first.
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
When dispatched for a PR found by `list_prs_ready_to_merge`, the worker's
|
||||
decision tree is simple: the PR is approved and current, so it calls
|
||||
[`merge_pr`](../merge_pr/) immediately without checking for staleness or
|
||||
conflicts.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
The watchdog could call this periodically to verify that the merge pipeline
|
||||
is healthy. A PR that appears in `list_prs_ready_to_merge` for many
|
||||
consecutive watchdog cycles without being merged indicates the
|
||||
`pr-merge-pool-supervisor` may be stuck or absent.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
# list_prs_stale_clean — Open PRs Approved, Behind Base, No Conflicts
|
||||
|
||||
**Script name:** `list_prs_stale_clean`
|
||||
|
||||
**Script location:** [`scripts/list_prs_stale_clean.ts`](../../../scripts/list_prs_stale_clean.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **at least 1 non-dismissed
|
||||
approval**, are **stale** (the base branch has advanced since the PR was last
|
||||
synced), and have **no merge conflicts** (`PR.mergeable == true`). These PRs
|
||||
are approved and almost ready — they just need a server-side rebase to bring
|
||||
them current before merging.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
minApprovals: 1
|
||||
stale: 'stale_no_conflicts'
|
||||
(no ciStatus filter — all CI states are included)
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1:
|
||||
`ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded and cannot
|
||||
be overridden via CLI flags on this wrapper.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
No optional filter arguments are accepted. Passing any filter-style flag
|
||||
(e.g. `--min-approvals`, `--stale`, `--state`) causes immediate exit 1.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
|
||||
| `stale` | `stale_no_conflicts` | Base has advanced AND `PR.mergeable == true` |
|
||||
|
||||
**"Stale no conflicts"** means two things are simultaneously true:
|
||||
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
|
||||
2. `PR.mergeable == true` — Forgejo has determined the PR's commits can be rebased/merged on top of the new base without producing conflicts.
|
||||
|
||||
This combination means the rebase can be triggered automatically via the
|
||||
Forgejo server-side rebase API (`POST /pulls/{index}/update?style=rebase`)
|
||||
without any manual intervention. See [`rebase_pr`](../rebase_pr/).
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
|
||||
| `stale_state` | string | Will always be `stale_no_conflicts` for results of this script |
|
||||
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` means no open PR currently matches all three conditions.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 3/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_stale_clean` when you need to identify approved PRs that can be
|
||||
**brought up-to-date automatically** (no human conflict resolution needed).
|
||||
Typical use cases:
|
||||
|
||||
- **`pr-merge-pool-supervisor`** calls this as **step 3** of its cycle (after
|
||||
processing ready-to-merge PRs). For each result it dispatches a
|
||||
`pr-merge-worker` to trigger a server-side rebase, then re-checks step 2
|
||||
before continuing — because a successful rebase moves the PR from this
|
||||
bucket into `list_prs_ready_to_merge`.
|
||||
- A **rebase automation** script could use this as its sole input to keep all
|
||||
approved PRs current without any merge logic.
|
||||
- A **monitoring agent** could track this bucket's size over time as a
|
||||
measure of base-branch churn.
|
||||
|
||||
### Position in the Four-Bucket System
|
||||
|
||||
```
|
||||
pr-merge-pool-supervisor processes buckets in this order:
|
||||
1. list_prs_ready_to_merge
|
||||
2. list_prs_stale_clean ← THIS SCRIPT (second priority)
|
||||
3. list_prs_stale_conflicts
|
||||
4. list_prs_needs_review
|
||||
|
||||
Workflow for a PR in this bucket:
|
||||
rebase_pr → moves PR to list_prs_ready_to_merge → merge_pr
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count stale-but-clean PRs awaiting rebase
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Get PR numbers and their base branches (useful for batch rebase planning)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[] | {number, title, base: .base.ref}]'
|
||||
|
||||
# Get the top-priority stale-clean PR
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor calls this script as **step 3** of its main cycle. If the
|
||||
list is non-empty, it dispatches `pr-merge-worker` sequentially for each PR
|
||||
and then restarts the cycle at step 1.
|
||||
|
||||
```bash
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_clean.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
|
||||
# If non-empty → dispatch pr-merge-worker for each PR
|
||||
```
|
||||
|
||||
The worker receives the PR's `stale_state == stale_no_conflicts` in its
|
||||
prompt and follows the "stale, no conflicts" path: call
|
||||
[`rebase_pr`](../rebase_pr/) first, then call [`merge_pr`](../merge_pr/).
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
When dispatched for a PR from this bucket, the worker:
|
||||
1. Calls [`rebase_pr`](../rebase_pr/) — triggers server-side rebase
|
||||
2. Calls [`merge_pr`](../merge_pr/) — schedules the merge
|
||||
|
||||
The worker does **not** need to clone the repo or resolve conflicts — the
|
||||
`stale_no_conflicts` state guarantees the server can do it automatically.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
The watchdog can compare the sizes of the `list_prs_stale_clean` and
|
||||
`list_prs_stale_conflicts` buckets over time. A growing `stale_clean`
|
||||
bucket paired with a shrinking `list_prs_ready_to_merge` bucket suggests
|
||||
the merge supervisor is running but rebases are not completing successfully.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
# list_prs_stale_conflicts — Open PRs Approved, Stale, and Conflicted
|
||||
|
||||
**Script name:** `list_prs_stale_conflicts`
|
||||
|
||||
**Script location:** [`scripts/list_prs_stale_conflicts.ts`](../../../scripts/list_prs_stale_conflicts.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
list_prs_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
```
|
||||
|
||||
Returns all **open** pull requests that have **at least 1 non-dismissed
|
||||
approval**, are **stale** (the base branch has advanced since the PR was last
|
||||
synced), and **have merge conflicts** (`PR.mergeable == false`). These PRs have
|
||||
been reviewed and approved but cannot progress without manual conflict
|
||||
resolution by the PR author or an agent with a local clone.
|
||||
|
||||
This script is a thin wrapper around [`list_prs`](../list_prs/). It
|
||||
hard-codes the following filters and delegates all logic to that script:
|
||||
|
||||
```
|
||||
state: 'open'
|
||||
minApprovals: 1
|
||||
stale: 'stale_with_conflicts'
|
||||
(no ciStatus filter — all CI states are included)
|
||||
```
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All four arguments are **required**. No optional filter arguments exist — the
|
||||
filters are baked in and cannot be changed.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with read access to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
Any flag other than these five is **rejected** with exit code 1:
|
||||
`ERROR: Unknown argument: <flag>`. Filter parameters are hard-coded and cannot
|
||||
be overridden via CLI flags on this wrapper.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
No optional filter arguments are accepted. Passing any filter-style flag
|
||||
(e.g. `--min-approvals`, `--stale`, `--state`) causes immediate exit 1.
|
||||
|
||||
|
||||
## Hard-Coded Filters
|
||||
|
||||
| Filter | Value | Meaning |
|
||||
|--------|-------|---------|
|
||||
| `state` | `open` | Only open PRs are returned |
|
||||
| `minApprovals` | `1` | At least one non-dismissed `APPROVED` review required |
|
||||
| `stale` | `stale_with_conflicts` | Base has advanced AND `PR.mergeable == false` |
|
||||
|
||||
**"Stale with conflicts"** means two things are simultaneously true:
|
||||
1. `PR.merge_base != current base branch HEAD` — the base branch has been pushed to since the PR was last synced.
|
||||
2. `PR.mergeable == false` — Forgejo has determined that rebasing the PR's commits onto the new base would produce conflicts that cannot be resolved automatically.
|
||||
|
||||
This combination requires manual intervention. The resolution path is:
|
||||
1. Clone the repository locally (or use `repo-isolator`).
|
||||
2. Rebase the head branch against the latest base branch.
|
||||
3. Resolve all merge conflicts.
|
||||
4. Force-push with lease (`--force-with-lease`).
|
||||
5. Request re-review if the original approvals are now considered stale.
|
||||
6. Call [`merge_pr`](../merge_pr/) to initiate the merge.
|
||||
|
||||
The server-side rebase endpoint (`POST /pulls/{index}/update?style=rebase`,
|
||||
used by [`rebase_pr`](../rebase_pr/)) **cannot** be used for these PRs — it
|
||||
requires `mergeable == true`.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** as a pretty-printed JSON array sorted by `priority_rank`
|
||||
(highest priority first). Each element is the full Forgejo PR object augmented
|
||||
with four fields:
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `approvals_count` | integer | Will always be ≥ 1 for results of this script |
|
||||
| `stale_state` | string | Will always be `stale_with_conflicts` for results of this script |
|
||||
| `ci_status` | string | `passing`, `failing`, `pending`, or `unknown` — **not filtered**; any CI state is included |
|
||||
| `priority_rank` | integer | 0 (highest) through 6 (unlabelled) |
|
||||
| `priority_label` | string \| null | Matched `Priority/*` label name, or `null` |
|
||||
|
||||
An **empty array** `[]` means no open PR currently matches all three conditions.
|
||||
|
||||
See [`list_prs`](../list_prs/) for the full output schema documentation.
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
Progress messages are written to stderr and do not affect the JSON output:
|
||||
|
||||
```
|
||||
Fetching PRs from https://git.example.com/org/repo (state=open)...
|
||||
Fetched 42 PR(s). Enriching and filtering...
|
||||
Fetching HEAD SHAs for 3 unique base branch(es)...
|
||||
Fetching reviews for 42 PR(s) concurrently (limit=20)...
|
||||
Fetching CI status for 42 PR(s) concurrently (limit=20)...
|
||||
|
||||
Result: 2/42 PR(s) matched the filter criteria.
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success — JSON array written to stdout (may be `[]`) |
|
||||
| 1 | Fatal error — message written to stderr |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Condition | Behaviour |
|
||||
|-----------|-----------|
|
||||
| Missing `--url`, `--pat`, `--owner`, or `--repo` | Exit 1: `ERROR: --<flag> is required` |
|
||||
| Any unknown flag passed | Exit 1: `ERROR: Unknown argument: <flag>` |
|
||||
| Forgejo API non-2xx on PR list | Exit 1 with HTTP status and body detail |
|
||||
| Forgejo API failure for a single branch or review | Warning to stderr; processing continues |
|
||||
| Network timeout (30 s per request) | Exit 1 with error message |
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `list_prs_stale_conflicts` to identify approved PRs that are **blocked by
|
||||
conflicts** and need manual or agent-driven resolution. Typical use cases:
|
||||
|
||||
- **`pr-merge-pool-supervisor`** calls this as **step 4** of its cycle, after
|
||||
processing ready-to-merge and stale-clean PRs. For each result it dispatches
|
||||
a `pr-merge-worker` to perform a local clone, resolve conflicts, force-push,
|
||||
and then trigger the merge.
|
||||
- A **human-liaison agent** could use this to generate a "conflict backlog"
|
||||
report, listing PRs that require author attention.
|
||||
- A **monitoring alert** could trigger when this bucket grows beyond a
|
||||
threshold, signalling that the codebase is accumulating merge debt.
|
||||
|
||||
### Position in the Four-Bucket System
|
||||
|
||||
```
|
||||
pr-merge-pool-supervisor processes buckets in this order:
|
||||
1. list_prs_ready_to_merge
|
||||
2. list_prs_stale_clean
|
||||
3. list_prs_stale_conflicts ← THIS SCRIPT (third priority)
|
||||
4. list_prs_needs_review
|
||||
|
||||
Workflow for a PR in this bucket (requires local clone):
|
||||
clone repo → rebase locally → resolve conflicts → force-push
|
||||
→ merge_pr
|
||||
```
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Standard usage
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo
|
||||
|
||||
# Count conflicted approved PRs
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'length'
|
||||
|
||||
# Get PR numbers, titles, and head branches (for conflict resolution planning)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq '[.[] | {number, title, head_branch: .head.ref, base_branch: .base.ref}]'
|
||||
|
||||
# Get the highest-priority conflicted PR
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
| jq 'first'
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor calls this script as **step 4** of its main cycle. If the
|
||||
list is non-empty, it dispatches `pr-merge-worker` sequentially for each PR
|
||||
and then restarts the cycle at step 1.
|
||||
|
||||
```bash
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/list_prs_stale_conflicts.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT --owner $REPO_OWNER --repo $REPO_NAME)
|
||||
# If non-empty → dispatch pr-merge-worker for each PR (conflict resolution path)
|
||||
```
|
||||
|
||||
The worker receives `stale_state == stale_with_conflicts` in its prompt and
|
||||
follows the conflict-resolution path: clone via `repo-isolator`, rebase
|
||||
locally, resolve conflicts, force-push via `git-commit-helper`, then call
|
||||
[`merge_pr`](../merge_pr/).
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
When dispatched for a PR from this bucket, the worker cannot use the server-
|
||||
side rebase shortcut. Instead it must:
|
||||
1. Use `repo-isolator` to create a local clone with the PR branch.
|
||||
2. Run `git rebase <base>` locally.
|
||||
3. Inspect conflict markers; use recent git history to inform resolutions.
|
||||
4. Stage resolved files and continue the rebase.
|
||||
5. Use `git-commit-helper` to force-push with lease.
|
||||
6. Call [`merge_pr`](../merge_pr/) to schedule the merge.
|
||||
|
||||
### human-liaison-pool-supervisor
|
||||
|
||||
The liaison could filter this script's output by `created_at` to identify
|
||||
PRs that have been stuck in conflict state for more than N days, then post
|
||||
a comment pinging the PR author to resolve the conflict.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
A growing `list_prs_stale_conflicts` bucket over consecutive watchdog cycles
|
||||
(while the merge supervisor is running) indicates that conflict resolution
|
||||
is failing — possibly because the automated resolver is not capable of
|
||||
handling the specific type of conflict. The watchdog should create a
|
||||
`Priority/High` announcement.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
@@ -0,0 +1,322 @@
|
||||
# merge_pr — Initiate a Rebase-Style Merge (with Automerge) on a PR
|
||||
|
||||
**Script name:** `merge_pr`
|
||||
|
||||
**Script location:** [`scripts/merge_pr.ts`](../../../scripts/merge_pr.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER \
|
||||
[--dep error|delete|reverse]
|
||||
```
|
||||
|
||||
**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:".
|
||||
|
||||
**CRITICAL:** All attempts to merge pull requests **must** use this script.
|
||||
|
||||
## Synopsis
|
||||
|
||||
```
|
||||
merge_pr.ts --url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
|
||||
[--dep error|delete|reverse]
|
||||
```
|
||||
|
||||
Calls the Forgejo REST API to merge a pull request using the `rebase` merge
|
||||
style with `merge_when_checks_succeed=true`. If all CI checks and review
|
||||
requirements are already satisfied, the PR merges immediately. Otherwise,
|
||||
Forgejo queues it for automatic merging once those conditions are met — the
|
||||
script does not wait; it returns as soon as the merge request is accepted.
|
||||
|
||||
The script also detects and handles **open blocking issue dependencies** before
|
||||
calling the merge endpoint, since Forgejo silently ignores merge requests when
|
||||
a PR has open dependencies (returns HTTP 200 but does nothing).
|
||||
|
||||
## Arguments
|
||||
|
||||
### Required
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with **merge permission** on the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `--pr NUMBER` | positive integer | Pull request number to merge |
|
||||
|
||||
### Optional
|
||||
|
||||
| Flag | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `--dep STRATEGY` | string | `error` | How to handle open blocking issue dependencies (see below) |
|
||||
| `-h`, `--help` | — | — | Print usage to stderr and exit 0 |
|
||||
|
||||
### Dependency Strategy (`--dep`)
|
||||
|
||||
Forgejo PRs can declare issue dependencies. When a PR has **open** (unresolved)
|
||||
dependencies, Forgejo silently ignores merge requests — it returns HTTP 200 but
|
||||
the PR is never actually merged. This script detects open dependencies first
|
||||
and handles them according to `--dep`:
|
||||
|
||||
| Value | Behaviour |
|
||||
|-------|-----------|
|
||||
| `error` | **(default)** Abort with exit code 1 and list all open blocking dependencies. State is never modified. Safe for read-before-write workflows. |
|
||||
| `delete` | Delete each open dependency link from the PR, then proceed with the merge. The dependent issues are unaffected; only the link is removed. |
|
||||
| `reverse` | Delete each open dependency link, then create a new reversed link (the formerly-blocking issue now depends on the PR instead of the other way around). Useful when the intent is "merge this PR, then finish the related issue". |
|
||||
|
||||
### Argument Validity Rules
|
||||
|
||||
- `--pr` must be a positive integer. Floats, zero, and negatives are rejected
|
||||
with exit code 1.
|
||||
- `--dep` must be exactly `error`, `delete`, or `reverse`. Any other value
|
||||
causes exit code 1.
|
||||
- All five named arguments are required (except `--dep` which defaults to
|
||||
`error`). Any missing required argument causes exit code 1.
|
||||
- Unknown flags cause exit code 1.
|
||||
|
||||
## What the Script Does
|
||||
|
||||
The script executes these steps in order:
|
||||
|
||||
1. **Fetch the PR** — verifies it is open and not already merged.
|
||||
2. **Fetch all dependencies** (exhaustively paginated) — filters to open ones.
|
||||
3. **Handle open dependencies** per `--dep` strategy (error / delete / reverse).
|
||||
4. **POST to the merge endpoint**:
|
||||
```
|
||||
POST /api/v1/repos/{owner}/{repo}/pulls/{index}/merge
|
||||
{
|
||||
"Do": "rebase",
|
||||
"merge_when_checks_succeed": true,
|
||||
"head_commit_id": "<current HEAD SHA>"
|
||||
}
|
||||
```
|
||||
The `head_commit_id` acts as an **optimistic lock** — if someone pushed to
|
||||
the branch between the script reading the PR and calling merge, Forgejo
|
||||
returns HTTP 409, preventing a stale-read merge.
|
||||
5. **Re-fetch the PR** — inspects `merged` flag to determine the outcome.
|
||||
6. **Return JSON result** with `status: "merged"` or `status: "auto_merge_scheduled"`.
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** on success as a pretty-printed JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "merged" | "auto_merge_scheduled",
|
||||
"pr_number": 42,
|
||||
"pr_title": "feat: add new feature",
|
||||
"head_sha": "abc123...",
|
||||
"merge_commit_sha": "<sha>" | null,
|
||||
"merged_at": "2026-04-17T12:00:00Z" | null,
|
||||
"deps_handled": [
|
||||
{
|
||||
"action": "deleted" | "reversed",
|
||||
"dep_number": 10,
|
||||
"dep_title": "Related issue title",
|
||||
"dep_repo": "owner/repo"
|
||||
}
|
||||
],
|
||||
"message": "PR #42 merged immediately using rebase style."
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `status` | string | `merged` — PR merged immediately; `auto_merge_scheduled` — Forgejo accepted the request and will merge when checks pass |
|
||||
| `pr_number` | integer | The PR number that was processed |
|
||||
| `pr_title` | string | The PR title at the time of the call |
|
||||
| `head_sha` | string | The head commit SHA that was submitted for merge |
|
||||
| `merge_commit_sha` | string \| null | Non-null only when `status == "merged"` |
|
||||
| `merged_at` | string \| null | ISO 8601 timestamp, non-null only when `status == "merged"` |
|
||||
| `deps_handled` | array | Zero or more dependency actions taken (empty if no open deps existed) |
|
||||
| `message` | string | Human-readable summary of the outcome |
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
All progress information is written to stderr:
|
||||
|
||||
```
|
||||
Fetching PR #42 from https://git.example.com/org/repo...
|
||||
PR #42: "feat: add new feature"
|
||||
State: open
|
||||
Head SHA: abc123def456...
|
||||
Mergeable: true
|
||||
|
||||
Fetching dependencies for PR #42...
|
||||
Total dependencies: 2 (1 open / blocking)
|
||||
BLOCKING: #10 [owner/repo] "Related issue"
|
||||
|
||||
Handling 1 open dependency(ies) with strategy 'delete'...
|
||||
DELETE dependency: PR #42 → #10 (owner/repo)
|
||||
Deleted OK (HTTP 200)
|
||||
|
||||
POST https://git.example.com/api/v1/repos/owner/repo/pulls/42/merge
|
||||
Do=rebase merge_when_checks_succeed=true head_commit_id=abc123def456…
|
||||
Response: HTTP 200
|
||||
|
||||
Merge request accepted. Re-fetching PR to determine state...
|
||||
merged=false state=open
|
||||
PR #42 not yet merged — auto-merge is pending checks/approvals.
|
||||
```
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Merge initiated — `status` is `merged` or `auto_merge_scheduled` |
|
||||
| 1 | Any failure — descriptive error on stderr with machine-readable error code |
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Error Code | HTTP Status | Condition |
|
||||
|------------|-------------|-----------|
|
||||
| `PR_MERGED` | — | PR is already merged; nothing to do |
|
||||
| `PR_NOT_OPEN` | — | PR is closed (not open) |
|
||||
| `OPEN_DEPENDENCIES` | — | Open deps found and `--dep=error` (default); lists all blockers |
|
||||
| `DEP_DELETE_FAILED` | varies | DELETE of a dependency link returned non-200 |
|
||||
| `DEP_REVERSE_FAILED` | varies | POST of the reversed dependency returned non-201 |
|
||||
| `MERGE_FORBIDDEN` | 403 | The PAT lacks merge access to the repository |
|
||||
| `MERGE_NOT_ALLOWED` | 405 | Branch protection disallows the `rebase` merge style, or automerge is disabled |
|
||||
| `MERGE_CONFLICT` | 409 | Merge conflicts present, or `head_commit_id` mismatch (concurrent push between read and merge call); re-run to retry with fresh HEAD |
|
||||
| `MERGE_UNPROCESSABLE` | 422 | PR is a draft, already merged, or otherwise not mergeable |
|
||||
| `HTTP_NNN` | NNN | Any other unexpected HTTP response from the merge endpoint |
|
||||
|
||||
A special case: HTTP 409 with the message `"already scheduled to auto merge"`
|
||||
is treated as **success** (not an error). This happens when the script is run
|
||||
twice on the same PR; the second run detects the already-scheduled automerge
|
||||
and returns `status: "auto_merge_scheduled"`.
|
||||
|
||||
## Important Behaviours and Caveats
|
||||
|
||||
### Automerge State Is Not Directly Readable
|
||||
Forgejo provides no read-only endpoint to confirm automerge is scheduled. The
|
||||
script infers `status: "auto_merge_scheduled"` from the combination of a 200
|
||||
response from the merge endpoint plus `merged=false` on the re-fetched PR.
|
||||
This is the authoritative signal — it means Forgejo has accepted the request.
|
||||
|
||||
### Optimistic Locking
|
||||
The `head_commit_id` field in the merge request body is an optimistic lock. If
|
||||
someone pushes to the PR branch between when the script fetches the PR (step 1)
|
||||
and when it calls the merge endpoint (step 4), Forgejo returns HTTP 409
|
||||
(`MERGE_CONFLICT`). Simply re-running the script resolves this.
|
||||
|
||||
### No Waiting for CI
|
||||
The script returns immediately after Forgejo accepts the merge request. It does
|
||||
**not** poll for the merge to complete. When `status: "auto_merge_scheduled"`,
|
||||
the caller should expect the PR to eventually close on its own once CI passes.
|
||||
This is intentional — agents should never block waiting for CI.
|
||||
|
||||
### Rebase Merge Style
|
||||
The `Do: "rebase"` merge style rewrites the PR's commits linearly on top of
|
||||
the base branch HEAD. No merge commit is created. This produces a clean,
|
||||
linear history. Other merge styles (`merge`, `squash`, `rebase-merge`) are
|
||||
not used by this script.
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `merge_pr` whenever you want to **initiate a merge on a specific PR**:
|
||||
|
||||
- After [`rebase_pr`](../rebase_pr/) has brought a stale PR current.
|
||||
- After manual conflict resolution and force-push on a conflicted PR.
|
||||
- Directly on a PR returned by [`list_prs_ready_to_merge`](../list_prs_ready_to_merge/).
|
||||
- Any time you need to queue a PR for automerge once its CI finishes.
|
||||
|
||||
Do **not** use this script if the PR is still stale — call
|
||||
[`rebase_pr`](../rebase_pr/) first (if `stale_no_conflicts`) or resolve
|
||||
conflicts locally (if `stale_with_conflicts`).
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Merge PR #42 (default: abort if open dependencies exist)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--pr 42
|
||||
|
||||
# Merge PR #42, deleting any open dependency links first
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--pr 42 \
|
||||
--dep delete
|
||||
|
||||
# Merge PR #42, reversing dependency links (issue now depends on PR)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--pr 42 \
|
||||
--dep reverse
|
||||
|
||||
# Parse just the status from the output
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --pr 42 \
|
||||
| jq -r '.status'
|
||||
|
||||
# Check if the merge was immediate or scheduled
|
||||
result=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --pr 42)
|
||||
status=$(echo "$result" | jq -r '.status')
|
||||
if [ "$status" = "merged" ]; then
|
||||
echo "Merged immediately"
|
||||
else
|
||||
echo "Queued for automerge"
|
||||
fi
|
||||
```
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
The worker is the **primary caller** of this script. It always calls
|
||||
`merge_pr` as the final step after any necessary rebase or conflict resolution:
|
||||
|
||||
```
|
||||
# After rebase_pr (stale_no_conflicts path):
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER --repo $REPO_NAME \
|
||||
--pr $PR_NUMBER --dep delete
|
||||
|
||||
# After local conflict resolution (stale_with_conflicts path):
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER --repo $REPO_NAME \
|
||||
--pr $PR_NUMBER --dep delete
|
||||
|
||||
# For a ready-to-merge PR (not stale, already approved):
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER --repo $REPO_NAME \
|
||||
--pr $PR_NUMBER
|
||||
```
|
||||
|
||||
The worker uses `--dep delete` by default for the stale buckets because those
|
||||
PRs have already been verified to meet all quality gates; open dependency links
|
||||
at that point are likely stale metadata rather than genuine blockers.
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor does **not** call this script directly. It dispatches
|
||||
`pr-merge-worker` subagents, which call this script as part of their procedure.
|
||||
|
||||
### implementation-worker
|
||||
|
||||
An implementation worker creating a PR would never call this script — that
|
||||
would be outside its responsibility. However, it might call it after creating
|
||||
a PR if the project's workflow involves self-merging after CI passes (unusual
|
||||
but possible with `--dep error` for safety).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
@@ -0,0 +1,322 @@
|
||||
# rebase_pr — Trigger a Server-Side Rebase on a Stale, Conflict-Free PR
|
||||
|
||||
**Script name:** `rebase_pr`
|
||||
|
||||
**Script location:** [`scripts/rebase_pr.ts`](../../../scripts/rebase_pr.ts)
|
||||
|
||||
**Invoke:**
|
||||
```bash
|
||||
npx --yes tsx .opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
|
||||
```
|
||||
|
||||
**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
|
||||
|
||||
```
|
||||
rebase_pr.ts --url URL --pat TOKEN --owner OWNER --repo REPO --pr NUMBER
|
||||
```
|
||||
|
||||
Calls the Forgejo REST API to rebase a pull request's head branch onto the
|
||||
latest commit of its base branch — **entirely server-side, without a local
|
||||
git clone**. The PR's commits are rewritten on top of the current base branch
|
||||
HEAD, bringing the PR fully up-to-date.
|
||||
|
||||
The script enforces three strict pre-flight conditions before calling the
|
||||
rebase endpoint. If any condition fails, the script exits with code 1 and a
|
||||
descriptive error; it **never proceeds blindly**.
|
||||
|
||||
|
||||
## Arguments
|
||||
|
||||
All five arguments are **required**. There are no optional arguments beyond
|
||||
`--help`.
|
||||
|
||||
| Flag | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `--url URL` | string | Forgejo base URL, **no trailing slash** (e.g. `https://git.example.com`) |
|
||||
| `--pat TOKEN` | string | Personal Access Token with **write access** to the repository |
|
||||
| `--owner OWNER` | string | Repository owner or organisation name |
|
||||
| `--repo REPO` | string | Repository name |
|
||||
| `--pr NUMBER` | positive integer | Pull request number to rebase |
|
||||
| `-h`, `--help` | — | Print usage to stderr and exit 0 |
|
||||
|
||||
### Argument Validity Rules
|
||||
|
||||
- `--pr` must be a **positive integer**. Floats, zero, and negatives are
|
||||
rejected with exit code 1: `ERROR: --pr must be a positive integer`.
|
||||
- All five arguments are required. Any missing argument causes exit code 1.
|
||||
- Unknown flags cause exit code 1.
|
||||
|
||||
### Invalid Argument Combinations
|
||||
|
||||
There are no multi-flag combinations to validate — the five arguments are
|
||||
independent. However the following are logically invalid and will be caught
|
||||
by the pre-flight checks (not by argument parsing):
|
||||
|
||||
- Passing the number of an already-merged PR → `PR_MERGED` error
|
||||
- Passing a PR that is not stale → `PR_NOT_STALE` error (informational, not a bug)
|
||||
- Passing a PR with conflicts → `PR_HAS_CONFLICTS` error
|
||||
|
||||
|
||||
## Pre-Flight Conditions
|
||||
|
||||
The script enforces **all three** of the following before calling the Forgejo
|
||||
rebase endpoint. Failing any one causes an immediate exit 1:
|
||||
|
||||
| Condition | Check | Error Code if Failed |
|
||||
|-----------|-------|---------------------|
|
||||
| PR must be open | `PR.state == "open"` AND `PR.merged == false` | `PR_MERGED` / `PR_NOT_OPEN` |
|
||||
| PR must be stale | `PR.merge_base != current base-branch HEAD SHA` | `PR_NOT_STALE` (informational — no rebase needed) |
|
||||
| PR must have no conflicts | `PR.mergeable == true` | `MERGEABLE_UNKNOWN` (null) or `PR_HAS_CONFLICTS` (false) |
|
||||
|
||||
The staleness check requires one additional API call to fetch the current HEAD
|
||||
SHA of the base branch. This is cached internally but requires the PAT to have
|
||||
read access to branches.
|
||||
|
||||
|
||||
## What the Script Does
|
||||
|
||||
1. **Fetch the PR** — reads `state`, `merged`, `mergeable`, `merge_base`,
|
||||
`base.ref`, `head.sha`.
|
||||
2. **Guard: PR must be open and not merged.**
|
||||
3. **Fetch the current base-branch HEAD SHA** via
|
||||
`GET /api/v1/repos/{owner}/{repo}/branches/{branch}`.
|
||||
4. **Guard: PR must be stale** (`merge_base != base HEAD`).
|
||||
5. **Guard: PR must have no conflicts** (`mergeable == true`; rejects `null` and `false`).
|
||||
6. **POST to the rebase endpoint**:
|
||||
```
|
||||
POST /api/v1/repos/{owner}/{repo}/pulls/{index}/update?style=rebase
|
||||
```
|
||||
No request body; the `style=rebase` query parameter selects the rebase
|
||||
strategy (as opposed to `style=merge` which creates a merge commit).
|
||||
7. **Re-fetch the PR** — captures the new head SHA to confirm the rebase applied.
|
||||
8. **Return JSON result** with the old and new SHAs.
|
||||
|
||||
|
||||
## Output
|
||||
|
||||
Written to **stdout** on success as a pretty-printed JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "PR #42 successfully rebased onto 'master'.",
|
||||
"pr_number": 42,
|
||||
"base_branch": "master",
|
||||
"old_merge_base": "abc123def456...",
|
||||
"new_head_sha": "xyz789abc012..."
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `success` | boolean | Always `true` on a successful exit |
|
||||
| `message` | string | Human-readable summary |
|
||||
| `pr_number` | integer | The PR number that was rebased |
|
||||
| `base_branch` | string | The base branch the PR was rebased onto |
|
||||
| `old_merge_base` | string | The `merge_base` SHA before the rebase (documents what changed) |
|
||||
| `new_head_sha` | string | The PR's new head SHA after the rebase |
|
||||
|
||||
|
||||
## Diagnostics / stderr
|
||||
|
||||
All progress information is written to stderr:
|
||||
|
||||
```
|
||||
Fetching PR #42 from https://git.example.com/org/repo...
|
||||
PR #42: "feat: add new feature"
|
||||
State: open
|
||||
Base: master
|
||||
Head: feature/my-feature
|
||||
Merge base: abc123def456...
|
||||
Mergeable: true
|
||||
|
||||
Fetching current HEAD of base branch 'master'...
|
||||
Base HEAD: def789abc123...
|
||||
|
||||
PR is stale: merge_base (abc123def4…) != base HEAD (def789abc1…).
|
||||
No conflicts detected (mergeable=true). Triggering server-side rebase...
|
||||
|
||||
POST https://git.example.com/api/v1/repos/org/repo/pulls/42/update?style=rebase
|
||||
Response: HTTP 200
|
||||
|
||||
Rebase triggered. Fetching updated PR details...
|
||||
New head SHA: xyz789abc012...
|
||||
New merge_base: (pending — Forgejo will compute shortly)
|
||||
```
|
||||
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Rebase triggered successfully — JSON result written to stdout |
|
||||
| 1 | Any failure — descriptive error on stderr with machine-readable error code |
|
||||
|
||||
|
||||
## Errors the Script May Throw
|
||||
|
||||
| Error Code | Condition |
|
||||
|------------|-----------|
|
||||
| `PR_MERGED` | The PR is already merged; nothing to rebase |
|
||||
| `PR_NOT_OPEN` | The PR is closed (not open) |
|
||||
| `MERGE_BASE_MISSING` | `PR.merge_base` is null — Forgejo hasn't set it yet; retry shortly |
|
||||
| `PR_NOT_STALE` | `PR.merge_base == base HEAD` — PR is already up-to-date; no rebase needed (informational, not a bug) |
|
||||
| `MERGEABLE_UNKNOWN` | `PR.mergeable == null` — Forgejo hasn't finished computing the conflict status; retry in a few seconds |
|
||||
| `PR_HAS_CONFLICTS` | `PR.mergeable == false` — PR has merge conflicts; server-side rebase cannot proceed; manual resolution required |
|
||||
| `BASE_HEAD_UNKNOWN` | The branch API did not return a commit id for the base branch |
|
||||
| `FORBIDDEN` | HTTP 403 — the PAT lacks write access to the head repository |
|
||||
| `NOT_FOUND` | HTTP 404 — the PR or repository was not found |
|
||||
| `REBASE_CONFLICT` | HTTP 409 — conflicts were detected during the rebase itself despite `mergeable=true` pre-flight check (race condition: concurrent push between pre-flight and rebase call); re-run |
|
||||
| `ALREADY_UP_TO_DATE` | HTTP 422 — PR was already current by the time the rebase was called (race condition: another process rebased it first); treat as success and proceed |
|
||||
| `HTTP_NNN` | Any other unexpected HTTP response from the update endpoint |
|
||||
|
||||
### Race Condition Notes
|
||||
|
||||
Two race conditions are possible between the pre-flight check and the rebase call:
|
||||
|
||||
1. **`REBASE_CONFLICT` (HTTP 409)**: Another agent pushed to the base branch
|
||||
between your staleness check (step 3) and the rebase call (step 6), causing
|
||||
newly introduced conflicts. Resolution: re-run the script; if conflicts
|
||||
persist, the PR needs manual resolution.
|
||||
|
||||
2. **`ALREADY_UP_TO_DATE` (HTTP 422)**: Another process rebased the PR first.
|
||||
This should be treated as a success — proceed to call
|
||||
[`merge_pr`](../merge_pr/).
|
||||
|
||||
|
||||
## Important Behaviours and Caveats
|
||||
|
||||
### Server-Side Only
|
||||
This script uses Forgejo's built-in rebase capability. It does **not**
|
||||
clone the repository, run `git` locally, or require git to be installed.
|
||||
This is only possible because `PR.mergeable == true` guarantees there are
|
||||
no conflicts for the server to stumble on.
|
||||
|
||||
### `mergeable == null` Is Not Processed
|
||||
Forgejo computes `PR.mergeable` asynchronously after a PR is created or
|
||||
updated. If the value is `null`, the script exits with `MERGEABLE_UNKNOWN`
|
||||
rather than guessing. Retry after a few seconds.
|
||||
|
||||
### After the Rebase
|
||||
The re-fetched PR may show `merge_base` as still `null` or a stale value —
|
||||
Forgejo computes the new `merge_base` asynchronously after the rebase. The
|
||||
`new_head_sha` field in the output is the reliable indicator that the rebase
|
||||
applied. The next call to a `list_prs_*` script will see the updated state
|
||||
once Forgejo catches up (typically within seconds).
|
||||
|
||||
### This Script Does Not Merge
|
||||
`rebase_pr` only brings the PR up-to-date. To actually merge it after rebasing,
|
||||
call [`merge_pr`](../merge_pr/).
|
||||
|
||||
|
||||
## When to Use This Script
|
||||
|
||||
Use `rebase_pr` when you have a PR whose `stale_state` is `stale_no_conflicts`
|
||||
(i.e. [`list_prs_stale_clean`](../list_prs_stale_clean/) returns it). This is
|
||||
the correct and only safe use of this script.
|
||||
|
||||
Do **not** use this script for:
|
||||
- PRs with `stale_state == stale_with_conflicts` — use a local clone instead.
|
||||
- PRs with `stale_state == stale_unknown` — wait for Forgejo to compute the
|
||||
conflict status, then retry.
|
||||
- PRs with `stale_state == not_stale` — they are already current; call
|
||||
[`merge_pr`](../merge_pr/) directly.
|
||||
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Rebase PR #42 onto its base branch
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--pr 42
|
||||
|
||||
# Check the new head SHA after a successful rebase
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url https://git.example.com \
|
||||
--pat ghp_XXXX \
|
||||
--owner my-org \
|
||||
--repo my-repo \
|
||||
--pr 42 \
|
||||
| jq -r '.new_head_sha'
|
||||
|
||||
# Rebase then immediately queue for merge (full pipeline for stale-clean PRs)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --pr 42 \
|
||||
&& \
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --pr 42
|
||||
|
||||
# Handle PR_NOT_STALE gracefully in a shell script
|
||||
output=$(npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url https://git.example.com --pat ghp_XXXX \
|
||||
--owner my-org --repo my-repo --pr 42 2>&1)
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
if echo "$output" | grep -q "PR_NOT_STALE"; then
|
||||
echo "PR is already current — proceeding to merge"
|
||||
# call merge_pr
|
||||
else
|
||||
echo "Rebase failed: $output"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
|
||||
## Agent Usage Examples
|
||||
|
||||
### pr-merge-worker
|
||||
|
||||
The worker is the **primary caller** of this script, specifically on the
|
||||
`stale_no_conflicts` path:
|
||||
|
||||
```
|
||||
# Step 1: Server-side rebase (stale_no_conflicts path)
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/rebase_pr.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER --repo $REPO_NAME \
|
||||
--pr $PR_NUMBER
|
||||
|
||||
# Step 2: Immediately schedule the merge
|
||||
npx --yes tsx /app/.opencode/skills/auto-agents-system/scripts/merge_pr.ts \
|
||||
--url $FORGEJO_URL --pat $FORGEJO_PAT \
|
||||
--owner $REPO_OWNER --repo $REPO_NAME \
|
||||
--pr $PR_NUMBER --dep delete
|
||||
```
|
||||
|
||||
The worker does **not** call `rebase_pr` for the `stale_with_conflicts` path —
|
||||
that path requires a local clone with manual conflict resolution.
|
||||
|
||||
### pr-merge-pool-supervisor
|
||||
|
||||
The supervisor never calls this script directly. It dispatches `pr-merge-worker`
|
||||
subagents (via the Task tool, blocking), which call this script as part of
|
||||
the stale-clean processing path.
|
||||
|
||||
### system-watchdog-pool-supervisor
|
||||
|
||||
The watchdog would not normally call `rebase_pr`. However, it could be
|
||||
used in an emergency intervention workflow to manually rebase a PR that the
|
||||
merge supervisor has been unable to process.
|
||||
|
||||
### grooming-pool-supervisor
|
||||
|
||||
The grooming supervisor focuses on issue/PR metadata and would not normally
|
||||
call `rebase_pr`. However, it might verify that `rebase_pr` is available
|
||||
and runnable as part of a pipeline health check.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Node.js ≥ 18 (native `fetch` API)
|
||||
- `npx tsx` for TypeScript execution
|
||||
- Zero external npm packages
|
||||
@@ -13,7 +13,6 @@ The system uses four model tiers for implementation work, ordered by cost and ca
|
||||
|
||||
All tiers have `max_tokens: 200000`.
|
||||
|
||||
---
|
||||
|
||||
## How Tier Selectors Work
|
||||
|
||||
@@ -41,7 +40,6 @@ This applies to any agent that uses tier-based execution. The same `tier-*` sele
|
||||
- `typecheck-fixer`, `lint-fixer`, `test-fixer`
|
||||
- `coverage-improver`
|
||||
|
||||
---
|
||||
|
||||
## Progressive Escalation
|
||||
|
||||
@@ -84,7 +82,6 @@ Steps:
|
||||
3. **Stop dispatching workers** for this item until `needs feedback` is removed
|
||||
4. Create announcement: `[{prefix}] Announce: Human escalation needed for issue/PR #N` at Priority/High
|
||||
|
||||
---
|
||||
|
||||
## Default Model Assignments
|
||||
|
||||
@@ -147,7 +144,6 @@ Several agents switch to **Gemini 2.5 Pro** at runtime for large context windows
|
||||
- `test-infra-worker` → Gemini 2.5 Pro
|
||||
- `architecture-guard-worker` → Gemini 2.5 Pro
|
||||
|
||||
---
|
||||
|
||||
## Escalation Path Reference
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ The CleverAgents system has no shared memory between agents. All coordination ha
|
||||
| **Status issue** | Current agent state — what it's doing, health, progress | Replaced each cycle (old one closed) | `[{PREFIX}] Status: {Type} (Cycle N)` |
|
||||
| **Announcement issue** | Persistent signals to other agents | Persists until explicitly closed | `[{PREFIX}] Announce: {Message}` |
|
||||
|
||||
---
|
||||
|
||||
## Status Tracking Issues
|
||||
|
||||
@@ -65,7 +64,6 @@ Any agent that wants to find another agent's current status can:
|
||||
2. The most recent open issue is the current cycle
|
||||
3. Read its body and comments for detailed state
|
||||
|
||||
---
|
||||
|
||||
## Announcement Issues
|
||||
|
||||
@@ -116,7 +114,6 @@ Agents read others' announcements via `READ_ANNOUNCEMENTS`:
|
||||
- High: process before starting next work cycle
|
||||
- Medium/Low: opportunistically when convenient
|
||||
|
||||
---
|
||||
|
||||
## System-Specific Labels
|
||||
|
||||
@@ -150,7 +147,6 @@ For complete label rules — forbidden operations (`forgejo_create_label` etc.),
|
||||
- **`cleverthis-guidelines` skill** — company-wide label and priority hierarchy definitions
|
||||
- **`forgejo-api` skill** — curl patterns for all Forgejo API operations including label endpoints (`forgejo-label-manager` loads this skill automatically)
|
||||
|
||||
---
|
||||
|
||||
## automation-tracking-manager Operations Summary
|
||||
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
# Announcement Relevancy Matrix
|
||||
|
||||
Which agents consume announcements from which other agents, and at what
|
||||
minimum priority threshold.
|
||||
|
||||
For context on the announcement system itself (how to create, read, and close
|
||||
announcements) see [`../`](../) (the tracking-system reference).
|
||||
|
||||
For dynamic programmatic lookup use the `agent-prefix-info` subagent with
|
||||
operation `GET_RELEVANCY_MATRIX`.
|
||||
|
||||
|
||||
## Universal Baseline — Applies to ALL Agents Without Exception
|
||||
|
||||
```
|
||||
Priority/CI-Blocker from ANY agent → consume immediately, always
|
||||
```
|
||||
|
||||
No agent is exempt from this rule. CI-Blocker signals block all other work.
|
||||
|
||||
|
||||
## Per-Agent Relevancy Table
|
||||
|
||||
### `AUTO-PROD-BLDR` — product-builder (process supervisor)
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| ALL agents | Priority/Low+ | Monitors everything; must see all signals |
|
||||
|
||||
|
||||
### `AUTO-WDOG` — system-watchdog
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| ALL agents | Priority/Low+ | Must observe the full system to audit it |
|
||||
|
||||
|
||||
### `AUTO-HUMAN` — human-liaison
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| ALL agents | Priority/High+ | Relays important events to humans |
|
||||
|
||||
|
||||
### `AUTO-EVLV` — agent-evolution
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| ALL agents | Priority/Medium+ | Needs broad pattern detection across all pools |
|
||||
|
||||
|
||||
### `AUTO-IMP-SUP` — implementation pool (primary code producer)
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts that may block implementation work |
|
||||
| `AUTO-EPIC` | Priority/High+ | New issues created and ready to implement |
|
||||
| `AUTO-REV-SUP` | Priority/High+ | Review feedback requiring code fixes |
|
||||
| `AUTO-PRMRG-SUP` | Priority/High+ | Merge status, rebase failures affecting PR work |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architectural decisions affecting implementation approach |
|
||||
| `AUTO-OWNR` | Priority/High+ | Priority and scope changes |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human requests relayed by liaison |
|
||||
| `AUTO-GROOM` | Priority/Medium+ | Issue quality corrections affecting work items |
|
||||
| `AUTO-GUARD` | Priority/Medium+ | Pattern drift warnings to apply to new code |
|
||||
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting implementation approach |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-REV-SUP` — PR review pool
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | New PRs available for review |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architecture decisions affecting review criteria |
|
||||
| `AUTO-PRMRG-SUP` | Priority/High+ | Merge status of previously reviewed PRs |
|
||||
| `AUTO-GUARD` | Priority/Medium+ | Pattern standards to check for in reviews |
|
||||
| `AUTO-SPEC` | Priority/Medium+ | Spec alignment criteria updates |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-PRMRG-SUP` — PR merge pool
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | CI-Blocker alerts, system health |
|
||||
| `AUTO-REV-SUP` | Priority/High+ | Review approvals that enable merging |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | New PRs entering the merge pipeline |
|
||||
| `AUTO-GROOM` | Priority/Medium+ | PR quality corrections before merge |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-UAT-SUP` — UAT test pool
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | New code merged and ready for UAT |
|
||||
| `AUTO-SPEC` | Priority/High+ | Spec changes requiring retesting |
|
||||
| `AUTO-ARCH` | Priority/High+ | Behavioral changes affecting test scope |
|
||||
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merged PRs triggering retest cycles |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-BUG-SUP` — bug hunt pool
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | New code to analyze for bugs |
|
||||
| `AUTO-UAT-SUP` | Priority/Medium+ | Test failures that may reveal underlying bugs |
|
||||
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting analysis scope |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-INF-SUP` — test infrastructure pool
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | CI pipeline failures |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | CI changes, test additions requiring infra update |
|
||||
| `AUTO-BUG-SUP` | Priority/Medium+ | Test reliability issues affecting infrastructure |
|
||||
| `AUTO-UAT-SUP` | Priority/Medium+ | Test infrastructure problems discovered during UAT |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-ARCH` — architecture
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | Implementation discoveries affecting spec |
|
||||
| `AUTO-SPEC` | Priority/High+ | Spec evolution feedback requiring arch input |
|
||||
| `AUTO-GUARD` | Priority/High+ | Pattern drift requiring architectural response |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human architectural feedback |
|
||||
| `AUTO-EPIC` | Priority/Medium+ | Planning gaps needing spec coverage |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-EPIC` — epic planning
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architecture to decompose into epics/issues |
|
||||
| `AUTO-OWNR` | Priority/High+ | Priority and scope decisions affecting planning |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human requests for work breakdown |
|
||||
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting issue planning |
|
||||
| `AUTO-IMP-SUP` | Priority/Medium+ | Implementation progress affecting future plans |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-GUARD` — architecture guard
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architecture pattern standards to enforce |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | New code merges that may introduce pattern drift |
|
||||
| `AUTO-SPEC` | Priority/Medium+ | Spec changes affecting acceptable patterns |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-SPEC` — spec update
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architecture changes to reflect in spec |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | Implementation divergences from spec |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human feedback on spec content |
|
||||
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merges triggering spec-vs-implementation comparison |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-GROOM` — backlog grooming
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-OWNR` | Priority/High+ | Priority corrections from project owner |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | PR quality issues surfaced during implementation |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human requests about specific issues |
|
||||
| `AUTO-EPIC` | Priority/Medium+ | New epics with children needing grooming |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-DOCS` — documentation
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-ARCH` | Priority/High+ | Architecture changes to document |
|
||||
| `AUTO-SPEC` | Priority/High+ | Spec changes requiring documentation updates |
|
||||
| `AUTO-IMP-SUP` | Priority/Medium+ | New features completed and ready to document |
|
||||
| `AUTO-UAT-SUP` | Priority/Medium+ | Test examples suitable for documentation |
|
||||
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Milestone completions triggering doc cycle |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-TIME` — timeline update
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-IMP-SUP` | Priority/Medium+ | Progress data for timeline entries |
|
||||
| `AUTO-PRMRG-SUP` | Priority/Medium+ | Merged PRs to record in timeline |
|
||||
| `AUTO-PROD-BLDR` | Priority/Medium+ | Milestone status updates |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
### `AUTO-OWNR` — project owner
|
||||
|
||||
| Source | Min Priority | Rationale |
|
||||
|--------|-------------|-----------|
|
||||
| `AUTO-WDOG` | Priority/Critical+ | System alerts |
|
||||
| `AUTO-HUMAN` | Priority/High+ | Human requests and feedback |
|
||||
| `AUTO-EPIC` | Priority/High+ | New epics and scope changes |
|
||||
| `AUTO-IMP-SUP` | Priority/High+ | Implementation progress affecting priority decisions |
|
||||
| `AUTO-GROOM` | Priority/Medium+ | Issue quality reports requiring owner action |
|
||||
| `AUTO-UAT-SUP` | Priority/Medium+ | Test results affecting priority decisions |
|
||||
| All others | Priority/Critical+ | Universal baseline |
|
||||
|
||||
|
||||
## Rule of Thumb
|
||||
|
||||
When in doubt, **lower the threshold** (consume more). Missing an important
|
||||
announcement is always worse than reading a slightly irrelevant one.
|
||||
@@ -3,7 +3,6 @@
|
||||
These rules apply to **every** agent in the CleverAgents system without exception.
|
||||
No agent, at any tier or role, is exempt from any of these rules.
|
||||
|
||||
---
|
||||
|
||||
## Rule 1 — Exhaustive Pagination
|
||||
|
||||
@@ -51,7 +50,6 @@ causing incorrect escalation decisions, duplicate filings, or incomplete
|
||||
audits. The cost of an extra API call is always less than the cost of
|
||||
a missed item.
|
||||
|
||||
---
|
||||
|
||||
## Rule 2 — Label Management via `forgejo-label-manager`
|
||||
|
||||
@@ -90,7 +88,6 @@ All labels applied by agents must exist at the **organization level**. Labels
|
||||
are defined once at the org level and inherited by all repos. Repo-level labels
|
||||
are not used by the autonomous agent system.
|
||||
|
||||
---
|
||||
|
||||
## Rule 3 — Bot Signature on All Forgejo Content
|
||||
|
||||
@@ -119,7 +116,6 @@ after code blocks, after any closing notes. Never buried in the middle.
|
||||
**Values:** Use the values given in your system prompt. Do not invent or guess
|
||||
the pool name or agent name — they are always provided in context.
|
||||
|
||||
---
|
||||
|
||||
## Rule 4 — Credential Flow: Workers Never Read Environment Variables
|
||||
|
||||
@@ -160,7 +156,6 @@ workers use credentials
|
||||
**If a supervisor omits any of these, the worker cannot proceed.** Supervisors
|
||||
bear full responsibility for including complete credentials in every worker prompt.
|
||||
|
||||
---
|
||||
|
||||
## Rule 5 — localhost:4096 Restriction
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
// USAGE (as CLI):
|
||||
// list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
|
||||
//
|
||||
// Notable filter options:
|
||||
// --stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown
|
||||
// --ci-status passing|failing|pending|unknown (comma-separated, any combination)
|
||||
//
|
||||
// USAGE (as module, imported by the four wrapper scripts):
|
||||
// import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
// =============================================================================
|
||||
@@ -35,6 +39,13 @@ export type StaleState =
|
||||
| 'stale_unknown' // base advanced; mergeable=null (Forgejo pending)
|
||||
| 'compute_error'; // missing data or branch API failure
|
||||
|
||||
// CIStatus — combined commit-status result for the PR head SHA
|
||||
// 'passing' — all checks reported success (Forgejo combined state == 'success')
|
||||
// 'failing' — at least one check failed/errored (state == 'failure'|'error'|'warning')
|
||||
// 'pending' — checks are queued or still running (state == 'pending')
|
||||
// 'unknown' — no checks have been reported yet (state == ''|'unknown')
|
||||
export type CIStatus = 'passing' | 'failing' | 'pending' | 'unknown';
|
||||
|
||||
export interface Config {
|
||||
url: string; // Forgejo base URL, no trailing slash
|
||||
pat: string; // Personal Access Token
|
||||
@@ -48,6 +59,7 @@ export interface Filters {
|
||||
maxApprovals?: number; // approvals_count <= N
|
||||
mergeable?: boolean; // filter on PR.mergeable directly
|
||||
stale?: StaleState; // filter on computed stale_state
|
||||
ciStatus?: CIStatus[]; // whitelist: PR's ci_status must be one of these values
|
||||
}
|
||||
|
||||
// Raw shape of a Forgejo pull request object (only the fields we use).
|
||||
@@ -55,6 +67,7 @@ export interface Filters {
|
||||
interface RawPR {
|
||||
number: number;
|
||||
title: string;
|
||||
head: { sha: string };
|
||||
base: { ref: string };
|
||||
merge_base?: string | null;
|
||||
mergeable: boolean | null;
|
||||
@@ -65,6 +78,7 @@ interface RawPR {
|
||||
export interface AugmentedPR extends RawPR {
|
||||
approvals_count: number;
|
||||
stale_state: StaleState;
|
||||
ci_status: CIStatus;
|
||||
priority_rank: number; // 0 = CI Blocker (highest), higher = lower; PRIORITY_NONE if unlabelled
|
||||
priority_label: string | null; // matched Priority/* label name, or null if none
|
||||
}
|
||||
@@ -80,6 +94,10 @@ interface BranchInfo {
|
||||
commit: { id: string };
|
||||
}
|
||||
|
||||
interface CombinedStatus {
|
||||
state: string; // 'success' | 'pending' | 'failure' | 'error' | 'warning' | '' | 'unknown'
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// CONSTANTS
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -271,6 +289,17 @@ function computeStaleState(
|
||||
return 'stale_unknown';
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// mapCIState — translate Forgejo's combined commit-status state string into
|
||||
// our canonical CIStatus enum value
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
function mapCIState(state: string): CIStatus {
|
||||
if (state === 'success') return 'passing';
|
||||
if (state === 'pending') return 'pending';
|
||||
if (state === 'failure' || state === 'error' || state === 'warning') return 'failing';
|
||||
return 'unknown'; // '' | 'unknown' | anything else → no checks reported
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// listPRs — fetch, enrich, filter, and return matching PRs
|
||||
//
|
||||
@@ -347,12 +376,34 @@ export async function listPRs(
|
||||
REVIEW_CONCURRENCY,
|
||||
);
|
||||
|
||||
// ── Step 4: Compute fields, apply filters, collect results ────────────────
|
||||
// ── Step 4: Fetch CI (combined commit-status) for every PR concurrently ───
|
||||
// Uses GET /api/v1/repos/{owner}/{repo}/commits/{sha}/status which returns
|
||||
// the aggregated combined state for all status checks on the head commit.
|
||||
log(`Fetching CI status for ${rawPRs.length} PR(s) concurrently (limit=${REVIEW_CONCURRENCY})...`);
|
||||
|
||||
const allCIStatuses = await pLimit<CIStatus>(
|
||||
rawPRs.map(pr => async () => {
|
||||
try {
|
||||
const combined = await apiGet<CombinedStatus>(
|
||||
`${repoBase}/commits/${encodeURIComponent(pr.head.sha)}/status`,
|
||||
config.pat,
|
||||
);
|
||||
return mapCIState(combined.state ?? '');
|
||||
} catch {
|
||||
log(`WARNING: Could not fetch CI status for PR #${pr.number}; treating as 'unknown'`);
|
||||
return 'unknown' as CIStatus;
|
||||
}
|
||||
}),
|
||||
REVIEW_CONCURRENCY,
|
||||
);
|
||||
|
||||
// ── Step 5: Compute fields, apply filters, collect results ────────────────
|
||||
const results: AugmentedPR[] = [];
|
||||
|
||||
for (let i = 0; i < rawPRs.length; i++) {
|
||||
const pr = rawPRs[i];
|
||||
const approvalsCount = countApprovals(allReviews[i]);
|
||||
const ciStatus = allCIStatuses[i];
|
||||
const baseHead = branchCache.get(pr.base?.ref ?? '') ?? null;
|
||||
const staleState = computeStaleState(
|
||||
pr.merge_base ?? null,
|
||||
@@ -365,12 +416,14 @@ export async function listPRs(
|
||||
if (filters.maxApprovals !== undefined && approvalsCount > filters.maxApprovals) continue;
|
||||
if (filters.mergeable !== undefined && pr.mergeable !== filters.mergeable) continue;
|
||||
if (filters.stale !== undefined && staleState !== filters.stale) continue;
|
||||
if (filters.ciStatus !== undefined && !filters.ciStatus.includes(ciStatus)) continue;
|
||||
|
||||
const { rank: priorityRank, label: priorityLabel } = prPriority(pr);
|
||||
results.push({
|
||||
...pr,
|
||||
approvals_count: approvalsCount,
|
||||
stale_state: staleState,
|
||||
ci_status: ciStatus,
|
||||
priority_rank: priorityRank,
|
||||
priority_label: priorityLabel,
|
||||
});
|
||||
@@ -444,11 +497,12 @@ function parseFullArgs(argv: string[]): { config: Config; filters: Filters } {
|
||||
case '--pat': config.pat = val; i++; break;
|
||||
case '--owner': config.owner = val; i++; break;
|
||||
case '--repo': config.repo = val; i++; break;
|
||||
case '--state': filters.state = val as Filters['state']; i++; break;
|
||||
case '--min-approvals': filters.minApprovals = Number(val); i++; break;
|
||||
case '--max-approvals': filters.maxApprovals = Number(val); i++; break;
|
||||
case '--mergeable': filters.mergeable = val === 'true'; i++; break;
|
||||
case '--stale': filters.stale = val as StaleState; i++; break;
|
||||
case '--state': filters.state = val as Filters['state']; i++; break;
|
||||
case '--min-approvals': filters.minApprovals = Number(val); i++; break;
|
||||
case '--max-approvals': filters.maxApprovals = Number(val); i++; break;
|
||||
case '--mergeable': filters.mergeable = val === 'true'; i++; break;
|
||||
case '--stale': filters.stale = val as StaleState; i++; break;
|
||||
case '--ci-status': filters.ciStatus = val.split(',').map(s => s.trim()) as CIStatus[]; i++; break;
|
||||
case '-h':
|
||||
case '--help':
|
||||
printUsage();
|
||||
@@ -473,6 +527,7 @@ function printUsage(): void {
|
||||
process.stderr.write(`\
|
||||
Usage:
|
||||
list_prs.ts --url URL --pat TOKEN --owner OWNER --repo REPO [OPTIONS]
|
||||
[--ci-status passing|failing|pending|unknown[,...]]
|
||||
|
||||
REQUIRED:
|
||||
--url URL Forgejo base URL, no trailing slash (e.g. https://git.example.com)
|
||||
@@ -487,11 +542,20 @@ OPTIONAL FILTERS (all default to no filter):
|
||||
--mergeable true|false Filter on PR.mergeable field
|
||||
--stale not_stale|stale_no_conflicts|stale_with_conflicts|stale_unknown
|
||||
Filter on computed staleness state
|
||||
--ci-status passing|failing|pending|unknown[,...]
|
||||
Comma-separated whitelist of CI statuses to include.
|
||||
passing = all checks succeeded (Forgejo state: success)
|
||||
failing = at least one check failed/errored (failure|error|warning)
|
||||
pending = checks are queued or running (state: pending)
|
||||
unknown = no checks reported yet (state: ''|unknown)
|
||||
Multiple values: --ci-status passing,pending
|
||||
Omit flag entirely to include all CI statuses.
|
||||
|
||||
OUTPUT (stdout): JSON array sorted by priority (highest first); each object is
|
||||
the full Forgejo PR plus:
|
||||
.approvals_count integer distinct non-dismissed APPROVED review count
|
||||
.stale_state string one of the stale states listed above
|
||||
.ci_status string passing|failing|pending|unknown (see --ci-status above)
|
||||
.priority_rank integer 0=CI Blocker, 1=Critical, 2=High, 3=Medium,
|
||||
4=Low, 5=Backlog, 6=none (unlabelled)
|
||||
.priority_label string|null matched Priority/* label name, or null
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env -S npx --yes tsx
|
||||
// =============================================================================
|
||||
// list_prs_needs_review.ts — Open PRs with no approvals yet ("everything else")
|
||||
//
|
||||
// Part of: .opencode/skills/auto-agents-system/scripts/
|
||||
//
|
||||
// Delegates to list_prs.ts with hard-coded filters.
|
||||
//
|
||||
// Returns all OPEN pull requests that:
|
||||
// • have zero review approvals (approvals_count == 0)
|
||||
//
|
||||
// These are the "everything else" bucket — PRs that have not received any
|
||||
// approvals from any reviewer yet, regardless of their staleness state.
|
||||
// They need a first review before any merge decision can be made.
|
||||
//
|
||||
// Why this is "everything else":
|
||||
// The three complementary scripts together cover every open PR that has at
|
||||
// least one approval, split by staleness state:
|
||||
// list_prs_ready_to_merge → approved + not stale
|
||||
// list_prs_stale_clean → approved + stale (no conflicts)
|
||||
// list_prs_stale_conflicts → approved + stale (with conflicts)
|
||||
// This script covers the remaining bucket: PRs awaiting a first review.
|
||||
//
|
||||
// Note: PRs with approvals but stale_state == stale_unknown (Forgejo has not
|
||||
// yet finished computing the conflict status) are a brief transient state that
|
||||
// will resolve shortly. They are intentionally absent from all four scripts
|
||||
// during that window and will appear in one of the approved scripts once
|
||||
// Forgejo finishes.
|
||||
//
|
||||
// Hard-coded filters (not configurable):
|
||||
// state: 'open' only open PRs are considered
|
||||
// maxApprovals: 0 PRs with no approvals whatsoever
|
||||
//
|
||||
// USAGE:
|
||||
// list_prs_needs_review.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
//
|
||||
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
|
||||
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
|
||||
// =============================================================================
|
||||
import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = parseConnectionArgs(process.argv);
|
||||
const prs = await listPRs(config, {
|
||||
state: 'open',
|
||||
maxApprovals: 0,
|
||||
});
|
||||
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
|
||||
}
|
||||
|
||||
main().catch((err: unknown) => {
|
||||
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env -S npx --yes tsx
|
||||
// =============================================================================
|
||||
// list_prs_needs_review_not_stale.ts — Open PRs with no approvals, up-to-date
|
||||
//
|
||||
// Part of: .opencode/skills/auto-agents-system/scripts/
|
||||
//
|
||||
// Delegates to list_prs.ts with hard-coded filters.
|
||||
//
|
||||
// Returns all OPEN pull requests that:
|
||||
// • have zero review approvals (approvals_count == 0)
|
||||
// • are NOT stale (stale_state == not_stale)
|
||||
// i.e. the PR's merge_base matches the current HEAD of its base branch —
|
||||
// the PR is fully up-to-date and requires no rebase before merging.
|
||||
//
|
||||
// These are PRs that need only a first review — no rebase or conflict
|
||||
// resolution will be required when they are eventually approved.
|
||||
//
|
||||
// Why this bucket exists:
|
||||
// Together with list_prs_needs_review_stale_clean and
|
||||
// list_prs_needs_review_stale_conflicts, these three scripts partition every
|
||||
// open PR with zero approvals into three actionable sub-buckets based on
|
||||
// what additional work will be required after a reviewer approves:
|
||||
// list_prs_needs_review_not_stale → review only; merge immediately on approval
|
||||
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
|
||||
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
|
||||
//
|
||||
// Note: PRs with zero approvals and stale_state == stale_unknown are
|
||||
// transiently absent while Forgejo computes conflict status; they will appear
|
||||
// in stale_clean or stale_conflicts once Forgejo finishes.
|
||||
//
|
||||
// Hard-coded filters (not configurable):
|
||||
// state: 'open' only open PRs are considered
|
||||
// maxApprovals: 0 PRs with no approvals whatsoever
|
||||
// stale: 'not_stale' PR is current with its base branch
|
||||
//
|
||||
// USAGE:
|
||||
// list_prs_needs_review_not_stale.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
//
|
||||
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
|
||||
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
|
||||
// =============================================================================
|
||||
import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = parseConnectionArgs(process.argv);
|
||||
const prs = await listPRs(config, {
|
||||
state: 'open',
|
||||
maxApprovals: 0,
|
||||
stale: 'not_stale',
|
||||
});
|
||||
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
|
||||
}
|
||||
|
||||
main().catch((err: unknown) => {
|
||||
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env -S npx --yes tsx
|
||||
// =============================================================================
|
||||
// list_prs_needs_review_stale_clean.ts — Open PRs with no approvals, stale, no conflicts
|
||||
//
|
||||
// Part of: .opencode/skills/auto-agents-system/scripts/
|
||||
//
|
||||
// Delegates to list_prs.ts with hard-coded filters.
|
||||
//
|
||||
// Returns all OPEN pull requests that:
|
||||
// • have zero review approvals (approvals_count == 0)
|
||||
// • are stale but have NO merge conflicts (stale_state == stale_no_conflicts)
|
||||
// i.e. the base branch has advanced since the PR was last synced,
|
||||
// but rebasing/merging would succeed without any conflict resolution.
|
||||
//
|
||||
// These are PRs that need a first review AND will also need a server-side
|
||||
// rebase before they can be merged — but no conflict resolution will be
|
||||
// required. Once approved, the workflow is:
|
||||
//
|
||||
// rebase_pr → (wait for approval if not yet given) → merge_pr
|
||||
//
|
||||
// Why this bucket exists:
|
||||
// Together with list_prs_needs_review_not_stale and
|
||||
// list_prs_needs_review_stale_conflicts, these three scripts partition every
|
||||
// open PR with zero approvals into three actionable sub-buckets based on
|
||||
// what additional work will be required after a reviewer approves:
|
||||
// list_prs_needs_review_not_stale → review only; merge immediately on approval
|
||||
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
|
||||
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
|
||||
//
|
||||
// Note: PRs with zero approvals and stale_state == stale_unknown are
|
||||
// transiently absent while Forgejo computes conflict status; they will appear
|
||||
// here or in stale_conflicts once Forgejo finishes.
|
||||
//
|
||||
// Hard-coded filters (not configurable):
|
||||
// state: 'open' only open PRs are considered
|
||||
// maxApprovals: 0 PRs with no approvals whatsoever
|
||||
// stale: 'stale_no_conflicts' PR is behind base but conflict-free
|
||||
//
|
||||
// USAGE:
|
||||
// list_prs_needs_review_stale_clean.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
//
|
||||
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
|
||||
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
|
||||
// =============================================================================
|
||||
import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = parseConnectionArgs(process.argv);
|
||||
const prs = await listPRs(config, {
|
||||
state: 'open',
|
||||
maxApprovals: 0,
|
||||
stale: 'stale_no_conflicts',
|
||||
});
|
||||
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
|
||||
}
|
||||
|
||||
main().catch((err: unknown) => {
|
||||
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env -S npx --yes tsx
|
||||
// =============================================================================
|
||||
// list_prs_needs_review_stale_conflicts.ts — Open PRs with no approvals, stale, with conflicts
|
||||
//
|
||||
// Part of: .opencode/skills/auto-agents-system/scripts/
|
||||
//
|
||||
// Delegates to list_prs.ts with hard-coded filters.
|
||||
//
|
||||
// Returns all OPEN pull requests that:
|
||||
// • have zero review approvals (approvals_count == 0)
|
||||
// • are stale AND have merge conflicts (stale_state == stale_with_conflicts)
|
||||
// i.e. the base branch has advanced since the PR was last synced,
|
||||
// and rebasing/merging would produce conflicts that cannot be resolved
|
||||
// automatically (PR.mergeable == false).
|
||||
//
|
||||
// These are PRs that need BOTH a first review AND manual conflict resolution
|
||||
// before they can be merged. The conflict resolution path requires a local
|
||||
// clone or repo-isolator since the Forgejo server-side rebase endpoint
|
||||
// (POST .../update?style=rebase) cannot handle conflicted PRs.
|
||||
//
|
||||
// Why this bucket exists:
|
||||
// Together with list_prs_needs_review_not_stale and
|
||||
// list_prs_needs_review_stale_clean, these three scripts partition every
|
||||
// open PR with zero approvals into three actionable sub-buckets based on
|
||||
// what additional work will be required after a reviewer approves:
|
||||
// list_prs_needs_review_not_stale → review only; merge immediately on approval
|
||||
// list_prs_needs_review_stale_clean → review + server-side rebase; no conflicts
|
||||
// list_prs_needs_review_stale_conflicts → review + local rebase; conflicts present
|
||||
//
|
||||
// Note: PRs with zero approvals and stale_state == stale_unknown are
|
||||
// transiently absent while Forgejo computes conflict status; they will appear
|
||||
// in stale_clean or here once Forgejo finishes.
|
||||
//
|
||||
// Hard-coded filters (not configurable):
|
||||
// state: 'open' only open PRs are considered
|
||||
// maxApprovals: 0 PRs with no approvals whatsoever
|
||||
// stale: 'stale_with_conflicts' PR is behind base AND has conflicts
|
||||
//
|
||||
// USAGE:
|
||||
// list_prs_needs_review_stale_conflicts.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
//
|
||||
// OUTPUT (stdout): JSON array — same schema as list_prs.ts
|
||||
// DEPENDENCIES: Node.js >= 18 (native fetch), npx tsx (for TypeScript execution)
|
||||
// =============================================================================
|
||||
import { listPRs, parseConnectionArgs } from './list_prs.ts';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = parseConnectionArgs(process.argv);
|
||||
const prs = await listPRs(config, {
|
||||
state: 'open',
|
||||
maxApprovals: 0,
|
||||
stale: 'stale_with_conflicts',
|
||||
});
|
||||
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
|
||||
}
|
||||
|
||||
main().catch((err: unknown) => {
|
||||
process.stderr.write(`ERROR: ${err instanceof Error ? err.message : String(err)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env -S npx --yes tsx
|
||||
// =============================================================================
|
||||
// list_prs_ready_to_merge.ts — Open PRs approved and up-to-date with base
|
||||
// list_prs_ready_to_merge.ts — Open PRs approved, up-to-date, and CI passing
|
||||
//
|
||||
// Part of: .opencode/skills/auto-agents-system/scripts/
|
||||
//
|
||||
@@ -9,15 +9,22 @@
|
||||
// Returns all OPEN pull requests that:
|
||||
// • have at least 1 review approval (approvals_count >= 1)
|
||||
// • are NOT stale (stale_state == not_stale)
|
||||
// • have passing CI (ci_status == 'passing')
|
||||
//
|
||||
// These PRs are ready to be merged immediately — they are approved and their
|
||||
// branch is already up-to-date with the base branch, so no rebase or conflict
|
||||
// resolution is required before merging.
|
||||
// These PRs are ready to be merged immediately — they are approved, their
|
||||
// branch is already up-to-date with the base branch, and all CI checks have
|
||||
// passed. No rebase, conflict resolution, or CI wait is required.
|
||||
//
|
||||
// CI filter rationale: merging a PR with failing or pending CI would push
|
||||
// broken code to the base branch. Only 'passing' is accepted here. PRs
|
||||
// with 'pending' or 'failing' CI appear in none of the approved buckets
|
||||
// until their CI resolves, preventing premature merges.
|
||||
//
|
||||
// Hard-coded filters (not configurable):
|
||||
// state: 'open' only open PRs are considered
|
||||
// minApprovals: 1 at least one non-dismissed approval required
|
||||
// stale: 'not_stale' PR head must be current with its base branch
|
||||
// state: 'open' only open PRs are considered
|
||||
// minApprovals: 1 at least one non-dismissed approval required
|
||||
// stale: 'not_stale' PR head must be current with its base branch
|
||||
// ciStatus: ['passing'] all CI checks must have succeeded
|
||||
//
|
||||
// USAGE:
|
||||
// list_prs_ready_to_merge.ts --url URL --pat TOKEN --owner OWNER --repo REPO
|
||||
@@ -33,6 +40,7 @@ async function main(): Promise<void> {
|
||||
state: 'open',
|
||||
minApprovals: 1,
|
||||
stale: 'not_stale',
|
||||
ciStatus: ['passing'],
|
||||
});
|
||||
process.stdout.write(JSON.stringify(prs, null, 2) + '\n');
|
||||
}
|
||||
|
||||
+70
-8
@@ -7,6 +7,53 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Actor v3 YAML Schema Validation in CLI** (#5869): The `agents actor add --config`
|
||||
command now validates v3 YAML files using `ActorConfigSchema`, ensuring proper
|
||||
schema compliance including cycle detection for GRAPH actors, required field
|
||||
validation, and enum validation. v3 YAML is detected by the presence of ANY
|
||||
`type` field (any value — invalid type values are then rejected by schema
|
||||
validation) or a `version` field whose string value starts with `"3"` (e.g.
|
||||
`"3"`, `"3.0"`, `"3.0.0"`). Configs with `type: null` are not treated as v3.
|
||||
Invalid v3 actors are rejected with clear error messages before registration.
|
||||
|
||||
- **Alembic Files Missing from Wheel Distribution** (#4180): Alembic configuration
|
||||
(`alembic.ini`) and migration files are now part of the Python package structure
|
||||
at `src/cleveragents/infrastructure/database/migrations/`. Previously, when
|
||||
`agents init` was run in Docker containers or any wheel-based installation,
|
||||
`FileNotFoundError` was raised because alembic files were stored at the
|
||||
repository root and excluded from the wheel distribution. Now alembic files
|
||||
follow standard Python packaging conventions and are automatically included.
|
||||
`MigrationRunner._find_alembic_ini()` has been updated to search the new package
|
||||
location as the primary anchor point. This fix enables `agents init` to work
|
||||
correctly in all deployment modes: Docker containers, local pip installs
|
||||
(wheel or editable), and development environments.
|
||||
- **TDD Non-AssertionError Guard Visibility** (#8294): `apply_tdd_inversion` in
|
||||
- **bug-hunt-pool-supervisor Non-Blocking Tracking** (#8835): The automation-tracking-manager
|
||||
call in step 5 was blocking the main loop indefinitely, causing 3+ consecutive initialization
|
||||
failures. Step 5 now explicitly marks tracking as best-effort -- if the call does not complete
|
||||
within a reasonable time or fails, it is skipped and the supervisor continues to the next
|
||||
cycle. A new Rule 9 reinforces that tracking must never block the main loop; core
|
||||
functionality (module mapping, worker dispatch, monitoring) takes priority over status
|
||||
reporting.
|
||||
|
||||
`features/environment.py` now emits its non-assertion exception guard warning to
|
||||
both the structured logger and `stderr` via a new `_warning_with_stderr` helper.
|
||||
This makes the guard firing visible in standard Behave console output and CI log
|
||||
snippets where the structured logging sink may not be displayed. BDD infrastructure
|
||||
coverage added: a new scenario in `tdd_expected_fail_infrastructure.feature`
|
||||
asserts that the warning is emitted to stderr when a non-AssertionError exception
|
||||
is encountered in an `@tdd_expected_fail` scenario, and a second scenario asserts
|
||||
the warning is NOT emitted when the exception is an `AssertionError`. The
|
||||
`CONTRIBUTING.md` now documents that `@tdd_expected_fail` step definitions must
|
||||
signal expected failures via `AssertionError`.
|
||||
|
||||
- **Parallel Behave Runner Log Noise Reduction** (#8351): The parallel behave
|
||||
runner now suppresses captured stdout/stderr for passing worker chunks and
|
||||
only replays diagnostics for failed, errored, or crashed chunks. This makes
|
||||
failure output significantly easier to spot in CI and local runs. A worker
|
||||
crash (unhandled exception) is detected via an all-zero summary and the
|
||||
captured traceback is always surfaced.
|
||||
|
||||
- **Automation Profile Silent Fallback** (#8232): `_resolve_profile_for_plan` in
|
||||
`PlanLifecycleService` now raises a clear `ValidationError` when a plan's
|
||||
automation profile name is not a known built-in profile, instead of silently
|
||||
@@ -15,6 +62,15 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
message listing available built-in profiles. The resolved profile name is also
|
||||
logged at debug level for observability.
|
||||
|
||||
- **CheckpointManager rollback_to always returned False** (#7488): Fixed a data
|
||||
integrity bug in `CheckpointManager.create_checkpoint()` where `sandbox_path`
|
||||
was computed from `sandbox.context.sandbox_path` but never stored in the
|
||||
checkpoint metadata. As a result, `rollback_to()` always found
|
||||
`checkpoint.metadata.get("sandbox_path")` returning `None` and silently
|
||||
skipped the rollback, returning `False`. The fix adds `sandbox_path` to the
|
||||
metadata dict before constructing the `SandboxCheckpoint`, enabling
|
||||
`rollback_to()` to correctly restore the sandbox filesystem state.
|
||||
|
||||
### Added
|
||||
|
||||
- **TDD Issue-Capture Test Activation** (#7025): Replaced 234 bare `@skip` tags
|
||||
@@ -69,14 +125,6 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
Priority-based filtering (Critical/High/Medium/Low) reduces noise. Backlog-groomer
|
||||
performs intelligent cleanup with age thresholds by priority.
|
||||
|
||||
- **OpenAI Quota Fallback to Anthropic Haiku** (#10042): Implemented graceful degradation
|
||||
for E2E robot integration tests when OpenAI API hits quota limit errors (429, insufficient_quota,
|
||||
rate_limit). The `StrategyActor` now detects quota-specific errors and automatically falls back
|
||||
to Anthropic Haiku for strategy decisions, ensuring CI/CD pipelines complete E2E tests even
|
||||
when the primary provider hits capacity limits. Improved pipeline reliability and reduced false
|
||||
negatives caused by provider-specific quota issues. Added comprehensive logging for quota error
|
||||
detection and provider fallback, plus E2E test scenarios for fallback verification.
|
||||
|
||||
- **PR Agent Reorganization**: All PR-related agents renamed and reorganized to follow
|
||||
the `*-pool-supervisor` naming pattern. New agents added: `pr-editor` (safe PR editing
|
||||
with description preservation), `pr-manager` (unified PR interface), and
|
||||
@@ -201,6 +249,20 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
`pr-merge-pool-supervisor` to the product-builder's supervisor launch list (18 total
|
||||
supervisors). Updated all numeric references, pre-flight checklists, and validation logic.
|
||||
|
||||
- `ActionRepository.update()` now uses explicit bulk `sa_delete()` + `session.flush()`
|
||||
before re-inserting child rows for `action_arguments` and `action_invariants`, fixing
|
||||
a `sqlite3.IntegrityError: UNIQUE constraint failed` crash when `agents plan use` was
|
||||
called on an action that already had arguments registered via `action create`. (#4197)
|
||||
|
||||
- Fixed CheckpointManager not wired into PlanExecutor — checkpoints were
|
||||
never created during plan execution because `_get_plan_executor()` in
|
||||
the CLI constructed PlanExecutor without a CheckpointManager (defaulted
|
||||
to None, silently skipping all checkpoint hooks). `_get_plan_executor()`
|
||||
now resolves the container singleton so CLI `plan execute` and `plan
|
||||
rollback` share the same registry, and `_try_create_checkpoint()` raises
|
||||
`PlanError` if checkpoint metadata cannot be persisted. Writable sandboxable
|
||||
resources and write-capable tools now default to `checkpointable=True`, and
|
||||
new Behave scenarios cover DI wiring, rollback, and capability defaults. (#1253)
|
||||
---
|
||||
|
||||
## [3.8.0] — 2026-04-05
|
||||
|
||||
@@ -19,5 +19,7 @@ Below are some of the specific details of various contributions.
|
||||
* HAL 9000 has contributed concurrency safety improvements, including thread-safe context tier management (issue #7547) for parallel plan execution.
|
||||
* HAL 9000 has contributed the plan concurrency race-condition fix (#7989): wired `LockService` into the plan lifecycle, guarding `execute_plan()` and `apply_plan()` with plan-level advisory locks and unique per-invocation owner identities to prevent silent concurrent state corruption.
|
||||
* HAL 9000 has contributed the plugin entry point security hardening fix (#7476): enforced entry point allowlist validation before importing plugin modules to prevent malicious plugin loading.
|
||||
* Rui Hu has contributed the v3 actor YAML schema validation fix (#5869): added `ActorConfigSchema` validation to the `agents actor add --config` CLI command, covering cycle detection, required field validation, and enum validation for v3 YAML actor definitions.
|
||||
* HAL 9000 has contributed automated bug fixes, including fix #7488 (store sandbox_path in checkpoint metadata to enable rollback).
|
||||
* This project was made possible thanks to considerable donation of time, money, and resources by CleverThis, Inc.
|
||||
* HAL 9000 has contributed automated bug fixes, CLI output formatting improvements, and ongoing maintenance as part of the CleverAgents automation system.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user