@olegkoval/agent-skills 1.18.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,151 @@
1
+ # GraphQL queries reference
2
+
3
+ Field names verified by introspection against GitHub's live GraphQL schema
4
+ (`AddPullRequestReviewThreadReplyInput`) and against a real Qodo install's
5
+ comment output — not guessed.
6
+
7
+ **The bot's login string is spelled differently in REST vs GraphQL.** REST
8
+ (`.user.login` on `issues/.../comments`) returns `qodo-code-review[bot]`.
9
+ GraphQL (`author.login` on `reviewThreads`) returns `qodo-code-review` — no
10
+ `[bot]` suffix — confirmed live against a real PR with real Qodo inline
11
+ threads. Using the REST spelling in a GraphQL filter silently matches
12
+ nothing, which reads as "no findings" instead of "wrong filter" — exactly the
13
+ kind of bug that has no crash and no error to notice. Use `[bot]` only in
14
+ REST-based jq filters (`.user.login`); use the bare name everywhere you're
15
+ filtering a GraphQL `author.login`.
16
+
17
+ ## Fetch unresolved Qodo threads (paginated)
18
+
19
+ ```graphql
20
+ query($cursor: String) {
21
+ repository(owner: "OWNER", name: "REPO") {
22
+ pullRequest(number: PR_NUMBER) {
23
+ reviewThreads(first: 100, after: $cursor) {
24
+ pageInfo { hasNextPage endCursor }
25
+ nodes {
26
+ id
27
+ isResolved
28
+ comments(first: 1) {
29
+ nodes { body path line author { login } }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ Filter client-side to `qodo-code-review` (GraphQL spelling — see the note
39
+ above) and `isResolved == false` — the author isn't filterable server-side in
40
+ this shape. **Follow `pageInfo.hasNextPage`/`endCursor` until it's exhausted**;
41
+ stopping after the first page silently drops every thread past the 100th on a
42
+ PR with a lot of findings:
43
+
44
+ A page fetch can occasionally come back malformed (a transient API hiccup,
45
+ not anything specific to this query — reproduced live, then failed to
46
+ reproduce on an identical immediate retry). Retry once per page before
47
+ giving up rather than letting the whole loop crash on it:
48
+
49
+ ```bash
50
+ CURSOR=null
51
+ ALL_THREADS='[]'
52
+ while :; do
53
+ for attempt in 1 2; do
54
+ PAGE=$(gh api graphql -f query='
55
+ query($cursor: String) {
56
+ repository(owner: "OWNER", name: "REPO") {
57
+ pullRequest(number: PR_NUMBER) {
58
+ reviewThreads(first: 100, after: $cursor) {
59
+ pageInfo { hasNextPage endCursor }
60
+ nodes {
61
+ id
62
+ isResolved
63
+ comments(first: 1) { nodes { body path line author { login } } }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }' -f cursor="$CURSOR")
69
+ jq -e . >/dev/null 2>&1 <<< "$PAGE" && break
70
+ [ "$attempt" = "2" ] && { echo "page fetch failed twice, aborting" >&2; exit 1; }
71
+ done
72
+
73
+ ALL_THREADS=$(jq -c --argjson acc "$ALL_THREADS" \
74
+ '$acc + .data.repository.pullRequest.reviewThreads.nodes' <<< "$PAGE")
75
+
76
+ HAS_NEXT=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.hasNextPage' <<< "$PAGE")
77
+ [ "$HAS_NEXT" = "true" ] || break
78
+ CURSOR=$(jq -r '.data.repository.pullRequest.reviewThreads.pageInfo.endCursor' <<< "$PAGE")
79
+ done
80
+
81
+ echo "$ALL_THREADS" | jq \
82
+ '.[] | select(.comments.nodes[0].author.login == "qodo-code-review") | select(.isResolved == false)'
83
+ ```
84
+
85
+ ## Parsing a thread's finding out of `comments.nodes[0].body`
86
+
87
+ The body is markdown with embedded HTML. Extract:
88
+ - **Title + severity**: first line has a badge image; `alt="Remediation recommended"` = actionable, `alt="Informational"` = optional. The finding title/tags follow on the next line (e.g. `3\. pickclaimroaster branch untested <code>📘 Rule violation</code> ...`).
89
+ - **Agent Prompt**: the fenced ```` ```...``` ```` block under a `<summary>` reading either `Agent Prompt` or `Agent prompt` (Qodo's casing differs between the inline-comment surface and the rollup issue-comment surface — match case-insensitively). This block is the whole fix spec: issue description, context, fix focus files/lines, and often a suggested fix. Use it verbatim as the task.
90
+
91
+ If a thread somehow has no Agent Prompt block (seen only on the rollup's
92
+ lower-severity "Optional" entries in some cases), fall back to the finding's
93
+ plain-text description above the badge.
94
+
95
+ ## Reply to a thread
96
+
97
+ ```bash
98
+ gh api graphql -f query='
99
+ mutation($threadId: ID!, $body: String!) {
100
+ addPullRequestReviewThreadReply(input: {pullRequestReviewThreadId: $threadId, body: $body}) {
101
+ comment { id }
102
+ }
103
+ }' -f threadId="$THREAD_ID" -f body="$REPLY_TEXT"
104
+ ```
105
+
106
+ Pass the thread id and reply text as GraphQL **variables** (`-f`), never
107
+ interpolated straight into the query string. A reply containing a quote,
108
+ backtick, or embedded newline breaks — or, worse, injects into — a
109
+ hand-built query string; `gh api graphql -f` handles the escaping correctly
110
+ when the value travels as a variable instead.
111
+
112
+ `pullRequestReviewThreadId` and `body` are the only required input fields
113
+ (`pullRequestReviewId` and `clientMutationId` are optional — omit them).
114
+
115
+ ## Resolve a thread (batch)
116
+
117
+ ```graphql
118
+ mutation {
119
+ t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } }
120
+ t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } }
121
+ }
122
+ ```
123
+
124
+ Only resolve a thread whose fix is already pushed and confirmed durable on
125
+ the branch (SKILL.md §2E-F) — resolving first and pushing second means a
126
+ failed push leaves GitHub showing the finding as handled when it isn't. Never
127
+ resolve a blocked/skipped finding at all; reply to it and leave it open.
128
+
129
+ ## Fetch the rollup issue comment (context only, not the source of truth)
130
+
131
+ Useful for the human-readable summary counts (bugs/rule-violations) in your
132
+ final report, or as a fallback if `reviewThreads` ever comes back empty for a
133
+ PR that clearly has a completed review. Select the latest by `created_at`.
134
+ Whether Qodo edits this comment in place across passes or posts a new one
135
+ each time is **unconfirmed** — every PR checked had exactly one, untouched
136
+ since creation, which doesn't distinguish the two. Sort by `created_at` and
137
+ take the last one either way; it's correct under both behaviors:
138
+
139
+ ```bash
140
+ gh api --paginate "repos/{owner}/{repo}/issues/<PR_NUMBER>/comments?per_page=100" \
141
+ | jq -s 'add
142
+ | map(select(.user.login == "qodo-code-review[bot]"))
143
+ | map(select(.body | startswith("<h3>Code Review by Qodo</h3>")))
144
+ | sort_by(.created_at)
145
+ | last'
146
+ ```
147
+
148
+ A rate-limit/paused comment reads `<h3>Qodo is busy working</h3>` while
149
+ in-flight, or contains "Qodo reviews are paused" / "review limit" when
150
+ terminally blocked — check for that text before assuming a missing review
151
+ comment just means "still running".