diff --git a/.github/workflows/agent-deep-dive.lock.yml b/.github/workflows/agent-deep-dive.lock.yml index d7256405..c60df773 100644 --- a/.github/workflows/agent-deep-dive.lock.yml +++ b/.github/workflows/agent-deep-dive.lock.yml @@ -35,7 +35,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"861e87a99c68fbf45c047c6d7f90c836bced9503ffed8916302fdd738737c88d"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"25c6c9d0ef8b46a82822e917434f9cb53eb104e30f688ebca3bfcaa769488aaf"} name: "Internal: Agent Deep Dive" "on": @@ -554,7 +554,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -562,6 +562,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} RUN_COUNT: ${{ inputs.run-count }} diff --git a/.github/workflows/agent-efficiency.lock.yml b/.github/workflows/agent-efficiency.lock.yml index 831b6fcb..fa2f8d0e 100644 --- a/.github/workflows/agent-efficiency.lock.yml +++ b/.github/workflows/agent-efficiency.lock.yml @@ -35,7 +35,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"77a58bd453d3e1aa561d027e594de762f37d79abd29e18d6d51a82904b26dd2f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8f58a51f562f7ce5c60ec0e4f50fd3973af2f542155b85c381c5a9d297e7aa4d"} name: "Internal: Agent Efficiency" "on": @@ -520,7 +520,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -528,6 +528,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} name: Download failed run logs diff --git a/.github/workflows/downstream-users.lock.yml b/.github/workflows/downstream-users.lock.yml index 47288110..8a720acb 100644 --- a/.github/workflows/downstream-users.lock.yml +++ b/.github/workflows/downstream-users.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1dba193ef82fd955d37fa68d92ca0bc2f0f511a7add8a6f482e3647cf9cb4f4a"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2af4e8b8cdb1ae88a3f4c13292b8b55bca643a5177cbcba3f01564342aa90e75"} name: "Internal: Downstream Users" "on": @@ -468,7 +468,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -476,6 +476,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - name: Configure Git credentials env: diff --git a/.github/workflows/gh-aw-agent-suggestions.lock.yml b/.github/workflows/gh-aw-agent-suggestions.lock.yml index 9ee63c95..5de1c199 100644 --- a/.github/workflows/gh-aw-agent-suggestions.lock.yml +++ b/.github/workflows/gh-aw-agent-suggestions.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2615cfe99f9c91953e128b697453715020548c7f26cea7bcaac03d4d2c7cf055"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"663006e2be2eb3c4e93a986e98470d787539ad5563b4b7985f41d7b45244684a"} name: "Agent Suggestions" "on": @@ -598,7 +598,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -606,6 +606,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml index 91efa8de..bacebc93 100644 --- a/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml +++ b/.github/workflows/gh-aw-autonomy-atomicity-analyzer.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5cc9a5e5cf0bf812e61b521dc101e0d1dfe808ea1122534b0931ee9fce6c112e"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"3cf02cf2d15257dd0f3bcc7743fc8dc021f4b1276a1fefeb7968c36fff013ed8"} name: "Autonomy Atomicity Analyzer" "on": @@ -602,7 +602,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -610,6 +610,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-branch-actions-detective.lock.yml b/.github/workflows/gh-aw-branch-actions-detective.lock.yml index 3b8d23bb..725a8d62 100644 --- a/.github/workflows/gh-aw-branch-actions-detective.lock.yml +++ b/.github/workflows/gh-aw-branch-actions-detective.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5659154d541ccb8ca6659861cdb1f4b3b2b2f2ff01a4dd5b9d0d9f14ec20fcf4"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"72bed0d881392eaeea8e1b2e3666c59039eb2ca935bd1ec3f609e4d056f36fd1"} name: "Branch Actions Detective" "on": @@ -526,7 +526,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -534,6 +534,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-breaking-change-detect.lock.yml b/.github/workflows/gh-aw-breaking-change-detect.lock.yml index 8bffb82c..fc6dd790 100644 --- a/.github/workflows/gh-aw-breaking-change-detect.lock.yml +++ b/.github/workflows/gh-aw-breaking-change-detect.lock.yml @@ -45,7 +45,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2e552c5b04ddd3eb735773c90127a28b1e68e4e594a5bd5e983d8993495b941b"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"cc2e60978c9dcb4c8c9bc7d737396ea679c08f1ffb7ed291d7bd18ba366370a1"} name: "Breaking Change Detector" "on": @@ -609,7 +609,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -617,6 +617,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-breaking-change-detector.lock.yml b/.github/workflows/gh-aw-breaking-change-detector.lock.yml index a60479c4..c72ad264 100644 --- a/.github/workflows/gh-aw-breaking-change-detector.lock.yml +++ b/.github/workflows/gh-aw-breaking-change-detector.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2e552c5b04ddd3eb735773c90127a28b1e68e4e594a5bd5e983d8993495b941b"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"cc2e60978c9dcb4c8c9bc7d737396ea679c08f1ffb7ed291d7bd18ba366370a1"} name: "Breaking Change Detector" "on": @@ -604,7 +604,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -612,6 +612,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-bug-exterminator.lock.yml b/.github/workflows/gh-aw-bug-exterminator.lock.yml index 8d7c3718..c399b6ce 100644 --- a/.github/workflows/gh-aw-bug-exterminator.lock.yml +++ b/.github/workflows/gh-aw-bug-exterminator.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d943487a7e29f0a90dd302d93a91a906e6dc21db6251f79c4037f528818f2fbc"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"218198d7daeb5075e026cb833b2fb8d909f16ed8457059e34022058af9743643"} name: "Gh Aw Bug Exterminator" "on": @@ -512,7 +512,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -520,6 +520,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-bug-hunter.lock.yml b/.github/workflows/gh-aw-bug-hunter.lock.yml index b5bf0541..f3728348 100644 --- a/.github/workflows/gh-aw-bug-hunter.lock.yml +++ b/.github/workflows/gh-aw-bug-hunter.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"ef21ef9e9db17115b521eea75b1098a7e250a4495331fb0f23166e78979cd13f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"ea15e8f22f140545f52922d4b8053a1d4c7395e7f1002fe94b991bfd88ceac89"} name: "Bug Hunter" "on": @@ -599,7 +599,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -607,6 +607,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-code-duplication-detector.lock.yml b/.github/workflows/gh-aw-code-duplication-detector.lock.yml index 916bd978..7e5e59a9 100644 --- a/.github/workflows/gh-aw-code-duplication-detector.lock.yml +++ b/.github/workflows/gh-aw-code-duplication-detector.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"7c3c4de3a2718779a11db13132c336c840c7bad9f6a5d6d66df8680401c59b7e"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b7c9de1e3fc79e70e5a30793b21f3748781fbe7926225724bb1fa576e3e92ae3"} name: "Code Duplication Detector" "on": @@ -644,7 +644,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -652,6 +652,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-code-duplication-fixer.lock.yml b/.github/workflows/gh-aw-code-duplication-fixer.lock.yml index c80772d2..6e6b11ee 100644 --- a/.github/workflows/gh-aw-code-duplication-fixer.lock.yml +++ b/.github/workflows/gh-aw-code-duplication-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"bb7aaec4d46c4fd1735e301a045d4a75ed19ae00193b4d4589446e910fcaee31"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"20c8f1a7ddd18d5b9e5596b052662c695ce9e398012cb5d02b374481e929efc3"} name: "Code Duplication Fixer" "on": @@ -514,7 +514,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -522,6 +522,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-code-simplifier.lock.yml b/.github/workflows/gh-aw-code-simplifier.lock.yml index 14e55770..93fb4944 100644 --- a/.github/workflows/gh-aw-code-simplifier.lock.yml +++ b/.github/workflows/gh-aw-code-simplifier.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0d2b6c05c633aab7c3f691918e60e77c216872bc01bdc7cc0960dc341aaa32b1"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1dd217c27d801a10753f45e835ebf26461c5cdb7effaf0d738a18a46c10ad048"} name: "Code Simplifier" "on": @@ -529,7 +529,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -537,6 +537,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-deep-research.lock.yml b/.github/workflows/gh-aw-deep-research.lock.yml index b0965443..620341a7 100644 --- a/.github/workflows/gh-aw-deep-research.lock.yml +++ b/.github/workflows/gh-aw-deep-research.lock.yml @@ -35,7 +35,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"27d2caa68b0f61eb756746772f601a036434d8212d4803cc5a4402fa769ea05a"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c9e19ea7a2dc5f7377cf623b671a9325b3243378e58e67f00306865a804638d2"} name: "Deep Research" "on": @@ -495,7 +495,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -503,6 +503,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-dependency-review.lock.yml b/.github/workflows/gh-aw-dependency-review.lock.yml index 83309c02..2b0bc688 100644 --- a/.github/workflows/gh-aw-dependency-review.lock.yml +++ b/.github/workflows/gh-aw-dependency-review.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"cdbf9e46b3d92ff76279c32420d49a89d42ccaf63af514b745ec360279eeaefb"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e127b7a9296830bfe921c071435d7f3d3220094b1f3748d0aecd541b9176d58a"} name: "Dependency Review" "on": @@ -629,7 +629,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -637,6 +637,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-docs-drift.lock.yml b/.github/workflows/gh-aw-docs-drift.lock.yml index 249705ab..b6f3c8b1 100644 --- a/.github/workflows/gh-aw-docs-drift.lock.yml +++ b/.github/workflows/gh-aw-docs-drift.lock.yml @@ -45,7 +45,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"66bbbb473d86204ed1ecd6201d3a2640ea5fd714ab9d1360cf361c98aeed47dd"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"7d87728633bfa4827a2f3d44b29e8e85189a00590ba228b01abc9ebd8655d13a"} name: "Docs Patrol" "on": @@ -617,7 +617,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -625,6 +625,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-docs-patrol.lock.yml b/.github/workflows/gh-aw-docs-patrol.lock.yml index 174f481c..bdfa45aa 100644 --- a/.github/workflows/gh-aw-docs-patrol.lock.yml +++ b/.github/workflows/gh-aw-docs-patrol.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"66bbbb473d86204ed1ecd6201d3a2640ea5fd714ab9d1360cf361c98aeed47dd"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"7d87728633bfa4827a2f3d44b29e8e85189a00590ba228b01abc9ebd8655d13a"} name: "Docs Patrol" "on": @@ -612,7 +612,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -620,6 +620,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-estc-actions-resource-not-accessible-detector.lock.yml b/.github/workflows/gh-aw-estc-actions-resource-not-accessible-detector.lock.yml index ef07e1e8..00979663 100644 --- a/.github/workflows/gh-aw-estc-actions-resource-not-accessible-detector.lock.yml +++ b/.github/workflows/gh-aw-estc-actions-resource-not-accessible-detector.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b6ba8cee4eb0375c45e815c6ab950a04253ddd1b30752434ff14c08d25ead129"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"34a006295a5d6282e25f7b0ef67380b1d110647c8b80fe09cf4a59b935b40b98"} name: "Resource Not Accessible By Integration Detector" "on": @@ -564,7 +564,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -572,6 +572,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-estc-docs-patrol-external.lock.yml b/.github/workflows/gh-aw-estc-docs-patrol-external.lock.yml index e560653d..d21f4b2e 100644 --- a/.github/workflows/gh-aw-estc-docs-patrol-external.lock.yml +++ b/.github/workflows/gh-aw-estc-docs-patrol-external.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a32488c56a0c8029eba48d3d75b782ecf75e83ba942995f7b6ad8d77a07837d8"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9201a43ea2c6da9afdc3599346e1f2cb5e50656f0c8a11781588c87a4bac5ae2"} name: "Estc Docs Patrol External" "on": @@ -603,7 +603,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -611,6 +611,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-estc-docs-pr-review.lock.yml b/.github/workflows/gh-aw-estc-docs-pr-review.lock.yml index a2702553..6114bf0c 100644 --- a/.github/workflows/gh-aw-estc-docs-pr-review.lock.yml +++ b/.github/workflows/gh-aw-estc-docs-pr-review.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"98d361cdb91c9fdd42daa8e6d3936f57e422549d7dffdc9f1edafbdb2ba94257"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"12692d7c7baa56ee3760b0b5beaca26eca375a1aabc74e386eb5db9af8c66db6"} name: "Estc Docs PR Review" "on": @@ -629,7 +629,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -637,6 +637,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - name: Download style guide reference pages run: "set -euo pipefail\nmkdir -p /tmp/style-guide\nurls=(\n \"https://www.elastic.co/docs/contribute-docs/style-guide\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/voice-tone\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/grammar-spelling\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/formatting\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/word-choice\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/accessibility\"\n \"https://www.elastic.co/docs/contribute-docs/style-guide/ui-writing\"\n \"https://www.elastic.co/docs/contribute-docs/how-to/cumulative-docs/guidelines\"\n \"https://www.elastic.co/docs/contribute-docs/how-to/cumulative-docs/reference\"\n \"https://docs-v3-preview.elastic.dev/elastic/docs-builder/tree/main/syntax/applies\"\n)\nfor url in \"${urls[@]}\"; do\n slug=$(echo \"$url\" | sed 's|https\\?://||; s|/|_|g; s|[^a-zA-Z0-9_-]||g')\n curl -sSfL --retry 2 --max-time 30 \"$url\" -o \"/tmp/style-guide/${slug}.html\" || echo \"::warning::Failed to download ${url}\"\ndone\necho \"Downloaded $(ls /tmp/style-guide/ | wc -l) style guide pages to /tmp/style-guide/\"\n" - env: diff --git a/.github/workflows/gh-aw-estc-downstream-health.lock.yml b/.github/workflows/gh-aw-estc-downstream-health.lock.yml index f9435446..730445ce 100644 --- a/.github/workflows/gh-aw-estc-downstream-health.lock.yml +++ b/.github/workflows/gh-aw-estc-downstream-health.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"3e2c8e2e8ca23305968f2184a03e89988d03ac2d765652d2210103bd31b49ad7"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"21c08a060fd9e852e76f9b6cfa749e3e4f7e125630a27f4e8daef7c57909f4ff"} name: "Estc Downstream Health" "on": @@ -612,7 +612,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -620,6 +620,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-estc-newbie-contributor-patrol-external.lock.yml b/.github/workflows/gh-aw-estc-newbie-contributor-patrol-external.lock.yml index 3fdf6621..57a5e67b 100644 --- a/.github/workflows/gh-aw-estc-newbie-contributor-patrol-external.lock.yml +++ b/.github/workflows/gh-aw-estc-newbie-contributor-patrol-external.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"7522b0f33af527ff95b45fe8742e2ae7a6de8f104ba41ab5ad05d5ad71736411"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b7ffa4522d17935ff9504389b1630d15645277cec6e90b6659e0477947a0564d"} name: "Estc Newbie Contributor Patrol External" "on": @@ -551,7 +551,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -559,6 +559,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-estc-pr-buildkite-detective.lock.yml b/.github/workflows/gh-aw-estc-pr-buildkite-detective.lock.yml index 615d150a..0293ce90 100644 --- a/.github/workflows/gh-aw-estc-pr-buildkite-detective.lock.yml +++ b/.github/workflows/gh-aw-estc-pr-buildkite-detective.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"42e634b12d0e689011ec9326d55cb3312faab79b5c7452ed01375f2d67f1ed7a"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5a57dde9ff3d0576701b09a47766052d6412d8c58ebea4896ff41a4b8e1975d0"} name: "PR Buildkite Detective" "on": @@ -564,7 +564,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -572,6 +572,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - name: Resolve event context run: | set -euo pipefail diff --git a/.github/workflows/gh-aw-flaky-test-investigator.lock.yml b/.github/workflows/gh-aw-flaky-test-investigator.lock.yml index b76a9923..a65ddeca 100644 --- a/.github/workflows/gh-aw-flaky-test-investigator.lock.yml +++ b/.github/workflows/gh-aw-flaky-test-investigator.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2a20d3a48ebdef0ee93034c039ae48b1e24eda8975476abc96ff21d702d82e0f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9c08afe1327933930f4699c0c001a6b39ff24e246509864b2ec8b0372a3facac"} name: "Flaky Test Investigator" "on": @@ -563,7 +563,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -571,6 +571,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-fragments/pr-context.md b/.github/workflows/gh-aw-fragments/pr-context.md index bac69c97..a859c20b 100644 --- a/.github/workflows/gh-aw-fragments/pr-context.md +++ b/.github/workflows/gh-aw-fragments/pr-context.md @@ -29,6 +29,14 @@ steps: echo "$entry" | jq -r '.patch // empty' > "/tmp/pr-context/diffs/${filename}.diff" done + # File orderings for sub-agent review (3 strategies) + jq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \ + > /tmp/pr-context/file_order_az.txt + jq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \ + > /tmp/pr-context/file_order_za.txt + jq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \ + > /tmp/pr-context/file_order_largest.txt + # Existing reviews gh api "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" --paginate \ | jq -s 'add // []' > /tmp/pr-context/reviews.json @@ -105,6 +113,9 @@ steps: | `pr.diff` | Full unified diff of all changes | | `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` | | `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` | + | `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line | + | `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line | + | `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line | | `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body | | `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author | | `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` | diff --git a/.github/workflows/gh-aw-fragments/runtime-setup.md b/.github/workflows/gh-aw-fragments/runtime-setup.md index 67f905f5..98aaafba 100644 --- a/.github/workflows/gh-aw-fragments/runtime-setup.md +++ b/.github/workflows/gh-aw-fragments/runtime-setup.md @@ -50,4 +50,16 @@ steps: cp "$UV_PATH" "$install_dir/uv" chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" + + - name: Configure Copilot CLI settings + shell: bash + run: | + set -euo pipefail + mkdir -p ~/.copilot + CONFIG="$HOME/.copilot/config.json" + if [ -f "$CONFIG" ]; then + jq '. + {"chat.customAgentInSubagent.enabled": true}' "$CONFIG" > "$CONFIG.tmp" && mv "$CONFIG.tmp" "$CONFIG" + else + echo '{"chat.customAgentInSubagent.enabled":true}' > "$CONFIG" + fi --- diff --git a/.github/workflows/gh-aw-framework-best-practices.lock.yml b/.github/workflows/gh-aw-framework-best-practices.lock.yml index 342d846a..26094b83 100644 --- a/.github/workflows/gh-aw-framework-best-practices.lock.yml +++ b/.github/workflows/gh-aw-framework-best-practices.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"093850fadff9e9b68d742b737199d7354eca59130936f670807ad47f373ff5d3"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a506c3d1c642f61a259db6ab04065cb100d171c09a0591c909e0ac78db642d8b"} name: "Framework Best Practices" "on": @@ -608,7 +608,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -616,6 +616,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-information-architecture.lock.yml b/.github/workflows/gh-aw-information-architecture.lock.yml index 83988550..096a701f 100644 --- a/.github/workflows/gh-aw-information-architecture.lock.yml +++ b/.github/workflows/gh-aw-information-architecture.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5e08e3e5c45114c1cce3be8dc800f21e6579246378ccdf43dd94621a6911abd9"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d8e316890682ffe0175df845ff2c5867d7a460d202081145e97783f83058bc61"} name: "Information Architecture" "on": @@ -603,7 +603,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -611,6 +611,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-issue-fixer.lock.yml b/.github/workflows/gh-aw-issue-fixer.lock.yml index e3a097ee..02ac88fd 100644 --- a/.github/workflows/gh-aw-issue-fixer.lock.yml +++ b/.github/workflows/gh-aw-issue-fixer.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"72c94eb38a709725cfed3a3e99d575dc9d93d7c654f20e4540dcac1a8698d5dc"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"38f1a8915f4a710c85bb4bb481fcd8f5a16fc304c1ec8975935d366c2eac8f04"} name: "Issue Fixer" "on": @@ -523,7 +523,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -531,6 +531,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-issue-triage.lock.yml b/.github/workflows/gh-aw-issue-triage.lock.yml index db0a4c45..c666524e 100644 --- a/.github/workflows/gh-aw-issue-triage.lock.yml +++ b/.github/workflows/gh-aw-issue-triage.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"faee5abe5d7ca73e9a54a48dd721aea4a29a644d035ab9f56aca6bc16ce8b9c4"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"4d1f8d46281d03cee75d906281b5fe60ea685f2f86592b11bca6fd662f5c379d"} name: "Issue Triage" "on": @@ -550,7 +550,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -558,6 +558,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml index f5b1579d..6cb5a8df 100644 --- a/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml +++ b/.github/workflows/gh-aw-mention-in-issue-no-sandbox.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"54a63f522d6040758fcb860c66b5e6ffba194e80bff65818ae64b9012150c25f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"5bfcb667b2eba53298d9d9cca9697fe53c865a0630c15bd0e9a4369b6d1f1731"} name: "Mention in Issue (no sandbox)" "on": @@ -539,7 +539,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -547,6 +547,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-mention-in-issue.lock.yml b/.github/workflows/gh-aw-mention-in-issue.lock.yml index a2feb56e..575e2462 100644 --- a/.github/workflows/gh-aw-mention-in-issue.lock.yml +++ b/.github/workflows/gh-aw-mention-in-issue.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2ded4a298690475553c0f0f61d4fb5a3a4bb04e89d59e7559a521b9fc81abc39"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c8178043454e97abbcd7fd7885e3f0144c1ae947263f00ff78296bfc7792e375"} name: "Mention in Issue" "on": @@ -541,7 +541,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -549,6 +549,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml b/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml index 1f96af55..14bc4de2 100644 --- a/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr-by-id.lock.yml @@ -43,7 +43,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"348bb144fcffb257a123572220f49d538279c90a52b15fe61b45c89b846695b5"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f043fc0691132592cc78f7aa21ce5968eddce5733a24562b6dd4ee676e32744c"} name: "Mention in PR by ID" "on": @@ -637,7 +637,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -645,11 +645,14 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || inputs.target-pr-number || github.event.issue.number }} name: Fetch PR context to disk - run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" + run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# File orderings for sub-agent review (3 strategies)\njq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_az.txt\njq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_za.txt\njq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_largest.txt\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line |\n| `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line |\n| `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" - name: Write review instructions to disk run: "mkdir -p /tmp/pr-context\ncat > /tmp/pr-context/review-instructions.md << 'REVIEW_EOF'\n# Review Instructions for Sub-agents\n\nYou are a code review sub-agent. Read these instructions, then review the PR files in the order provided in your prompt.\n\n## Context\n\nBefore reviewing files, read these to understand the PR:\n\n1. `/tmp/pr-context/pr.json` — PR title, description, author, and branches. Understand what the PR is trying to accomplish.\n2. `/tmp/pr-context/agents.md` — Repository coding conventions and guidelines (if it exists).\n3. `/tmp/pr-context/review_comments.json` — Existing review threads. Note which files already have threads so you don't duplicate.\n4. `/tmp/pr-context/issue-*.json` — Linked issue details (if any). Understand the motivation and acceptance criteria.\n\n## Process\n\nReview the PR diff file by file in your assigned order. For each changed file:\n\n1. **Read the diff** for this file from `/tmp/pr-context/diffs/.diff` to understand what changed. If the diff is empty or truncated (e.g., binary files or very large changes), fall back to reading the full file from the workspace and comparing against context.\n2. **Read the full file from the workspace.** The PR branch is checked out locally — open the file directly to get complete contents with line numbers.\n3. **Check existing threads** for this file from `/tmp/pr-context/threads/.json` (if it exists). Skip issues that are already under discussion — each thread has `isResolved` and `isOutdated` fields.\n4. **Identify potential issues** matching the review criteria below.\n5. **Quick-check each issue** before including it:\n - What specific code pattern or change triggers this concern?\n - Is there an obvious guard, handler, or mitigation visible in the immediate context?\n - Can you describe a concrete failure scenario (the `evidence` field)? If you cannot articulate what specific input or state triggers the problem, drop the finding.\n - If the issue is clearly handled, skip it. If you're unsure, include it — the parent will verify.\n6. **Add to your findings list.** Do NOT leave inline comments — you don't have that tool. Return findings in this format:\n\n```\n- file: path/to/file\n line: 42\n severity: HIGH\n title: Brief title\n description: What the issue is and why it matters\n evidence: The specific code pattern and failure scenario\n suggestion: corrected code here (optional — only if you can provide a concrete fix)\n```\n\n**Review every file in your assigned order.** Files reviewed earlier get more attention, which is why different sub-agents use different orderings.\n\n**Check existing threads** — per-file threads are at `/tmp/pr-context/threads/.json` (step 3 above). The full list is at `/tmp/pr-context/review_comments.json`. Do not flag issues that are already under discussion (resolved or unresolved). For outdated threads, only re-flag if the issue still applies to the current diff.\n\n**Return your full findings list** when done, or an empty list if no issues were found.\n\n## Review Criteria\n\nFocus on these categories in priority order:\n\n1. Security vulnerabilities (injection, XSS, auth bypass, secrets exposure)\n2. Logic bugs that could cause runtime failures or incorrect behavior\n3. Data integrity issues (race conditions, missing transactions, corruption risk)\n4. Performance bottlenecks (N+1 queries, memory leaks, blocking operations)\n5. Error handling gaps (unhandled exceptions, missing validation)\n6. Breaking changes to public APIs without migration path\n7. Missing or incorrect test coverage for critical paths\n\n## What NOT to Flag\n\nOnly review the diff — do not flag issues in unchanged code, pre-existing problems not introduced by this PR, or style preferences handled by linters or formatters.\n\n**Common false positives** — these patterns look like issues but usually aren't. Before flagging anything in these categories, confirm the problem is real by reading the surrounding code:\n\n- **Security — input already sanitized:** Don't flag injection or XSS risks when inputs are sanitized upstream, parameterized queries are used, or the framework auto-escapes output.\n- **Null/undefined — guarded elsewhere:** Don't flag potential null dereferences if the value is guaranteed by a type guard, assertion, schema validation, or upstream null check.\n- **Error handling — handled at a different layer:** Don't flag missing try/catch if the caller, middleware, or framework catches and handles the error (e.g., Express error middleware, React error boundaries).\n- **Performance — theoretical, not practical:** Don't flag algorithmic complexity (e.g., O(n^2)) unless N is demonstrably large enough to matter in the actual usage context. \"This could be slow\" without evidence is not actionable.\n- **Validation — exists at another layer:** Don't flag missing input validation if it's handled by an API gateway, middleware, schema validator, or type system.\n- **Test coverage — trivial or generated code:** Don't flag missing tests for trivial getters/setters, auto-generated code, or simple delegation methods.\n- **Style or naming — not in coding guidelines:** Don't flag naming conventions or code style unless they violate the repository's documented coding guidelines (from `generate_agents_md` or CONTRIBUTING docs).\n\n**Existing review threads** — check BEFORE flagging any issue:\n\n- **Resolved with reviewer reply** (e.g. \"This is intentional\") — reviewer's decision is final. Do NOT re-flag.\n- **Resolved without reply** — author likely fixed it. Do NOT re-raise unless the fix introduced a new problem.\n- **Unresolved** — already flagged. Do NOT duplicate.\n- **Outdated** — only re-flag if the issue still applies to the current diff.\n\nWhen in doubt, do not duplicate. Redundant comments erode trust.\n\nFinding no issues is a valid and valuable outcome. An empty findings list is better than findings that waste the author's time or erode trust. Do not manufacture findings to justify your review — if the code is sound, return an empty list.\n\n## Severity Classification\n\nDetermine severity AFTER investigating the issue, not before. First identify the problem and trace through the code, then assign a severity based on the evidence you found.\n\n- 🔴 CRITICAL — Must fix before merge (security vulnerabilities, data corruption, production-breaking bugs)\n- 🟠 HIGH — Should fix before merge (logic errors, missing validation, significant performance issues)\n- 🟡 MEDIUM — Address soon, non-blocking (error handling gaps, suboptimal patterns, missing edge cases)\n- ⚪ LOW — Author discretion (minor improvements, documentation gaps)\n- 💬 NITPICK — Truly optional (stylistic preferences, alternative approaches)\n\n## Review Intensity\n\nThe review intensity is `${{ inputs.intensity || 'balanced' }}`.\n\n- **conservative**: High evidence bar. Only flag when you can demonstrate a concrete failure scenario. If you can construct a reasonable counterargument, do not flag. Approval with zero findings is the expected outcome for most PRs.\n- **balanced**: Standard evidence bar. Flag when you can point to specific code that would fail. If the issue is ambiguous, lean toward not flagging.\n- **aggressive**: Lower evidence bar. Flag when evidence exists even if the failure scenario is not fully confirmed. Improvement suggestions welcome but must cite specific code.\n\n## Calibration Examples\n\nUse these examples to calibrate your judgment. Each pair shows a real issue and a similar-looking pattern that is NOT an issue.\n\n### Example 1: Null/Undefined Access\n\n**True positive — flag this:**\n\n```js\n// PR adds this handler\napp.get('/user/:id', async (req, res) => {\n const user = await db.findUser(req.params.id);\n res.json({ name: user.name, email: user.email });\n});\n```\n\nWhy flag: `db.findUser()` can return `null` when no user matches the ID. Accessing `user.name` will throw a TypeError at runtime. No upstream guard exists — the route handler is the entry point.\n\n**False positive — do NOT flag this:**\n\n```ts\n// PR adds this line inside an existing function\nconst settings = user.getSettings();\n```\n\nWhy skip: Reading the full file reveals `user` is typed as `User` (not `User | null`), and the calling function only runs after `authenticateUser()` middleware which guarantees a valid user object. The null case is handled at a different layer.\n\n### Example 2: SQL Injection\n\n**True positive — flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE customer_id = '{customer_id}'\")\n```\n\nWhy flag: String interpolation in a SQL query with user-controlled input (`customer_id` comes from the request). No parameterization or sanitization anywhere in the call chain.\n\n**False positive — do NOT flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE status = '{OrderStatus.PENDING.value}'\")\n```\n\nWhy skip: The interpolated value is a hardcoded enum constant (`OrderStatus.PENDING`), not user input. There is no injection vector.\n\n### Example 3: Borderline — Do NOT Flag\n\n```go\n// PR adds this function\nfunc processItems(items []Item) []Result {\n results := make([]Result, 0)\n for _, item := range items {\n for _, tag := range item.Tags {\n results = append(results, process(item, tag))\n }\n }\n return results\n}\n```\n\nThis looks like an O(n*m) performance concern. But without evidence that `items` or `Tags` are large in practice, this is speculative. The function processes a bounded dataset (items from a single user request). Do not flag theoretical performance issues without evidence of real-world impact.\nREVIEW_EOF" - env: diff --git a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml index 1904b3bc..37505db5 100644 --- a/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr-no-sandbox.lock.yml @@ -44,7 +44,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e3f38a4324efedbed42d66c68f23e3f24397eae498756c8a0fff7a348db99f86"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"764aa68cced612fafebc99df7d93376341b5031834e5c0e6363a66671047ebef"} name: "Mention in PR (no sandbox)" "on": @@ -711,7 +711,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -719,11 +719,14 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || inputs.target-pr-number || github.event.issue.number }} name: Fetch PR context to disk - run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" + run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# File orderings for sub-agent review (3 strategies)\njq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_az.txt\njq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_za.txt\njq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_largest.txt\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line |\n| `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line |\n| `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" - name: Write review instructions to disk run: "mkdir -p /tmp/pr-context\ncat > /tmp/pr-context/review-instructions.md << 'REVIEW_EOF'\n# Review Instructions for Sub-agents\n\nYou are a code review sub-agent. Read these instructions, then review the PR files in the order provided in your prompt.\n\n## Context\n\nBefore reviewing files, read these to understand the PR:\n\n1. `/tmp/pr-context/pr.json` — PR title, description, author, and branches. Understand what the PR is trying to accomplish.\n2. `/tmp/pr-context/agents.md` — Repository coding conventions and guidelines (if it exists).\n3. `/tmp/pr-context/review_comments.json` — Existing review threads. Note which files already have threads so you don't duplicate.\n4. `/tmp/pr-context/issue-*.json` — Linked issue details (if any). Understand the motivation and acceptance criteria.\n\n## Process\n\nReview the PR diff file by file in your assigned order. For each changed file:\n\n1. **Read the diff** for this file from `/tmp/pr-context/diffs/.diff` to understand what changed. If the diff is empty or truncated (e.g., binary files or very large changes), fall back to reading the full file from the workspace and comparing against context.\n2. **Read the full file from the workspace.** The PR branch is checked out locally — open the file directly to get complete contents with line numbers.\n3. **Check existing threads** for this file from `/tmp/pr-context/threads/.json` (if it exists). Skip issues that are already under discussion — each thread has `isResolved` and `isOutdated` fields.\n4. **Identify potential issues** matching the review criteria below.\n5. **Quick-check each issue** before including it:\n - What specific code pattern or change triggers this concern?\n - Is there an obvious guard, handler, or mitigation visible in the immediate context?\n - Can you describe a concrete failure scenario (the `evidence` field)? If you cannot articulate what specific input or state triggers the problem, drop the finding.\n - If the issue is clearly handled, skip it. If you're unsure, include it — the parent will verify.\n6. **Add to your findings list.** Do NOT leave inline comments — you don't have that tool. Return findings in this format:\n\n```\n- file: path/to/file\n line: 42\n severity: HIGH\n title: Brief title\n description: What the issue is and why it matters\n evidence: The specific code pattern and failure scenario\n suggestion: corrected code here (optional — only if you can provide a concrete fix)\n```\n\n**Review every file in your assigned order.** Files reviewed earlier get more attention, which is why different sub-agents use different orderings.\n\n**Check existing threads** — per-file threads are at `/tmp/pr-context/threads/.json` (step 3 above). The full list is at `/tmp/pr-context/review_comments.json`. Do not flag issues that are already under discussion (resolved or unresolved). For outdated threads, only re-flag if the issue still applies to the current diff.\n\n**Return your full findings list** when done, or an empty list if no issues were found.\n\n## Review Criteria\n\nFocus on these categories in priority order:\n\n1. Security vulnerabilities (injection, XSS, auth bypass, secrets exposure)\n2. Logic bugs that could cause runtime failures or incorrect behavior\n3. Data integrity issues (race conditions, missing transactions, corruption risk)\n4. Performance bottlenecks (N+1 queries, memory leaks, blocking operations)\n5. Error handling gaps (unhandled exceptions, missing validation)\n6. Breaking changes to public APIs without migration path\n7. Missing or incorrect test coverage for critical paths\n\n## What NOT to Flag\n\nOnly review the diff — do not flag issues in unchanged code, pre-existing problems not introduced by this PR, or style preferences handled by linters or formatters.\n\n**Common false positives** — these patterns look like issues but usually aren't. Before flagging anything in these categories, confirm the problem is real by reading the surrounding code:\n\n- **Security — input already sanitized:** Don't flag injection or XSS risks when inputs are sanitized upstream, parameterized queries are used, or the framework auto-escapes output.\n- **Null/undefined — guarded elsewhere:** Don't flag potential null dereferences if the value is guaranteed by a type guard, assertion, schema validation, or upstream null check.\n- **Error handling — handled at a different layer:** Don't flag missing try/catch if the caller, middleware, or framework catches and handles the error (e.g., Express error middleware, React error boundaries).\n- **Performance — theoretical, not practical:** Don't flag algorithmic complexity (e.g., O(n^2)) unless N is demonstrably large enough to matter in the actual usage context. \"This could be slow\" without evidence is not actionable.\n- **Validation — exists at another layer:** Don't flag missing input validation if it's handled by an API gateway, middleware, schema validator, or type system.\n- **Test coverage — trivial or generated code:** Don't flag missing tests for trivial getters/setters, auto-generated code, or simple delegation methods.\n- **Style or naming — not in coding guidelines:** Don't flag naming conventions or code style unless they violate the repository's documented coding guidelines (from `generate_agents_md` or CONTRIBUTING docs).\n\n**Existing review threads** — check BEFORE flagging any issue:\n\n- **Resolved with reviewer reply** (e.g. \"This is intentional\") — reviewer's decision is final. Do NOT re-flag.\n- **Resolved without reply** — author likely fixed it. Do NOT re-raise unless the fix introduced a new problem.\n- **Unresolved** — already flagged. Do NOT duplicate.\n- **Outdated** — only re-flag if the issue still applies to the current diff.\n\nWhen in doubt, do not duplicate. Redundant comments erode trust.\n\nFinding no issues is a valid and valuable outcome. An empty findings list is better than findings that waste the author's time or erode trust. Do not manufacture findings to justify your review — if the code is sound, return an empty list.\n\n## Severity Classification\n\nDetermine severity AFTER investigating the issue, not before. First identify the problem and trace through the code, then assign a severity based on the evidence you found.\n\n- 🔴 CRITICAL — Must fix before merge (security vulnerabilities, data corruption, production-breaking bugs)\n- 🟠 HIGH — Should fix before merge (logic errors, missing validation, significant performance issues)\n- 🟡 MEDIUM — Address soon, non-blocking (error handling gaps, suboptimal patterns, missing edge cases)\n- ⚪ LOW — Author discretion (minor improvements, documentation gaps)\n- 💬 NITPICK — Truly optional (stylistic preferences, alternative approaches)\n\n## Review Intensity\n\nThe review intensity is `${{ inputs.intensity || 'balanced' }}`.\n\n- **conservative**: High evidence bar. Only flag when you can demonstrate a concrete failure scenario. If you can construct a reasonable counterargument, do not flag. Approval with zero findings is the expected outcome for most PRs.\n- **balanced**: Standard evidence bar. Flag when you can point to specific code that would fail. If the issue is ambiguous, lean toward not flagging.\n- **aggressive**: Lower evidence bar. Flag when evidence exists even if the failure scenario is not fully confirmed. Improvement suggestions welcome but must cite specific code.\n\n## Calibration Examples\n\nUse these examples to calibrate your judgment. Each pair shows a real issue and a similar-looking pattern that is NOT an issue.\n\n### Example 1: Null/Undefined Access\n\n**True positive — flag this:**\n\n```js\n// PR adds this handler\napp.get('/user/:id', async (req, res) => {\n const user = await db.findUser(req.params.id);\n res.json({ name: user.name, email: user.email });\n});\n```\n\nWhy flag: `db.findUser()` can return `null` when no user matches the ID. Accessing `user.name` will throw a TypeError at runtime. No upstream guard exists — the route handler is the entry point.\n\n**False positive — do NOT flag this:**\n\n```ts\n// PR adds this line inside an existing function\nconst settings = user.getSettings();\n```\n\nWhy skip: Reading the full file reveals `user` is typed as `User` (not `User | null`), and the calling function only runs after `authenticateUser()` middleware which guarantees a valid user object. The null case is handled at a different layer.\n\n### Example 2: SQL Injection\n\n**True positive — flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE customer_id = '{customer_id}'\")\n```\n\nWhy flag: String interpolation in a SQL query with user-controlled input (`customer_id` comes from the request). No parameterization or sanitization anywhere in the call chain.\n\n**False positive — do NOT flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE status = '{OrderStatus.PENDING.value}'\")\n```\n\nWhy skip: The interpolated value is a hardcoded enum constant (`OrderStatus.PENDING`), not user input. There is no injection vector.\n\n### Example 3: Borderline — Do NOT Flag\n\n```go\n// PR adds this function\nfunc processItems(items []Item) []Result {\n results := make([]Result, 0)\n for _, item := range items {\n for _, tag := range item.Tags {\n results = append(results, process(item, tag))\n }\n }\n return results\n}\n```\n\nThis looks like an O(n*m) performance concern. But without evidence that `items` or `Tags` are large in practice, this is speculative. The function processes a bounded dataset (items from a single user request). Do not flag theoretical performance issues without evidence of real-world impact.\nREVIEW_EOF" - env: diff --git a/.github/workflows/gh-aw-mention-in-pr.lock.yml b/.github/workflows/gh-aw-mention-in-pr.lock.yml index e2cc4644..af53e3c7 100644 --- a/.github/workflows/gh-aw-mention-in-pr.lock.yml +++ b/.github/workflows/gh-aw-mention-in-pr.lock.yml @@ -44,7 +44,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8d20590bf294d888940de1885bc1e17dba9d0e7a58b0808cdac0022034157222"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"fe4c371271b200c834cbcbfd5c5a34a949df5b303d0abc5ed3b3a0c72640d893"} name: "Mention in PR" "on": @@ -712,7 +712,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -720,11 +720,14 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || inputs.target-pr-number || github.event.issue.number }} name: Fetch PR context to disk - run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" + run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# File orderings for sub-agent review (3 strategies)\njq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_az.txt\njq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_za.txt\njq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_largest.txt\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line |\n| `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line |\n| `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" - name: Write review instructions to disk run: "mkdir -p /tmp/pr-context\ncat > /tmp/pr-context/review-instructions.md << 'REVIEW_EOF'\n# Review Instructions for Sub-agents\n\nYou are a code review sub-agent. Read these instructions, then review the PR files in the order provided in your prompt.\n\n## Context\n\nBefore reviewing files, read these to understand the PR:\n\n1. `/tmp/pr-context/pr.json` — PR title, description, author, and branches. Understand what the PR is trying to accomplish.\n2. `/tmp/pr-context/agents.md` — Repository coding conventions and guidelines (if it exists).\n3. `/tmp/pr-context/review_comments.json` — Existing review threads. Note which files already have threads so you don't duplicate.\n4. `/tmp/pr-context/issue-*.json` — Linked issue details (if any). Understand the motivation and acceptance criteria.\n\n## Process\n\nReview the PR diff file by file in your assigned order. For each changed file:\n\n1. **Read the diff** for this file from `/tmp/pr-context/diffs/.diff` to understand what changed. If the diff is empty or truncated (e.g., binary files or very large changes), fall back to reading the full file from the workspace and comparing against context.\n2. **Read the full file from the workspace.** The PR branch is checked out locally — open the file directly to get complete contents with line numbers.\n3. **Check existing threads** for this file from `/tmp/pr-context/threads/.json` (if it exists). Skip issues that are already under discussion — each thread has `isResolved` and `isOutdated` fields.\n4. **Identify potential issues** matching the review criteria below.\n5. **Quick-check each issue** before including it:\n - What specific code pattern or change triggers this concern?\n - Is there an obvious guard, handler, or mitigation visible in the immediate context?\n - Can you describe a concrete failure scenario (the `evidence` field)? If you cannot articulate what specific input or state triggers the problem, drop the finding.\n - If the issue is clearly handled, skip it. If you're unsure, include it — the parent will verify.\n6. **Add to your findings list.** Do NOT leave inline comments — you don't have that tool. Return findings in this format:\n\n```\n- file: path/to/file\n line: 42\n severity: HIGH\n title: Brief title\n description: What the issue is and why it matters\n evidence: The specific code pattern and failure scenario\n suggestion: corrected code here (optional — only if you can provide a concrete fix)\n```\n\n**Review every file in your assigned order.** Files reviewed earlier get more attention, which is why different sub-agents use different orderings.\n\n**Check existing threads** — per-file threads are at `/tmp/pr-context/threads/.json` (step 3 above). The full list is at `/tmp/pr-context/review_comments.json`. Do not flag issues that are already under discussion (resolved or unresolved). For outdated threads, only re-flag if the issue still applies to the current diff.\n\n**Return your full findings list** when done, or an empty list if no issues were found.\n\n## Review Criteria\n\nFocus on these categories in priority order:\n\n1. Security vulnerabilities (injection, XSS, auth bypass, secrets exposure)\n2. Logic bugs that could cause runtime failures or incorrect behavior\n3. Data integrity issues (race conditions, missing transactions, corruption risk)\n4. Performance bottlenecks (N+1 queries, memory leaks, blocking operations)\n5. Error handling gaps (unhandled exceptions, missing validation)\n6. Breaking changes to public APIs without migration path\n7. Missing or incorrect test coverage for critical paths\n\n## What NOT to Flag\n\nOnly review the diff — do not flag issues in unchanged code, pre-existing problems not introduced by this PR, or style preferences handled by linters or formatters.\n\n**Common false positives** — these patterns look like issues but usually aren't. Before flagging anything in these categories, confirm the problem is real by reading the surrounding code:\n\n- **Security — input already sanitized:** Don't flag injection or XSS risks when inputs are sanitized upstream, parameterized queries are used, or the framework auto-escapes output.\n- **Null/undefined — guarded elsewhere:** Don't flag potential null dereferences if the value is guaranteed by a type guard, assertion, schema validation, or upstream null check.\n- **Error handling — handled at a different layer:** Don't flag missing try/catch if the caller, middleware, or framework catches and handles the error (e.g., Express error middleware, React error boundaries).\n- **Performance — theoretical, not practical:** Don't flag algorithmic complexity (e.g., O(n^2)) unless N is demonstrably large enough to matter in the actual usage context. \"This could be slow\" without evidence is not actionable.\n- **Validation — exists at another layer:** Don't flag missing input validation if it's handled by an API gateway, middleware, schema validator, or type system.\n- **Test coverage — trivial or generated code:** Don't flag missing tests for trivial getters/setters, auto-generated code, or simple delegation methods.\n- **Style or naming — not in coding guidelines:** Don't flag naming conventions or code style unless they violate the repository's documented coding guidelines (from `generate_agents_md` or CONTRIBUTING docs).\n\n**Existing review threads** — check BEFORE flagging any issue:\n\n- **Resolved with reviewer reply** (e.g. \"This is intentional\") — reviewer's decision is final. Do NOT re-flag.\n- **Resolved without reply** — author likely fixed it. Do NOT re-raise unless the fix introduced a new problem.\n- **Unresolved** — already flagged. Do NOT duplicate.\n- **Outdated** — only re-flag if the issue still applies to the current diff.\n\nWhen in doubt, do not duplicate. Redundant comments erode trust.\n\nFinding no issues is a valid and valuable outcome. An empty findings list is better than findings that waste the author's time or erode trust. Do not manufacture findings to justify your review — if the code is sound, return an empty list.\n\n## Severity Classification\n\nDetermine severity AFTER investigating the issue, not before. First identify the problem and trace through the code, then assign a severity based on the evidence you found.\n\n- 🔴 CRITICAL — Must fix before merge (security vulnerabilities, data corruption, production-breaking bugs)\n- 🟠 HIGH — Should fix before merge (logic errors, missing validation, significant performance issues)\n- 🟡 MEDIUM — Address soon, non-blocking (error handling gaps, suboptimal patterns, missing edge cases)\n- ⚪ LOW — Author discretion (minor improvements, documentation gaps)\n- 💬 NITPICK — Truly optional (stylistic preferences, alternative approaches)\n\n## Review Intensity\n\nThe review intensity is `${{ inputs.intensity || 'balanced' }}`.\n\n- **conservative**: High evidence bar. Only flag when you can demonstrate a concrete failure scenario. If you can construct a reasonable counterargument, do not flag. Approval with zero findings is the expected outcome for most PRs.\n- **balanced**: Standard evidence bar. Flag when you can point to specific code that would fail. If the issue is ambiguous, lean toward not flagging.\n- **aggressive**: Lower evidence bar. Flag when evidence exists even if the failure scenario is not fully confirmed. Improvement suggestions welcome but must cite specific code.\n\n## Calibration Examples\n\nUse these examples to calibrate your judgment. Each pair shows a real issue and a similar-looking pattern that is NOT an issue.\n\n### Example 1: Null/Undefined Access\n\n**True positive — flag this:**\n\n```js\n// PR adds this handler\napp.get('/user/:id', async (req, res) => {\n const user = await db.findUser(req.params.id);\n res.json({ name: user.name, email: user.email });\n});\n```\n\nWhy flag: `db.findUser()` can return `null` when no user matches the ID. Accessing `user.name` will throw a TypeError at runtime. No upstream guard exists — the route handler is the entry point.\n\n**False positive — do NOT flag this:**\n\n```ts\n// PR adds this line inside an existing function\nconst settings = user.getSettings();\n```\n\nWhy skip: Reading the full file reveals `user` is typed as `User` (not `User | null`), and the calling function only runs after `authenticateUser()` middleware which guarantees a valid user object. The null case is handled at a different layer.\n\n### Example 2: SQL Injection\n\n**True positive — flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE customer_id = '{customer_id}'\")\n```\n\nWhy flag: String interpolation in a SQL query with user-controlled input (`customer_id` comes from the request). No parameterization or sanitization anywhere in the call chain.\n\n**False positive — do NOT flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE status = '{OrderStatus.PENDING.value}'\")\n```\n\nWhy skip: The interpolated value is a hardcoded enum constant (`OrderStatus.PENDING`), not user input. There is no injection vector.\n\n### Example 3: Borderline — Do NOT Flag\n\n```go\n// PR adds this function\nfunc processItems(items []Item) []Result {\n results := make([]Result, 0)\n for _, item := range items {\n for _, tag := range item.Tags {\n results = append(results, process(item, tag))\n }\n }\n return results\n}\n```\n\nThis looks like an O(n*m) performance concern. But without evidence that `items` or `Tags` are large in practice, this is speculative. The function processes a bounded dataset (items from a single user request). Do not flag theoretical performance issues without evidence of real-world impact.\nREVIEW_EOF" - env: diff --git a/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml b/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml index 6bd4ea24..4e43221c 100644 --- a/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml +++ b/.github/workflows/gh-aw-newbie-contributor-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"73718d7f4a6dc547a830f19821394962de7b454fb94c06a0a0fcd1690c7701b6"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"024dac322c2a829d3934945b47e8d4fee6d109bc488ace55b42d8fbbc62c3c58"} name: "Newbie Contributor Fixer" "on": @@ -515,7 +515,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -523,6 +523,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-newbie-contributor-patrol.lock.yml b/.github/workflows/gh-aw-newbie-contributor-patrol.lock.yml index 258e6d25..d1ac0990 100644 --- a/.github/workflows/gh-aw-newbie-contributor-patrol.lock.yml +++ b/.github/workflows/gh-aw-newbie-contributor-patrol.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a19caf81a94b55dae7ec7e97793220c1a40d4693e5adedcc081013797cbdd719"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"878a5e48cc3df644fd1a36b790e6eb19efb2f7938d744bfd0ab337c98409619f"} name: "Newbie Contributor Patrol" "on": @@ -542,7 +542,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -550,6 +550,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-performance-profiler.lock.yml b/.github/workflows/gh-aw-performance-profiler.lock.yml index 5e68b3db..75fc0239 100644 --- a/.github/workflows/gh-aw-performance-profiler.lock.yml +++ b/.github/workflows/gh-aw-performance-profiler.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"b868c97faed6d215ab3d84415133371e5855fb6575a62e2ec848e05d0a22f270"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c68271d69b8bd050f23795aae51ccea0574d633d75c2e81d42cf12db9929e038"} name: "Performance Profiler" "on": @@ -642,7 +642,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -650,6 +650,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-plan.lock.yml b/.github/workflows/gh-aw-plan.lock.yml index b410b15c..93d7f8eb 100644 --- a/.github/workflows/gh-aw-plan.lock.yml +++ b/.github/workflows/gh-aw-plan.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9615cc5f9b93cb7a5d767e425571afec57cfaf0c73d1bb6ee0980532d5582973"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"14cb9e4bd7855c9832967e78cfd69e77723402bd26d41857164f5c019ec7d15d"} name: "Plan" "on": @@ -510,7 +510,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -518,6 +518,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-pr-actions-detective.lock.yml b/.github/workflows/gh-aw-pr-actions-detective.lock.yml index 0cde5eec..62e35ceb 100644 --- a/.github/workflows/gh-aw-pr-actions-detective.lock.yml +++ b/.github/workflows/gh-aw-pr-actions-detective.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"4e5d1107d29decd3b6df3022c6c7de767cdddca98e3cf01106c92eb06b992ff0"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"58c69adeec2e628be014d2bcc28e1a56ab85b69fe0c0bed36e88cb1fcd0ee6cb"} name: "PR Actions Detective" "on": @@ -481,7 +481,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -489,6 +489,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-pr-actions-fixer.lock.yml b/.github/workflows/gh-aw-pr-actions-fixer.lock.yml index f8461cf1..d12ce28b 100644 --- a/.github/workflows/gh-aw-pr-actions-fixer.lock.yml +++ b/.github/workflows/gh-aw-pr-actions-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c711f87882d2c7b8edb9b0c1de8a7822c3bf3e47b8890e4ed2f3acabda9cb216"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e490edb6d9a4e54d16cbbef444ea346179e20b8ad15ccb211e1edb6efc039de2"} name: "PR Actions Fixer" "on": @@ -514,7 +514,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -522,6 +522,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-pr-ci-detective.lock.yml b/.github/workflows/gh-aw-pr-ci-detective.lock.yml index 7cea37dc..a77a747f 100644 --- a/.github/workflows/gh-aw-pr-ci-detective.lock.yml +++ b/.github/workflows/gh-aw-pr-ci-detective.lock.yml @@ -41,7 +41,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"4e5d1107d29decd3b6df3022c6c7de767cdddca98e3cf01106c92eb06b992ff0"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"58c69adeec2e628be014d2bcc28e1a56ab85b69fe0c0bed36e88cb1fcd0ee6cb"} name: "PR Actions Detective" "on": @@ -486,7 +486,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -494,6 +494,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-pr-review-addresser.lock.yml b/.github/workflows/gh-aw-pr-review-addresser.lock.yml index 6faee67a..2bfa2baf 100644 --- a/.github/workflows/gh-aw-pr-review-addresser.lock.yml +++ b/.github/workflows/gh-aw-pr-review-addresser.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9564307564f6118e5125f6b8ddff78b350665801035a5e38eb7ddb58c7372256"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"4f1ee1257f4864d55ec2da7ea89e4f721fd045e23e88ff58a32ed227cf00ba16"} name: "PR Review Addresser" "on": @@ -554,7 +554,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -562,11 +562,14 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || inputs.target-pr-number || github.event.issue.number }} name: Fetch PR context to disk - run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" + run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# File orderings for sub-agent review (3 strategies)\njq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_az.txt\njq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_za.txt\njq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_largest.txt\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line |\n| `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line |\n| `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-pr-review.lock.yml b/.github/workflows/gh-aw-pr-review.lock.yml index 3e493aac..ebdffd12 100644 --- a/.github/workflows/gh-aw-pr-review.lock.yml +++ b/.github/workflows/gh-aw-pr-review.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d941ffb5b429f1f46680b2464a5997d02b5a2c64fa030af30bd120e30ea5deaa"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1b2161458056b26894b5284f34bbf728738acc188f845d353b31224304013428"} name: "PR Review" "on": @@ -459,16 +459,16 @@ jobs: ### Step 2: Sub-agent Review - **Compute file orderings:** Read `/tmp/pr-context/files.json` to get the changed file list with `additions` and `deletions` counts per file. Compute three orderings: - - **Agent 1**: Files in alphabetical order (A → Z) - - **Agent 2**: Files in reverse alphabetical order (Z → A) - - **Agent 3**: Files sorted by diff size descending (largest `additions + deletions` first) + **File orderings are pre-computed** at `/tmp/pr-context/`: + - **Agent 1**: `/tmp/pr-context/file_order_az.txt` — alphabetical (A → Z) + - **Agent 2**: `/tmp/pr-context/file_order_za.txt` — reverse alphabetical (Z → A) + - **Agent 3**: `/tmp/pr-context/file_order_largest.txt` — by diff size descending **Spawn sub-agents:** Follow the **Pick Three, Keep Many** process — spawn 3 `code-review` sub-agents to review the PR diff in parallel. Each sub-agent prompt must include: - Instruction to read `/tmp/pr-context/review-instructions.md` for the review process, criteria, and calibration examples - Instruction to read `/tmp/pr-context/README.md` for a manifest of all available context files - The review intensity (`__GH_AW_INPUTS_INTENSITY__`) and minimum severity (`__GH_AW_INPUTS_MINIMUM_SEVERITY__`) - - The ordered file list for that sub-agent (per-file diffs are at `/tmp/pr-context/diffs/.diff`) + - The path to that sub-agent's file ordering (e.g., `/tmp/pr-context/file_order_az.txt`) — tell it to read the file for its ordered list (per-file diffs are at `/tmp/pr-context/diffs/.diff`) - Instruction to read changed files from the workspace (the PR branch is checked out) Each sub-agent returns a structured findings list. They do NOT leave inline comments. @@ -670,7 +670,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -678,11 +678,14 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.pull_request.number || inputs.target-pr-number || github.event.issue.number }} name: Fetch PR context to disk - run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" + run: "set -euo pipefail\nmkdir -p /tmp/pr-context\n\n# PR metadata\ngh pr view \"$PR_NUMBER\" --json title,body,author,baseRefName,headRefName,url \\\n > /tmp/pr-context/pr.json\n\n# Full diff\nif ! gh pr diff \"$PR_NUMBER\" > /tmp/pr-context/pr.diff; then\n echo \"::warning::Failed to fetch full PR diff; per-file diffs from files.json are still available.\"\n : > /tmp/pr-context/pr.diff\nfi\n\n# Changed files list (--paginate may output concatenated arrays; jq -s 'add' merges them)\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/files\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/files.json\n\n# Per-file diffs\njq -c '.[]' /tmp/pr-context/files.json | while IFS= read -r entry; do\n filename=$(echo \"$entry\" | jq -r '.filename')\n mkdir -p \"/tmp/pr-context/diffs/$(dirname \"$filename\")\"\n echo \"$entry\" | jq -r '.patch // empty' > \"/tmp/pr-context/diffs/${filename}.diff\"\ndone\n\n# File orderings for sub-agent review (3 strategies)\njq -r '[.[] | .filename] | sort | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_az.txt\njq -r '[.[] | .filename] | sort | reverse | .[]' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_za.txt\njq -r '[.[] | {filename, size: ((.additions // 0) + (.deletions // 0))}] | sort_by(-.size) | .[].filename' /tmp/pr-context/files.json \\\n > /tmp/pr-context/file_order_largest.txt\n\n# Existing reviews\ngh api \"repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/reviews.json\n\n# Review threads with resolution status (GraphQL — REST lacks isResolved/isOutdated)\ngh api graphql --paginate -f query='\n query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) {\n repository(owner: $owner, name: $repo) {\n pullRequest(number: $number) {\n reviewThreads(first: 100, after: $endCursor) {\n pageInfo { hasNextPage endCursor }\n nodes {\n id\n isResolved\n isOutdated\n isCollapsed\n path\n line\n startLine\n comments(first: 100) {\n nodes {\n id\n databaseId\n body\n author { login }\n createdAt\n }\n }\n }\n }\n }\n }\n }\n' -F owner=\"${GITHUB_REPOSITORY%/*}\" -F repo=\"${GITHUB_REPOSITORY#*/}\" -F \"number=$PR_NUMBER\" \\\n --jq '.data.repository.pullRequest.reviewThreads.nodes' \\\n | jq -s 'add // []' > /tmp/pr-context/review_comments.json\n\n# Per-file review threads (mirrors diffs/ structure)\njq -c '.[]' /tmp/pr-context/review_comments.json | while IFS= read -r thread; do\n filepath=$(echo \"$thread\" | jq -r '.path // empty')\n [ -z \"$filepath\" ] && continue\n mkdir -p \"/tmp/pr-context/threads/$(dirname \"$filepath\")\"\n echo \"$thread\" >> \"/tmp/pr-context/threads/${filepath}.jsonl\"\ndone\n# Convert per-file JSONL to proper JSON arrays\nmkdir -p /tmp/pr-context/threads\nfind /tmp/pr-context/threads -name '*.jsonl' 2>/dev/null | while IFS= read -r jsonl; do\n jq -s '.' \"$jsonl\" > \"${jsonl%.jsonl}.json\"\n rm \"$jsonl\"\ndone\n\n# PR discussion comments\ngh api \"repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments\" --paginate \\\n | jq -s 'add // []' > /tmp/pr-context/comments.json\n\n# Linked issues\njq -r '.body // \"\"' /tmp/pr-context/pr.json 2>/dev/null \\\n | grep -oiE '(fixes|closes|resolves)\\s+#[0-9]+' \\\n | grep -oE '[0-9]+$' \\\n | sort -u \\\n | while read -r issue; do\n gh api \"repos/$GITHUB_REPOSITORY/issues/$issue\" > \"/tmp/pr-context/issue-${issue}.json\" || true\n done || true\n\n# Write manifest\ncat > /tmp/pr-context/README.md << 'MANIFEST'\n# PR Context\n\nPre-fetched PR data. All files are in `/tmp/pr-context/`.\n\n| File | Description |\n| --- | --- |\n| `pr.json` | PR metadata — title, body, author, base/head branches, URL |\n| `pr.diff` | Full unified diff of all changes |\n| `files.json` | Changed files array — each entry has `filename`, `status`, `additions`, `deletions`, `patch` |\n| `diffs/.diff` | Per-file diffs — one file per changed file, mirroring the repo path under `diffs/` |\n| `file_order_az.txt` | Changed files sorted alphabetically (A→Z), one filename per line |\n| `file_order_za.txt` | Changed files sorted reverse-alphabetically (Z→A), one filename per line |\n| `file_order_largest.txt` | Changed files sorted by diff size descending (largest first), one filename per line |\n| `reviews.json` | Prior review submissions — author, state (APPROVED/CHANGES_REQUESTED/COMMENTED), body |\n| `review_comments.json` | All review threads (GraphQL) — each thread has `id` (node ID for resolving), `isResolved`, `isOutdated`, `path`, `line`, and nested `comments` with `id`, `databaseId` (numeric REST ID for replies), body/author |\n| `threads/.json` | Per-file review threads — one file per changed file with existing threads, mirroring the repo path under `threads/` |\n| `comments.json` | PR discussion comments (not inline) |\n| `issue-{N}.json` | Linked issue details (one file per linked issue, if any) |\n| `agents.md` | Repository conventions from `generate_agents_md` (if written by agent) |\n| `review-instructions.md` | Review instructions, criteria, and calibration examples (if written by review-process fragment) |\nMANIFEST\n\necho \"PR context written to /tmp/pr-context/\"\nls -la /tmp/pr-context/" - name: Write review instructions to disk run: "mkdir -p /tmp/pr-context\ncat > /tmp/pr-context/review-instructions.md << 'REVIEW_EOF'\n# Review Instructions for Sub-agents\n\nYou are a code review sub-agent. Read these instructions, then review the PR files in the order provided in your prompt.\n\n## Context\n\nBefore reviewing files, read these to understand the PR:\n\n1. `/tmp/pr-context/pr.json` — PR title, description, author, and branches. Understand what the PR is trying to accomplish.\n2. `/tmp/pr-context/agents.md` — Repository coding conventions and guidelines (if it exists).\n3. `/tmp/pr-context/review_comments.json` — Existing review threads. Note which files already have threads so you don't duplicate.\n4. `/tmp/pr-context/issue-*.json` — Linked issue details (if any). Understand the motivation and acceptance criteria.\n\n## Process\n\nReview the PR diff file by file in your assigned order. For each changed file:\n\n1. **Read the diff** for this file from `/tmp/pr-context/diffs/.diff` to understand what changed. If the diff is empty or truncated (e.g., binary files or very large changes), fall back to reading the full file from the workspace and comparing against context.\n2. **Read the full file from the workspace.** The PR branch is checked out locally — open the file directly to get complete contents with line numbers.\n3. **Check existing threads** for this file from `/tmp/pr-context/threads/.json` (if it exists). Skip issues that are already under discussion — each thread has `isResolved` and `isOutdated` fields.\n4. **Identify potential issues** matching the review criteria below.\n5. **Quick-check each issue** before including it:\n - What specific code pattern or change triggers this concern?\n - Is there an obvious guard, handler, or mitigation visible in the immediate context?\n - Can you describe a concrete failure scenario (the `evidence` field)? If you cannot articulate what specific input or state triggers the problem, drop the finding.\n - If the issue is clearly handled, skip it. If you're unsure, include it — the parent will verify.\n6. **Add to your findings list.** Do NOT leave inline comments — you don't have that tool. Return findings in this format:\n\n```\n- file: path/to/file\n line: 42\n severity: HIGH\n title: Brief title\n description: What the issue is and why it matters\n evidence: The specific code pattern and failure scenario\n suggestion: corrected code here (optional — only if you can provide a concrete fix)\n```\n\n**Review every file in your assigned order.** Files reviewed earlier get more attention, which is why different sub-agents use different orderings.\n\n**Check existing threads** — per-file threads are at `/tmp/pr-context/threads/.json` (step 3 above). The full list is at `/tmp/pr-context/review_comments.json`. Do not flag issues that are already under discussion (resolved or unresolved). For outdated threads, only re-flag if the issue still applies to the current diff.\n\n**Return your full findings list** when done, or an empty list if no issues were found.\n\n## Review Criteria\n\nFocus on these categories in priority order:\n\n1. Security vulnerabilities (injection, XSS, auth bypass, secrets exposure)\n2. Logic bugs that could cause runtime failures or incorrect behavior\n3. Data integrity issues (race conditions, missing transactions, corruption risk)\n4. Performance bottlenecks (N+1 queries, memory leaks, blocking operations)\n5. Error handling gaps (unhandled exceptions, missing validation)\n6. Breaking changes to public APIs without migration path\n7. Missing or incorrect test coverage for critical paths\n\n## What NOT to Flag\n\nOnly review the diff — do not flag issues in unchanged code, pre-existing problems not introduced by this PR, or style preferences handled by linters or formatters.\n\n**Common false positives** — these patterns look like issues but usually aren't. Before flagging anything in these categories, confirm the problem is real by reading the surrounding code:\n\n- **Security — input already sanitized:** Don't flag injection or XSS risks when inputs are sanitized upstream, parameterized queries are used, or the framework auto-escapes output.\n- **Null/undefined — guarded elsewhere:** Don't flag potential null dereferences if the value is guaranteed by a type guard, assertion, schema validation, or upstream null check.\n- **Error handling — handled at a different layer:** Don't flag missing try/catch if the caller, middleware, or framework catches and handles the error (e.g., Express error middleware, React error boundaries).\n- **Performance — theoretical, not practical:** Don't flag algorithmic complexity (e.g., O(n^2)) unless N is demonstrably large enough to matter in the actual usage context. \"This could be slow\" without evidence is not actionable.\n- **Validation — exists at another layer:** Don't flag missing input validation if it's handled by an API gateway, middleware, schema validator, or type system.\n- **Test coverage — trivial or generated code:** Don't flag missing tests for trivial getters/setters, auto-generated code, or simple delegation methods.\n- **Style or naming — not in coding guidelines:** Don't flag naming conventions or code style unless they violate the repository's documented coding guidelines (from `generate_agents_md` or CONTRIBUTING docs).\n\n**Existing review threads** — check BEFORE flagging any issue:\n\n- **Resolved with reviewer reply** (e.g. \"This is intentional\") — reviewer's decision is final. Do NOT re-flag.\n- **Resolved without reply** — author likely fixed it. Do NOT re-raise unless the fix introduced a new problem.\n- **Unresolved** — already flagged. Do NOT duplicate.\n- **Outdated** — only re-flag if the issue still applies to the current diff.\n\nWhen in doubt, do not duplicate. Redundant comments erode trust.\n\nFinding no issues is a valid and valuable outcome. An empty findings list is better than findings that waste the author's time or erode trust. Do not manufacture findings to justify your review — if the code is sound, return an empty list.\n\n## Severity Classification\n\nDetermine severity AFTER investigating the issue, not before. First identify the problem and trace through the code, then assign a severity based on the evidence you found.\n\n- 🔴 CRITICAL — Must fix before merge (security vulnerabilities, data corruption, production-breaking bugs)\n- 🟠 HIGH — Should fix before merge (logic errors, missing validation, significant performance issues)\n- 🟡 MEDIUM — Address soon, non-blocking (error handling gaps, suboptimal patterns, missing edge cases)\n- ⚪ LOW — Author discretion (minor improvements, documentation gaps)\n- 💬 NITPICK — Truly optional (stylistic preferences, alternative approaches)\n\n## Review Intensity\n\nThe review intensity is `${{ inputs.intensity || 'balanced' }}`.\n\n- **conservative**: High evidence bar. Only flag when you can demonstrate a concrete failure scenario. If you can construct a reasonable counterargument, do not flag. Approval with zero findings is the expected outcome for most PRs.\n- **balanced**: Standard evidence bar. Flag when you can point to specific code that would fail. If the issue is ambiguous, lean toward not flagging.\n- **aggressive**: Lower evidence bar. Flag when evidence exists even if the failure scenario is not fully confirmed. Improvement suggestions welcome but must cite specific code.\n\n## Calibration Examples\n\nUse these examples to calibrate your judgment. Each pair shows a real issue and a similar-looking pattern that is NOT an issue.\n\n### Example 1: Null/Undefined Access\n\n**True positive — flag this:**\n\n```js\n// PR adds this handler\napp.get('/user/:id', async (req, res) => {\n const user = await db.findUser(req.params.id);\n res.json({ name: user.name, email: user.email });\n});\n```\n\nWhy flag: `db.findUser()` can return `null` when no user matches the ID. Accessing `user.name` will throw a TypeError at runtime. No upstream guard exists — the route handler is the entry point.\n\n**False positive — do NOT flag this:**\n\n```ts\n// PR adds this line inside an existing function\nconst settings = user.getSettings();\n```\n\nWhy skip: Reading the full file reveals `user` is typed as `User` (not `User | null`), and the calling function only runs after `authenticateUser()` middleware which guarantees a valid user object. The null case is handled at a different layer.\n\n### Example 2: SQL Injection\n\n**True positive — flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE customer_id = '{customer_id}'\")\n```\n\nWhy flag: String interpolation in a SQL query with user-controlled input (`customer_id` comes from the request). No parameterization or sanitization anywhere in the call chain.\n\n**False positive — do NOT flag this:**\n\n```python\n# PR adds this query\ncursor.execute(f\"SELECT * FROM orders WHERE status = '{OrderStatus.PENDING.value}'\")\n```\n\nWhy skip: The interpolated value is a hardcoded enum constant (`OrderStatus.PENDING`), not user input. There is no injection vector.\n\n### Example 3: Borderline — Do NOT Flag\n\n```go\n// PR adds this function\nfunc processItems(items []Item) []Result {\n results := make([]Result, 0)\n for _, item := range items {\n for _, tag := range item.Tags {\n results = append(results, process(item, tag))\n }\n }\n return results\n}\n```\n\nThis looks like an O(n*m) performance concern. But without evidence that `items` or `Tags` are large in practice, this is speculative. The function processes a bounded dataset (items from a single user request). Do not flag theoretical performance issues without evidence of real-world impact.\nREVIEW_EOF" - env: diff --git a/.github/workflows/gh-aw-pr-review.md b/.github/workflows/gh-aw-pr-review.md index 2ea78cf0..b73c41a9 100644 --- a/.github/workflows/gh-aw-pr-review.md +++ b/.github/workflows/gh-aw-pr-review.md @@ -122,16 +122,16 @@ Follow these steps in order. ### Step 2: Sub-agent Review -**Compute file orderings:** Read `/tmp/pr-context/files.json` to get the changed file list with `additions` and `deletions` counts per file. Compute three orderings: -- **Agent 1**: Files in alphabetical order (A → Z) -- **Agent 2**: Files in reverse alphabetical order (Z → A) -- **Agent 3**: Files sorted by diff size descending (largest `additions + deletions` first) +**File orderings are pre-computed** at `/tmp/pr-context/`: +- **Agent 1**: `/tmp/pr-context/file_order_az.txt` — alphabetical (A → Z) +- **Agent 2**: `/tmp/pr-context/file_order_za.txt` — reverse alphabetical (Z → A) +- **Agent 3**: `/tmp/pr-context/file_order_largest.txt` — by diff size descending **Spawn sub-agents:** Follow the **Pick Three, Keep Many** process — spawn 3 `code-review` sub-agents to review the PR diff in parallel. Each sub-agent prompt must include: - Instruction to read `/tmp/pr-context/review-instructions.md` for the review process, criteria, and calibration examples - Instruction to read `/tmp/pr-context/README.md` for a manifest of all available context files - The review intensity (`${{ inputs.intensity }}`) and minimum severity (`${{ inputs.minimum_severity }}`) -- The ordered file list for that sub-agent (per-file diffs are at `/tmp/pr-context/diffs/.diff`) +- The path to that sub-agent's file ordering (e.g., `/tmp/pr-context/file_order_az.txt`) — tell it to read the file for its ordered list (per-file diffs are at `/tmp/pr-context/diffs/.diff`) - Instruction to read changed files from the workspace (the PR branch is checked out) Each sub-agent returns a structured findings list. They do NOT leave inline comments. diff --git a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml index ace2e89c..a721e058 100644 --- a/.github/workflows/gh-aw-product-manager-impersonator.lock.yml +++ b/.github/workflows/gh-aw-product-manager-impersonator.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"3f6aae05a9c33f2841009fefaa7315c7a8b346f88fcf9b1bebfa9f5ee56f534f"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c7aa3089b1a1e91cdb2926949a8bfa5ae113adc7b4c4622c32a2f3b8759c0298"} name: "Product Manager Impersonator" "on": @@ -651,7 +651,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -659,6 +659,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-project-summary.lock.yml b/.github/workflows/gh-aw-project-summary.lock.yml index a33ecf59..99f36814 100644 --- a/.github/workflows/gh-aw-project-summary.lock.yml +++ b/.github/workflows/gh-aw-project-summary.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"39c92ba1c35bec8b2574fbcf1f60f826996e18599a57483750700632f0666e27"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"ea1641e3df830eb0fbe1e25a76febf6da49ece76cf133d8cc1c9d7231d7282af"} name: "Project Summary" "on": @@ -564,7 +564,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -572,6 +572,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-refactor-opportunist.lock.yml b/.github/workflows/gh-aw-refactor-opportunist.lock.yml index 40591b8e..8300b755 100644 --- a/.github/workflows/gh-aw-refactor-opportunist.lock.yml +++ b/.github/workflows/gh-aw-refactor-opportunist.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"548fa840e69775229c59e5cd2879f9bf328154e425f01975f4ddccfd616ca815"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8ba11cfdc9733793c22bca88f72a87eae3a1ef37234e52be8fc706977d6a4071"} name: "Refactor Opportunist" "on": @@ -619,7 +619,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -627,6 +627,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/gh-aw-release-update.lock.yml b/.github/workflows/gh-aw-release-update.lock.yml index aed78da4..e69b541c 100644 --- a/.github/workflows/gh-aw-release-update.lock.yml +++ b/.github/workflows/gh-aw-release-update.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0b6237e0806733f975c6d12c6f256274868588e757ee89bcafc8a9bc8fdd5efd"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"540fed2332d999fe5901bc59a882c439fe966cffe03b7910e56f993df13555e6"} name: "Release Update Check" "on": @@ -483,7 +483,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -491,6 +491,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-scheduled-audit.lock.yml b/.github/workflows/gh-aw-scheduled-audit.lock.yml index 1501c3f5..5dbc197e 100644 --- a/.github/workflows/gh-aw-scheduled-audit.lock.yml +++ b/.github/workflows/gh-aw-scheduled-audit.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"94cf40207057a60016559ed389bebb6a2b93d7f246dc5726a00481a8100f2cb8"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"bc0565906470ea37244b4d25e4a9926cf503c621f631fbd879ff829bd3cc01ce"} name: "Scheduled Audit" "on": @@ -532,7 +532,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -540,6 +540,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-scheduled-fix.lock.yml b/.github/workflows/gh-aw-scheduled-fix.lock.yml index 95b2fa95..8becb0c8 100644 --- a/.github/workflows/gh-aw-scheduled-fix.lock.yml +++ b/.github/workflows/gh-aw-scheduled-fix.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"24f475e3a2993dd129ad8be4404ab5fd3e4e081deabbef5b4a10db20862dbe38"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"18eac1fd19c9aa09b0f306acbbc1b3a08d4f214f087b25be62fb8b5b8a947e7d"} name: "Scheduled Fix" "on": @@ -533,7 +533,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -541,6 +541,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-small-problem-fixer.lock.yml b/.github/workflows/gh-aw-small-problem-fixer.lock.yml index 09ed0983..08806e21 100644 --- a/.github/workflows/gh-aw-small-problem-fixer.lock.yml +++ b/.github/workflows/gh-aw-small-problem-fixer.lock.yml @@ -37,7 +37,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e0c2c421f13e9ce468bdb7536716845eb1bfe5f3dd96327f2c35c9e06ffc6bec"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"bba6645ad30ad38083fb374055d6952f84711b2304ebe53704bb5f00a7043069"} name: "Small Problem Fixer" "on": @@ -527,7 +527,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -535,6 +535,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-stale-issues.lock.yml b/.github/workflows/gh-aw-stale-issues.lock.yml index 5cfdfb05..34a1fa02 100644 --- a/.github/workflows/gh-aw-stale-issues.lock.yml +++ b/.github/workflows/gh-aw-stale-issues.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8068cbc63838900c3a0a726b61363634043bc0d84c19d6b89b09b32d752b126e"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2bece55b2b8814c1825118bea95b6f469ade271740670ab968ba72dc20f1d2f1"} name: "Stale Issues" "on": @@ -595,7 +595,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -603,6 +603,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-test-improvement.lock.yml b/.github/workflows/gh-aw-test-improvement.lock.yml index e2284d23..f8296b42 100644 --- a/.github/workflows/gh-aw-test-improvement.lock.yml +++ b/.github/workflows/gh-aw-test-improvement.lock.yml @@ -41,7 +41,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8aaa1fb234b83c6087c0ca590188b4b6240204eb8e085d3969d3f017a84f8898"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"08d168e02162376fdd5be78c4b6cfa1f910732fad86deb9e101fab2c9271416d"} name: "Test Improver" "on": @@ -526,7 +526,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -534,6 +534,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-test-improver.lock.yml b/.github/workflows/gh-aw-test-improver.lock.yml index 10a5df80..0106c706 100644 --- a/.github/workflows/gh-aw-test-improver.lock.yml +++ b/.github/workflows/gh-aw-test-improver.lock.yml @@ -36,7 +36,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8aaa1fb234b83c6087c0ca590188b4b6240204eb8e085d3969d3f017a84f8898"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"08d168e02162376fdd5be78c4b6cfa1f910732fad86deb9e101fab2c9271416d"} name: "Test Improver" "on": @@ -521,7 +521,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -529,6 +529,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-text-auditor.lock.yml b/.github/workflows/gh-aw-text-auditor.lock.yml index d49fa427..1b1c69a0 100644 --- a/.github/workflows/gh-aw-text-auditor.lock.yml +++ b/.github/workflows/gh-aw-text-auditor.lock.yml @@ -39,7 +39,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d93d636ba529f70b8fb4893143d11651d56e57cdbd82a51e605412a283bee5f3"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a3a55d646f184e99b809a64db2b29f46c01c532b4a17d91aa4e5882dae038c6a"} name: "Text Auditor" "on": @@ -688,7 +688,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -696,6 +696,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/gh-aw-text-beautifier.lock.yml b/.github/workflows/gh-aw-text-beautifier.lock.yml index a89cedb0..445d7740 100644 --- a/.github/workflows/gh-aw-text-beautifier.lock.yml +++ b/.github/workflows/gh-aw-text-beautifier.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"2c95f9b03d6a21556f4408e2a3163ae2e781dfe8c8db8793c44f01d3581ee1dc"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"8276eb97a80c0abd997c5d568c174ee440b4fa4624945e95e0e21aa0a1bb3f37"} name: "Text Beautifier" "on": @@ -523,7 +523,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -531,6 +531,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-update-pr-body.lock.yml b/.github/workflows/gh-aw-update-pr-body.lock.yml index f5819416..0787915e 100644 --- a/.github/workflows/gh-aw-update-pr-body.lock.yml +++ b/.github/workflows/gh-aw-update-pr-body.lock.yml @@ -35,7 +35,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"1a2f6c188e577f6e555e95b76a4276f3d616f6d79e52fdb1d8788c10d3cd9025"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"a4b89690f8c885ed2c8157657b3fc60a9554de563b6cd35ca60821dd565ade6c"} name: "Update PR Body" "on": @@ -565,7 +565,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -573,6 +573,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: SETUP_COMMANDS: ${{ inputs.setup-commands }} if: ${{ inputs.setup-commands != '' }} diff --git a/.github/workflows/gh-aw-ux-design-patrol.lock.yml b/.github/workflows/gh-aw-ux-design-patrol.lock.yml index 268817a1..ea0e0829 100644 --- a/.github/workflows/gh-aw-ux-design-patrol.lock.yml +++ b/.github/workflows/gh-aw-ux-design-patrol.lock.yml @@ -40,7 +40,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"4cb979062bcf68fcaa934725785e6590671d9083e5403af10413ecb35206b598"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"16221bcf878646b93d83835c6227d99642c02431790b86a5b9778afd36247f7f"} name: "UX Design Patrol" "on": @@ -618,7 +618,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -626,6 +626,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GITHUB_TOKEN: ${{ github.token }} REPO_NAME: ${{ github.repository }} diff --git a/.github/workflows/trigger-pr-review-addresser.yml b/.github/workflows/trigger-pr-review-addresser.yml index 4d02c21b..983316c4 100644 --- a/.github/workflows/trigger-pr-review-addresser.yml +++ b/.github/workflows/trigger-pr-review-addresser.yml @@ -11,6 +11,10 @@ permissions: issues: write pull-requests: write +concurrency: + group: pr-review-addresser-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: run: if: >- @@ -18,5 +22,7 @@ jobs: !github.event.pull_request.draft && !contains(github.event.pull_request.labels.*.name, 'skip-auto-pr-review-addresser') uses: ./.github/workflows/gh-aw-pr-review-addresser.lock.yml + with: + allowed-bot-users: "coderabbitai[bot],github-actions[bot],copilot" secrets: COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} diff --git a/.github/workflows/upgrade-check.lock.yml b/.github/workflows/upgrade-check.lock.yml index 8e0b2166..4e93ded8 100644 --- a/.github/workflows/upgrade-check.lock.yml +++ b/.github/workflows/upgrade-check.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"9a0ef2c510b36c74bb10565234b6d6132a21e698b1cebfb9bf7b93a6f4981536"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"e75ea16f83e2b2e6404e905c76277dc8063a40b7f61b1b746be3e3786170152a"} name: "Internal: Upgrade Check" "on": @@ -555,7 +555,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -563,6 +563,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/.github/workflows/workflow-patrol.lock.yml b/.github/workflows/workflow-patrol.lock.yml index dc710086..056e2ac5 100644 --- a/.github/workflows/workflow-patrol.lock.yml +++ b/.github/workflows/workflow-patrol.lock.yml @@ -38,7 +38,7 @@ # # inlined-imports: true # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"85df52c7c48e1c6f376a5411a36e2f16039e99da97836d1d62382e5b62302da0"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"c8397959f7a2714ac40c47b153fd2df394ced55762128cc117478358dea39a2d"} name: "Internal: Workflow Patrol" "on": @@ -545,7 +545,7 @@ jobs: WORKSPACE: ${{ github.workspace }} if: hashFiles('pyproject.toml', 'uv.lock') != '' name: Expose uv in workspace - run: |- + run: | set -euo pipefail install_dir="$WORKSPACE/.gh-aw-tools/bin" mkdir -p "$install_dir" @@ -553,6 +553,9 @@ jobs: chmod +x "$install_dir/uv" echo "$install_dir" >> "$GITHUB_PATH" shell: bash + - name: Configure Copilot CLI settings + run: "set -euo pipefail\nmkdir -p ~/.copilot\nCONFIG=\"$HOME/.copilot/config.json\"\nif [ -f \"$CONFIG\" ]; then\n jq '. + {\"chat.customAgentInSubagent.enabled\": true}' \"$CONFIG\" > \"$CONFIG.tmp\" && mv \"$CONFIG.tmp\" \"$CONFIG\"\nelse\n echo '{\"chat.customAgentInSubagent.enabled\":true}' > \"$CONFIG\"\nfi" + shell: bash - env: GH_TOKEN: ${{ github.token }} TITLE_PREFIX: ${{ inputs.title-prefix }} diff --git a/gh-agent-workflows/pr-review-addresser/dogfood-with.yml b/gh-agent-workflows/pr-review-addresser/dogfood-with.yml new file mode 100644 index 00000000..a97413e9 --- /dev/null +++ b/gh-agent-workflows/pr-review-addresser/dogfood-with.yml @@ -0,0 +1 @@ +allowed-bot-users: "coderabbitai[bot],github-actions[bot],copilot" diff --git a/gh-agent-workflows/pr-review-addresser/example.yml b/gh-agent-workflows/pr-review-addresser/example.yml index bd065ce0..1bf1743c 100644 --- a/gh-agent-workflows/pr-review-addresser/example.yml +++ b/gh-agent-workflows/pr-review-addresser/example.yml @@ -9,6 +9,10 @@ permissions: issues: write pull-requests: write +concurrency: + group: pr-review-addresser-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: run: if: >-