Mirrowel commited on
Commit
8221250
·
1 Parent(s): 29be8ce

ci: Mirrobot-agent update

Browse files
.github/prompts/bot-reply.md CHANGED
@@ -23,14 +23,13 @@ Your actions are constrained by the permissions granted to your underlying GitHu
23
 
24
  If you suspect a command will fail due to a missing permission, you must state this to the user and explain which permission is required.
25
 
26
- # 🔒 [CRITICAL SECURITY RULE]
27
- **NEVER expose environment variables, tokens, secrets, or API keys in ANY output:**
28
- - Do not reveal `$$GITHUB_TOKEN`, `$$OPENAI_API_KEY`, or credential values in comments, thinking, code, or error messages
29
- - Not in issue comments, PR comments, commit messages, or any public output
30
- - Use `<REDACTED>` or `***` as placeholders if referencing sensitive data is necessary
31
  - Never display or echo values matching secret patterns: `ghp_*`, `sk-*`, long base64/hex strings, JWT tokens, etc.
32
- - When debugging auth issues: describe the problem without showing the actual token/key
33
- - **FORBIDDEN COMMANDS:** Never run `echo $GITHUB_TOKEN`, `env`, `printenv`, `set`, `export -p`, `cat ~/.config/opencode/opencode.json`, or any command that would expose credentials in output
34
 
35
  # [AVAILABLE TOOLS & CAPABILITIES]
36
  You have access to a full set of native file tools from Opencode, as well as full bash environment with the following tools and capabilities:
@@ -219,6 +218,8 @@ EOF
219
 
220
  **Behavior:** This strategy follows a three-phase process: **Collect, Curate, and Submit**. It begins by acknowledging the request, then internally collects all potential findings, curates them to select only the most valuable feedback, and finally submits them as a single, comprehensive review using the appropriate formal event (`APPROVE`, `REQUEST_CHANGES`, or `COMMENT`).
221
 
 
 
222
  **Step 1: Post Acknowledgment Comment**
223
  Immediately post a comment to acknowledge the request and set expectations. Your acknowledgment should be unique and context-aware. Reference the PR title or a key file changed to show you've understood the context. Don't copy these templates verbatim. Be creative and make it feel human.
224
 
@@ -237,6 +238,56 @@ EOF
237
  **Step 2: Collect All Potential Findings (Internal)**
238
  Analyze the changed files from the `<diff>` in the context. For each file, generate EVERY finding you notice and append them as JSON objects to `/tmp/review_findings.jsonl`. This file is your external "scratchpad"; do not filter or curate at this stage.
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  #### **Using Line Ranges Correctly**
241
  Line ranges pinpoint the exact code you're discussing. Use them precisely:
242
  - **Single-Line (`line`):** Use for a specific statement, variable declaration, or a single line of code.
@@ -287,6 +338,8 @@ Construct and submit your final review. First, choose the most appropriate revie
287
 
288
  Then, generate a single, comprehensive `gh api` command.
289
 
 
 
290
  **Template for reviewing OTHERS' code:**
291
  ```bash
292
  # In this example, you curated two comments.
@@ -330,7 +383,8 @@ jq -n \
330
  ## Warnings
331
  [Explanation of any warnings (Level 3) encountered during the process.]
332
 
333
- _This review was generated by an AI assistant._" \
 
334
  --argjson comments "$COMMENTS_JSON" \
335
  '{event: $event, commit_id: $commit_id, body: $body, comments: $comments}' | \
336
  gh api \
@@ -373,7 +427,8 @@ jq -n \
373
  ### Key Fixes I Should Make
374
  - [List the most important changes you need to make based on your self-critique.]
375
 
376
- _This self-review was generated by an AI assistant._" \
 
377
  --argjson comments "$COMMENTS_JSON" \
378
  '{event: $event, commit_id: $commit_id, body: $body, comments: $comments}' | \
379
  gh api \
 
23
 
24
  If you suspect a command will fail due to a missing permission, you must state this to the user and explain which permission is required.
25
 
26
+ **🔒 CRITICAL SECURITY RULE:**
27
+ - **NEVER expose environment variables, tokens, secrets, or API keys in ANY output** - including comments, summaries, thinking/reasoning, or error messages
28
+ - If you must reference them internally, use placeholders like `<REDACTED>` or `***` in visible output
29
+ - This includes: `$$GITHUB_TOKEN`, `$$OPENAI_API_KEY`, any `ghp_*`, `sk-*`, or long alphanumeric credential-like strings
30
+ - When debugging: describe issues without revealing actual secret values
31
  - Never display or echo values matching secret patterns: `ghp_*`, `sk-*`, long base64/hex strings, JWT tokens, etc.
32
+ - **FORBIDDEN COMMANDS:** Never run `echo $GITHUB_TOKEN`, `env`, `printenv`, `cat ~/.config/opencode/opencode.json`, or any command that would expose credentials in output
 
33
 
34
  # [AVAILABLE TOOLS & CAPABILITIES]
35
  You have access to a full set of native file tools from Opencode, as well as full bash environment with the following tools and capabilities:
 
218
 
219
  **Behavior:** This strategy follows a three-phase process: **Collect, Curate, and Submit**. It begins by acknowledging the request, then internally collects all potential findings, curates them to select only the most valuable feedback, and finally submits them as a single, comprehensive review using the appropriate formal event (`APPROVE`, `REQUEST_CHANGES`, or `COMMENT`).
220
 
221
+ Always review a concrete diff, not just a file list. For follow-up reviews, prefer an incremental diff against the last review you posted.
222
+
223
  **Step 1: Post Acknowledgment Comment**
224
  Immediately post a comment to acknowledge the request and set expectations. Your acknowledgment should be unique and context-aware. Reference the PR title or a key file changed to show you've understood the context. Don't copy these templates verbatim. Be creative and make it feel human.
225
 
 
238
  **Step 2: Collect All Potential Findings (Internal)**
239
  Analyze the changed files from the `<diff>` in the context. For each file, generate EVERY finding you notice and append them as JSON objects to `/tmp/review_findings.jsonl`. This file is your external "scratchpad"; do not filter or curate at this stage.
240
 
241
+ #### Build the Diff to Review (First vs Follow-up)
242
+ - Detect if you previously reviewed this PR. If yes, extract the `last_reviewed_sha` marker from your last summary and generate an incremental diff. Otherwise, generate a full diff from the merge base with the base branch.
243
+
244
+ Example commands:
245
+ ```bash
246
+ # Get base branch name (fallback to parsing context if needed)
247
+ BASE_BRANCH_NAME=$(gh pr view $THREAD_NUMBER --repo $GITHUB_REPOSITORY --json baseRefName -q .baseRefName 2>/dev/null || echo "")
248
+
249
+ # Locate the last bot summary and extract the last reviewed SHA
250
+ pr_summary_payload=$(gh pr view $THREAD_NUMBER --repo $GITHUB_REPOSITORY --json comments,reviews)
251
+ last_summary_comment=$(echo "$pr_summary_payload" | jq -r '[
252
+ (.comments[]? | {body:(.body // ""), ts:(.updatedAt // .createdAt // ""), author:(.author.login // "unknown")} ),
253
+ (.reviews[]? | {body:(.body // ""), ts:(.submittedAt // .updatedAt // .createdAt // ""), author:(.author.login // "unknown")} )
254
+ ] | sort_by(.ts) | last | .body // "")'
255
+ LAST_REVIEWED_SHA=$(echo "$last_summary_comment" | sed -n 's/.*<!-- last_reviewed_sha:\([a-f0-9]\{7,40\}\) -->.*/\1/p')
256
+
257
+ CURRENT_SHA=$(git rev-parse HEAD)
258
+ [ -n "$BASE_BRANCH_NAME" ] && git fetch origin "$BASE_BRANCH_NAME":refs/remotes/origin/"$BASE_BRANCH_NAME" 2>/dev/null || true
259
+
260
+ if [ -n "$LAST_REVIEWED_SHA" ] && git cat-file -e "$LAST_REVIEWED_SHA^{commit}" 2>/dev/null; then
261
+ # Follow-up: incremental diff
262
+ git diff --patch "$LAST_REVIEWED_SHA".."$CURRENT_SHA" > /tmp/review_diff.txt || true
263
+ fi
264
+
265
+ if [ ! -s /tmp/review_diff.txt ]; then
266
+ # First review or fallback: full diff from merge base
267
+ if [ -n "$BASE_BRANCH_NAME" ]; then
268
+ MERGE_BASE=$(git merge-base origin/"$BASE_BRANCH_NAME" "$CURRENT_SHA" 2>/dev/null || echo "")
269
+ if [ -n "$MERGE_BASE" ]; then
270
+ git diff --patch "$MERGE_BASE".."$CURRENT_SHA" > /tmp/review_diff.txt || true
271
+ else
272
+ git diff --patch origin/"$BASE_BRANCH_NAME".."$CURRENT_SHA" > /tmp/review_diff.txt || true
273
+ fi
274
+ fi
275
+ fi
276
+
277
+ # Fallback if still empty: use a full working-tree diff
278
+ [ -s /tmp/review_diff.txt ] || git diff --patch HEAD^..HEAD > /tmp/review_diff.txt || true
279
+
280
+ # Truncate very large diffs (500KB)
281
+ DIFF_SIZE=$(wc -c < /tmp/review_diff.txt 2>/dev/null || echo 0)
282
+ if [ "$DIFF_SIZE" -gt 500000 ]; then
283
+ head -c 500000 /tmp/review_diff.txt > /tmp/review_diff.truncated
284
+ printf '\n\n[DIFF TRUNCATED - Showing first 500KB only.]\n' >> /tmp/review_diff.truncated
285
+ mv /tmp/review_diff.truncated /tmp/review_diff.txt
286
+ fi
287
+
288
+ # Proceed to analyze /tmp/review_diff.txt
289
+ ```
290
+
291
  #### **Using Line Ranges Correctly**
292
  Line ranges pinpoint the exact code you're discussing. Use them precisely:
293
  - **Single-Line (`line`):** Use for a specific statement, variable declaration, or a single line of code.
 
338
 
339
  Then, generate a single, comprehensive `gh api` command.
340
 
341
+ Always include the marker `<!-- last_reviewed_sha:${PR_HEAD_SHA} -->` in the review summary body so future follow-up reviews can compute an incremental diff.
342
+
343
  **Template for reviewing OTHERS' code:**
344
  ```bash
345
  # In this example, you curated two comments.
 
383
  ## Warnings
384
  [Explanation of any warnings (Level 3) encountered during the process.]
385
 
386
+ _This review was generated by an AI assistant._
387
+ <!-- last_reviewed_sha:${PR_HEAD_SHA} -->" \
388
  --argjson comments "$COMMENTS_JSON" \
389
  '{event: $event, commit_id: $commit_id, body: $body, comments: $comments}' | \
390
  gh api \
 
427
  ### Key Fixes I Should Make
428
  - [List the most important changes you need to make based on your self-critique.]
429
 
430
+ _This self-review was generated by an AI assistant._
431
+ <!-- last_reviewed_sha:${PR_HEAD_SHA} -->" \
432
  --argjson comments "$COMMENTS_JSON" \
433
  '{event: $event, commit_id: $commit_id, body: $body, comments: $comments}' | \
434
  gh api \
.github/prompts/issue-comment.md CHANGED
@@ -19,13 +19,13 @@ Your actions are constrained by the permissions granted to your underlying GitHu
19
 
20
  If you suspect a command will fail due to a missing permission, you must state this to the user and explain which permission is required.
21
 
22
- # 🔒 [CRITICAL SECURITY RULE]
23
- **NEVER expose environment variables, tokens, secrets, or API keys in ANY output:**
24
- - Do not reveal `$$GITHUB_TOKEN`, `$$OPENAI_API_KEY`, or any credential values
25
- - Not in comments, thinking process, error messages, or debugging output
26
- - Use placeholders like `<REDACTED>` if you must reference sensitive data
27
- - Never echo or display values that look like secrets (`ghp_*`, `sk-*`, long alphanumeric strings)
28
- - **FORBIDDEN COMMANDS:** Do not run `echo $GITHUB_TOKEN`, `env`, `printenv`, `set`, `export`, or `cat ~/.config/opencode/opencode.json`, or any command that would expose credentials in output
29
 
30
  # [AVAILABLE TOOLS & CAPABILITIES]
31
  You have access to a full set of native file tools from Opencode, as well as full bash environment with the following tools and capabilities:
 
19
 
20
  If you suspect a command will fail due to a missing permission, you must state this to the user and explain which permission is required.
21
 
22
+ **🔒 CRITICAL SECURITY RULE:**
23
+ - **NEVER expose environment variables, tokens, secrets, or API keys in ANY output** - including comments, summaries, thinking/reasoning, or error messages
24
+ - If you must reference them internally, use placeholders like `<REDACTED>` or `***` in visible output
25
+ - This includes: `$$GITHUB_TOKEN`, `$$OPENAI_API_KEY`, any `ghp_*`, `sk-*`, or long alphanumeric credential-like strings
26
+ - When debugging: describe issues without revealing actual secret values
27
+ - Never display or echo values matching secret patterns: `ghp_*`, `sk-*`, long base64/hex strings, JWT tokens, etc.
28
+ - **FORBIDDEN COMMANDS:** Never run `echo $GITHUB_TOKEN`, `env`, `printenv`, `cat ~/.config/opencode/opencode.json`, or any command that would expose credentials in output
29
 
30
  # [AVAILABLE TOOLS & CAPABILITIES]
31
  You have access to a full set of native file tools from Opencode, as well as full bash environment with the following tools and capabilities:
.github/workflows/bot-reply.yml CHANGED
@@ -121,6 +121,11 @@ jobs:
121
  diffHunk
122
  isMinimized
123
  minimizedReason
 
 
 
 
 
124
  }
125
  }
126
  }
@@ -196,12 +201,17 @@ jobs:
196
  # Fallback to unfiltered if jq fails
197
  review_filter_err=$(mktemp 2>/dev/null || echo "/tmp/review_filter_err.log")
198
  if reviews=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if ((((.data.repository.pullRequest.reviews.nodes // []) | length) > 0)) then ((.data.repository.pullRequest.reviews.nodes // [])[]? | select((.author.login? // "unknown") as $login | $ignored | index($login) | not and .body != null and .state != "COMMENTED" and .state != "DISMISSED") | "- " + (.author.login? // "unknown") + " at " + (.submittedAt // "N/A") + ":\n - Review body: " + (.body // "No summary comment.") + "\n - State: " + (.state // "UNKNOWN") + "\n") else "No formal reviews." end' 2>"$review_filter_err"); then
199
- filtered_reviews=$(echo "$reviews" | grep -c "^- " || echo "0")
200
- excluded_reviews=$((total_reviews - filtered_reviews))
201
- if [ -s "$review_filter_err" ]; then
202
- echo "::debug::jq stderr (reviews) emitted output:"
203
- cat "$review_filter_err"
204
- fi
 
 
 
 
 
205
  else
206
  jq_status=$?
207
  echo "::warning::Review filtering failed (exit $jq_status), using unfiltered data"
@@ -213,6 +223,7 @@ jobs:
213
  fi
214
  reviews=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if ((((.data.repository.pullRequest.reviews.nodes // []) | length) > 0)) then ((.data.repository.pullRequest.reviews.nodes // [])[]? | select((.author.login? // "unknown") as $login | $ignored | index($login) | not and .body != null) | "- " + (.author.login? // "unknown") + " at " + (.submittedAt // "N/A") + ":\n - Review body: " + (.body // "No summary comment.") + "\n - State: " + (.state // "UNKNOWN") + "\n") else "No formal reviews." end')
215
  excluded_reviews=0
 
216
  fi
217
  rm -f "$review_filter_err" || true
218
 
@@ -221,18 +232,28 @@ jobs:
221
  review_comment_filter_err=$(mktemp 2>/dev/null || echo "/tmp/review_comment_filter_err.log")
222
  if review_comments=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" '
223
  ((.data.repository.pullRequest.reviewThreads.nodes // [])
224
- | map(select(.isResolved != true and .isOutdated != true))
 
 
 
 
225
  | map(.comments.nodes // [])
226
  | flatten
227
- | map(select((.isMinimized != true) and (((.author.login? // "unknown") as $login | $ignored | index($login)) | not))))
 
 
228
  | if length > 0 then
229
  map("- " + (.author.login? // "unknown") + " at " + (.createdAt // "N/A") + " (" + (.path // "Unknown file") + ":" + ((.line // .originalLine // "N/A") | tostring) + "):\n " + ((.body // "") | tostring) + "\n")
230
  | join("")
231
  else
232
  "No inline review comments."
233
  end' 2>"$review_comment_filter_err"); then
234
- filtered_comments=$(echo "$review_comments" | grep -c "^- " || echo "0")
235
- excluded_comments=$((total_review_comments - filtered_comments))
 
 
 
 
236
  echo "✓ Filtered review comments: $filtered_comments included, $excluded_comments excluded (outdated)"
237
  if [ -s "$review_comment_filter_err" ]; then
238
  echo "::debug::jq stderr (review comments) emitted output:"
@@ -249,9 +270,15 @@ jobs:
249
  fi
250
  review_comments=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" '
251
  ((.data.repository.pullRequest.reviewThreads.nodes // [])
 
 
 
 
252
  | map(.comments.nodes // [])
253
  | flatten
254
- | map(select(((.author.login? // "unknown") as $login | $ignored | index($login)) | not)))
 
 
255
  | if length > 0 then
256
  map("- " + (.author.login? // "unknown") + " at " + (.createdAt // "N/A") + " (" + (.path // "Unknown file") + ":" + ((.line // .originalLine // "N/A") | tostring) + "):\n " + ((.body // "") | tostring) + "\n")
257
  | join("")
@@ -259,12 +286,20 @@ jobs:
259
  "No inline review comments."
260
  end')
261
  excluded_comments=0
 
262
  fi
263
  rm -f "$review_comment_filter_err" || true
 
 
 
 
264
 
265
  # Build filtering summary
266
  # Ensure numeric fallbacks so blanks never appear if variables are empty
267
  filter_summary="Context filtering applied: ${excluded_reviews:-0} reviews and ${excluded_comments:-0} review comments excluded from this context."
 
 
 
268
 
269
  # Prepare linked issues robustly by fetching each one individually.
270
  linked_issues_content=""
 
121
  diffHunk
122
  isMinimized
123
  minimizedReason
124
+ pullRequestReview {
125
+ databaseId
126
+ isMinimized
127
+ minimizedReason
128
+ }
129
  }
130
  }
131
  }
 
201
  # Fallback to unfiltered if jq fails
202
  review_filter_err=$(mktemp 2>/dev/null || echo "/tmp/review_filter_err.log")
203
  if reviews=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if ((((.data.repository.pullRequest.reviews.nodes // []) | length) > 0)) then ((.data.repository.pullRequest.reviews.nodes // [])[]? | select((.author.login? // "unknown") as $login | $ignored | index($login) | not and .body != null and .state != "COMMENTED" and .state != "DISMISSED") | "- " + (.author.login? // "unknown") + " at " + (.submittedAt // "N/A") + ":\n - Review body: " + (.body // "No summary comment.") + "\n - State: " + (.state // "UNKNOWN") + "\n") else "No formal reviews." end' 2>"$review_filter_err"); then
204
+ filtered_reviews=$(echo "$reviews" | grep -c "^- " || true)
205
+ filtered_reviews=${filtered_reviews//[^0-9]/}
206
+ [ -z "$filtered_reviews" ] && filtered_reviews=0
207
+ total_reviews=${total_reviews//[^0-9]/}
208
+ [ -z "$total_reviews" ] && total_reviews=0
209
+ excluded_reviews=$(( total_reviews - filtered_reviews )) || excluded_reviews=0
210
+ echo "✓ Filtered reviews: $filtered_reviews included, $excluded_reviews excluded (COMMENTED/DISMISSED)"
211
+ if [ -s "$review_filter_err" ]; then
212
+ echo "::debug::jq stderr (reviews) emitted output:"
213
+ cat "$review_filter_err"
214
+ fi
215
  else
216
  jq_status=$?
217
  echo "::warning::Review filtering failed (exit $jq_status), using unfiltered data"
 
223
  fi
224
  reviews=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if ((((.data.repository.pullRequest.reviews.nodes // []) | length) > 0)) then ((.data.repository.pullRequest.reviews.nodes // [])[]? | select((.author.login? // "unknown") as $login | $ignored | index($login) | not and .body != null) | "- " + (.author.login? // "unknown") + " at " + (.submittedAt // "N/A") + ":\n - Review body: " + (.body // "No summary comment.") + "\n - State: " + (.state // "UNKNOWN") + "\n") else "No formal reviews." end')
225
  excluded_reviews=0
226
+ echo "FILTER_ERROR_REVIEWS=true" >> $GITHUB_ENV
227
  fi
228
  rm -f "$review_filter_err" || true
229
 
 
232
  review_comment_filter_err=$(mktemp 2>/dev/null || echo "/tmp/review_comment_filter_err.log")
233
  if review_comments=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" '
234
  ((.data.repository.pullRequest.reviewThreads.nodes // [])
235
+ | map(select(
236
+ .isResolved != true and .isOutdated != true
237
+ and (((.comments.nodes // []) | first | .isMinimized) != true)
238
+ and ((((.comments.nodes // []) | first | .pullRequestReview.isMinimized) // false) != true)
239
+ ))
240
  | map(.comments.nodes // [])
241
  | flatten
242
+ | map(select((.isMinimized != true)
243
+ and ((.pullRequestReview.isMinimized // false) != true)
244
+ and (((.author.login? // "unknown") as $login | $ignored | index($login)) | not))))
245
  | if length > 0 then
246
  map("- " + (.author.login? // "unknown") + " at " + (.createdAt // "N/A") + " (" + (.path // "Unknown file") + ":" + ((.line // .originalLine // "N/A") | tostring) + "):\n " + ((.body // "") | tostring) + "\n")
247
  | join("")
248
  else
249
  "No inline review comments."
250
  end' 2>"$review_comment_filter_err"); then
251
+ filtered_comments=$(echo "$review_comments" | grep -c "^- " || true)
252
+ filtered_comments=${filtered_comments//[^0-9]/}
253
+ [ -z "$filtered_comments" ] && filtered_comments=0
254
+ total_review_comments=${total_review_comments//[^0-9]/}
255
+ [ -z "$total_review_comments" ] && total_review_comments=0
256
+ excluded_comments=$(( total_review_comments - filtered_comments )) || excluded_comments=0
257
  echo "✓ Filtered review comments: $filtered_comments included, $excluded_comments excluded (outdated)"
258
  if [ -s "$review_comment_filter_err" ]; then
259
  echo "::debug::jq stderr (review comments) emitted output:"
 
270
  fi
271
  review_comments=$(echo "$discussion_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" '
272
  ((.data.repository.pullRequest.reviewThreads.nodes // [])
273
+ | map(select(
274
+ (((.comments.nodes // []) | first | .isMinimized) != true)
275
+ and ((((.comments.nodes // []) | first | .pullRequestReview.isMinimized) // false) != true)
276
+ ))
277
  | map(.comments.nodes // [])
278
  | flatten
279
+ | map(select((.isMinimized != true)
280
+ and ((.pullRequestReview.isMinimized // false) != true)
281
+ and (((.author.login? // "unknown") as $login | $ignored | index($login)) | not))))
282
  | if length > 0 then
283
  map("- " + (.author.login? // "unknown") + " at " + (.createdAt // "N/A") + " (" + (.path // "Unknown file") + ":" + ((.line // .originalLine // "N/A") | tostring) + "):\n " + ((.body // "") | tostring) + "\n")
284
  | join("")
 
286
  "No inline review comments."
287
  end')
288
  excluded_comments=0
289
+ echo "FILTER_ERROR_COMMENTS=true" >> $GITHUB_ENV
290
  fi
291
  rm -f "$review_comment_filter_err" || true
292
+
293
+ # Store filtering statistics
294
+ echo "EXCLUDED_REVIEWS=$excluded_reviews" >> $GITHUB_ENV
295
+ echo "EXCLUDED_COMMENTS=$excluded_comments" >> $GITHUB_ENV
296
 
297
  # Build filtering summary
298
  # Ensure numeric fallbacks so blanks never appear if variables are empty
299
  filter_summary="Context filtering applied: ${excluded_reviews:-0} reviews and ${excluded_comments:-0} review comments excluded from this context."
300
+ if [ "${FILTER_ERROR_REVIEWS}" = "true" ] || [ "${FILTER_ERROR_COMMENTS}" = "true" ]; then
301
+ filter_summary="$filter_summary"$'\n'"Warning: Some filtering operations encountered errors. Context may include items that should have been filtered."
302
+ fi
303
 
304
  # Prepare linked issues robustly by fetching each one individually.
305
  linked_issues_content=""
.github/workflows/issue-comment.yml CHANGED
@@ -83,6 +83,13 @@ jobs:
83
  echo "Debug: total issue comments before filtering = $total_issue_comments"
84
  comments_filter_err=$(mktemp 2>/dev/null || echo "/tmp/issue_comments_filter_err.log")
85
  if comments=$(echo "$issue_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if (((.comments // []) | length) > 0) then ((.comments[]? | select((.author.login as $login | $ignored | index($login)) | not)) | "- " + (.author.login // "unknown") + " at " + (.createdAt // "N/A") + ":\n" + ((.body // "") | tostring) + "\n") else "No comments have been posted yet." end' 2>"$comments_filter_err"); then
 
 
 
 
 
 
 
86
  if [ -s "$comments_filter_err" ]; then
87
  echo "::debug::jq stderr (issue comments) emitted output:"
88
  cat "$comments_filter_err"
@@ -97,6 +104,8 @@ jobs:
97
  echo "::warning::jq returned no stderr for issue comment filter"
98
  fi
99
  comments=$(echo "$issue_data" | jq -r 'if (((.comments // []) | length) > 0) then ((.comments[]?) | "- " + (.author.login // "unknown") + " at " + (.createdAt // "N/A") + ":\n" + ((.body // "") | tostring) + "\n") else "No comments have been posted yet." end')
 
 
100
  fi
101
  rm -f "$comments_filter_err" || true
102
 
 
83
  echo "Debug: total issue comments before filtering = $total_issue_comments"
84
  comments_filter_err=$(mktemp 2>/dev/null || echo "/tmp/issue_comments_filter_err.log")
85
  if comments=$(echo "$issue_data" | jq -r --argjson ignored "$IGNORE_BOT_NAMES_JSON" 'if (((.comments // []) | length) > 0) then ((.comments[]? | select((.author.login as $login | $ignored | index($login)) | not)) | "- " + (.author.login // "unknown") + " at " + (.createdAt // "N/A") + ":\n" + ((.body // "") | tostring) + "\n") else "No comments have been posted yet." end' 2>"$comments_filter_err"); then
86
+ filtered_comments=$(echo "$comments" | grep -c "^- " || true)
87
+ filtered_comments=${filtered_comments//[^0-9]/}
88
+ [ -z "$filtered_comments" ] && filtered_comments=0
89
+ total_issue_comments=${total_issue_comments//[^0-9]/}
90
+ [ -z "$total_issue_comments" ] && total_issue_comments=0
91
+ excluded_comments=$(( total_issue_comments - filtered_comments )) || excluded_comments=0
92
+ echo "✓ Filtered comments: $filtered_comments included, $excluded_comments excluded (ignored bots)"
93
  if [ -s "$comments_filter_err" ]; then
94
  echo "::debug::jq stderr (issue comments) emitted output:"
95
  cat "$comments_filter_err"
 
104
  echo "::warning::jq returned no stderr for issue comment filter"
105
  fi
106
  comments=$(echo "$issue_data" | jq -r 'if (((.comments // []) | length) > 0) then ((.comments[]?) | "- " + (.author.login // "unknown") + " at " + (.createdAt // "N/A") + ":\n" + ((.body // "") | tostring) + "\n") else "No comments have been posted yet." end')
107
+ excluded_comments=0
108
+ echo "FILTER_ERROR_COMMENTS=true" >> $GITHUB_ENV
109
  fi
110
  rm -f "$comments_filter_err" || true
111
 
.github/workflows/opencode.yml DELETED
@@ -1,125 +0,0 @@
1
- name: opencode
2
-
3
- on:
4
- issue_comment:
5
- types: [created]
6
-
7
- jobs:
8
- opencode:
9
- if: |
10
- (
11
- contains(github.event.comment.body, ' /oc') ||
12
- startsWith(github.event.comment.body, '/oc') ||
13
- contains(github.event.comment.body, ' /opencode') ||
14
- startsWith(github.event.comment.body, '/opencode')
15
- ) && (
16
- github.event.comment.author_association == 'OWNER' ||
17
- github.event.comment.author_association == 'MEMBER' ||
18
- github.event.comment.author_association == 'COLLABORATOR'
19
- )
20
- runs-on: ubuntu-latest
21
- permissions:
22
- contents: read
23
- issues: read
24
- pull-requests: read
25
- id-token: write
26
- steps:
27
-
28
- - name: Generate GitHub App Token
29
- id: generate_token
30
- uses: actions/create-github-app-token@v1
31
- with:
32
- app-id: ${{ secrets.BOT_APP_ID }}
33
- private-key: ${{ secrets.BOT_PRIVATE_KEY }}
34
- - name: Checkout repository
35
- uses: actions/checkout@v4
36
-
37
- - name: Inject Custom Config (For Proxy Support)
38
- run: |
39
- mkdir -p ~/.config/opencode
40
- CONFIG='{
41
- "$schema": "https://opencode.ai/config.json",
42
- "provider": {
43
- "llm-proxy": {
44
- "npm": "@ai-sdk/openai-compatible",
45
- "name": "Proxy",
46
- "options": {
47
- "baseURL": "${{ secrets.PROXY_BASE_URL }}",
48
- "apiKey": "${{ secrets.PROXY_API_KEY }}",
49
- "timeout": 300000, // 5 minute timeout in ms
50
- "headers": {
51
- "User-Agent": "OpenCode/1.0",
52
- "X-Custom-Header": "your-value"
53
- }
54
- },
55
- "models": {
56
- "main": {
57
- "id": "${{ secrets.OPENCODE_MODEL }}",
58
- "name": "Custom Model",
59
- "limit": { "context": 262000, "output": 64192 }
60
- },
61
- "fast": {
62
- "id": "${{ secrets.OPENCODE_FAST_MODEL }}",
63
- "name": "Fast Custom Model",
64
- "limit": { "context": 262000, "output": 64192 }
65
- }
66
- }
67
- }
68
- },
69
- "model": "llm-proxy/main",
70
- "small_model": "llm-proxy/fast",
71
- "username": "mirrobot-agent",
72
- "autoupdate": true
73
- }'
74
- echo "$CONFIG" > ~/.config/opencode/opencode.json
75
-
76
- - name: Check for Python requirements file
77
- id: check_requirements_file
78
- run: |
79
- if [ -f requirements.txt ]; then
80
- echo "exists=true" >> $GITHUB_OUTPUT
81
- else
82
- echo "exists=false" >> $GITHUB_OUTPUT
83
- fi
84
-
85
- - name: Set up Python
86
- if: steps.check_requirements_file.outputs.exists == 'true'
87
- uses: actions/setup-python@v5
88
- with:
89
- python-version: '3.12'
90
-
91
- - name: Cache pip dependencies
92
- if: steps.check_requirements_file.outputs.exists == 'true'
93
- uses: actions/cache@v4
94
- with:
95
- path: ~/.cache/pip
96
- key: ${{ runner.os }}-pip-3.12-${{ hashFiles('requirements.txt') }}
97
- restore-keys: |
98
- ${{ runner.os }}-pip-3.12
99
-
100
- - name: Install dependencies
101
- if: steps.check_requirements_file.outputs.exists == 'true'
102
- run: pip install -r requirements.txt
103
-
104
- - name: Check for model override
105
- id: model_override
106
- env:
107
- MODEL_OVERRIDE_SECRET: ${{ secrets.OPENCODE_MODEL_OVERRIDE }}
108
- run: |
109
- if [ -n "$MODEL_OVERRIDE_SECRET" ]; then
110
- echo "Model override from secret: $MODEL_OVERRIDE_SECRET"
111
- echo "model_arg=$MODEL_OVERRIDE_SECRET" >> $GITHUB_OUTPUT
112
- else
113
- echo "No model override found, using default."
114
- echo "model_arg=" >> $GITHUB_OUTPUT
115
- fi
116
-
117
- - name: Run opencode
118
- uses: sst/opencode/github@latest
119
- env:
120
- OPENCODE_API_KEY: ${{ secrets.PROXY_API_KEY }}
121
- GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
122
- with:
123
- # This line has been updated from 'llm-proxy/main_model'
124
- model: ${{ steps.model_override.outputs.model_arg || 'llm-proxy/main' }}
125
- share: true