diff --git a/.github/agents/agentic-workflows.agent.md b/.github/agents/agentic-workflows.agent.md index 2b29249..7b74d00 100644 --- a/.github/agents/agentic-workflows.agent.md +++ b/.github/agents/agentic-workflows.agent.md @@ -30,7 +30,7 @@ Workflows may optionally include: - Workflow files: `.github/workflows/*.md` and `.github/workflows/**/*.md` - Workflow lock files: `.github/workflows/*.lock.yml` - Shared components: `.github/workflows/shared/*.md` -- Configuration: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/github-agentic-workflows.md +- Configuration: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/github-agentic-workflows.md ## Problems This Solves @@ -52,7 +52,7 @@ When you interact with this agent, it will: ### Create New Workflow **Load when**: User wants to create a new workflow from scratch, add automation, or design a workflow that doesn't exist yet -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/create-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/create-agentic-workflow.md **Use cases**: - "Create a workflow that triages issues" @@ -62,7 +62,7 @@ When you interact with this agent, it will: ### Update Existing Workflow **Load when**: User wants to modify, improve, or refactor an existing workflow -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/update-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/update-agentic-workflow.md **Use cases**: - "Add web-fetch tool to the issue-classifier workflow" @@ -72,7 +72,7 @@ When you interact with this agent, it will: ### Debug Workflow **Load when**: User needs to investigate, audit, debug, or understand a workflow, troubleshoot issues, analyze logs, or fix errors -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/debug-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/debug-agentic-workflow.md **Use cases**: - "Why is this workflow failing?" @@ -82,7 +82,7 @@ When you interact with this agent, it will: ### Upgrade Agentic Workflows **Load when**: User wants to upgrade workflows to a new gh-aw version or fix deprecations -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/upgrade-agentic-workflows.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/upgrade-agentic-workflows.md **Use cases**: - "Upgrade all workflows to the latest version" @@ -92,7 +92,7 @@ When you interact with this agent, it will: ### Create a Report-Generating Workflow **Load when**: The workflow being created or updated produces reports — recurring status updates, audit summaries, analyses, or any structured output posted as a GitHub issue, discussion, or comment -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/report.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/report.md **Use cases**: - "Create a weekly CI health report" @@ -102,7 +102,7 @@ When you interact with this agent, it will: ### Create Shared Agentic Workflow **Load when**: User wants to create a reusable workflow component or wrap an MCP server -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/create-shared-agentic-workflow.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/create-shared-agentic-workflow.md **Use cases**: - "Create a shared component for Notion integration" @@ -112,7 +112,7 @@ When you interact with this agent, it will: ### Fix Dependabot PRs **Load when**: User needs to close or fix open Dependabot PRs that update dependencies in generated manifest files (`.github/workflows/package.json`, `.github/workflows/requirements.txt`, `.github/workflows/go.mod`) -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/dependabot.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/dependabot.md **Use cases**: - "Fix the open Dependabot PRs for npm dependencies" @@ -122,7 +122,7 @@ When you interact with this agent, it will: ### Analyze Test Coverage **Load when**: The workflow reads, analyzes, or reports test coverage — whether triggered by a PR, a schedule, or a slash command. Always consult this prompt before designing the coverage data strategy. -**Prompt file**: https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/test-coverage.md +**Prompt file**: https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/test-coverage.md **Use cases**: - "Create a workflow that comments coverage on PRs" @@ -169,7 +169,7 @@ gh aw compile --validate ## Important Notes -- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.51.2/.github/aw/github-agentic-workflows.md for complete documentation +- Always reference the instructions file at https://github.com/github/gh-aw/blob/v0.53.3/.github/aw/github-agentic-workflows.md for complete documentation - Use the MCP tool `agentic-workflows` when running in GitHub Copilot Cloud - Workflows must be compiled to `.lock.yml` files before running in GitHub Actions - **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index 11ac08e..aa4ff96 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -5,10 +5,10 @@ "version": "v8", "sha": "ed597411d8f924073f98dfc5c65a23a2325f34cd" }, - "github/gh-aw/actions/setup@v0.51.2": { + "github/gh-aw/actions/setup@v0.53.3": { "repo": "github/gh-aw/actions/setup", - "version": "v0.51.2", - "sha": "cccf96100f50705c4291b91a6071c556f72cb3ef" + "version": "v0.53.3", + "sha": "a0ed2f46906483dcf634e8694268e4fab9b21e65" } } } diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index 3fc6c5c..415198b 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -13,7 +13,7 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.51.2). DO NOT EDIT. +# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.53.3). DO NOT EDIT. # # To regenerate this workflow, run: # gh aw compile @@ -37,12 +37,24 @@ on: schedule: - cron: "37 */6 * * *" # Every 6 hours (based on minimum expires: 2 days) workflow_dispatch: + inputs: + operation: + description: 'Optional maintenance operation to run' + required: false + type: choice + default: '' + options: + - '' + - 'disable' + - 'enable' + - 'update' + - 'upgrade' permissions: {} jobs: close-expired-entities: - if: ${{ !github.event.repository.fork }} + if: ${{ !github.event.repository.fork && (github.event_name != 'workflow_dispatch' || github.event.inputs.operation == '') }} runs-on: ubuntu-slim permissions: discussions: write @@ -50,7 +62,7 @@ jobs: pull-requests: write steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions @@ -80,3 +92,50 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/close_expired_pull_requests.cjs'); await main(); + + run_operation: + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.operation != '' && !github.event.repository.fork }} + runs-on: ubuntu-slim + permissions: + actions: write + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup Scripts + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 + with: + destination: /opt/gh-aw/actions + + - name: Check admin/maintainer permissions + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/check_team_member.cjs'); + await main(); + + - name: Install gh-aw + uses: github/gh-aw/actions/setup-cli@v0.53.3 + with: + version: v0.53.3 + + - name: Run operation + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_AW_OPERATION: ${{ github.event.inputs.operation }} + GH_AW_CMD_PREFIX: gh aw + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/run_operation_update_upgrade.cjs'); + await main(); diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml index e476e8d..915c7e4 100644 --- a/.github/workflows/ci-coach.lock.yml +++ b/.github/workflows/ci-coach.lock.yml @@ -13,9 +13,9 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.51.2). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.53.3). DO NOT EDIT. # -# To update this file, edit githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 and run: +# To update this file, edit githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be and run: # gh aw compile # Not all edits will cause changes to this file. # @@ -23,9 +23,9 @@ # # Daily CI optimization coach that analyzes GitHub Actions workflows for efficiency improvements and cost reduction opportunities # -# Source: githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 +# Source: githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f967f7be68f30dbcbae2fc6788b68c65378bf1dff0843c0ed5a3e489c9e75a34","compiler_version":"v0.51.2"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"0735d0f5b9774a0f3afaf0ae061df93ca61aca3a9e10f9ab7b63cdb7700c819f","compiler_version":"v0.53.3"} name: "CI Optimization Coach" "on": @@ -53,7 +53,7 @@ jobs: secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Generate agentic run info @@ -63,8 +63,8 @@ jobs: GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.419" - GH_AW_INFO_CLI_VERSION: "v0.51.2" + GH_AW_INFO_AGENT_VERSION: "0.0.421" + GH_AW_INFO_CLI_VERSION: "v0.53.3" GH_AW_INFO_WORKFLOW_NAME: "CI Optimization Coach" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" @@ -255,12 +255,13 @@ jobs: detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} detection_success: ${{ steps.detection_conclusion.outputs.success }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} model: ${{ needs.activation.outputs.model }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Checkout repository @@ -296,7 +297,7 @@ jobs: const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.419 + run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.421 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 - name: Determine automatic lockdown mode for GitHub MCP Server @@ -310,14 +311,14 @@ jobs: const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); await determineAutomaticLockdown(github, context, core); - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p /opt/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"create_pull_request":{"expires":48,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} + {"create_pull_request":{"expires":48,"max":1,"title_prefix":"[ci-coach] "},"missing_data":{},"missing_tool":{},"noop":{"max":1}} GH_AW_SAFE_OUTPUTS_CONFIG_EOF cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' [ @@ -338,6 +339,10 @@ jobs: "description": "Whether to create the PR as a draft. Draft PRs cannot be merged until marked as ready for review. Use mark_pull_request_as_ready_for_review to convert a draft PR. Default: true.", "type": "boolean" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "labels": { "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.", "items": { @@ -345,6 +350,14 @@ jobs: }, "type": "array" }, + "repo": { + "description": "Target repository in 'owner/repo' format. For multi-repo workflows where the target repo differs from the workflow repo, this must match a repo in the allowed-repos list or the configured target-repo. If omitted, defaults to the configured target-repo (from safe-outputs config), NOT the workflow repository. In most cases, you should omit this parameter and let the system use the configured default.", + "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "title": { "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.", "type": "string" @@ -367,10 +380,18 @@ jobs: "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", "type": "string" }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "tool": { "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", "type": "string" @@ -388,9 +409,17 @@ jobs: "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "message": { "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -417,9 +446,17 @@ jobs: "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this data is needed to complete the task (max 256 characters).", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [], @@ -588,7 +625,7 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8' mkdir -p /home/runner/.copilot cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh @@ -635,12 +672,12 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.jsr.io,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,deb.nodesource.com,deno.land,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,s.symcb.com,s.symcd.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} GITHUB_API_URL: ${{ github.api_url }} @@ -651,6 +688,11 @@ jobs: GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} GITHUB_WORKSPACE: ${{ github.workspace }} XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash /opt/gh-aw/actions/detect_inference_access_error.sh - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -856,11 +898,11 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GITHUB_API_URL: ${{ github.api_url }} GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -918,22 +960,27 @@ jobs: contents: write issues: write pull-requests: write + concurrency: + group: "gh-aw-conclusion-ci-coach" + cancel-in-progress: false outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print @@ -945,8 +992,8 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" GH_AW_TRACKER_ID: "ci-coach-daily" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -961,8 +1008,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" GH_AW_TRACKER_ID: "ci-coach-daily" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -977,17 +1024,19 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" GH_AW_TRACKER_ID: "ci-coach-daily" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "ci-coach" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} GH_AW_GROUP_REPORTS: "false" + GH_AW_TIMEOUT_MINUTES: "30" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1001,8 +1050,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" GH_AW_TRACKER_ID: "ci-coach-daily" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} @@ -1021,8 +1070,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" GH_AW_TRACKER_ID: "ci-coach-daily" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} with: @@ -1045,12 +1094,13 @@ jobs: pull-requests: write timeout-minutes: 15 env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/ci-coach" GH_AW_ENGINE_ID: "copilot" GH_AW_TRACKER_ID: "ci-coach-daily" GH_AW_WORKFLOW_ID: "ci-coach" GH_AW_WORKFLOW_NAME: "CI Optimization Coach" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/ci-coach.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/ci-coach.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1062,16 +1112,18 @@ jobs: process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print diff --git a/.github/workflows/ci-coach.md b/.github/workflows/ci-coach.md index 5daa4c1..3bf0b93 100644 --- a/.github/workflows/ci-coach.md +++ b/.github/workflows/ci-coach.md @@ -2,8 +2,7 @@ description: Daily CI optimization coach that analyzes GitHub Actions workflows for efficiency improvements and cost reduction opportunities on: - schedule: - - cron: daily + schedule: daily workflow_dispatch: network: @@ -31,8 +30,7 @@ safe-outputs: title-prefix: "[ci-coach] " github-token-for-extra-empty-commit: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} timeout-minutes: 30 -source: githubnext/agentics/workflows/ci-coach.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 -engine: copilot +source: githubnext/agentics/workflows/ci-coach.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be --- # CI Optimization Coach @@ -140,7 +138,7 @@ If no significant improvements are found: needs: [build] lint: needs: [build] - + # After: Parallel test: needs: [build] @@ -236,4 +234,4 @@ When creating a PR, use this structure: ✅ If no changes: Used noop tool to report analysis complete ✅ Completed analysis in under 30 minutes -Begin your analysis now. Identify CI workflows, analyze their performance, and either propose optimizations through a pull request or report that no improvements are needed. \ No newline at end of file +Begin your analysis now. Identify CI workflows, analyze their performance, and either propose optimizations through a pull request or report that no improvements are needed. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a20aeef..103ed4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,11 +6,33 @@ on: push: branches: - main + paths: + - 'src/**' + - 'package.json' + - 'package-lock.json' + - 'tsconfig.json' + - 'eslint.config.mjs' + - '.vscode-test.mjs' + - '.github/workflows/ci.yml' pull_request: + paths: + - 'src/**' + - 'package.json' + - 'package-lock.json' + - 'tsconfig.json' + - 'eslint.config.mjs' + - '.vscode-test.mjs' + - '.github/workflows/ci.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: + timeout-minutes: 15 strategy: + fail-fast: false matrix: os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} @@ -18,19 +40,22 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Install Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: node-version: 22.x cache: 'npm' - run: npm ci - - run: npm run compile - run: xvfb-run -a npm run test:coverage if: runner.os == 'Linux' - - run: npm test + # On non-Linux, compile and run tests directly to skip the redundant lint + # (lint is OS-agnostic and already runs on Linux via test:coverage) + - run: npm run compile + if: runner.os != 'Linux' + - run: npm run test:vscode if: runner.os != 'Linux' - name: Upload coverage to Codecov if: runner.os == 'Linux' - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 with: directory: ./coverage fail_ci_if_error: false diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index eb23d04..b7a4ecb 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -16,10 +16,10 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Install Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: node-version: 22.x - name: Install gh-aw extension - uses: github/gh-aw/actions/setup-cli@cccf96100f50705c4291b91a6071c556f72cb3ef #v0.51.2 + uses: github/gh-aw/actions/setup-cli@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: - version: v0.51.2 + version: v0.53.3 diff --git a/.github/workflows/issue-triage.lock.yml b/.github/workflows/issue-triage.lock.yml index e3b1289..5332b91 100644 --- a/.github/workflows/issue-triage.lock.yml +++ b/.github/workflows/issue-triage.lock.yml @@ -13,9 +13,9 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.51.2). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.53.3). DO NOT EDIT. # -# To update this file, edit githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 and run: +# To update this file, edit githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be and run: # gh aw compile # Not all edits will cause changes to this file. # @@ -27,9 +27,9 @@ # reproduction steps, and resource links. Helps maintainers quickly understand and # prioritize incoming issues. # -# Source: githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 +# Source: githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"6534d4ae8d7057b36b3c33de3573eaa691beed1a982fd08c30a1742291e5ecbc","compiler_version":"v0.51.2"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"36f0b5ee5c61882ba6e00e831e2425a2f93405422f76de1c038784f50c7cdc9b","compiler_version":"v0.53.3"} name: "Agentic Triage" "on": @@ -41,7 +41,7 @@ name: "Agentic Triage" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number }}" + group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.run_id }}" run-name: "Agentic Triage" @@ -65,7 +65,7 @@ jobs: title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Generate agentic run info @@ -75,8 +75,8 @@ jobs: GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.419" - GH_AW_INFO_CLI_VERSION: "v0.51.2" + GH_AW_INFO_AGENT_VERSION: "0.0.421" + GH_AW_INFO_CLI_VERSION: "v0.53.3" GH_AW_INFO_WORKFLOW_NAME: "Agentic Triage" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" @@ -105,6 +105,19 @@ jobs: sparse-checkout-cone-mode: true fetch-depth: 1 persist-credentials: false + - name: Add eyes reaction for immediate feedback + id: react + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REACTION: "eyes" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/add_reaction.cjs'); + await main(); - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: @@ -269,12 +282,13 @@ jobs: detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} detection_success: ${{ steps.detection_conclusion.outputs.success }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} model: ${{ needs.activation.outputs.model }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Checkout repository @@ -310,11 +324,11 @@ jobs: const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.419 + run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.421 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p /opt/gh-aw/safeoutputs @@ -334,9 +348,17 @@ jobs: "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "item_number": { "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.", "type": "number" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -351,6 +373,10 @@ jobs: "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "item_number": { "description": "Issue or PR number to add labels to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, adds labels to the issue or PR that triggered this workflow. Only works for issue or pull_request event triggers. For schedule, workflow_dispatch, or other triggers, item_number is required — omitting it will silently skip the label operation.", "type": "number" @@ -361,6 +387,10 @@ jobs: "type": "string" }, "type": "array" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "type": "object" @@ -376,10 +406,18 @@ jobs: "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", "type": "string" }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "tool": { "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", "type": "string" @@ -397,9 +435,17 @@ jobs: "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "message": { "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -426,9 +472,17 @@ jobs: "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this data is needed to complete the task (max 256 characters).", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [], @@ -597,7 +651,7 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8' mkdir -p /home/runner/.copilot cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh @@ -643,12 +697,12 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} GITHUB_API_URL: ${{ github.api_url }} @@ -659,6 +713,11 @@ jobs: GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} GITHUB_WORKSPACE: ${{ github.workspace }} XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash /opt/gh-aw/actions/detect_inference_access_error.sh - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -863,11 +922,11 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GITHUB_API_URL: ${{ github.api_url }} GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -926,22 +985,27 @@ jobs: discussions: write issues: write pull-requests: write + concurrency: + group: "gh-aw-conclusion-issue-triage" + cancel-in-progress: false outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print @@ -953,8 +1017,8 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "Agentic Triage" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/issue-triage.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/issue-triage.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -968,8 +1032,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Agentic Triage" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/issue-triage.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/issue-triage.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -983,14 +1047,16 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Agentic Triage" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/issue-triage.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/issue-triage.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "issue-triage" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_GROUP_REPORTS: "false" + GH_AW_TIMEOUT_MINUTES: "10" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1004,8 +1070,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Agentic Triage" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/issue-triage.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/issue-triage.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} @@ -1020,31 +1086,14 @@ jobs: pre_activation: runs-on: ubuntu-slim - permissions: - discussions: write - issues: write - pull-requests: write outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} matched_command: '' steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - - name: Add eyes reaction for immediate feedback - id: react - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_REACTION: "eyes" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/add_reaction.cjs'); - await main(); - name: Check team membership for workflow id: check_membership uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -1069,11 +1118,12 @@ jobs: pull-requests: write timeout-minutes: 15 env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/issue-triage" GH_AW_ENGINE_ID: "copilot" GH_AW_WORKFLOW_ID: "issue-triage" GH_AW_WORKFLOW_NAME: "Agentic Triage" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/issue-triage.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/issue-triage.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1085,16 +1135,18 @@ jobs: process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print diff --git a/.github/workflows/issue-triage.md b/.github/workflows/issue-triage.md index 6f5a727..08728a7 100644 --- a/.github/workflows/issue-triage.md +++ b/.github/workflows/issue-triage.md @@ -27,11 +27,10 @@ tools: # If in a public repo, setting `lockdown: false` allows # reading issues, pull requests and comments from 3rd-parties # If in a private repo this has no particular effect. - lockdown: false + lockdown: false timeout-minutes: 10 -source: githubnext/agentics/workflows/issue-triage.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 -engine: copilot +source: githubnext/agentics/workflows/issue-triage.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be --- # Agentic Triage @@ -88,4 +87,4 @@ You're a triage assistant for GitHub issues. Your task is to analyze issue #${{ - If you have possible reproduction steps, include them in the comment - If you have any debugging strategies, include them in the comment - If appropriate break the issue down to sub-tasks and write a checklist of things to do. - - Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. \ No newline at end of file + - Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c167d6..a111f2e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,7 @@ on: jobs: release-please: + timeout-minutes: 5 permissions: contents: write # for googleapis/release-please-action to create release commit pull-requests: write # for googleapis/release-please-action to create release PR @@ -26,6 +27,7 @@ jobs: release: needs: release-please + timeout-minutes: 20 runs-on: ubuntu-latest environment: marketplace if: needs.release-please.outputs.release_created == 'true' @@ -38,7 +40,7 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Install Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: node-version: 22.x cache: 'npm' diff --git a/.github/workflows/repo-assist.lock.yml b/.github/workflows/repo-assist.lock.yml index 1010c8f..55f4e1b 100644 --- a/.github/workflows/repo-assist.lock.yml +++ b/.github/workflows/repo-assist.lock.yml @@ -13,9 +13,9 @@ # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # -# This file was automatically generated by gh-aw (v0.51.2). DO NOT EDIT. +# This file was automatically generated by gh-aw (v0.53.3). DO NOT EDIT. # -# To update this file, edit githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 and run: +# To update this file, edit githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be and run: # gh aw compile # Not all edits will cause changes to this file. # @@ -34,9 +34,9 @@ # - Maintains a persistent memory of work done and what remains # Always polite, constructive, and mindful of the project's goals. # -# Source: githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 +# Source: githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be # -# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"f61f4c84338864ef25275fd4236afac8ea184907bdacabcef7f6c26a7dd0f6d3","compiler_version":"v0.51.2"} +# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"d8ee4ebfd7239ae5f4f34384b93d7425164144af4d26d90a90afe5919ecc1117","compiler_version":"v0.53.3"} name: "Repo Assist" "on": @@ -73,7 +73,7 @@ name: "Repo Assist" permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}" + group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}" run-name: "Repo Assist" @@ -112,7 +112,7 @@ jobs: title: ${{ steps.sanitized.outputs.title }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Generate agentic run info @@ -122,8 +122,8 @@ jobs: GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.419" - GH_AW_INFO_CLI_VERSION: "v0.51.2" + GH_AW_INFO_AGENT_VERSION: "0.0.421" + GH_AW_INFO_CLI_VERSION: "v0.53.3" GH_AW_INFO_WORKFLOW_NAME: "Repo Assist" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" @@ -152,6 +152,19 @@ jobs: sparse-checkout-cone-mode: true fetch-depth: 1 persist-credentials: false + - name: Add eyes reaction for immediate feedback + id: react + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REACTION: "eyes" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); + setupGlobals(core, github, context, exec, io); + const { main } = require('/opt/gh-aw/actions/add_reaction.cjs'); + await main(); - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: @@ -348,12 +361,13 @@ jobs: detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} detection_success: ${{ steps.detection_conclusion.outputs.success }} has_patch: ${{ steps.collect_output.outputs.has_patch }} + inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }} model: ${{ needs.activation.outputs.model }} output: ${{ steps.collect_output.outputs.output }} output_types: ${{ steps.collect_output.outputs.output_types }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Checkout repository @@ -399,7 +413,7 @@ jobs: const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.419 + run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.421 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 - name: Determine automatic lockdown mode for GitHub MCP Server @@ -413,19 +427,19 @@ jobs: const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); await determineAutomaticLockdown(github, context, core); - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.6 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p /opt/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":10,"target":"*"},"add_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":30,"target":"*"},"create_issue":{"max":4},"create_pull_request":{"max":4},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":4,"target":"*"},"remove_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":5},"update_issue":{"max":1}} + {"add_comment":{"max":10,"target":"*"},"add_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":30,"target":"*"},"create_issue":{"max":4},"create_pull_request":{"draft":true,"max":4,"title_prefix":"[Repo Assist] "},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":4,"target":"*"},"remove_labels":{"allowed":["bug","enhancement","help wanted","good first issue","spam","off topic","documentation","question","duplicate","wontfix","needs triage","needs investigation","breaking change","performance","security","refactor"],"max":5},"update_issue":{"max":1}} GH_AW_SAFE_OUTPUTS_CONFIG_EOF cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' [ { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 4 issue(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [automation repo-assist] will be automatically added.", + "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 4 issue(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added.", "inputSchema": { "additionalProperties": false, "properties": { @@ -433,6 +447,10 @@ jobs: "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "labels": { "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", "items": { @@ -447,6 +465,10 @@ jobs: "string" ] }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "temporary_id": { "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 3 to 8 alphanumeric characters (e.g., 'aw_abc1', 'aw_Test123'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", "pattern": "^aw_[A-Za-z0-9]{3,8}$", @@ -474,9 +496,17 @@ jobs: "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation. CONSTRAINTS: The complete comment (your body text + automatically added footer) must not exceed 65536 characters total. Maximum 10 mentions (@username), maximum 50 links (http/https URLs). A footer (~200-500 characters) is automatically appended with workflow attribution, so leave adequate space. If these limits are exceeded, the tool call will fail with a detailed error message indicating which constraint was violated.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "item_number": { "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool auto-targets the issue, PR, or discussion that triggered this workflow. Auto-targeting only works for issue, pull_request, discussion, and comment event triggers — it does NOT work for schedule, workflow_dispatch, push, or workflow_run triggers. For those trigger types, always provide item_number explicitly, or the comment will be silently discarded.", "type": "number" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -487,7 +517,7 @@ jobs: "name": "add_comment" }, { - "description": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 4 pull request(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [automation repo-assist] will be automatically added. PRs will be created as drafts.", + "description": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 4 pull request(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added. PRs will be created as drafts.", "inputSchema": { "additionalProperties": false, "properties": { @@ -503,6 +533,10 @@ jobs: "description": "Whether to create the PR as a draft. Draft PRs cannot be merged until marked as ready for review. Use mark_pull_request_as_ready_for_review to convert a draft PR. Default: true.", "type": "boolean" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "labels": { "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.", "items": { @@ -510,6 +544,14 @@ jobs: }, "type": "array" }, + "repo": { + "description": "Target repository in 'owner/repo' format. For multi-repo workflows where the target repo differs from the workflow repo, this must match a repo in the allowed-repos list or the configured target-repo. If omitted, defaults to the configured target-repo (from safe-outputs config), NOT the workflow repository. In most cases, you should omit this parameter and let the system use the configured default.", + "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "title": { "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.", "type": "string" @@ -524,10 +566,14 @@ jobs: "name": "create_pull_request" }, { - "description": "Add labels to an existing GitHub issue or pull request for categorization and filtering. Labels must already exist in the repository. For creating new issues with labels, use create_issue with the labels property instead. CONSTRAINTS: Maximum 30 label(s) can be added. Only these labels are allowed: [bug enhancement help wanted good first issue spam off topic documentation question duplicate wontfix needs triage needs investigation breaking change performance security refactor]. Target: *.", + "description": "Add labels to an existing GitHub issue or pull request for categorization and filtering. Labels must already exist in the repository. For creating new issues with labels, use create_issue with the labels property instead. CONSTRAINTS: Maximum 30 label(s) can be added. Only these labels are allowed: [\"bug\" \"enhancement\" \"help wanted\" \"good first issue\" \"spam\" \"off topic\" \"documentation\" \"question\" \"duplicate\" \"wontfix\" \"needs triage\" \"needs investigation\" \"breaking change\" \"performance\" \"security\" \"refactor\"]. Target: *.", "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "item_number": { "description": "Issue or PR number to add labels to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, adds labels to the issue or PR that triggered this workflow. Only works for issue or pull_request event triggers. For schedule, workflow_dispatch, or other triggers, item_number is required — omitting it will silently skip the label operation.", "type": "number" @@ -538,6 +584,10 @@ jobs: "type": "string" }, "type": "array" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "type": "object" @@ -549,6 +599,10 @@ jobs: "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "item_number": { "description": "Issue or PR number to remove labels from. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, removes labels from the item that triggered this workflow.", "type": "number" @@ -559,6 +613,10 @@ jobs: "type": "string" }, "type": "array" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -584,6 +642,10 @@ jobs: "description": "Issue body content in Markdown. For 'replace', this becomes the entire body. For 'append'/'prepend', this content is added with a separator and an attribution footer. For 'replace-island', only the run-specific section is updated.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "issue_number": { "description": "Issue number to update. This is the numeric ID from the GitHub URL (e.g., 789 in github.com/owner/repo/issues/789). Required when the workflow target is '*' (any issue).", "type": [ @@ -615,6 +677,10 @@ jobs: ], "type": "string" }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "status": { "description": "New issue status: 'open' to reopen a closed issue, 'closed' to close an open issue.", "enum": [ @@ -641,6 +707,10 @@ jobs: "description": "Branch name to push changes from. If omitted, uses the current working branch. Only specify if you need to push from a different branch.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "message": { "description": "Commit message describing the changes. Follow repository commit message conventions (e.g., conventional commits).", "type": "string" @@ -651,6 +721,10 @@ jobs: "number", "string" ] + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -669,10 +743,18 @@ jobs: "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", "type": "string" }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" + }, "tool": { "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", "type": "string" @@ -690,9 +772,17 @@ jobs: "inputSchema": { "additionalProperties": false, "properties": { + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "message": { "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [ @@ -719,9 +809,17 @@ jobs: "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", "type": "string" }, + "integrity": { + "description": "Trustworthiness level of the message source (e.g., \"low\", \"medium\", \"high\").", + "type": "string" + }, "reason": { "description": "Explanation of why this data is needed to complete the task (max 256 characters).", "type": "string" + }, + "secrecy": { + "description": "Confidentiality level of the message content (e.g., \"public\", \"internal\", \"private\").", + "type": "string" } }, "required": [], @@ -1053,7 +1151,7 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.6' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8' mkdir -p /home/runner/.copilot cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh @@ -1100,12 +1198,12 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.jsr.io,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,deb.nodesource.com,deno.land,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,s.symcb.com,s.symcd.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} GITHUB_API_URL: ${{ github.api_url }} @@ -1116,6 +1214,11 @@ jobs: GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} GITHUB_WORKSPACE: ${{ github.workspace }} XDG_CONFIG_HOME: /home/runner + - name: Detect inference access error + id: detect-inference-error + if: always() + continue-on-error: true + run: bash /opt/gh-aw/actions/detect_inference_access_error.sh - name: Configure Git credentials env: REPO_NAME: ${{ github.repository }} @@ -1331,11 +1434,11 @@ jobs: set -o pipefail # shellcheck disable=SC1003 sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.23.0 --skip-pull --enable-api-proxy \ - -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"}' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + -- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} + COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GITHUB_API_URL: ${{ github.api_url }} GITHUB_HEAD_REF: ${{ github.head_ref }} @@ -1395,22 +1498,27 @@ jobs: discussions: write issues: write pull-requests: write + concurrency: + group: "gh-aw-conclusion-repo-assist" + cancel-in-progress: false outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} total_count: ${{ steps.missing_tool.outputs.total_count }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print @@ -1422,8 +1530,8 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1437,8 +1545,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1452,18 +1560,20 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "repo-assist" GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} + GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }} GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }} GH_AW_REPO_MEMORY_VALIDATION_FAILED_default: ${{ needs.push_repo_memory.outputs.validation_failed_default }} GH_AW_REPO_MEMORY_VALIDATION_ERROR_default: ${{ needs.push_repo_memory.outputs.validation_error_default }} GH_AW_GROUP_REPORTS: "false" + GH_AW_TIMEOUT_MINUTES: "60" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1477,8 +1587,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} @@ -1496,8 +1606,8 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} @@ -1524,31 +1634,14 @@ jobs: github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment')) runs-on: ubuntu-slim - permissions: - discussions: write - issues: write - pull-requests: write outputs: activated: ${{ (steps.check_membership.outputs.is_team_member == 'true') && (steps.check_command_position.outputs.command_position_ok == 'true') }} matched_command: ${{ steps.check_command_position.outputs.matched_command }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - - name: Add eyes reaction for immediate feedback - id: react - if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_REACTION: "eyes" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/add_reaction.cjs'); - await main(); - name: Check team membership for command workflow id: check_membership uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 @@ -1579,12 +1672,15 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + concurrency: + group: "push-repo-memory-${{ github.repository }}" + cancel-in-progress: false outputs: validation_error_default: ${{ steps.push_repo_memory_default.outputs.validation_error }} validation_failed_default: ${{ steps.push_repo_memory_default.outputs.validation_failed }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Checkout repository @@ -1646,11 +1742,12 @@ jobs: pull-requests: write timeout-minutes: 15 env: + GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/repo-assist" GH_AW_ENGINE_ID: "copilot" GH_AW_WORKFLOW_ID: "repo-assist" GH_AW_WORKFLOW_NAME: "Repo Assist" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/442992eda2ccb11ee75a39c019ec6d38ae5a84a2/workflows/repo-assist.md" + GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/tree/b466f28f0f65b68d6f2b10b15b44f51d787b93be/workflows/repo-assist.md" outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} @@ -1668,16 +1765,18 @@ jobs: push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }} steps: - name: Setup Scripts - uses: github/gh-aw/actions/setup@cccf96100f50705c4291b91a6071c556f72cb3ef # v0.51.2 + uses: github/gh-aw/actions/setup@a0ed2f46906483dcf634e8694268e4fab9b21e65 # v0.53.3 with: destination: /opt/gh-aw/actions - name: Download agent output artifact + id: download-agent-output continue-on-error: true uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: name: agent-output path: /tmp/gh-aw/safeoutputs/ - name: Setup agent output environment variable + if: steps.download-agent-output.outcome == 'success' run: | mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print diff --git a/.github/workflows/repo-assist.md b/.github/workflows/repo-assist.md index 395af6b..3bf61ba 100644 --- a/.github/workflows/repo-assist.md +++ b/.github/workflows/repo-assist.md @@ -71,8 +71,7 @@ tools: bash: true repo-memory: true -source: githubnext/agentics/workflows/repo-assist.md@442992eda2ccb11ee75a39c019ec6d38ae5a84a2 -engine: copilot +source: githubnext/agentics/workflows/repo-assist.md@b466f28f0f65b68d6f2b10b15b44f51d787b93be --- # Repo Assist @@ -290,4 +289,4 @@ Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` - **Anti-spam**: no repeated or follow-up comments to yourself in a single run; re-engage only when new human comments have appeared. - **Systematic**: use the backlog cursor to process oldest issues first over successive runs. Do not stop early. - **Quality over quantity**: noise erodes trust. Do nothing rather than add low-value output. -- **Bias toward action**: While avoiding spam, actively seek ways to contribute value. If you're about to conclude "no action needed", first verify: (a) you've checked the full open issue list, not just recent activity, (b) check there are no uncommented issues where you haven't engaged but should, (c) check there are no issues that are fixable or investigatable, (d) check all labeling is current, (e) check there are no useful engineering improvements you could perform, (f) check there is no testing to improve, (g) check there are no dependency updates to make, (h) check there are no code simplifications to make, (i) check there are no documentation improvements to make, (j) check there are no CI performance improvements to make. A "no action" run should be genuinely exceptional except in a near-perfect repository with no recent changes. \ No newline at end of file +- **Bias toward action**: While avoiding spam, actively seek ways to contribute value. If you're about to conclude "no action needed", first verify: (a) you've checked the full open issue list, not just recent activity, (b) check there are no uncommented issues where you haven't engaged but should, (c) check there are no issues that are fixable or investigatable, (d) check all labeling is current, (e) check there are no useful engineering improvements you could perform, (f) check there is no testing to improve, (g) check there are no dependency updates to make, (h) check there are no code simplifications to make, (i) check there are no documentation improvements to make, (j) check there are no CI performance improvements to make. A "no action" run should be genuinely exceptional except in a near-perfect repository with no recent changes. diff --git a/.github/workflows/validate_pr_title.yml b/.github/workflows/validate_pr_title.yml index 9abe214..6b37e3b 100644 --- a/.github/workflows/validate_pr_title.yml +++ b/.github/workflows/validate_pr_title.yml @@ -11,6 +11,7 @@ jobs: main: name: Validate PR title runs-on: ubuntu-latest + timeout-minutes: 5 permissions: contents: read pull-requests: write diff --git a/package-lock.json b/package-lock.json index ae2d320..164ca6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,19 +10,21 @@ "dependencies": { "tree-sitter": "^0.21.1", "tree-sitter-c-sharp": "^0.23.1", - "tree-sitter-go": "^0.21.0" + "tree-sitter-go": "^0.21.0", + "tree-sitter-javascript": "^0.21.4", + "tree-sitter-typescript": "^0.21.2" }, "devDependencies": { "@types/mocha": "^10.0.10", "@types/node": "^22.18.0", "@types/vscode": "^1.106.1", - "@typescript-eslint/eslint-plugin": "^8.56.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.0", "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^3.7.1", - "c8": "^10.1.2", - "eslint": "^10.0.1", + "c8": "^11.0.0", + "eslint": "^10.0.3", "mocha": "^11.7.5", "typescript": "^5.9.3" }, @@ -281,15 +283,15 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.2.tgz", - "integrity": "sha512-YF+fE6LV4v5MGWRGj7G404/OZzGNepVF8fxk7jqmqo3lrza7a0uUcDnROGRBG1WFC1omYUS/Wp1f42i0M+3Q3A==", + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz", + "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^3.0.2", + "@eslint/object-schema": "^3.0.3", "debug": "^4.3.1", - "minimatch": "^10.2.1" + "minimatch": "^10.2.4" }, "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -306,9 +308,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -348,9 +350,9 @@ } }, "node_modules/@eslint/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", - "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz", + "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -361,9 +363,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.2.tgz", - "integrity": "sha512-HOy56KJt48Bx8KmJ+XGQNSUMT/6dZee/M54XyUyuvTvPXJmsERRvBchsUVx1UMe1WwIH49XLAczNC7V2INsuUw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz", + "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -371,13 +373,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", - "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz", + "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^1.1.0", + "@eslint/core": "^1.1.1", "levn": "^0.4.1" }, "engines": { @@ -949,17 +951,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -972,22 +974,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", + "@typescript-eslint/parser": "^8.56.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3" }, "engines": { @@ -1003,14 +1005,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", "debug": "^4.4.3" }, "engines": { @@ -1025,14 +1027,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1043,9 +1045,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", "dev": true, "license": "MIT", "engines": { @@ -1060,15 +1062,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -1085,9 +1087,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", "dev": true, "license": "MIT", "engines": { @@ -1099,18 +1101,18 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", "debug": "^4.4.3", - "minimatch": "^9.0.5", + "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" @@ -1126,17 +1128,56 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1151,13 +1192,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1220,6 +1261,63 @@ "node": ">=18" } }, + "node_modules/@vscode/test-cli/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vscode/test-cli/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@vscode/test-cli/node_modules/c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, "node_modules/@vscode/test-cli/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -1281,6 +1379,37 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@vscode/test-cli/node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@vscode/test-cli/node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@vscode/test-electron": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.5.2.tgz", @@ -1849,9 +1978,9 @@ } }, "node_modules/c8": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", - "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz", + "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==", "dev": true, "license": "ISC", "dependencies": { @@ -1862,7 +1991,7 @@ "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.6", - "test-exclude": "^7.0.1", + "test-exclude": "^8.0.0", "v8-to-istanbul": "^9.0.0", "yargs": "^17.7.2", "yargs-parser": "^21.1.1" @@ -1871,7 +2000,7 @@ "c8": "bin/c8.js" }, "engines": { - "node": ">=18" + "node": "20 || >=22" }, "peerDependencies": { "monocart-coverage-reports": "^2" @@ -2652,27 +2781,27 @@ } }, "node_modules/eslint": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.1.tgz", - "integrity": "sha512-20MV9SUdeN6Jd84xESsKhRly+/vxI+hwvpBMA93s+9dAcjdCuCojn4IqUGS3lvVaqjVYGYHSRMCpeFtF2rQYxQ==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.3.tgz", + "integrity": "sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.2", + "@eslint/config-array": "^0.23.3", "@eslint/config-helpers": "^0.5.2", - "@eslint/core": "^1.1.0", - "@eslint/plugin-kit": "^0.6.0", + "@eslint/core": "^1.1.1", + "@eslint/plugin-kit": "^0.6.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.1", + "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.1.1", "esquery": "^1.7.0", @@ -2685,7 +2814,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.1", + "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -2708,9 +2837,9 @@ } }, "node_modules/eslint-scope": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.1.tgz", - "integrity": "sha512-GaUN0sWim5qc8KVErfPBWmc31LEsOkrUJbvJZV+xuL3u2phMUK4HIvXlWAakfC8W4nzlK+chPEAkYOYb5ZScIw==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4303,11 +4432,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -4952,9 +5081,9 @@ } }, "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4962,7 +5091,7 @@ "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6020,76 +6149,72 @@ } }, "node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", + "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^9.0.4" + "glob": "^13.0.6", + "minimatch": "^10.2.2" }, "engines": { - "node": ">=18" + "node": "20 || >=22" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "balanced-match": "^4.0.2" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/test-exclude/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/test-exclude/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/test-exclude/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/test-exclude/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/test-exclude/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6238,6 +6363,44 @@ } } }, + "node_modules/tree-sitter-javascript": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.21.4.tgz", + "integrity": "sha512-Lrk8yahebwrwc1sWJE9xPcz1OnnqiEV7Dh5fbN6EN3wNAdu9r06HpTqLqDwUUbnG4EB46Sfk+FJFAOldfoKLOw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.8.1" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree_sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-typescript": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.21.2.tgz", + "integrity": "sha512-/RyNK41ZpkA8PuPZimR6pGLvNR1p0ibRUJwwQn4qAjyyLEIQD/BNlwS3NSxWtGsAWZe9gZ44VK1mWx2+eQVldg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.0.0", + "node-gyp-build": "^4.8.1" + }, + "peerDependencies": { + "tree-sitter": "^0.21.0" + }, + "peerDependenciesMeta": { + "tree_sitter": { + "optional": true + } + } + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", diff --git a/package.json b/package.json index c1821e5..54a859c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,11 @@ ], "activationEvents": [ "onLanguage:csharp", - "onLanguage:go" + "onLanguage:go", + "onLanguage:javascript", + "onLanguage:javascriptreact", + "onLanguage:typescript", + "onLanguage:typescriptreact" ], "main": "./out/extension.js", "contributes": { @@ -97,27 +101,30 @@ "pretest": "npm run compile && npm run lint", "lint": "eslint src", "test": "vscode-test", + "test:vscode": "vscode-test", "test:unit": "npm run compile && c8 --config .c8rc.json mocha out/unit/unit.test.js", - "test:coverage": "npm run test:unit && npm test", + "test:coverage": "npm run compile && npm run lint && c8 --config .c8rc.json mocha out/unit/unit.test.js && vscode-test", "deploy": "vsce publish" }, "devDependencies": { "@types/mocha": "^10.0.10", "@types/node": "^22.18.0", "@types/vscode": "^1.106.1", - "@typescript-eslint/eslint-plugin": "^8.56.0", + "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.0", "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^3.7.1", - "c8": "^10.1.2", - "eslint": "^10.0.1", + "c8": "^11.0.0", + "eslint": "^10.0.3", "mocha": "^11.7.5", "typescript": "^5.9.3" }, "dependencies": { "tree-sitter": "^0.21.1", "tree-sitter-c-sharp": "^0.23.1", - "tree-sitter-go": "^0.21.0" + "tree-sitter-go": "^0.21.0", + "tree-sitter-javascript": "^0.21.4", + "tree-sitter-typescript": "^0.21.2" } } diff --git a/samples/Test.js b/samples/Test.js new file mode 100644 index 0000000..f7e93bc --- /dev/null +++ b/samples/Test.js @@ -0,0 +1,99 @@ +/** + * Sample JavaScript file to demonstrate cognitive complexity analysis. + * Open this file in VS Code with the Code Metrics extension active to see CodeLens overlays. + */ + +// Simple function - low complexity +function add(a, b) { + return a + b; +} + +// Medium complexity - if/else and logical operators +function validateAge(age) { + if (age === null || age === undefined) { + return false; + } else if (age < 0 || age > 150) { + return false; + } else { + return true; + } +} + +// Higher complexity - nested control flow +function processItems(items) { + const results = []; + + for (const item of items) { + if (item.active) { + if (item.value > 100) { + for (let i = 0; i < item.count; i++) { + if (i % 2 === 0 && item.value > 50) { + results.push(item.value * i); + } + } + } else { + results.push(item.value); + } + } + } + + return results; +} + +// Arrow function with ternary +const classify = (score) => + score >= 90 ? "A" : + score >= 80 ? "B" : + score >= 70 ? "C" : "F"; + +// Class with methods +class TaskManager { + constructor(maxTasks) { + this.tasks = []; + this.maxTasks = maxTasks; + } + + addTask(task) { + if (!task || !task.name) { + throw new Error("Invalid task"); + } + + if (this.tasks.length >= this.maxTasks) { + return false; + } + + this.tasks.push(task); + return true; + } + + findTask(name) { + for (const task of this.tasks) { + if (task.name === name) { + return task; + } + } + return null; + } + + processAll() { + let completed = 0; + let failed = 0; + + for (const task of this.tasks) { + try { + if (task.priority === "high" && !task.done) { + task.execute(); + completed++; + } else if (task.priority === "low" || task.done) { + // Skip low-priority or already done tasks + continue; + } + } catch (e) { + failed++; + console.error(`Task ${task.name} failed:`, e); + } + } + + return { completed, failed }; + } +} diff --git a/samples/Test.ts b/samples/Test.ts new file mode 100644 index 0000000..ec61804 --- /dev/null +++ b/samples/Test.ts @@ -0,0 +1,121 @@ +/** + * Sample TypeScript file to demonstrate cognitive complexity analysis. + * Open this file in VS Code with the Code Metrics extension active to see CodeLens overlays. + */ + +// Simple function - low complexity +function add(a: number, b: number): number { + return a + b; +} + +// Interface and type definitions do not contribute to complexity +interface Task { + name: string; + priority: "high" | "medium" | "low"; + done: boolean; + value: number; +} + +// Medium complexity - typed function with conditionals +function validateTask(task: Task | null | undefined): boolean { + if (!task) { + return false; + } + + if (!task.name || task.name.trim().length === 0) { + return false; + } + + return task.value >= 0 && task.priority !== undefined; +} + +// Higher complexity - nested loops and conditions +function processItems(items: Task[]): number[] { + const results: number[] = []; + + for (const item of items) { + if (item.done) { + continue; + } + + if (item.priority === "high") { + for (let i = 0; i < item.value; i++) { + if (i % 3 === 0 || item.value > 100) { + results.push(i * item.value); + } + } + } else if (item.priority === "medium") { + results.push(item.value); + } else { + results.push(0); + } + } + + return results; +} + +// Generic function - type parameters don't add complexity +function findFirst(items: T[], predicate: (item: T) => boolean): T | undefined { + for (const item of items) { + if (predicate(item)) { + return item; + } + } + return undefined; +} + +// Class with typed methods +class TaskManager { + private tasks: Task[] = []; + private maxTasks: number; + + constructor(maxTasks: number) { + this.maxTasks = maxTasks; + } + + addTask(task: Task): boolean { + if (!validateTask(task)) { + return false; + } + + if (this.tasks.length >= this.maxTasks) { + return false; + } + + this.tasks.push(task); + return true; + } + + getByPriority(priority: Task["priority"]): Task[] { + return this.tasks.filter( + (task) => task.priority === priority && !task.done + ); + } + + processAll(): { completed: number; skipped: number; failed: number } { + let completed = 0; + let skipped = 0; + let failed = 0; + + for (const task of this.tasks) { + try { + if (task.done) { + skipped++; + continue; + } + + if (task.priority === "high" || (task.priority === "medium" && task.value > 50)) { + // Process important tasks + completed++; + } else { + skipped++; + } + } catch (e) { + failed++; + console.error(`Task ${task.name} failed:`, e); + } + } + + return { completed, skipped, failed }; + } +} diff --git a/src/metricsAnalyzer/languages/javascriptAnalyzer.ts b/src/metricsAnalyzer/languages/javascriptAnalyzer.ts new file mode 100644 index 0000000..194c9da --- /dev/null +++ b/src/metricsAnalyzer/languages/javascriptAnalyzer.ts @@ -0,0 +1,447 @@ +/** + * @fileoverview JavaScript Cognitive Complexity Analyzer + * + * This module provides cognitive complexity analysis for JavaScript source code using Tree-sitter. + * It implements the cognitive complexity metric which measures how difficult code is to + * understand, taking into account control flow, nesting, and other complexity factors. + * + * The analyzer uses the tree-sitter-javascript parser to build an Abstract Syntax Tree (AST) + * and then traverses it to calculate complexity scores for each function/method. + */ + +import Parser from "tree-sitter"; +const JavaScript = require("tree-sitter-javascript"); // noqa + +/** + * Represents a single complexity detail for a specific JavaScript code construct. + * Each detail contributes to the overall cognitive complexity of a function. + */ +interface JavaScriptMetricsDetail { + /** The complexity increment this detail adds to the total complexity */ + increment: number; + /** Human-readable explanation of why this construct increases complexity */ + reason: string; + /** Line number where this complexity-contributing construct is located (0-based) */ + line: number; + /** Column number where this complexity-contributing construct starts (0-based) */ + column: number; + /** Current nesting level of this construct (0 for top-level) */ + nesting: number; +} + +/** + * Represents the complete cognitive complexity analysis results for a single JavaScript function. + * Includes the overall complexity score and detailed breakdown of contributing factors. + */ +interface JavaScriptFunctionMetrics { + /** The name or identifier of the function/method */ + name: string; + /** The total cognitive complexity score for this function */ + complexity: number; + /** Array of individual complexity details that contribute to the total score */ + details: JavaScriptMetricsDetail[]; + /** Line number where the function definition starts (0-based) */ + startLine: number; + /** Line number where the function definition ends (0-based) */ + endLine: number; + /** Column number where the function definition starts (0-based) */ + startColumn: number; + /** Column number where the function definition ends (0-based) */ + endColumn: number; +} + +/** + * Cognitive Complexity Analyzer for JavaScript source code. + * + * This class implements cognitive complexity analysis specifically for JavaScript code. + * Cognitive complexity is a metric that measures how difficult code is to understand, + * taking into account factors like: + * - Control flow statements (if, for, while, do, switch) + * - Nesting levels + * - Catch clauses (exception handling) + * - Logical operators (&&, ||, ??) + * - Ternary expressions + * - Nested functions and arrow functions + * + * The analyzer uses Tree-sitter for parsing and provides detailed analysis + * including the exact location and reason for each complexity increment. + * + * @example + * ```typescript + * const results = JavaScriptMetricsAnalyzer.analyzeFile(jsSourceCode); + * console.log(`Function ${results[0].name} has complexity ${results[0].complexity}`); + * ``` + */ +export class JavaScriptMetricsAnalyzer { + /** Current nesting level during analysis */ + private nesting = 0; + /** Current complexity score during analysis */ + private complexity = 0; + /** Array of complexity details for the current function being analyzed */ + private details: JavaScriptMetricsDetail[] = []; + /** The source code text being analyzed */ + private sourceText: string; + /** Tree-sitter parser instance configured for JavaScript */ + private parser: Parser; + + /** + * Creates a new instance of the JavaScript cognitive complexity analyzer. + * Initializes the Tree-sitter parser with the JavaScript language grammar. + */ + constructor() { + this.parser = new Parser(); + this.parser.setLanguage(JavaScript); + this.sourceText = ""; + } + + /** + * Analyzes all functions in the provided JavaScript source code. + * + * @param sourceText - The complete JavaScript source code to analyze + * @returns An array of complexity analysis results, one for each function found + */ + public analyzeFunctions(sourceText: string): JavaScriptFunctionMetrics[] { + this.sourceText = sourceText; + const tree = this.parser.parse(sourceText); + const functions: JavaScriptFunctionMetrics[] = []; + this.collectFunctions(tree.rootNode, functions, false); + return functions; + } + + /** + * Recursively collects functions from the AST and calculates their complexity. + * + * @param node - The current AST node to process + * @param functions - The array to accumulate function metrics into + * @param isNested - Whether this function is nested inside another function + */ + private collectFunctions( + node: Parser.SyntaxNode, + functions: JavaScriptFunctionMetrics[], + isNested: boolean + ): void { + const isFunctionNode = + node.type === "function_declaration" || + node.type === "function_expression" || + node.type === "method_definition" || + node.type === "arrow_function"; + + if (isFunctionNode) { + // If nested, add complexity for the nesting + if (isNested) { + this.complexity += 1 + this.nesting; + this.details.push({ + increment: 1 + this.nesting, + reason: this.getFunctionReason(node.type), + line: node.startPosition.row, + column: node.startPosition.column, + nesting: this.nesting, + }); + } + + // Save current state before analyzing nested function + const savedComplexity = this.complexity; + const savedDetails = this.details; + const savedNesting = this.nesting; + + // Reset for the new function + this.complexity = 0; + this.details = []; + this.nesting = 0; + + // Analyze the function body + const funcName = this.getFunctionName(node); + this.analyzeNode(node); + + const metrics: JavaScriptFunctionMetrics = { + name: funcName, + complexity: this.complexity, + details: this.details, + startLine: node.startPosition.row, + endLine: node.endPosition.row, + startColumn: node.startPosition.column, + endColumn: node.endPosition.column, + }; + functions.push(metrics); + + // Restore state + this.complexity = savedComplexity; + this.details = savedDetails; + this.nesting = savedNesting; + } else { + for (const child of node.children) { + this.collectFunctions(child, functions, isNested); + } + } + } + + /** + * Returns a human-readable reason for a function node type. + */ + private getFunctionReason(nodeType: string): string { + switch (nodeType) { + case "arrow_function": + return "arrow function (nested)"; + case "function_expression": + return "function expression (nested)"; + case "method_definition": + return "method (nested)"; + default: + return "function (nested)"; + } + } + + /** + * Extracts the name of a function from its AST node. + * + * @param node - The function AST node + * @returns The function name or a descriptive placeholder + */ + private getFunctionName(node: Parser.SyntaxNode): string { + if (node.type === "function_declaration" || node.type === "function_expression") { + const nameNode = node.children.find((c) => c.type === "identifier"); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + + if (node.type === "method_definition") { + const nameNode = node.children.find( + (c) => c.type === "property_identifier" || c.type === "identifier" + ); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + + if (node.type === "arrow_function") { + // Arrow functions may be assigned to a variable - check parent + const parent = node.parent; + if (parent && parent.type === "variable_declarator") { + const nameNode = parent.children.find((c) => c.type === "identifier"); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + return "(arrow function)"; + } + + return "(anonymous)"; + } + + /** + * Analyzes a single AST node and its children for complexity contributions. + * + * @param node - The AST node to analyze + * @param skipSelfIncrement - When true, skip incrementing complexity for this node (used for else-if) + */ + private analyzeNode(node: Parser.SyntaxNode, skipSelfIncrement = false): void { + if (!skipSelfIncrement) { + const increment = this.getComplexityIncrement(node); + if (increment > 0) { + this.details.push({ + increment, + reason: this.getComplexityReason(node), + line: node.startPosition.row, + column: node.startPosition.column, + nesting: this.nesting, + }); + this.complexity += increment; + } + } + + const nestingIncreased = this.increasesNesting(node); + if (nestingIncreased) { + this.nesting++; + } + + for (const child of node.children) { + // Skip nested function bodies - they are analyzed separately + if (this.isNestedFunction(child)) { + this.collectFunctions(child, [], true); + continue; + } + // For else_clause containing if_statement (else-if): + // The else_clause is already counted above. The inner if_statement's structural + // increment is skipped to avoid double-counting, but its body is still analyzed. + if (node.type === "else_clause" && child.type === "if_statement") { + this.analyzeNode(child, true); + continue; + } + this.analyzeNode(child); + } + + if (nestingIncreased) { + this.nesting--; + } + } + + /** + * Checks if a node is a nested function definition. + */ + private isNestedFunction(node: Parser.SyntaxNode): boolean { + return ( + node.type === "function_expression" || + node.type === "arrow_function" || + node.type === "method_definition" + ); + } + + /** + * Calculates the complexity increment for a specific syntax node type. + * + * Based on cognitive complexity rules: + * - Control flow statements: +1 (+ nesting level) + * - Else/else-if clauses: +1 (flat, no nesting) + * - Catch clauses: +1 + * - Ternary expressions: +1 + * - Logical operators (&&, ||, ??): +1 each + * - Labeled break/continue: +1 + * + * @param node - The syntax node to evaluate + * @returns The complexity increment (0 or positive integer) + */ + private getComplexityIncrement(node: Parser.SyntaxNode): number { + switch (node.type) { + // Control flow statements (+1 + nesting) + case "if_statement": + case "for_statement": + case "for_in_statement": + case "for_of_statement": + case "while_statement": + case "do_statement": + case "switch_statement": + return 1 + this.nesting; + + // Else/else-if clauses (+1, flat) + case "else_clause": + return 1; + + // Exception handling (+1) + case "catch_clause": + return 1; + + // Ternary expressions (+1) + case "ternary_expression": + return 1; + + // Logical operators (+1 each) + case "binary_expression": + case "logical_expression": { + const op = this.getOperator(node); + if (op === "&&" || op === "||" || op === "??") { + return 1; + } + return 0; + } + + // Labeled break/continue (+1) + case "break_statement": + case "continue_statement": { + const hasLabel = node.children.some( + (c) => c.type === "statement_identifier" + ); + return hasLabel ? 1 : 0; + } + + default: + return 0; + } + } + + /** + * Extracts the operator from a binary or logical expression node. + */ + private getOperator(node: Parser.SyntaxNode): string | null { + for (const child of node.children) { + const text = this.sourceText.substring(child.startIndex, child.endIndex); + if (text === "&&" || text === "||" || text === "??") { + return text; + } + } + return null; + } + + /** + * Generates a human-readable reason for why a syntax node increases complexity. + * + * @param node - The syntax node that contributes to complexity + * @returns A descriptive string explaining the complexity increment + */ + private getComplexityReason(node: Parser.SyntaxNode): string { + switch (node.type) { + case "if_statement": + return "if statement"; + case "else_clause": { + // Distinguish between else and else-if + const hasNestedIf = node.children.some((c) => c.type === "if_statement"); + return hasNestedIf ? "else if clause" : "else clause"; + } + case "for_statement": + return "for loop"; + case "for_in_statement": + return "for...in loop"; + case "for_of_statement": + return "for...of loop"; + case "while_statement": + return "while loop"; + case "do_statement": + return "do...while loop"; + case "switch_statement": + return "switch statement"; + case "catch_clause": + return "catch clause"; + case "ternary_expression": + return "ternary expression"; + case "binary_expression": + case "logical_expression": { + const op = this.getOperator(node); + return `logical ${op} operator`; + } + case "break_statement": + return "labeled break statement"; + case "continue_statement": + return "labeled continue statement"; + default: + return "complexity source"; + } + } + + /** + * Determines if a syntax node increases the nesting level. + * + * @param node - The syntax node to check + * @returns True if the node increases nesting level + */ + private increasesNesting(node: Parser.SyntaxNode): boolean { + return ( + node.type === "if_statement" || + node.type === "for_statement" || + node.type === "for_in_statement" || + node.type === "for_of_statement" || + node.type === "while_statement" || + node.type === "do_statement" || + node.type === "switch_statement" || + node.type === "catch_clause" + ); + } + + /** + * Static factory method to analyze JavaScript source code. + * + * @param sourceText - The complete JavaScript source code to analyze + * @returns An array of complexity analysis results for all functions found + * + * @example + * ```typescript + * const results = JavaScriptMetricsAnalyzer.analyzeFile(jsCode); + * results.forEach(func => { + * console.log(`${func.name}: ${func.complexity}`); + * }); + * ``` + */ + public static analyzeFile(sourceText: string): JavaScriptFunctionMetrics[] { + const analyzer = new JavaScriptMetricsAnalyzer(); + return analyzer.analyzeFunctions(sourceText); + } +} diff --git a/src/metricsAnalyzer/languages/typescriptAnalyzer.ts b/src/metricsAnalyzer/languages/typescriptAnalyzer.ts new file mode 100644 index 0000000..0eb35e8 --- /dev/null +++ b/src/metricsAnalyzer/languages/typescriptAnalyzer.ts @@ -0,0 +1,438 @@ +/** + * @fileoverview TypeScript Cognitive Complexity Analyzer + * + * This module provides cognitive complexity analysis for TypeScript source code using Tree-sitter. + * It implements the cognitive complexity metric which measures how difficult code is to + * understand, taking into account control flow, nesting, and other complexity factors. + * + * TypeScript is a superset of JavaScript, so this analyzer handles the same constructs + * as the JavaScript analyzer plus TypeScript-specific syntax. It uses the tree-sitter-typescript + * parser for accurate AST generation. + */ + +import Parser from "tree-sitter"; +const { typescript: TypeScriptLanguage } = require("tree-sitter-typescript"); // noqa + +/** + * Represents a single complexity detail for a specific TypeScript code construct. + * Each detail contributes to the overall cognitive complexity of a function. + */ +interface TypeScriptMetricsDetail { + /** The complexity increment this detail adds to the total complexity */ + increment: number; + /** Human-readable explanation of why this construct increases complexity */ + reason: string; + /** Line number where this complexity-contributing construct is located (0-based) */ + line: number; + /** Column number where this complexity-contributing construct starts (0-based) */ + column: number; + /** Current nesting level of this construct (0 for top-level) */ + nesting: number; +} + +/** + * Represents the complete cognitive complexity analysis results for a single TypeScript function. + * Includes the overall complexity score and detailed breakdown of contributing factors. + */ +interface TypeScriptFunctionMetrics { + /** The name or identifier of the function/method */ + name: string; + /** The total cognitive complexity score for this function */ + complexity: number; + /** Array of individual complexity details that contribute to the total score */ + details: TypeScriptMetricsDetail[]; + /** Line number where the function definition starts (0-based) */ + startLine: number; + /** Line number where the function definition ends (0-based) */ + endLine: number; + /** Column number where the function definition starts (0-based) */ + startColumn: number; + /** Column number where the function definition ends (0-based) */ + endColumn: number; +} + +/** + * Cognitive Complexity Analyzer for TypeScript source code. + * + * This class implements cognitive complexity analysis specifically for TypeScript code. + * Since TypeScript is a superset of JavaScript, it handles the same control flow constructs + * as the JavaScript analyzer. TypeScript-specific syntax (type annotations, interfaces, + * generics) generally does not affect cognitive complexity. + * + * Cognitive complexity factors include: + * - Control flow statements (if, for, while, do, switch) + * - Nesting levels + * - Catch clauses (exception handling) + * - Logical operators (&&, ||, ??) + * - Ternary expressions + * - Nested functions and arrow functions + * + * @example + * ```typescript + * const results = TypeScriptMetricsAnalyzer.analyzeFile(tsSourceCode); + * console.log(`Function ${results[0].name} has complexity ${results[0].complexity}`); + * ``` + */ +export class TypeScriptMetricsAnalyzer { + /** Current nesting level during analysis */ + private nesting = 0; + /** Current complexity score during analysis */ + private complexity = 0; + /** Array of complexity details for the current function being analyzed */ + private details: TypeScriptMetricsDetail[] = []; + /** The source code text being analyzed */ + private sourceText: string; + /** Tree-sitter parser instance configured for TypeScript */ + private parser: Parser; + + /** + * Creates a new instance of the TypeScript cognitive complexity analyzer. + * Initializes the Tree-sitter parser with the TypeScript language grammar. + */ + constructor() { + this.parser = new Parser(); + this.parser.setLanguage(TypeScriptLanguage); + this.sourceText = ""; + } + + /** + * Analyzes all functions in the provided TypeScript source code. + * + * @param sourceText - The complete TypeScript source code to analyze + * @returns An array of complexity analysis results, one for each function found + */ + public analyzeFunctions(sourceText: string): TypeScriptFunctionMetrics[] { + this.sourceText = sourceText; + const tree = this.parser.parse(sourceText); + const functions: TypeScriptFunctionMetrics[] = []; + this.collectFunctions(tree.rootNode, functions, false); + return functions; + } + + /** + * Recursively collects functions from the AST and calculates their complexity. + * + * @param node - The current AST node to process + * @param functions - The array to accumulate function metrics into + * @param isNested - Whether this function is nested inside another function + */ + private collectFunctions( + node: Parser.SyntaxNode, + functions: TypeScriptFunctionMetrics[], + isNested: boolean + ): void { + const isFunctionNode = + node.type === "function_declaration" || + node.type === "function_expression" || + node.type === "method_definition" || + node.type === "arrow_function"; + + if (isFunctionNode) { + // If nested, add complexity for the nesting + if (isNested) { + this.complexity += 1 + this.nesting; + this.details.push({ + increment: 1 + this.nesting, + reason: this.getFunctionReason(node.type), + line: node.startPosition.row, + column: node.startPosition.column, + nesting: this.nesting, + }); + } + + // Save current state before analyzing nested function + const savedComplexity = this.complexity; + const savedDetails = this.details; + const savedNesting = this.nesting; + + // Reset for the new function + this.complexity = 0; + this.details = []; + this.nesting = 0; + + // Analyze the function body + const funcName = this.getFunctionName(node); + this.analyzeNode(node); + + const metrics: TypeScriptFunctionMetrics = { + name: funcName, + complexity: this.complexity, + details: this.details, + startLine: node.startPosition.row, + endLine: node.endPosition.row, + startColumn: node.startPosition.column, + endColumn: node.endPosition.column, + }; + functions.push(metrics); + + // Restore state + this.complexity = savedComplexity; + this.details = savedDetails; + this.nesting = savedNesting; + } else { + for (const child of node.children) { + this.collectFunctions(child, functions, isNested); + } + } + } + + /** + * Returns a human-readable reason for a function node type. + */ + private getFunctionReason(nodeType: string): string { + switch (nodeType) { + case "arrow_function": + return "arrow function (nested)"; + case "function_expression": + return "function expression (nested)"; + case "method_definition": + return "method (nested)"; + default: + return "function (nested)"; + } + } + + /** + * Extracts the name of a function from its AST node. + * + * @param node - The function AST node + * @returns The function name or a descriptive placeholder + */ + private getFunctionName(node: Parser.SyntaxNode): string { + if (node.type === "function_declaration" || node.type === "function_expression") { + const nameNode = node.children.find((c) => c.type === "identifier"); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + + if (node.type === "method_definition") { + const nameNode = node.children.find( + (c) => c.type === "property_identifier" || c.type === "identifier" + ); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + + if (node.type === "arrow_function") { + const parent = node.parent; + if (parent && parent.type === "variable_declarator") { + const nameNode = parent.children.find((c) => c.type === "identifier"); + if (nameNode) { + return this.sourceText.substring(nameNode.startIndex, nameNode.endIndex); + } + } + return "(arrow function)"; + } + + return "(anonymous)"; + } + + /** + * Analyzes a single AST node and its children for complexity contributions. + * + * @param node - The AST node to analyze + * @param skipSelfIncrement - When true, skip incrementing complexity for this node (used for else-if) + */ + private analyzeNode(node: Parser.SyntaxNode, skipSelfIncrement = false): void { + if (!skipSelfIncrement) { + const increment = this.getComplexityIncrement(node); + if (increment > 0) { + this.details.push({ + increment, + reason: this.getComplexityReason(node), + line: node.startPosition.row, + column: node.startPosition.column, + nesting: this.nesting, + }); + this.complexity += increment; + } + } + + const nestingIncreased = this.increasesNesting(node); + if (nestingIncreased) { + this.nesting++; + } + + for (const child of node.children) { + // Skip nested function bodies - they are analyzed separately + if (this.isNestedFunction(child)) { + this.collectFunctions(child, [], true); + continue; + } + // For else_clause containing if_statement (else-if): + // The else_clause is already counted above. The inner if_statement's structural + // increment is skipped to avoid double-counting, but its body is still analyzed. + if (node.type === "else_clause" && child.type === "if_statement") { + this.analyzeNode(child, true); + continue; + } + this.analyzeNode(child); + } + + if (nestingIncreased) { + this.nesting--; + } + } + + /** + * Checks if a node is a nested function definition. + */ + private isNestedFunction(node: Parser.SyntaxNode): boolean { + return ( + node.type === "function_expression" || + node.type === "arrow_function" || + node.type === "method_definition" + ); + } + + /** + * Calculates the complexity increment for a specific syntax node type. + * + * @param node - The syntax node to evaluate + * @returns The complexity increment (0 or positive integer) + */ + private getComplexityIncrement(node: Parser.SyntaxNode): number { + switch (node.type) { + // Control flow statements (+1 + nesting) + case "if_statement": + case "for_statement": + case "for_in_statement": + case "for_of_statement": + case "while_statement": + case "do_statement": + case "switch_statement": + return 1 + this.nesting; + + // Else/else-if clauses (+1, flat) + case "else_clause": + return 1; + + // Exception handling (+1) + case "catch_clause": + return 1; + + // Ternary expressions (+1) + case "ternary_expression": + return 1; + + // Logical operators (+1 each) + case "binary_expression": + case "logical_expression": { + const op = this.getOperator(node); + if (op === "&&" || op === "||" || op === "??") { + return 1; + } + return 0; + } + + // Labeled break/continue (+1) + case "break_statement": + case "continue_statement": { + const hasLabel = node.children.some( + (c) => c.type === "statement_identifier" + ); + return hasLabel ? 1 : 0; + } + + default: + return 0; + } + } + + /** + * Extracts the operator from a binary or logical expression node. + */ + private getOperator(node: Parser.SyntaxNode): string | null { + for (const child of node.children) { + const text = this.sourceText.substring(child.startIndex, child.endIndex); + if (text === "&&" || text === "||" || text === "??") { + return text; + } + } + return null; + } + + /** + * Generates a human-readable reason for why a syntax node increases complexity. + * + * @param node - The syntax node that contributes to complexity + * @returns A descriptive string explaining the complexity increment + */ + private getComplexityReason(node: Parser.SyntaxNode): string { + switch (node.type) { + case "if_statement": + return "if statement"; + case "else_clause": { + const hasNestedIf = node.children.some((c) => c.type === "if_statement"); + return hasNestedIf ? "else if clause" : "else clause"; + } + case "for_statement": + return "for loop"; + case "for_in_statement": + return "for...in loop"; + case "for_of_statement": + return "for...of loop"; + case "while_statement": + return "while loop"; + case "do_statement": + return "do...while loop"; + case "switch_statement": + return "switch statement"; + case "catch_clause": + return "catch clause"; + case "ternary_expression": + return "ternary expression"; + case "binary_expression": + case "logical_expression": { + const op = this.getOperator(node); + return `logical ${op} operator`; + } + case "break_statement": + return "labeled break statement"; + case "continue_statement": + return "labeled continue statement"; + default: + return "complexity source"; + } + } + + /** + * Determines if a syntax node increases the nesting level. + * + * @param node - The syntax node to check + * @returns True if the node increases nesting level + */ + private increasesNesting(node: Parser.SyntaxNode): boolean { + return ( + node.type === "if_statement" || + node.type === "for_statement" || + node.type === "for_in_statement" || + node.type === "for_of_statement" || + node.type === "while_statement" || + node.type === "do_statement" || + node.type === "switch_statement" || + node.type === "catch_clause" + ); + } + + /** + * Static factory method to analyze TypeScript source code. + * + * @param sourceText - The complete TypeScript source code to analyze + * @returns An array of complexity analysis results for all functions found + * + * @example + * ```typescript + * const results = TypeScriptMetricsAnalyzer.analyzeFile(tsCode); + * results.forEach(func => { + * console.log(`${func.name}: ${func.complexity}`); + * }); + * ``` + */ + public static analyzeFile(sourceText: string): TypeScriptFunctionMetrics[] { + const analyzer = new TypeScriptMetricsAnalyzer(); + return analyzer.analyzeFunctions(sourceText); + } +} diff --git a/src/metricsAnalyzer/metricsAnalyzerFactory.ts b/src/metricsAnalyzer/metricsAnalyzerFactory.ts index eece0ef..bd9a29c 100644 --- a/src/metricsAnalyzer/metricsAnalyzerFactory.ts +++ b/src/metricsAnalyzer/metricsAnalyzerFactory.ts @@ -140,6 +140,10 @@ const languageAnalyzers: Record< > = { csharp: createCSharpAnalyzer(), go: createGoAnalyzer(), + javascript: createJavaScriptAnalyzer(), + javascriptreact: createJavaScriptAnalyzer(), + typescript: createTypeScriptAnalyzer(), + typescriptreact: createTypeScriptAnalyzer(), }; /** @@ -238,3 +242,93 @@ function createGoAnalyzer(): (sourceText: string) => UnifiedFunctionMetrics[] { })); }; } + +/** + * Creates a JavaScript cognitive complexity analyzer function. + * + * @returns A function that analyzes JavaScript source code and returns an array of function complexity metrics. + */ +function createJavaScriptAnalyzer(): ( + sourceText: string +) => UnifiedFunctionMetrics[] { + return function (sourceText: string) { + const { JavaScriptMetricsAnalyzer } = require("./languages/javascriptAnalyzer"); + interface JSDetail { + increment: number; + reason: string; + line: number; + column: number; + nesting: number; + } + interface JSFunctionMetrics { + name: string; + complexity: number; + details: JSDetail[]; + startLine: number; + endLine: number; + startColumn: number; + endColumn: number; + } + const functions = JavaScriptMetricsAnalyzer.analyzeFile(sourceText) as JSFunctionMetrics[]; + return functions.map((func: JSFunctionMetrics) => ({ + name: func.name, + complexity: func.complexity, + details: func.details.map((detail: JSDetail) => ({ + increment: detail.increment, + reason: detail.reason, + line: detail.line + 1, // JS analyzer uses 0-based, normalize to 1-based + column: detail.column + 1, // JS analyzer uses 0-based, normalize to 1-based + nesting: detail.nesting, + })), + startLine: func.startLine, + endLine: func.endLine, + startColumn: func.startColumn, + endColumn: func.endColumn, + })); + }; +} + +/** + * Creates a TypeScript cognitive complexity analyzer function. + * + * @returns A function that analyzes TypeScript source code and returns an array of function complexity metrics. + */ +function createTypeScriptAnalyzer(): ( + sourceText: string +) => UnifiedFunctionMetrics[] { + return function (sourceText: string) { + const { TypeScriptMetricsAnalyzer } = require("./languages/typescriptAnalyzer"); + interface TSDetail { + increment: number; + reason: string; + line: number; + column: number; + nesting: number; + } + interface TSFunctionMetrics { + name: string; + complexity: number; + details: TSDetail[]; + startLine: number; + endLine: number; + startColumn: number; + endColumn: number; + } + const functions = TypeScriptMetricsAnalyzer.analyzeFile(sourceText) as TSFunctionMetrics[]; + return functions.map((func: TSFunctionMetrics) => ({ + name: func.name, + complexity: func.complexity, + details: func.details.map((detail: TSDetail) => ({ + increment: detail.increment, + reason: detail.reason, + line: detail.line + 1, // TS analyzer uses 0-based, normalize to 1-based + column: detail.column + 1, // TS analyzer uses 0-based, normalize to 1-based + nesting: detail.nesting, + })), + startLine: func.startLine, + endLine: func.endLine, + startColumn: func.startColumn, + endColumn: func.endColumn, + })); + }; +} diff --git a/src/unit/unit.test.ts b/src/unit/unit.test.ts index c07440f..b94449c 100644 --- a/src/unit/unit.test.ts +++ b/src/unit/unit.test.ts @@ -8,6 +8,8 @@ import * as assert from "assert"; import { CSharpMetricsAnalyzer } from "../metricsAnalyzer/languages/csharpAnalyzer"; import { GoMetricsAnalyzer } from "../metricsAnalyzer/languages/goAnalyzer"; +import { JavaScriptMetricsAnalyzer } from "../metricsAnalyzer/languages/javascriptAnalyzer"; +import { TypeScriptMetricsAnalyzer } from "../metricsAnalyzer/languages/typescriptAnalyzer"; import { MetricsAnalyzerFactory, UnifiedFunctionMetrics, @@ -403,4 +405,193 @@ func Subtract(a, b int) int { assert.strictEqual(results.length, 0); }); }); + + describe("JavaScript Analyzer Core Logic", () => { + it("should analyze simple function correctly", () => { + const sourceCode = ` +function add(a, b) { + return a + b; +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "add"); + assert.strictEqual(results[0].complexity, 0); + }); + + it("should analyze if statement correctly", () => { + const sourceCode = ` +function max(a, b) { + if (a > b) { + return a; + } + return b; +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "max"); + assert.strictEqual(results[0].complexity, 1); + }); + + it("should count if/else correctly", () => { + const sourceCode = ` +function greet(name) { + if (name) { + return 'Hello ' + name; + } else { + return 'Hello World'; + } +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results[0].complexity, 2); + }); + + it("should count else-if chains correctly", () => { + const sourceCode = ` +function classify(x) { + if (x > 10) { + return 'big'; + } else if (x > 5) { + return 'medium'; + } else { + return 'small'; + } +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results[0].complexity, 3); + }); + + it("should count logical operators", () => { + const sourceCode = ` +function check(a, b, c) { + if (a && b || c) { + return true; + } + return false; +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + // if=1, &&=1, ||=1 → 3 + assert.strictEqual(results[0].complexity, 3); + }); + + it("should count nested complexity", () => { + const sourceCode = ` +function process(items) { + for (let i = 0; i < items.length; i++) { + if (items[i] > 0) { + console.log(items[i]); + } + } +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + // for=1, if=2 (nesting=1) → 3 + assert.strictEqual(results[0].complexity, 3); + }); + + it("should analyze arrow functions", () => { + const sourceCode = ` +const double = (x) => x * 2; +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "double"); + assert.strictEqual(results[0].complexity, 0); + }); + + it("should analyze class methods", () => { + const sourceCode = ` +class Calculator { + add(a, b) { + return a + b; + } +} +`; + const results = JavaScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "add"); + }); + + it("should handle factory analyzeFile with javascript language id", () => { + const sourceCode = ` +function hello() { + return 'world'; +} +`; + const results = MetricsAnalyzerFactory.analyzeFile(sourceCode, "javascript"); + assert.ok(Array.isArray(results)); + assert.strictEqual(results.length, 1); + }); + }); + + describe("TypeScript Analyzer Core Logic", () => { + it("should analyze typed function correctly", () => { + const sourceCode = ` +function add(a: number, b: number): number { + return a + b; +} +`; + const results = TypeScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "add"); + assert.strictEqual(results[0].complexity, 0); + }); + + it("should analyze if with logical operators", () => { + const sourceCode = ` +function validate(a: number, b: number): boolean { + if (a < 0 || b < 0) { + return false; + } + return true; +} +`; + const results = TypeScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results[0].complexity, 2); // if=1, ||=1 + }); + + it("should analyze class methods with control flow", () => { + const sourceCode = ` +class Service { + process(items: number[]): number { + let total = 0; + for (const item of items) { + if (item > 0) { + total += item; + } + } + return total; + } +} +`; + const results = TypeScriptMetricsAnalyzer.analyzeFile(sourceCode); + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].name, "process"); + // for=1, if=2 (nesting=1) → 3 + assert.strictEqual(results[0].complexity, 3); + }); + + it("should handle factory analyzeFile with typescript language id", () => { + const sourceCode = ` +function hello(): string { + return 'world'; +} +`; + const results = MetricsAnalyzerFactory.analyzeFile(sourceCode, "typescript"); + assert.ok(Array.isArray(results)); + assert.strictEqual(results.length, 1); + }); + + it("should include javascript and typescript in supported languages", () => { + const languages = MetricsAnalyzerFactory.getSupportedLanguages(); + assert.ok(languages.includes("javascript")); + assert.ok(languages.includes("typescript")); + assert.ok(languages.includes("javascriptreact")); + assert.ok(languages.includes("typescriptreact")); + }); + }); }); diff --git a/tsconfig.json b/tsconfig.json index c5f1e07..51d16f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,6 @@ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ - } + }, + "exclude": ["samples"] }