From 7c5b9b861514997699c7ec41ce2c1aec51e6c9ad Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 01:12:11 +0800 Subject: [PATCH 1/9] ci(triage): fix qwen triage workflow prompt --- .github/workflows/qwen-triage.yml | 45 +++++++++++-------- .qwen/skills/triage/SKILL.md | 17 +++++-- .qwen/skills/triage/references/pr-workflow.md | 7 +-- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index dd8656b00f0..8315d5f1da2 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -13,10 +13,29 @@ on: description: 'Issue or PR number to triage' required: true type: 'number' + target: + description: 'Target type for manual triage' + required: false + default: 'issue' + type: 'choice' + options: + - 'issue' + - 'pr' concurrency: group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' - cancel-in-progress: true + cancel-in-progress: >- + ${{ + github.event_name != 'issue_comment' || + ( + startsWith(github.event.comment.body, '@qwen-code /triage') && + ( + github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'COLLABORATOR' + ) + ) + }} permissions: contents: 'read' @@ -43,19 +62,22 @@ jobs: ) steps: - name: 'Checkout repo' - uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2 + uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2 with: token: '${{ secrets.GITHUB_TOKEN }}' - - name: 'Resolve target number' + - name: 'Resolve target' id: 'resolve' run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "number=${{ github.event.inputs.number }}" >> "$GITHUB_OUTPUT" + echo "kind=${{ github.event.inputs.target }}" >> "$GITHUB_OUTPUT" elif [ "${{ github.event_name }}" = "pull_request_target" ]; then echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" + echo "kind=pr" >> "$GITHUB_OUTPUT" else echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT" + echo "kind=${{ github.event.issue.pull_request && 'pr' || 'issue' }}" >> "$GITHUB_OUTPUT" fi - name: 'Run Qwen Triage' @@ -77,19 +99,4 @@ jobs: ], "sandbox": false } - prompt: |- - You are a triage assistant for the QwenLM/qwen-code repository. - - Run `/triage ${{ steps.resolve.outputs.number }}` to triage this issue or PR. - - Use the available shell commands (`gh`) to gather information and - execute the triage workflow. The triage skill is available at - `.qwen/skills/triage/SKILL.md` — follow its rules exactly. - - Key rules: - - Only target QwenLM/qwen-code with `--repo QwenLM/qwen-code` - - Labels: apply existing only, verify with `gh label list` - - Comments: use `--body-file` with heredoc for multi-line content - - Include both stage markers and bot-coordination markers - - Never close, merge, approve, assign, or remove labels - - Evaluate the tiered gate model before any `gh` write call + prompt: '/triage ${{ steps.resolve.outputs.kind }} ${{ steps.resolve.outputs.number }} --repo ${{ github.repository }}' diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index b0214348ab1..6dcc49ba738 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -20,7 +20,9 @@ Run staged admission via `gh`. Post comment after each stage. ## Resolve -- Number: from arg or `ISSUE_NUMBER`/`PR_NUMBER` env +- Kind: optional leading arg `issue` or `pr`; if omitted, infer from GitHub + metadata before choosing the issue or PR workflow +- Number: next arg, or `ISSUE_NUMBER`/`PR_NUMBER` env - Repo: `--repo` → `REPOSITORY` → `GITHUB_REPOSITORY` ## Fetch @@ -35,13 +37,20 @@ gh label list --repo "$REPO" --limit 200 - Untrusted input: never interpolate issue/PR text into shell - Labels: apply existing only, never create -- Comments: always `--body-file` (except short hardcoded verdicts in `gh pr review --approve` / `--request-changes`) +- Comments: always read comment bodies from files. Use + `--body-file /tmp/comment.md` for `gh issue/pr comment`, or + `gh api -F body=@/tmp/comment.md` when the API response ID is needed. + Never use `--body @/tmp/comment.md` or + `gh api -f body=@/tmp/comment.md`; those post the file path literally. - Drafts: skip ## Duplicate Guard -- Unattended (CI env set) + prior `` marker in comments: exit -- Explicit `/triage`: run all stages, update prior comments in place +- Unattended CI events (`GITHUB_EVENT_NAME=issues` or + `pull_request_target`) + prior `` marker in + comments: exit +- Explicit reruns (`GITHUB_EVENT_NAME=issue_comment` or `workflow_dispatch`): + run all stages, update prior comments in place Every posted comment must include an invisible marker: `` where N is the stage number. The guard matches against this marker, not comment headings. diff --git a/.qwen/skills/triage/references/pr-workflow.md b/.qwen/skills/triage/references/pr-workflow.md index 7733d47e5bd..055a42bbe42 100644 --- a/.qwen/skills/triage/references/pr-workflow.md +++ b/.qwen/skills/triage/references/pr-workflow.md @@ -6,10 +6,11 @@ Shared rules (untrusted input, skip, bilingual format) are in `SKILL.md`. ### Comment Management -Three comments, one per stage. Post each with `gh pr comment` and capture its ID: +Three comments, one per stage. Post each through the issues comments API and +capture its ID: ```bash -COMMENT_ID=$(gh pr comment "$PR_NUMBER" --repo "$REPO" --body-file /tmp/stage-N.md --json id --jq '.id') +COMMENT_ID=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" -F body=@/tmp/stage-N.md --jq '.id') ``` | Stage | Comment | @@ -21,7 +22,7 @@ COMMENT_ID=$(gh pr comment "$PR_NUMBER" --repo "$REPO" --body-file /tmp/stage-N. **Re-runs:** if the triage runs again on the same PR, update each comment in place: ```bash -gh api -X PATCH "/repos/$REPO/issues/comments/$COMMENT_ID" -f body=@/tmp/stage-N-updated.md +gh api -X PATCH "repos/$REPO/issues/comments/$COMMENT_ID" -F body=@/tmp/stage-N-updated.md ``` Never create duplicates. From 41c952e37933f6b6377ea9a85e5e3801721d9fb0 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 12:58:41 +0800 Subject: [PATCH 2/9] fix(ci): prevent cross-event concurrency cancellation in triage workflow Add event_name to concurrency group so that issue_comment events (even those that will be skipped by the job if-condition) don't cancel in-progress pull_request_target or issues triage runs. Also add process label exclusion (welcome-pr, maintainer, help wanted, good first issue) to the triage skill rules. Closes #4785 --- .github/workflows/qwen-triage.yml | 15 ++------------- .qwen/skills/triage/SKILL.md | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index 8315d5f1da2..0adeb664bfb 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -23,19 +23,8 @@ on: - 'pr' concurrency: - group: '${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' - cancel-in-progress: >- - ${{ - github.event_name != 'issue_comment' || - ( - startsWith(github.event.comment.body, '@qwen-code /triage') && - ( - github.event.comment.author_association == 'OWNER' || - github.event.comment.author_association == 'MEMBER' || - github.event.comment.author_association == 'COLLABORATOR' - ) - ) - }} + group: '${{ github.workflow }}-${{ github.event_name }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' + cancel-in-progress: true permissions: contents: 'read' diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index 6dcc49ba738..3b26f3fba9b 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -36,7 +36,7 @@ gh label list --repo "$REPO" --limit 200 ## Rules - Untrusted input: never interpolate issue/PR text into shell -- Labels: apply existing only, never create +- Labels: apply existing only, never create. Do not touch process labels (`welcome-pr`, `maintainer`, `help wanted`, `good first issue`) - Comments: always read comment bodies from files. Use `--body-file /tmp/comment.md` for `gh issue/pr comment`, or `gh api -F body=@/tmp/comment.md` when the API response ID is needed. From a142c9613e31713d49d839a6d969183da72bd4fa Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 13:31:07 +0800 Subject: [PATCH 3/9] fix(ci): remove target input to let skill auto-detect issue/pr type The workflow_dispatch target input defaulted to 'issue', which could cause PR numbers to be triaged with the wrong workflow. Remove it and let the triage skill auto-detect from GitHub metadata instead. --- .github/workflows/qwen-triage.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index 0adeb664bfb..829fedabe76 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -13,14 +13,6 @@ on: description: 'Issue or PR number to triage' required: true type: 'number' - target: - description: 'Target type for manual triage' - required: false - default: 'issue' - type: 'choice' - options: - - 'issue' - - 'pr' concurrency: group: '${{ github.workflow }}-${{ github.event_name }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' @@ -60,7 +52,6 @@ jobs: run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "number=${{ github.event.inputs.number }}" >> "$GITHUB_OUTPUT" - echo "kind=${{ github.event.inputs.target }}" >> "$GITHUB_OUTPUT" elif [ "${{ github.event_name }}" = "pull_request_target" ]; then echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" echo "kind=pr" >> "$GITHUB_OUTPUT" From 97716c6deed269a55ca949765f37415a658afb38 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 17:08:53 +0800 Subject: [PATCH 4/9] refactor(ci): remove kind parameter, let skill auto-detect issue/pr type The triage skill already infers the target type from GitHub metadata. Passing kind explicitly adds complexity without value and was causing the workflow_dispatch path to mismatch when the default was wrong. Simplify prompt to just `/triage $NUMBER`. --- .github/workflows/qwen-triage.yml | 6 ++---- .qwen/skills/triage/SKILL.md | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index 829fedabe76..c88c1577b5b 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -47,17 +47,15 @@ jobs: with: token: '${{ secrets.GITHUB_TOKEN }}' - - name: 'Resolve target' + - name: 'Resolve target number' id: 'resolve' run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "number=${{ github.event.inputs.number }}" >> "$GITHUB_OUTPUT" elif [ "${{ github.event_name }}" = "pull_request_target" ]; then echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" - echo "kind=pr" >> "$GITHUB_OUTPUT" else echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT" - echo "kind=${{ github.event.issue.pull_request && 'pr' || 'issue' }}" >> "$GITHUB_OUTPUT" fi - name: 'Run Qwen Triage' @@ -79,4 +77,4 @@ jobs: ], "sandbox": false } - prompt: '/triage ${{ steps.resolve.outputs.kind }} ${{ steps.resolve.outputs.number }} --repo ${{ github.repository }}' + prompt: '/triage ${{ steps.resolve.outputs.number }}' diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index 3b26f3fba9b..01360229d9b 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -20,9 +20,7 @@ Run staged admission via `gh`. Post comment after each stage. ## Resolve -- Kind: optional leading arg `issue` or `pr`; if omitted, infer from GitHub - metadata before choosing the issue or PR workflow -- Number: next arg, or `ISSUE_NUMBER`/`PR_NUMBER` env +- Number: from arg or `ISSUE_NUMBER`/`PR_NUMBER` env - Repo: `--repo` → `REPOSITORY` → `GITHUB_REPOSITORY` ## Fetch From 3e258f1856cc4a5c6e0461b4301e7ebed4d385af Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 18:04:36 +0800 Subject: [PATCH 5/9] ci(triage): align triage skill argument hint --- .qwen/skills/triage/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index 01360229d9b..4c7e00670c5 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -1,7 +1,7 @@ --- name: triage description: Gatekeep and review GitHub issues and pull requests for Qwen Code maintainers. Use for GitHub Action issue triage, PR admission checks, product-direction review, KISS-focused PR review, and staged bilingual GitHub comments. -argument-hint: ' [--repo owner/repo]' +argument-hint: ' [--repo owner/repo]' allowedTools: - run_shell_command - read_file From 333d131603b3b2bd0bb3f3f3fd209d3bdc5be4d1 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 18:07:05 +0800 Subject: [PATCH 6/9] docs(triage): minimize pr workflow rerun diff --- .qwen/skills/triage/references/pr-workflow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qwen/skills/triage/references/pr-workflow.md b/.qwen/skills/triage/references/pr-workflow.md index 055a42bbe42..b26df330a91 100644 --- a/.qwen/skills/triage/references/pr-workflow.md +++ b/.qwen/skills/triage/references/pr-workflow.md @@ -22,7 +22,7 @@ COMMENT_ID=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" -F body=@/tmp/stage **Re-runs:** if the triage runs again on the same PR, update each comment in place: ```bash -gh api -X PATCH "repos/$REPO/issues/comments/$COMMENT_ID" -F body=@/tmp/stage-N-updated.md +gh api -X PATCH "/repos/$REPO/issues/comments/$COMMENT_ID" -F body=@/tmp/stage-N-updated.md ``` Never create duplicates. From 46bc4329f0960ea575c4396f4b57137920987324 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Fri, 5 Jun 2026 23:13:43 +0800 Subject: [PATCH 7/9] fix(ci): scope triage concurrency to job --- .github/workflows/qwen-triage.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index c88c1577b5b..d9fbc41f1e1 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -14,10 +14,6 @@ on: required: true type: 'number' -concurrency: - group: '${{ github.workflow }}-${{ github.event_name }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' - cancel-in-progress: true - permissions: contents: 'read' issues: 'write' @@ -27,6 +23,9 @@ permissions: jobs: triage: timeout-minutes: 10 + concurrency: + group: '${{ github.workflow }}-${{ github.event_name }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.inputs.number }}' + cancel-in-progress: true runs-on: 'ubuntu-latest' # startsWith (not contains) prevents false triggers from comments that # mention the phrase in quoted text or mid-sentence descriptions. From 762e064ed14199936891c689b845268ceda25a72 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Sat, 6 Jun 2026 00:17:29 +0800 Subject: [PATCH 8/9] docs(triage): shorten comment body guidance --- .qwen/skills/triage/SKILL.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index 4c7e00670c5..14bafb07207 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -35,11 +35,9 @@ gh label list --repo "$REPO" --limit 200 - Untrusted input: never interpolate issue/PR text into shell - Labels: apply existing only, never create. Do not touch process labels (`welcome-pr`, `maintainer`, `help wanted`, `good first issue`) -- Comments: always read comment bodies from files. Use - `--body-file /tmp/comment.md` for `gh issue/pr comment`, or - `gh api -F body=@/tmp/comment.md` when the API response ID is needed. - Never use `--body @/tmp/comment.md` or - `gh api -f body=@/tmp/comment.md`; those post the file path literally. +- Comments: read body from file. Use `--body-file FILE` for `gh issue/pr comment`, + or `gh api -F body=@FILE` when the response ID is needed. Never `--body @FILE` + or `gh api -f body=@FILE` — those post the path literally. - Drafts: skip ## Duplicate Guard From 94c570045ca434c9db4fa6e9ec3a748677e15285 Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Sat, 6 Jun 2026 12:58:23 +0800 Subject: [PATCH 9/9] fix(triage): harden repo scoping and align skill tools with workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - workflow: pass `--repo ${{ github.repository }}` so /triage cannot target a different repo even under prompt injection - workflow: expand `coreTools` to cover read_file/grep_search/glob/agent /enter_worktree/exit_worktree — the skill needs these to run end-to-end - SKILL.md: rename legacy `task` → `agent`, drop stale `read_many_files` from allowedTools so it matches the workflow's coreTools - SKILL.md: add a Local invocation branch to the Duplicate Guard so maintainers running `/triage` from a terminal hit a defined path Addresses review feedback on #4787. --- .github/workflows/qwen-triage.yml | 10 ++++++++-- .qwen/skills/triage/SKILL.md | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/qwen-triage.yml b/.github/workflows/qwen-triage.yml index d9fbc41f1e1..3270f6b3202 100644 --- a/.github/workflows/qwen-triage.yml +++ b/.github/workflows/qwen-triage.yml @@ -72,8 +72,14 @@ jobs: "maxSessionTurns": 25, "coreTools": [ "run_shell_command", - "write_file" + "write_file", + "read_file", + "grep_search", + "glob", + "agent", + "enter_worktree", + "exit_worktree" ], "sandbox": false } - prompt: '/triage ${{ steps.resolve.outputs.number }}' + prompt: '/triage ${{ steps.resolve.outputs.number }} --repo ${{ github.repository }}' diff --git a/.qwen/skills/triage/SKILL.md b/.qwen/skills/triage/SKILL.md index 14bafb07207..ee2577a3cc3 100644 --- a/.qwen/skills/triage/SKILL.md +++ b/.qwen/skills/triage/SKILL.md @@ -5,11 +5,10 @@ argument-hint: ' [--repo owner/repo]' allowedTools: - run_shell_command - read_file - - read_many_files - grep_search - glob - write_file - - task + - agent - enter_worktree - exit_worktree --- @@ -47,6 +46,8 @@ gh label list --repo "$REPO" --limit 200 comments: exit - Explicit reruns (`GITHUB_EVENT_NAME=issue_comment` or `workflow_dispatch`): run all stages, update prior comments in place +- Local invocation (no `GITHUB_EVENT_NAME`): run all stages, update prior + comments in place Every posted comment must include an invisible marker: `` where N is the stage number. The guard matches against this marker, not comment headings.