Full Code of fsprojects/SwaggerProvider for AI

master d30e27de7304 cached
122 files
3.4 MB
903.7k tokens
1 requests
Download .txt
Showing preview only (3,618K chars total). Download the full file or copy to clipboard to get everything.
Repository: fsprojects/SwaggerProvider
Branch: master
Commit: d30e27de7304
Files: 122
Total size: 3.4 MB

Directory structure:
gitextract_zkbrmfz_/

├── .config/
│   └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── aw/
│   │   └── actions-lock.json
│   ├── dependabot.yml
│   └── workflows/
│       ├── docs.yml
│       ├── dotnetcore.yml
│       ├── repo-assist.lock.yml
│       └── repo-assist.md
├── .gitignore
├── AGENTS.md
├── LICENSE.txt
├── README.md
├── SwaggerProvider.TestsAndDocs.sln
├── SwaggerProvider.sln
├── build.cmd
├── build.fsx
├── build.sh
├── docs/
│   ├── .gitignore
│   ├── .vitepress/
│   │   ├── config.mts
│   │   └── theme/
│   │       ├── custom.css
│   │       └── index.ts
│   ├── Customization.md
│   ├── OpenApiClientProvider.md
│   ├── RELEASE_NOTES.md
│   ├── files/
│   │   └── img/
│   │       └── logo.pdn
│   ├── getting-started.md
│   ├── index.md
│   └── package.json
├── global.json
├── paket.dependencies
├── src/
│   ├── Common/
│   │   └── AssemblyInfo.fs
│   ├── SwaggerProvider.DesignTime/
│   │   ├── Caching.fs
│   │   ├── DefinitionCompiler.fs
│   │   ├── OperationCompiler.fs
│   │   ├── Properties/
│   │   │   └── launchSettings.json
│   │   ├── Provider.OpenApiClient.fs
│   │   ├── SwaggerProvider.DesignTime.fsproj
│   │   ├── Utils.fs
│   │   └── paket.references
│   └── SwaggerProvider.Runtime/
│       ├── Exception.fs
│       ├── ProvidedApiClientBase.fs
│       ├── Runtime.fs
│       ├── RuntimeHelpers.fs
│       ├── SwaggerProvider.Runtime.fsproj
│       ├── SwaggerProvider.fsx
│       ├── paket.references
│       └── paket.template
└── tests/
    ├── SwaggerProvider.ProviderTests/
    │   ├── APIs.Guru.FSC.Tests.fs
    │   ├── Schemas/
    │   │   ├── Instagram.json
    │   │   ├── azure-arm-storage.json
    │   │   ├── clickmeter.com.json
    │   │   ├── github.json
    │   │   ├── i0027.json
    │   │   ├── issue132.json
    │   │   ├── issue173.json
    │   │   ├── issue181.yaml
    │   │   ├── issue219.yaml
    │   │   ├── issue255.yaml
    │   │   ├── issue279.json
    │   │   ├── my-swashbuckle.json
    │   │   ├── nullable-date.yaml
    │   │   ├── nullable-parameter-issue261.json
    │   │   ├── petstore-v2.json
    │   │   ├── petstore.yaml
    │   │   ├── slack.json
    │   │   ├── swashbuckle.json
    │   │   └── unsupported/
    │   │       ├── gettyimages.com.json
    │   │       └── issue0204.yaml
    │   ├── Script.fsx
    │   ├── Swagger.I0173.Tests.fs
    │   ├── Swagger.I0181.Tests.fs
    │   ├── Swagger.I0219.Tests.fs
    │   ├── Swagger.I0279.Tests.fs
    │   ├── Swagger.NullableDate.Tests.fs
    │   ├── Swagger.PetStore.Tests.fs
    │   ├── Swagger.SchemaReaderErrors.Tests.fs
    │   ├── SwaggerProvider.ProviderTests.fsproj
    │   ├── Swashbuckle.CancellationToken.Tests.fs
    │   ├── Swashbuckle.FileController.Tests.fs
    │   ├── Swashbuckle.NoContentControllers.Tests.fs
    │   ├── Swashbuckle.ResourceControllers.Tests.fs
    │   ├── Swashbuckle.ReturnControllers.Tests.fs
    │   ├── Swashbuckle.ReturnTextControllers.Tests.fs
    │   ├── Swashbuckle.SpecialCasesControllers.Tests.fs
    │   ├── Swashbuckle.UpdateControllers.Tests.fs
    │   ├── paket.references
    │   └── thing.fsx
    ├── SwaggerProvider.Tests/
    │   ├── APIs.guru.fs
    │   ├── PathResolutionTests.fs
    │   ├── RuntimeHelpersTests.fs
    │   ├── Schema.ArrayAndMapTypeMappingTests.fs
    │   ├── Schema.DefinitionPathTests.fs
    │   ├── Schema.OperationCompilationTests.fs
    │   ├── Schema.Parser.Tests.fs
    │   ├── Schema.TestHelpers.fs
    │   ├── Schema.TypeMappingTests.fs
    │   ├── Schema.V2SchemaCompilationTests.fs
    │   ├── Schema.XmlDocTests.fs
    │   ├── SsrfSecurityTests.fs
    │   ├── SwaggerProvider.Tests.fsproj
    │   ├── UtilsTests.fs
    │   └── paket.references
    ├── Swashbuckle.WebApi.Server/
    │   ├── Controllers/
    │   │   ├── FileController.fs
    │   │   ├── NoContentControllers.fs
    │   │   ├── ResourceControllers.fs
    │   │   ├── ReturnControllers.fs
    │   │   ├── ReturnTextControllers.fs
    │   │   ├── SpecialCasesControllers.fs
    │   │   ├── Types.fs
    │   │   ├── UpdateControllers.fs
    │   │   └── ValuesController.fs
    │   ├── Program.fs
    │   ├── Properties/
    │   │   └── launchSettings.json
    │   ├── Startup.fs
    │   ├── Swashbuckle.WebApi.Server.fsproj
    │   ├── app.config
    │   ├── appsettings.Development.json
    │   ├── appsettings.json
    │   └── paket.references
    └── test.fsx

================================================
FILE CONTENTS
================================================

================================================
FILE: .config/dotnet-tools.json
================================================
{
  "version": 1,
  "isRoot": true,
  "tools": {
    "paket": {
      "version": "10.3.1",
      "commands": [
        "paket"
      ],
      "rollForward": false
    },
    "dotnet-serve": {
      "version": "1.10.194",
      "commands": [
        "dotnet-serve"
      ],
      "rollForward": false
    },
    "fantomas": {
      "version": "7.0.5",
      "commands": [
        "fantomas"
      ],
      "rollForward": false
    }
  }
}

================================================
FILE: .editorconfig
================================================
; EditorConfig helps developers define and maintain consistent
; coding styles between different editors and IDEs.

; For more visit http://editorconfig.org.
root = true

; Choose between lf or rf on "end_of_line" property
[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{*.fs,*.fsx}]
indent_size = 4
indent_style = space
max_line_length=150
fsharp_max_function_binding_width=10
fsharp_max_infix_operator_expression=70
fsharp_space_before_parameter=false
fsharp_space_before_lowercase_invocation=false
fsharp_multiline_block_brackets_on_same_column=true
fsharp_experimental_stroustrup_style=true
fsharp_bar_before_discriminated_union_declaration = true
fsharp_keep_max_number_of_blank_lines=3


================================================
FILE: .gitattributes
================================================
# Auto detect text files
* text=auto 

# Custom for Visual Studio
*.cs diff=csharp text=auto eol=lf
*.fs diff=csharp text=auto eol=lf
*.fsi diff=csharp text=auto eol=lf
*.fsx diff=csharp text=auto eol=lf
*.sln text eol=crlf merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

.github/workflows/*.lock.yml linguist-generated=true merge=ours

================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
### Description

Please provide a succinct description of your issue.

### Repro steps

Please provide the steps required to reproduce the problem

1. Type provider type definition with parameters

2. Sample schema or relevant schema part

### Expected behavior

Please provide a description of the behavior you expect.

### Actual behavior

Please provide a description of the actual behavior you observe.

### Known workarounds

Please provide a description of any known workarounds.

### Affected Type Providers

- [ ] SwaggerClientProvider
- [ ] OpenApiClientProvider

### Related information

* Operating system
* Branch
* .NET Runtime, CoreCLR or Mono Version
* Performance information, links to performance testing scripts


================================================
FILE: .github/aw/actions-lock.json
================================================
{
  "entries": {
    "actions/github-script@v9.0.0": {
      "repo": "actions/github-script",
      "version": "v9.0.0",
      "sha": "d746ffe35508b1917358783b479e04febd2b8f71"
    },
    "github/gh-aw-actions/setup@v0.68.3": {
      "repo": "github/gh-aw-actions/setup",
      "version": "v0.68.3",
      "sha": "ba90f2186d7ad780ec640f364005fa24e797b360"
    },
    "github/gh-aw/actions/setup@v0.71.1": {
      "repo": "github/gh-aw/actions/setup",
      "version": "v0.71.1",
      "sha": "f01a9d118afa6e306f3645ca31e43f4ea8fb4d22"
    }
  },
  "containers": {
    "ghcr.io/github/gh-aw-firewall/agent:0.25.20": {
      "image": "ghcr.io/github/gh-aw-firewall/agent:0.25.20",
      "digest": "sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682",
      "pinned_image": "ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682"
    },
    "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20": {
      "image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20",
      "digest": "sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519",
      "pinned_image": "ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519"
    },
    "ghcr.io/github/gh-aw-firewall/squid:0.25.20": {
      "image": "ghcr.io/github/gh-aw-firewall/squid:0.25.20",
      "digest": "sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236",
      "pinned_image": "ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236"
    },
    "ghcr.io/github/gh-aw-mcpg:v0.2.19": {
      "image": "ghcr.io/github/gh-aw-mcpg:v0.2.19",
      "digest": "sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd",
      "pinned_image": "ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd"
    },
    "ghcr.io/github/github-mcp-server:v0.32.0": {
      "image": "ghcr.io/github/github-mcp-server:v0.32.0",
      "digest": "sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28",
      "pinned_image": "ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28"
    },
    "node:lts-alpine": {
      "image": "node:lts-alpine",
      "digest": "sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f",
      "pinned_image": "node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"
    }
  }
}


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    labels:
      - "enhancement"
  - package-ecosystem: "nuget"
    directory: "/.config"
    schedule:
      interval: "weekly"
    labels:
      - "enhancement"


================================================
FILE: .github/workflows/docs.yml
================================================
name: Deploy docs to GitHub Pages

on:
  push:
    branches: [master]
    paths:
      - 'docs/**'
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 22

      - name: Install dependencies
        run: npm ci
        working-directory: docs

      - name: Build docs
        run: npm run docs:build
        working-directory: docs

      - uses: actions/configure-pages@v6

      - uses: actions/upload-pages-artifact@v5
        with:
          path: docs/.vitepress/dist

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v5


================================================
FILE: .github/workflows/dotnetcore.yml
================================================
name: Build and Test

on:
  push:
    branches:
      - master
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest]
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v6
      - name: Setup .NET 10.0 SDK
        uses: actions/setup-dotnet@v5
        with:
          dotnet-version: "10.0.x"
      - name: Cache NuGet packages
        uses: actions/cache@v5
        with:
          path: |
            ~/.nuget/packages
            ~/.local/share/NuGet
            %LOCALAPPDATA%\NuGet\v3-cache
          key: ${{ runner.os }}-nuget-${{ hashFiles('**/paket.lock') }}
          restore-keys: |
            ${{ runner.os }}-nuget-
      - name: Cache .paket directory
        uses: actions/cache@v5
        with:
          path: .paket
          key: ${{ runner.os }}-paket-${{ hashFiles('**/paket.lock') }}
          restore-keys: |
            ${{ runner.os }}-paket-
      - name: Install local tools
        run: dotnet tool restore
      - name: Paket Restore
        run: dotnet paket restore
      - name: Build and Test
        run: dotnet fsi build.fsx


================================================
FILE: .github/workflows/repo-assist.lock.yml
================================================
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"9795d605bdecebc79c8c5cbb8fbf7ffa7b3dfd48ab232f75dcff9e0b162f1b62","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"}
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20","digest":"sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20","digest":"sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20","digest":"sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19","digest":"sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0","digest":"sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28","pinned_image":"ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
#    ___                   _   _      
#   / _ \                 | | (_)     
#  | |_| | __ _  ___ _ __ | |_ _  ___ 
#  |  _  |/ _` |/ _ \ '_ \| __| |/ __|
#  | | | | (_| |  __/ | | | |_| | (__ 
#  \_| |_/\__, |\___|_| |_|\__|_|\___|
#          __/ |
#  _    _ |___/ 
# | |  | |                / _| |
# | |  | | ___ _ __ _  __| |_| | _____      ____
# | |/\| |/ _ \ '__| |/ /|  _| |/ _ \ \ /\ / / ___|
# \  /\  / (_) | | | | ( | | | | (_) \ V  V /\__ \
#  \/  \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by gh-aw (v0.68.3). DO NOT EDIT.
#
# To update this file, edit githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95 and run:
#   gh aw compile
# Not all edits will cause changes to this file.
#
# For more information: https://github.github.com/gh-aw/introduction/overview/
#
# A friendly repository assistant that runs 2 times a day to support contributors and maintainers.
# Can also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.
# - Labels and triages open issues
# - Comments helpfully on open issues to unblock contributors and onboard newcomers
# - Identifies issues that can be fixed and creates draft pull requests with fixes
# - Improves performance, testing, and code quality via PRs
# - Makes engineering investments: dependency updates, CI improvements, tooling
# - Updates its own PRs when CI fails or merge conflicts arise
# - Nudges stale PRs waiting for author response
# - Takes the repository forward with proactive improvements
# - 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@3de4e604a36b5190a1c7dc4719c7341500ba8a95
#
# Secrets used:
#   - COPILOT_GITHUB_TOKEN
#   - GH_AW_CI_TRIGGER_TOKEN
#   - GH_AW_GITHUB_MCP_SERVER_TOKEN
#   - GH_AW_GITHUB_TOKEN
#   - GITHUB_TOKEN
#
# Custom actions used:
#   - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
#   - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
#   - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
#   - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
#   - github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
#
# Container images used:
#   - ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682
#   - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519
#   - ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236
#   - ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd
#   - ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28
#   - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f

name: "Repo Assist"
"on":
  discussion:
    types:
    - created
    - edited
  discussion_comment:
    types:
    - created
    - edited
  issue_comment:
    types:
    - created
    - edited
  issues:
    types:
    - opened
    - edited
    - reopened
  pull_request:
    types:
    - opened
    - edited
    - reopened
  pull_request_review_comment:
    types:
    - created
    - edited
  schedule:
  - cron: "46 12 * * *"
  workflow_dispatch:
    inputs:
      aw_context:
        default: ""
        description: Agent caller context (used internally by Agentic Workflows).
        required: false
        type: string

permissions: {}

concurrency:
  group: "gh-aw-${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}"

run-name: "Repo Assist"

jobs:
  activation:
    needs: pre_activation
    if: "needs.pre_activation.outputs.activated == 'true' && ((github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment') && (github.event_name == 'issues' && (startsWith(github.event.issue.body, '/repo-assist ') || startsWith(github.event.issue.body, '/repo-assist\n') || github.event.issue.body == '/repo-assist') || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request == null || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') || github.event_name == 'pull_request' && (startsWith(github.event.pull_request.body, '/repo-assist ') || startsWith(github.event.pull_request.body, '/repo-assist\n') || github.event.pull_request.body == '/repo-assist') || github.event_name == 'discussion' && (startsWith(github.event.discussion.body, '/repo-assist ') || startsWith(github.event.discussion.body, '/repo-assist\n') || github.event.discussion.body == '/repo-assist') || github.event_name == 'discussion_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist')) || (!(github.event_name == 'issues')) && (!(github.event_name == 'issue_comment')) && (!(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:
      actions: read
      contents: read
      discussions: write
      issues: write
      pull-requests: write
    outputs:
      body: ${{ steps.sanitized.outputs.body }}
      comment_id: ${{ steps.add-comment.outputs.comment-id }}
      comment_repo: ${{ steps.add-comment.outputs.comment-repo }}
      comment_url: ${{ steps.add-comment.outputs.comment-url }}
      lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
      model: ${{ steps.generate_aw_info.outputs.model }}
      secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
      setup-trace-id: ${{ steps.setup.outputs.trace-id }}
      slash_command: ${{ needs.pre_activation.outputs.matched_command }}
      stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
      text: ${{ steps.sanitized.outputs.text }}
      title: ${{ steps.sanitized.outputs.title }}
    steps:
      - name: Setup Scripts
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
      - name: Generate agentic run info
        id: generate_aw_info
        env:
          GH_AW_INFO_ENGINE_ID: "copilot"
          GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
          GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'auto' }}
          GH_AW_INFO_VERSION: "1.0.21"
          GH_AW_INFO_AGENT_VERSION: "1.0.21"
          GH_AW_INFO_CLI_VERSION: "v0.68.3"
          GH_AW_INFO_WORKFLOW_NAME: "Repo Assist"
          GH_AW_INFO_EXPERIMENTAL: "false"
          GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
          GH_AW_INFO_STAGED: "false"
          GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","dotnet","node","python","rust","java"]'
          GH_AW_INFO_FIREWALL_ENABLED: "true"
          GH_AW_INFO_AWF_VERSION: "v0.25.20"
          GH_AW_INFO_AWMG_VERSION: ""
          GH_AW_INFO_FIREWALL_TYPE: "squid"
          GH_AW_COMPILED_STRICT: "true"
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
            await main(core, context);
      - 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@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_REACTION: "eyes"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/add_reaction.cjs');
            await main();
      - name: Validate COPILOT_GITHUB_TOKEN secret
        id: validate-secret
        run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
        env:
          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
      - name: Checkout .github and .agents folders
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          sparse-checkout: |
            .github
            .agents
          sparse-checkout-cone-mode: true
          fetch-depth: 1
      - name: Check workflow lock file
        id: check-lock-file
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_WORKFLOW_FILE: "repo-assist.lock.yml"
          GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs');
            await main();
      - name: Check compile-agentic version
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_COMPILED_VERSION: "v0.68.3"
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs');
            await main();
      - name: Compute current body text
        id: sanitized
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/compute_text.cjs');
            await main();
      - name: Add comment with workflow run link
        id: add-comment
        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@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/add_workflow_run_comment.cjs');
            await main();
      - name: Create prompt with built-in context
        env:
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
          GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
          GH_AW_GITHUB_ACTOR: ${{ github.actor }}
          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
          GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }}
          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
          GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
          GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
          GH_AW_WIKI_NOTE: ${{ '' }}
        # poutine:ignore untrusted_checkout_exec
        run: |
          bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
          {
          cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
          <system>
          GH_AW_PROMPT_2095c4ee969b23af_EOF
          cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
          cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
          cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
          cat "${RUNNER_TEMP}/gh-aw/prompts/repo_memory_prompt.md"
          cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
          cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
          <safe-output-tools>
          Tools: add_comment(max:10), create_issue(max:4), update_issue, create_pull_request(max:4), add_labels(max:30), remove_labels(max:5), push_to_pull_request_branch(max:4), missing_tool, missing_data, noop
          GH_AW_PROMPT_2095c4ee969b23af_EOF
          cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md"
          cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
          cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
          </safe-output-tools>
          <github-context>
          The following GitHub context information is available for this workflow:
          {{#if __GH_AW_GITHUB_ACTOR__ }}
          - **actor**: __GH_AW_GITHUB_ACTOR__
          {{/if}}
          {{#if __GH_AW_GITHUB_REPOSITORY__ }}
          - **repository**: __GH_AW_GITHUB_REPOSITORY__
          {{/if}}
          {{#if __GH_AW_GITHUB_WORKSPACE__ }}
          - **workspace**: __GH_AW_GITHUB_WORKSPACE__
          {{/if}}
          {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
          - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
          {{/if}}
          {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
          - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
          {{/if}}
          {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
          - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
          {{/if}}
          {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
          - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
          {{/if}}
          {{#if __GH_AW_GITHUB_RUN_ID__ }}
          - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
          {{/if}}
          - **checkouts**: The following repositories have been checked out and are available in the workspace:
            - `$GITHUB_WORKSPACE` → `__GH_AW_GITHUB_REPOSITORY__` (cwd) [full history, all branches available as remote-tracking refs] [additional refs fetched: *]
            - **Note**: If a branch you need is not in the list above and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it without proper authentication. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: ["refs/pulls/open/*"]` for all open PR refs, or `fetch: ["main", "feature/my-branch"]` for specific branches).
          </github-context>
          
          GH_AW_PROMPT_2095c4ee969b23af_EOF
          cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
          if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
            cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md"
          fi
          if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
            cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_push_to_pr_branch_guidance.md"
          fi
          cat << 'GH_AW_PROMPT_2095c4ee969b23af_EOF'
          </system>
          {{#runtime-import .github/workflows/repo-assist.md}}
          GH_AW_PROMPT_2095c4ee969b23af_EOF
          } > "$GH_AW_PROMPT"
      - name: Interpolate variables and render templates
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
          GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }}
          GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs');
            await main();
      - name: Substitute placeholders
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
          GH_AW_GITHUB_ACTOR: ${{ github.actor }}
          GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
          GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
          GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
          GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
          GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
          GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
          GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }}
          GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
          GH_AW_IS_PR_COMMENT: ${{ github.event.issue.pull_request && 'true' || '' }}
          GH_AW_MEMORY_BRANCH_NAME: 'memory/repo-assist'
          GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Max File Size**: 10240 bytes (0.01 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n"
          GH_AW_MEMORY_DESCRIPTION: ''
          GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/'
          GH_AW_MEMORY_TARGET_REPO: ' of the current repository'
          GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
          GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }}
          GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: ${{ steps.sanitized.outputs.text }}
          GH_AW_WIKI_NOTE: ''
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            
            const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs');
            
            // Call the substitution function
            return await substitutePlaceholders({
              file: process.env.GH_AW_PROMPT,
              substitutions: {
                GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
                GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
                GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
                GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
                GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
                GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
                GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
                GH_AW_GITHUB_SERVER_URL: process.env.GH_AW_GITHUB_SERVER_URL,
                GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
                GH_AW_IS_PR_COMMENT: process.env.GH_AW_IS_PR_COMMENT,
                GH_AW_MEMORY_BRANCH_NAME: process.env.GH_AW_MEMORY_BRANCH_NAME,
                GH_AW_MEMORY_CONSTRAINTS: process.env.GH_AW_MEMORY_CONSTRAINTS,
                GH_AW_MEMORY_DESCRIPTION: process.env.GH_AW_MEMORY_DESCRIPTION,
                GH_AW_MEMORY_DIR: process.env.GH_AW_MEMORY_DIR,
                GH_AW_MEMORY_TARGET_REPO: process.env.GH_AW_MEMORY_TARGET_REPO,
                GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED,
                GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND,
                GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT: process.env.GH_AW_STEPS_SANITIZED_OUTPUTS_TEXT,
                GH_AW_WIKI_NOTE: process.env.GH_AW_WIKI_NOTE
              }
            });
      - name: Validate prompt placeholders
        env:
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
        # poutine:ignore untrusted_checkout_exec
        run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
      - name: Print prompt
        env:
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
        # poutine:ignore untrusted_checkout_exec
        run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
      - name: Upload activation artifact
        if: success()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: activation
          path: |
            /tmp/gh-aw/aw_info.json
            /tmp/gh-aw/aw-prompts/prompt.txt
            /tmp/gh-aw/github_rate_limits.jsonl
          if-no-files-found: ignore
          retention-days: 1

  agent:
    needs: activation
    runs-on: ubuntu-latest
    permissions: read-all
    env:
      DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
      GH_AW_ASSETS_ALLOWED_EXTS: ""
      GH_AW_ASSETS_BRANCH: ""
      GH_AW_ASSETS_MAX_SIZE_KB: 0
      GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
      GH_AW_WORKFLOW_ID_SANITIZED: repoassist
    outputs:
      agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
      checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
      effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
      has_patch: ${{ steps.collect_output.outputs.has_patch }}
      inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
      mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
      model: ${{ needs.activation.outputs.model }}
      model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
      output: ${{ steps.collect_output.outputs.output }}
      output_types: ${{ steps.collect_output.outputs.output_types }}
      setup-trace-id: ${{ steps.setup.outputs.trace-id }}
    steps:
      - name: Setup Scripts
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.activation.outputs.setup-trace-id }}
      - name: Set runtime paths
        id: set-runtime-paths
        run: |
          {
            echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
            echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
            echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
          } >> "$GITHUB_OUTPUT"
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          fetch-depth: 0
      - name: Fetch additional refs
        env:
          GH_AW_FETCH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
        run: |
          header=$(printf "x-access-token:%s" "${GH_AW_FETCH_TOKEN}" | base64 -w 0)
          git -c "http.extraheader=Authorization: Basic ${header}" fetch origin '+refs/heads/*:refs/remotes/origin/*'
      - name: Create gh-aw temp directory
        run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
      - name: Configure gh CLI for GitHub Enterprise
        run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
        env:
          GH_TOKEN: ${{ github.token }}
      - name: Start DIFC proxy for pre-agent gh calls
        env:
          GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          DIFC_PROXY_POLICY: '{"allow-only":{"min-integrity":"none","repos":"all"}}'
          DIFC_PROXY_IMAGE: 'ghcr.io/github/gh-aw-mcpg:v0.2.19'
        run: |
          bash "${RUNNER_TEMP}/gh-aw/actions/start_difc_proxy.sh"
      - name: Set GH_REPO for proxied steps
        run: |
          echo "GH_REPO=${GITHUB_REPOSITORY}" >> "$GITHUB_ENV"
      - env:
          GH_TOKEN: ${{ github.token }}
        name: Fetch repo data for task weighting
        run: "mkdir -p /tmp/gh-aw\n\n# Fetch open issues with labels (up to 500)\ngh issue list --state open --limit 500 --json number,labels > /tmp/gh-aw/issues.json\n\n# Fetch open PRs with titles (up to 200)\ngh pr list --state open --limit 200 --json number,title > /tmp/gh-aw/prs.json\n\n# Compute task weights and select two tasks for this run\npython3 - << 'EOF'\nimport json, random, os\n\nwith open('/tmp/gh-aw/issues.json') as f:\n    issues = json.load(f)\nwith open('/tmp/gh-aw/prs.json') as f:\n    prs = json.load(f)\n\nopen_issues     = len(issues)\nunlabelled      = sum(1 for i in issues if not i.get('labels'))\nrepo_assist_prs = sum(1 for p in prs if p['title'].startswith('[Repo Assist]'))\nother_prs       = sum(1 for p in prs if not p['title'].startswith('[Repo Assist]'))\n\ntask_names = {\n    1:  'Issue Labelling',\n    2:  'Issue Investigation and Comment',\n    3:  'Issue Investigation and Fix',\n    4:  'Engineering Investments',\n    5:  'Coding Improvements',\n    6:  'Maintain Repo Assist PRs',\n    7:  'Stale PR Nudges',\n    8:  'Performance Improvements',\n    9:  'Testing Improvements',\n    10: 'Take the Repository Forward',\n}\n\nweights = {\n    1:  1   + 3 * unlabelled,\n    2:  3   + 1 * open_issues,\n    3:  3   + 0.7 * open_issues,\n    4:  5   + 0.2 * open_issues,\n    5:  5   + 0.1 * open_issues,\n    6:  float(repo_assist_prs),\n    7:  0.1 * other_prs,\n    8:  3   + 0.05 * open_issues,\n    9:  3   + 0.05 * open_issues,\n    10: 3   + 0.05 * open_issues,\n}\n\n# Seed with run ID for reproducibility within a run\nrun_id = int(os.environ.get('GITHUB_RUN_ID', '0'))\nrng = random.Random(run_id)\n\ntask_ids     = list(weights.keys())\ntask_weights = [weights[t] for t in task_ids]\n\n# Weighted sample without replacement (pick 2 distinct tasks)\nchosen, seen = [], set()\nfor t in rng.choices(task_ids, weights=task_weights, k=30):\n    if t not in seen:\n        seen.add(t)\n        chosen.append(t)\n    if len(chosen) == 2:\n        break\n\nprint('=== Repo Assist Task Selection ===')\nprint(f'Open issues       : {open_issues}')\nprint(f'Unlabelled issues : {unlabelled}')\nprint(f'Repo Assist PRs   : {repo_assist_prs}')\nprint(f'Other open PRs    : {other_prs}')\nprint()\nprint('Task weights:')\nfor t, w in weights.items():\n    tag = ' <-- SELECTED' if t in chosen else ''\n    print(f'  Task {t:2d} ({task_names[t]}): weight {w:6.1f}{tag}')\nprint()\nprint(f'Selected tasks for this run: Task {chosen[0]} ({task_names[chosen[0]]}) and Task {chosen[1]} ({task_names[chosen[1]]})')\n\nresult = {\n    'open_issues': open_issues, 'unlabelled_issues': unlabelled,\n    'repo_assist_prs': repo_assist_prs, 'other_prs': other_prs,\n    'task_names': task_names,\n    'weights': {str(k): round(v, 2) for k, v in weights.items()},\n    'selected_tasks': chosen,\n}\nwith open('/tmp/gh-aw/task_selection.json', 'w') as f:\n    json.dump(result, f, indent=2)\nEOF\n"

      # Repo memory git-based storage configuration from frontmatter processed below
      - name: Clone repo-memory branch (default)
        env:
          GH_TOKEN: ${{ github.token }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          BRANCH_NAME: memory/repo-assist
          TARGET_REPO: ${{ github.repository }}
          MEMORY_DIR: /tmp/gh-aw/repo-memory/default
          CREATE_ORPHAN: true
        run: bash "${RUNNER_TEMP}/gh-aw/actions/clone_repo_memory_branch.sh"
      - name: Configure Git credentials
        env:
          REPO_NAME: ${{ github.repository }}
          SERVER_URL: ${{ github.server_url }}
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git config --global user.name "github-actions[bot]"
          git config --global am.keepcr true
          # Re-authenticate git with GitHub token
          SERVER_URL_STRIPPED="${SERVER_URL#https://}"
          git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
          echo "Git configured with standard GitHub Actions identity"
      - name: Checkout PR branch
        id: checkout-pr
        if: |
          github.event.pull_request || github.event.issue.pull_request
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
            await main();
      - name: Install GitHub Copilot CLI
        run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21
        env:
          GH_HOST: github.com
      - name: Install AWF binary
        run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20
      - name: Parse integrity filter lists
        id: parse-guard-vars
        env:
          GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }}
          GH_AW_TRUSTED_USERS_VAR: ${{ vars.GH_AW_GITHUB_TRUSTED_USERS || '' }}
          GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }}
        run: bash "${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh"
      - name: Stop DIFC proxy
        if: always()
        continue-on-error: true
        run: bash "${RUNNER_TEMP}/gh-aw/actions/stop_difc_proxy.sh"
      - name: Download container images
        run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519 ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236 ghcr.io/github/gh-aw-mcpg:v0.2.19@sha256:44d4d8de7e6c37aaea484eba489940c52df6a0b54078ddcbc9327592d5b3c3dd ghcr.io/github/github-mcp-server:v0.32.0@sha256:2763823c63bcca718ce53850a1d7fcf2f501ec84028394f1b63ce7e9f4f9be28 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
      - name: Write Safe Outputs Config
        run: |
          mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
          mkdir -p /tmp/gh-aw/safeoutputs
          mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
          cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_0438119ce4975251_EOF'
          {"add_comment":{"hide_older_comments":true,"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":{"labels":["automation","repo-assist"],"max":4,"title_prefix":"[Repo Assist] "},"create_pull_request":{"draft":true,"labels":["automation","repo-assist"],"max":4,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"title_prefix":"[Repo Assist] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":10240,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","max":4,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"target":"*","title_prefix":"[Repo Assist] "},"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,"target":"*"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":1,"target":"*","title_prefix":"[Repo Assist] "}}
          GH_AW_SAFE_OUTPUTS_CONFIG_0438119ce4975251_EOF
      - name: Write Safe Outputs Tools
        env:
          GH_AW_TOOLS_META_JSON: |
            {
              "description_suffixes": {
                "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.",
                "add_labels": " 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: *.",
                "create_issue": " CONSTRAINTS: Maximum 4 issue(s) can be created. Title will be prefixed with \"[Repo Assist] \". Labels [\"automation\" \"repo-assist\"] will be automatically added.",
                "create_pull_request": " 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.",
                "push_to_pull_request_branch": " CONSTRAINTS: Maximum 4 push(es) can be made. The target pull request title must start with \"[Repo Assist] \".",
                "remove_labels": " CONSTRAINTS: Maximum 5 label(s) can be removed. Only these labels can be removed: [bug enhancement help wanted good first issue spam off topic documentation question duplicate wontfix needs triage needs investigation breaking change performance security refactor]. Target: *.",
                "update_issue": " CONSTRAINTS: Maximum 1 issue(s) can be updated. Target: *. The target issue title must start with \"[Repo Assist] \"."
              },
              "repo_params": {},
              "dynamic_tools": []
            }
          GH_AW_VALIDATION_JSON: |
            {
              "add_comment": {
                "defaultMax": 1,
                "fields": {
                  "body": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "item_number": {
                    "issueOrPRNumber": true
                  },
                  "reply_to_id": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  }
                }
              },
              "add_labels": {
                "defaultMax": 5,
                "fields": {
                  "item_number": {
                    "issueNumberOrTemporaryId": true
                  },
                  "labels": {
                    "required": true,
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 128
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  }
                }
              },
              "create_issue": {
                "defaultMax": 1,
                "fields": {
                  "body": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "labels": {
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 128
                  },
                  "parent": {
                    "issueOrPRNumber": true
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "temporary_id": {
                    "type": "string"
                  },
                  "title": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 128
                  }
                }
              },
              "create_pull_request": {
                "defaultMax": 1,
                "fields": {
                  "body": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "branch": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  },
                  "draft": {
                    "type": "boolean"
                  },
                  "labels": {
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 128
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "title": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 128
                  }
                }
              },
              "missing_data": {
                "defaultMax": 20,
                "fields": {
                  "alternatives": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  },
                  "context": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  },
                  "data_type": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 128
                  },
                  "reason": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  }
                }
              },
              "missing_tool": {
                "defaultMax": 20,
                "fields": {
                  "alternatives": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 512
                  },
                  "reason": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  },
                  "tool": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 128
                  }
                }
              },
              "noop": {
                "defaultMax": 1,
                "fields": {
                  "message": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  }
                }
              },
              "push_to_pull_request_branch": {
                "defaultMax": 1,
                "fields": {
                  "branch": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 256
                  },
                  "message": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "pull_request_number": {
                    "issueOrPRNumber": true
                  }
                }
              },
              "remove_labels": {
                "defaultMax": 5,
                "fields": {
                  "item_number": {
                    "issueNumberOrTemporaryId": true
                  },
                  "labels": {
                    "required": true,
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 128
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  }
                }
              },
              "report_incomplete": {
                "defaultMax": 5,
                "fields": {
                  "details": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "reason": {
                    "required": true,
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 1024
                  }
                }
              },
              "update_issue": {
                "defaultMax": 1,
                "fields": {
                  "assignees": {
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 39
                  },
                  "body": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 65000
                  },
                  "issue_number": {
                    "issueOrPRNumber": true
                  },
                  "labels": {
                    "type": "array",
                    "itemType": "string",
                    "itemSanitize": true,
                    "itemMaxLength": 128
                  },
                  "milestone": {
                    "optionalPositiveInteger": true
                  },
                  "operation": {
                    "type": "string",
                    "enum": [
                      "replace",
                      "append",
                      "prepend",
                      "replace-island"
                    ]
                  },
                  "repo": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "closed"
                    ]
                  },
                  "title": {
                    "type": "string",
                    "sanitize": true,
                    "maxLength": 128
                  }
                },
                "customValidation": "requiresOneOf:status,title,body"
              }
            }
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs');
            await main();
      - name: Generate Safe Outputs MCP Server Config
        id: safe-outputs-config
        run: |
          # Generate a secure random API key (360 bits of entropy, 40+ chars)
          # Mask immediately to prevent timing vulnerabilities
          API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
          echo "::add-mask::${API_KEY}"
          
          PORT=3001
          
          # Set outputs for next steps
          {
            echo "safe_outputs_api_key=${API_KEY}"
            echo "safe_outputs_port=${PORT}"
          } >> "$GITHUB_OUTPUT"
          
          echo "Safe Outputs MCP server will run on port ${PORT}"
          
      - name: Start Safe Outputs MCP HTTP Server
        id: safe-outputs-start
        env:
          DEBUG: '*'
          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
          GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json
          GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json
          GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
        run: |
          # Environment variables are set above to prevent template injection
          export DEBUG
          export GH_AW_SAFE_OUTPUTS
          export GH_AW_SAFE_OUTPUTS_PORT
          export GH_AW_SAFE_OUTPUTS_API_KEY
          export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
          export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
          export GH_AW_MCP_LOG_DIR
          
          bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh"
          
      - name: Start MCP Gateway
        id: start-mcp-gateway
        env:
          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
          GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
          GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
        run: |
          set -eo pipefail
          mkdir -p /tmp/gh-aw/mcp-config
          
          # Export gateway environment variables for MCP config and gateway script
          export MCP_GATEWAY_PORT="80"
          export MCP_GATEWAY_DOMAIN="host.docker.internal"
          MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
          echo "::add-mask::${MCP_GATEWAY_API_KEY}"
          export MCP_GATEWAY_API_KEY
          export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
          mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
          export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
          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_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -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.2.19'
          
          mkdir -p /home/runner/.copilot
          cat << GH_AW_MCP_CONFIG_567b4b2b7203b398_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh"
          {
            "mcpServers": {
              "github": {
                "type": "stdio",
                "container": "ghcr.io/github/github-mcp-server:v0.32.0",
                "env": {
                  "GITHUB_HOST": "\${GITHUB_SERVER_URL}",
                  "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
                  "GITHUB_READ_ONLY": "1",
                  "GITHUB_TOOLSETS": "all"
                },
                "guard-policies": {
                  "allow-only": {
                    "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }},
                    "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }},
                    "min-integrity": "none",
                    "repos": "all",
                    "trusted-users": ${{ steps.parse-guard-vars.outputs.trusted_users }}
                  }
                }
              },
              "safeoutputs": {
                "type": "http",
                "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
                "headers": {
                  "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
                },
                "guard-policies": {
                  "write-sink": {
                    "accept": [
                      "*"
                    ]
                  }
                }
              }
            },
            "gateway": {
              "port": $MCP_GATEWAY_PORT,
              "domain": "${MCP_GATEWAY_DOMAIN}",
              "apiKey": "${MCP_GATEWAY_API_KEY}",
              "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
            }
          }
          GH_AW_MCP_CONFIG_567b4b2b7203b398_EOF
      - name: Download activation artifact
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: activation
          path: /tmp/gh-aw
      - name: Clean git credentials
        continue-on-error: true
        run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
      - name: Execute GitHub Copilot CLI
        id: agentic_execution
        # Copilot CLI tool arguments (sorted):
        timeout-minutes: 60
        run: |
          set -o pipefail
          touch /tmp/gh-aw/agent-step-summary.md
          (umask 177 && touch /tmp/gh-aw/agent-stdio.log)
          # shellcheck disable=SC1003
          sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.gradle-enterprise.cloud,*.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,develocity.apache.org,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,ge.spockframework.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-central.storage-download.googleapis.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,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.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.googleapis.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 --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \
            -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --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_PHASE: agent
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
          GH_AW_VERSION: v0.68.3
          GITHUB_API_URL: ${{ github.api_url }}
          GITHUB_AW: true
          GITHUB_HEAD_REF: ${{ github.head_ref }}
          GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
          GITHUB_WORKSPACE: ${{ github.workspace }}
          GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
          GIT_AUTHOR_NAME: github-actions[bot]
          GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
          GIT_COMMITTER_NAME: github-actions[bot]
          XDG_CONFIG_HOME: /home/runner
      - name: Detect Copilot errors
        id: detect-copilot-errors
        if: always()
        continue-on-error: true
        run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
      - name: Configure Git credentials
        env:
          REPO_NAME: ${{ github.repository }}
          SERVER_URL: ${{ github.server_url }}
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git config --global user.name "github-actions[bot]"
          git config --global am.keepcr true
          # Re-authenticate git with GitHub token
          SERVER_URL_STRIPPED="${SERVER_URL#https://}"
          git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
          echo "Git configured with standard GitHub Actions identity"
      - name: Copy Copilot session state files to logs
        if: always()
        continue-on-error: true
        run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
      - name: Stop MCP Gateway
        if: always()
        continue-on-error: true
        env:
          MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
          MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
          GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
        run: |
          bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
      - name: Redact secrets in logs
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs');
            await main();
        env:
          GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
          SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
          SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
          SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
          SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Append agent step summary
        if: always()
        run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
      - name: Copy Safe Outputs
        if: always()
        env:
          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
        run: |
          mkdir -p /tmp/gh-aw
          cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
      - name: Ingest agent output
        id: collect_output
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
          GH_AW_ALLOWED_DOMAINS: "*.gradle-enterprise.cloud,*.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,develocity.apache.org,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,ge.spockframework.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-central.storage-download.googleapis.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,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.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.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com"
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_API_URL: ${{ github.api_url }}
          GH_AW_COMMAND: repo-assist
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs');
            await main();
      - name: Parse agent logs for step summary
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs');
            await main();
      - name: Parse MCP Gateway logs for step summary
        if: always()
        id: parse-mcp-gateway
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs');
            await main();
      - name: Print firewall logs
        if: always()
        continue-on-error: true
        env:
          AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
        run: |
          # Fix permissions on firewall logs so they can be uploaded as artifacts
          # AWF runs with sudo, creating files owned by root
          sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
          # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
          if command -v awf &> /dev/null; then
            awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
          else
            echo 'AWF binary not installed, skipping firewall log summary'
          fi
      - name: Parse token usage for step summary
        if: always()
        continue-on-error: true
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs');
            await main();
      - name: Write agent output placeholder if missing
        if: always()
        run: |
          if [ ! -f /tmp/gh-aw/agent_output.json ]; then
            echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
          fi
      # Upload repo memory as artifacts for push job
      - name: Upload repo-memory artifact (default)
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: repo-memory-default
          path: /tmp/gh-aw/repo-memory/default
          retention-days: 1
          if-no-files-found: ignore
      - name: Upload agent artifacts
        if: always()
        continue-on-error: true
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: agent
          path: |
            /tmp/gh-aw/aw-prompts/prompt.txt
            /tmp/gh-aw/sandbox/agent/logs/
            /tmp/gh-aw/redacted-urls.log
            /tmp/gh-aw/mcp-logs/
            /tmp/gh-aw/proxy-logs/
            !/tmp/gh-aw/proxy-logs/proxy-tls/
            /tmp/gh-aw/agent_usage.json
            /tmp/gh-aw/agent-stdio.log
            /tmp/gh-aw/agent/
            /tmp/gh-aw/github_rate_limits.jsonl
            /tmp/gh-aw/safeoutputs.jsonl
            /tmp/gh-aw/agent_output.json
            /tmp/gh-aw/aw-*.patch
            /tmp/gh-aw/aw-*.bundle
            /tmp/gh-aw/sandbox/firewall/logs/
            /tmp/gh-aw/sandbox/firewall/audit/
          if-no-files-found: ignore

  conclusion:
    needs:
      - activation
      - agent
      - detection
      - push_repo_memory
      - safe_outputs
    if: >
      always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
      needs.activation.outputs.stale_lock_file_failed == 'true')
    runs-on: ubuntu-slim
    permissions:
      contents: write
      discussions: write
      issues: write
      pull-requests: write
    concurrency:
      group: "gh-aw-conclusion-repo-assist"
      cancel-in-progress: false
    outputs:
      incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}
      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
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.activation.outputs.setup-trace-id }}
      - name: Download agent output artifact
        id: download-agent-output
        continue-on-error: true
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: agent
          path: /tmp/gh-aw/
      - name: Setup agent output environment variable
        id: setup-agent-output-env
        if: steps.download-agent-output.outcome == 'success'
        run: |
          mkdir -p /tmp/gh-aw/
          find "/tmp/gh-aw/" -type f -print
          echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
      - name: Process no-op messages
        id: noop
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.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@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
          GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/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_REPORT_AS_ISSUE: "true"
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs');
            await main();
      - name: Log detection run
        id: detection_runs
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
          GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
          GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs');
            await main();
      - name: Record missing tool
        id: missing_tool
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
          GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs');
            await main();
      - name: Record incomplete
        id: report_incomplete
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
          GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/workflows/repo-assist.md"
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs');
            await main();
      - name: Handle agent failure
        id: handle_agent_failure
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
          GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/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_ENGINE_ID: "copilot"
          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_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
          GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
          GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_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_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
          GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
          GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
          GH_AW_PUSH_REPO_MEMORY_RESULT: ${{ needs.push_repo_memory.result }}
          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_REPO_MEMORY_PATCH_SIZE_EXCEEDED_default: ${{ needs.push_repo_memory.outputs.patch_size_exceeded_default }}
          GH_AW_GROUP_REPORTS: "false"
          GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
          GH_AW_TIMEOUT_MINUTES: "60"
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
            await main();
      - name: Update reaction comment with completion status
        id: conclusion
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
          GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }}
          GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          GH_AW_WORKFLOW_NAME: "Repo Assist"
          GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
          GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
          GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
          GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
            await main();

  detection:
    needs:
      - activation
      - agent
    if: >
      always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true')
    runs-on: ubuntu-latest
    permissions:
      contents: read
    outputs:
      detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
      detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
      detection_success: ${{ steps.detection_conclusion.outputs.success }}
    steps:
      - name: Setup Scripts
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.activation.outputs.setup-trace-id }}
      - name: Download agent output artifact
        id: download-agent-output
        continue-on-error: true
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: agent
          path: /tmp/gh-aw/
      - name: Setup agent output environment variable
        id: setup-agent-output-env
        if: steps.download-agent-output.outcome == 'success'
        run: |
          mkdir -p /tmp/gh-aw/
          find "/tmp/gh-aw/" -type f -print
          echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
      - name: Checkout repository for patch context
        if: needs.agent.outputs.has_patch == 'true'
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      # --- Threat Detection ---
      - name: Clean stale firewall files from agent artifact
        run: |
          rm -rf /tmp/gh-aw/sandbox/firewall/logs
          rm -rf /tmp/gh-aw/sandbox/firewall/audit
      - name: Download container images
        run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.20@sha256:9161f2415a3306a344aca34dd671ee69f122317e0a512e66dc64c94b9c508682 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20@sha256:6971639e381e82e45134bcd333181f456df3a52cd6f818a3e3d6de068ff91519 ghcr.io/github/gh-aw-firewall/squid:0.25.20@sha256:5411d903f73ee597e6a084971c2adef3eb0bd405910df3ed7bf5e3d6bd58a236
      - name: Check if detection needed
        id: detection_guard
        if: always()
        env:
          OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
          HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
        run: |
          if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
            echo "run_detection=true" >> "$GITHUB_OUTPUT"
            echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
          else
            echo "run_detection=false" >> "$GITHUB_OUTPUT"
            echo "Detection skipped: no agent outputs or patches to analyze"
          fi
      - name: Clear MCP configuration for detection
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        run: |
          rm -f /tmp/gh-aw/mcp-config/mcp-servers.json
          rm -f /home/runner/.copilot/mcp-config.json
          rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
      - name: Prepare threat detection files
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        run: |
          mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
          cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
          cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
          for f in /tmp/gh-aw/aw-*.patch; do
            [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
          done
          for f in /tmp/gh-aw/aw-*.bundle; do
            [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
          done
          echo "Prepared threat detection files:"
          ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true
      - name: Setup threat detection
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          WORKFLOW_NAME: "Repo Assist"
          WORKFLOW_DESCRIPTION: "A friendly repository assistant that runs 2 times a day to support contributors and maintainers.\nCan also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.\n- Labels and triages open issues\n- Comments helpfully on open issues to unblock contributors and onboard newcomers\n- Identifies issues that can be fixed and creates draft pull requests with fixes\n- Improves performance, testing, and code quality via PRs\n- Makes engineering investments: dependency updates, CI improvements, tooling\n- Updates its own PRs when CI fails or merge conflicts arise\n- Nudges stale PRs waiting for author response\n- Takes the repository forward with proactive improvements\n- Maintains a persistent memory of work done and what remains\nAlways polite, constructive, and mindful of the project's goals."
          HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs');
            await main();
      - name: Ensure threat-detection directory and log
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        run: |
          mkdir -p /tmp/gh-aw/threat-detection
          touch /tmp/gh-aw/threat-detection/detection.log
      - name: Install GitHub Copilot CLI
        run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.21
        env:
          GH_HOST: github.com
      - name: Install AWF binary
        run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.20
      - name: Execute GitHub Copilot CLI
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        id: detection_agentic_execution
        # Copilot CLI tool arguments (sorted):
        timeout-minutes: 20
        run: |
          set -o pipefail
          touch /tmp/gh-aw/agent-step-summary.md
          (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
          # shellcheck disable=SC1003
          sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --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,telemetry.enterprise.githubcopilot.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.20 --skip-pull --enable-api-proxy \
            -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --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 }}
          COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}
          GH_AW_PHASE: detection
          GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
          GH_AW_VERSION: v0.68.3
          GITHUB_API_URL: ${{ github.api_url }}
          GITHUB_AW: true
          GITHUB_HEAD_REF: ${{ github.head_ref }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
          GITHUB_WORKSPACE: ${{ github.workspace }}
          GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
          GIT_AUTHOR_NAME: github-actions[bot]
          GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
          GIT_COMMITTER_NAME: github-actions[bot]
          XDG_CONFIG_HOME: /home/runner
      - name: Upload threat detection log
        if: always() && steps.detection_guard.outputs.run_detection == 'true'
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: detection
          path: /tmp/gh-aw/threat-detection/detection.log
          if-no-files-found: ignore
      - name: Parse and conclude threat detection
        id: detection_conclusion
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
          GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs');
            await main();

  pre_activation:
    if: "(github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment') && (github.event_name == 'issues' && (startsWith(github.event.issue.body, '/repo-assist ') || startsWith(github.event.issue.body, '/repo-assist\n') || github.event.issue.body == '/repo-assist') || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request == null || github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') && github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist') || github.event_name == 'pull_request' && (startsWith(github.event.pull_request.body, '/repo-assist ') || startsWith(github.event.pull_request.body, '/repo-assist\n') || github.event.pull_request.body == '/repo-assist') || github.event_name == 'discussion' && (startsWith(github.event.discussion.body, '/repo-assist ') || startsWith(github.event.discussion.body, '/repo-assist\n') || github.event.discussion.body == '/repo-assist') || github.event_name == 'discussion_comment' && (startsWith(github.event.comment.body, '/repo-assist ') || startsWith(github.event.comment.body, '/repo-assist\n') || github.event.comment.body == '/repo-assist')) || (!(github.event_name == 'issues')) && (!(github.event_name == 'issue_comment')) && (!(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
    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 }}
      setup-trace-id: ${{ steps.setup.outputs.trace-id }}
    steps:
      - name: Setup Scripts
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
      - name: Check team membership for command workflow
        id: check_membership
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_REQUIRED_ROLES: "admin,maintainer,write"
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_membership.cjs');
            await main();
      - name: Check command position
        id: check_command_position
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_COMMANDS: "[\"repo-assist\"]"
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/check_command_position.cjs');
            await main();

  push_repo_memory:
    needs:
      - activation
      - agent
      - detection
    if: >
      always() && (!cancelled()) && (needs.detection.result == 'success' || needs.detection.result == 'skipped') &&
      needs.agent.result != 'skipped'
    runs-on: ubuntu-slim
    permissions:
      contents: write
    concurrency:
      group: "push-repo-memory-${{ github.repository }}|memory/repo-assist"
      cancel-in-progress: false
    outputs:
      patch_size_exceeded_default: ${{ steps.push_repo_memory_default.outputs.patch_size_exceeded }}
      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
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.activation.outputs.setup-trace-id }}
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
          sparse-checkout: .
      - name: Configure Git credentials
        env:
          REPO_NAME: ${{ github.repository }}
          SERVER_URL: ${{ github.server_url }}
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git config --global user.name "github-actions[bot]"
          git config --global am.keepcr true
          # Re-authenticate git with GitHub token
          SERVER_URL_STRIPPED="${SERVER_URL#https://}"
          git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
          echo "Git configured with standard GitHub Actions identity"
      - name: Download repo-memory artifact (default)
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        continue-on-error: true
        with:
          name: repo-memory-default
          path: /tmp/gh-aw/repo-memory/default
      - name: Push repo-memory changes (default)
        id: push_repo_memory_default
        if: always()
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_TOKEN: ${{ github.token }}
          GITHUB_RUN_ID: ${{ github.run_id }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          ARTIFACT_DIR: /tmp/gh-aw/repo-memory/default
          MEMORY_ID: default
          TARGET_REPO: ${{ github.repository }}
          BRANCH_NAME: memory/repo-assist
          MAX_FILE_SIZE: 10240
          MAX_FILE_COUNT: 100
          MAX_PATCH_SIZE: 10240
          ALLOWED_EXTENSIONS: '[]'
        with:
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/push_repo_memory.cjs');
            await main();

  safe_outputs:
    needs:
      - activation
      - agent
      - detection
    if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
    runs-on: ubuntu-slim
    permissions:
      contents: write
      discussions: write
      issues: write
      pull-requests: write
    timeout-minutes: 15
    env:
      GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/repo-assist"
      GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
      GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
      GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
      GH_AW_ENGINE_ID: "copilot"
      GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
      GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md).\",\"runStarted\":\"{workflow_name} is processing {event_type}, see [workflow run]({run_url})...\",\"runSuccess\":\"✓ {workflow_name} completed successfully, see [workflow run]({run_url}).\",\"runFailure\":\"✗ {workflow_name} encountered {status}, see [workflow run]({run_url}).\"}"
      GH_AW_WORKFLOW_ID: "repo-assist"
      GH_AW_WORKFLOW_NAME: "Repo Assist"
      GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95"
      GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/3de4e604a36b5190a1c7dc4719c7341500ba8a95/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 }}
      comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}
      comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}
      create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
      create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
      created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }}
      created_issue_url: ${{ steps.process_safe_outputs.outputs.created_issue_url }}
      created_pr_number: ${{ steps.process_safe_outputs.outputs.created_pr_number }}
      created_pr_url: ${{ steps.process_safe_outputs.outputs.created_pr_url }}
      process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
      process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
      push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }}
      push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }}
    steps:
      - name: Setup Scripts
        id: setup
        uses: github/gh-aw-actions/setup@ba90f2186d7ad780ec640f364005fa24e797b360 # v0.68.3
        with:
          destination: ${{ runner.temp }}/gh-aw/actions
          job-name: ${{ github.job }}
          trace-id: ${{ needs.activation.outputs.setup-trace-id }}
      - name: Download agent output artifact
        id: download-agent-output
        continue-on-error: true
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: agent
          path: /tmp/gh-aw/
      - name: Setup agent output environment variable
        id: setup-agent-output-env
        if: steps.download-agent-output.outcome == 'success'
        run: |
          mkdir -p /tmp/gh-aw/
          find "/tmp/gh-aw/" -type f -print
          echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
      - name: Download patch artifact
        continue-on-error: true
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: agent
          path: /tmp/gh-aw/
      - name: Checkout repository
        if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
          token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          persist-credentials: false
          fetch-depth: 1
      - name: Configure Git credentials
        if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') || (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')
        env:
          REPO_NAME: ${{ github.repository }}
          SERVER_URL: ${{ github.server_url }}
          GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
        run: |
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git config --global user.name "github-actions[bot]"
          git config --global am.keepcr true
          # Re-authenticate git with GitHub token
          SERVER_URL_STRIPPED="${SERVER_URL#https://}"
          git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
          echo "Git configured with standard GitHub Actions identity"
      - name: Configure GH_HOST for enterprise compatibility
        id: ghes-host-config
        shell: bash
        run: |
          # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
          # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
          GH_HOST="${GITHUB_SERVER_URL#https://}"
          GH_HOST="${GH_HOST#http://}"
          echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
      - name: Process Safe Outputs
        id: process_safe_outputs
        uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
        env:
          GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
          GH_AW_ALLOWED_DOMAINS: "*.gradle-enterprise.cloud,*.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,develocity.apache.org,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,ge.spockframework.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-central.storage-download.googleapis.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,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.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.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com"
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_API_URL: ${{ github.api_url }}
          GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"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\":{\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"title_prefix\":\"[Repo Assist] \"},\"create_pull_request\":{\"draft\":true,\"labels\":[\"automation\",\"repo-assist\"],\"max\":4,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"title_prefix\":\"[Repo Assist] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":4,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"},\"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,\"target\":\"*\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"*\",\"title_prefix\":\"[Repo Assist] \"}}"
          GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
        with:
          github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
          script: |
            const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
            setupGlobals(core, github, context, exec, io, getOctokit);
            const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs');
            await main();
      - name: Upload Safe Outputs Items
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: safe-outputs-items
          path: |
            /tmp/gh-aw/safe-output-items.jsonl
            /tmp/gh-aw/temporary-id-map.json
          if-no-files-found: ignore



================================================
FILE: .github/workflows/repo-assist.md
================================================
---
description: |
  A friendly repository assistant that runs 2 times a day to support contributors and maintainers.
  Can also be triggered on-demand via '/repo-assist <instructions>' to perform specific tasks.
  - Labels and triages open issues
  - Comments helpfully on open issues to unblock contributors and onboard newcomers
  - Identifies issues that can be fixed and creates draft pull requests with fixes
  - Improves performance, testing, and code quality via PRs
  - Makes engineering investments: dependency updates, CI improvements, tooling
  - Updates its own PRs when CI fails or merge conflicts arise
  - Nudges stale PRs waiting for author response
  - Takes the repository forward with proactive improvements
  - Maintains a persistent memory of work done and what remains
  Always polite, constructive, and mindful of the project's goals.

on:
  schedule: daily
  workflow_dispatch:
  slash_command:
    name: repo-assist
  reaction: "eyes"

timeout-minutes: 60

permissions: read-all

network:
  allowed:
  - defaults
  - dotnet
  - node
  - python
  - rust
  - java

checkout:
  fetch: ["*"]     # fetch all remote branches to allow working on PR branches
  fetch-depth: 0   # fetch full history

tools:
  web-fetch:
  github:
    toolsets: [all]
    allowed-repos: all
    min-integrity: none # This workflow is allowed to examine and comment on any issues or PRs
  bash: true
  repo-memory: true

safe-outputs:
  messages:
    footer: "> Generated by 🌈 {workflow_name}, see [workflow run]({run_url}). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md)."
    run-started: "{workflow_name} is processing {event_type}, see [workflow run]({run_url})..."
    run-success: "✓ {workflow_name} completed successfully, see [workflow run]({run_url})."
    run-failure: "✗ {workflow_name} encountered {status}, see [workflow run]({run_url})."
  add-comment:
    max: 10
    target: "*"
    hide-older-comments: true
  create-pull-request:
    draft: true
    title-prefix: "[Repo Assist] "
    labels: [automation, repo-assist]
    protected-files: fallback-to-issue
    max: 4
  push-to-pull-request-branch:
    target: "*"
    title-prefix: "[Repo Assist] "
    max: 4
    protected-files: fallback-to-issue
  create-issue:
    title-prefix: "[Repo Assist] "
    labels: [automation, repo-assist]
    max: 4
  update-issue:
    target: "*"
    title-prefix: "[Repo Assist] "
    max: 1
  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: "*"
  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
    target: "*"

steps:
  - name: Fetch repo data for task weighting
    env:
      GH_TOKEN: ${{ github.token }}
    run: |
      mkdir -p /tmp/gh-aw

      # Fetch open issues with labels (up to 500)
      gh issue list --state open --limit 500 --json number,labels > /tmp/gh-aw/issues.json

      # Fetch open PRs with titles (up to 200)
      gh pr list --state open --limit 200 --json number,title > /tmp/gh-aw/prs.json

      # Compute task weights and select two tasks for this run
      python3 - << 'EOF'
      import json, random, os

      with open('/tmp/gh-aw/issues.json') as f:
          issues = json.load(f)
      with open('/tmp/gh-aw/prs.json') as f:
          prs = json.load(f)

      open_issues     = len(issues)
      unlabelled      = sum(1 for i in issues if not i.get('labels'))
      repo_assist_prs = sum(1 for p in prs if p['title'].startswith('[Repo Assist]'))
      other_prs       = sum(1 for p in prs if not p['title'].startswith('[Repo Assist]'))

      task_names = {
          1:  'Issue Labelling',
          2:  'Issue Investigation and Comment',
          3:  'Issue Investigation and Fix',
          4:  'Engineering Investments',
          5:  'Coding Improvements',
          6:  'Maintain Repo Assist PRs',
          7:  'Stale PR Nudges',
          8:  'Performance Improvements',
          9:  'Testing Improvements',
          10: 'Take the Repository Forward',
      }

      weights = {
          1:  1   + 3 * unlabelled,
          2:  3   + 1 * open_issues,
          3:  3   + 0.7 * open_issues,
          4:  5   + 0.2 * open_issues,
          5:  5   + 0.1 * open_issues,
          6:  float(repo_assist_prs),
          7:  0.1 * other_prs,
          8:  3   + 0.05 * open_issues,
          9:  3   + 0.05 * open_issues,
          10: 3   + 0.05 * open_issues,
      }

      # Seed with run ID for reproducibility within a run
      run_id = int(os.environ.get('GITHUB_RUN_ID', '0'))
      rng = random.Random(run_id)

      task_ids     = list(weights.keys())
      task_weights = [weights[t] for t in task_ids]

      # Weighted sample without replacement (pick 2 distinct tasks)
      chosen, seen = [], set()
      for t in rng.choices(task_ids, weights=task_weights, k=30):
          if t not in seen:
              seen.add(t)
              chosen.append(t)
          if len(chosen) == 2:
              break

      print('=== Repo Assist Task Selection ===')
      print(f'Open issues       : {open_issues}')
      print(f'Unlabelled issues : {unlabelled}')
      print(f'Repo Assist PRs   : {repo_assist_prs}')
      print(f'Other open PRs    : {other_prs}')
      print()
      print('Task weights:')
      for t, w in weights.items():
          tag = ' <-- SELECTED' if t in chosen else ''
          print(f'  Task {t:2d} ({task_names[t]}): weight {w:6.1f}{tag}')
      print()
      print(f'Selected tasks for this run: Task {chosen[0]} ({task_names[chosen[0]]}) and Task {chosen[1]} ({task_names[chosen[1]]})')

      result = {
          'open_issues': open_issues, 'unlabelled_issues': unlabelled,
          'repo_assist_prs': repo_assist_prs, 'other_prs': other_prs,
          'task_names': task_names,
          'weights': {str(k): round(v, 2) for k, v in weights.items()},
          'selected_tasks': chosen,
      }
      with open('/tmp/gh-aw/task_selection.json', 'w') as f:
          json.dump(result, f, indent=2)
      EOF

source: githubnext/agentics/workflows/repo-assist.md@3de4e604a36b5190a1c7dc4719c7341500ba8a95
---

# Repo Assist

## Command Mode

Take heed of **instructions**: "${{ steps.sanitized.outputs.text }}"

If these are non-empty (not ""), then you have been triggered via `/repo-assist <instructions>`. Follow the user's instructions instead of the normal scheduled workflow. Focus exclusively on those instructions. Apply all the same guidelines (read AGENTS.md, run formatters/linters/tests, be polite, use AI disclosure). Skip the weighted task selection and Task 11 reporting, and instead directly do what the user requested. If no specific instructions were provided (empty or blank), proceed with the normal scheduled workflow below.

Then exit  -  do not run the normal workflow after completing the instructions.

## Non-Command Mode

You are Repo Assist for `${{ github.repository }}`. Your job is to support human contributors, help onboard newcomers, identify improvements, and fix bugs by creating pull requests. You never merge pull requests yourself; you leave that decision to the human maintainers.

Always be:

- **Polite and encouraging**: Every contributor deserves respect. Use warm, inclusive language.
- **Concise**: Keep comments focused and actionable. Avoid walls of text.
- **Mindful of project values**: Prioritize **stability**, **correctness**, and **minimal dependencies**. Do not introduce new dependencies without clear justification.
- **Transparent about your nature**: Always clearly identify yourself as Repo Assist, an automated AI assistant. Never pretend to be a human maintainer.
- **Restrained**: When in doubt, do nothing. It is always better to stay silent than to post a redundant, unhelpful, or spammy comment. Human maintainers' attention is precious  -  do not waste it.

## Memory

Use persistent repo memory to track:

- issues already commented on (with timestamps to detect new human activity)
- fix attempts and outcomes, improvement ideas already submitted, a short to-do list
- a **backlog cursor** so each run continues where the previous one left off
- previously checked off items (checked off by maintainer) in the Monthly Activity Summary to maintain an accurate pending actions list for maintainers

Read memory at the **start** of every run; update it at the **end**.

**Important**: Memory may not be 100% accurate. Issues may have been created, closed, or commented on; PRs may have been created, merged, commented on, or closed since the last run. Always verify memory against current repository state — reviewing recent activity since your last run is wise before acting on stale assumptions.

**Memory backlog tracking**: Your memory may contain notes about issues or PRs that still need attention (e.g., "issues #384, #336 have labels but no comments"). These are **action items for you**, not just informational notes. Each run, check your memory's `notes` field and other tracking fields for any explicitly flagged backlog work, and prioritise acting on it.

## Workflow

Each run, the deterministic pre-step collects live repo data (open issue count, unlabelled issue count, open Repo Assist PRs, other open PRs), computes a **weighted probability** for each task, and selects **two tasks** for this run using a seeded random draw. The weights and selected tasks are printed in the workflow logs. You will find the selection in `/tmp/gh-aw/task_selection.json`.

**Read the task selection**: at the start of your run, read `/tmp/gh-aw/task_selection.json` and confirm the two selected tasks in your opening reasoning. Execute **those two tasks** (plus the mandatory Task 11). If there's really nothing to do for a selected task, do not force yourself to do it - try any other different task instead that looks most useful.

The weighting scheme naturally adapts to repo state:

- When unlabelled issues pile up, Task 1 (labelling) dominates.
- When there are many open issues, Tasks 2 and 3 (commenting and fixing) get more weight.
- As the backlog clears, Tasks 4–10 (engineering, improvements, nudges, forward progress) draw more evenly.

**Repeat-run mode**: When invoked via `gh aw run repo-assist --repeat`, runs occur every 5–10 minutes. Each run is independent — do not skip a run. Always check memory to avoid duplicate work across runs.

**Progress Imperative**: Your primary purpose is to make forward progress on the repository. A "no action taken" outcome should be rare and only occur when every open issue has been addressed, all labelling is complete, and there are genuinely no improvements, fixes, or triage actions possible. If your memory flags backlog items, **act on them now** rather than deferring.

Always do Task 11 (Update Monthly Activity Summary Issue) every run. In all comments and PR descriptions, identify yourself as "Repo Assist". When engaging with first-time contributors, welcome them warmly and point them to README and CONTRIBUTING — this is good default behaviour regardless of which tasks are selected.

### Task 1: Issue Labelling

Process as many unlabelled issues and PRs as possible each run. Resume from memory's backlog cursor.

For each item, apply the best-fitting labels from: `bug`, `enhancement`, `help wanted`, `good first issue`, `documentation`, `question`, `duplicate`, `wontfix`, `spam`, `off topic`, `needs triage`, `needs investigation`, `breaking change`, `performance`, `security`, `refactor`. Remove misapplied labels. Apply multiple where appropriate; skip any you're not confident about. After labelling, post a brief comment if you have something genuinely useful to add.

Update memory with labels applied and cursor position.

### Task 2: Issue Investigation and Comment

1. List open issues sorted by creation date ascending (oldest first). Resume from your memory's backlog cursor; reset when you reach the end.
2. **Prioritise issues that have never received a Repo Assist comment.** Read the issue comments and check memory's `comments_made` field. Engage on an issue only if you have something insightful, accurate, helpful, and constructive to say. Expect to engage substantively on 1–3 issues per run; you may scan many more to find good candidates. Only re-engage on already-commented issues if new human comments have appeared since your last comment.
3. Respond based on type: bugs → investigate the code and suggest a root cause or workaround; feature requests → discuss feasibility and implementation approach; questions → answer concisely with references to relevant code; onboarding → point to README/CONTRIBUTING. Never post vague acknowledgements, restatements, or follow-ups to your own comments.
4. Begin every comment with: `🤖 *This is an automated response from Repo Assist.*`
5. Update memory with comments made and the new cursor position.

### Task 3: Issue Investigation and Fix

**Only attempt fixes you are confident about.** It is fine to work on issues you have previously commented on.

1. Review issues labelled `bug`, `help wanted`, or `good first issue`, plus any identified as fixable during investigation.
2. For each fixable issue:
   a. Check memory — skip if you've already tried and the attempt is still open. Never create duplicate PRs.
   b. Create a fresh branch off the default branch of the repository: `repo-assist/fix-issue-<N>-<desc>`.
   c. Implement a minimal, surgical fix. Do not refactor unrelated code.
   d. **Build and test (required)**: do not create a PR if the build fails or tests fail due to your changes. If tests fail due to infrastructure, create the PR but document it.
   e. Add a test for the bug if feasible; re-run tests.
   f. Create a draft PR with: AI disclosure, `Closes #N`, root cause, fix rationale, trade-offs, and a Test Status section showing build/test outcome.
   g. Post a single brief comment on the issue linking to the PR.
3. Update memory with fix attempts and outcomes.

### Task 4: Engineering Investments

Improve the engineering foundations of the repository. Consider:

- **Dependency updates**: Check for outdated dependencies. Prefer minor/patch updates; propose major bumps only with clear benefit. **Bundle Dependabot PRs**: If multiple open Dependabot PRs exist, create a single bundled PR applying all compatible updates. Reference the original PRs so maintainers can close them after merging.
- **CI improvements**: Speed up CI pipelines, fix flaky tests, improve caching, upgrade actions.
- **Tooling and SDK versions**: Update runtime versions, linters, formatters.
- **Build system**: Simplify or modernise the build configuration.

For any change: create a fresh branch `repo-assist/eng-<desc>-<date>`, implement the change, build and test, then create a draft PR with AI disclosure and Test Status section. Update memory with what was checked and when.

### Task 5: Coding Improvements

Study the codebase and make clearly beneficial, low-risk improvements. **Be highly selective — only propose changes with obvious value.**

Good candidates: code clarity and readability, removing dead code, API usability, documentation gaps, reducing duplication.

Check memory for already-submitted ideas; do not re-propose them. Create a fresh branch `repo-assist/improve-<desc>` off the default branch of the repository, implement the improvement, build and test (same requirements as Task 3), then create a draft PR with AI disclosure, rationale, and Test Status section. If not ready to implement, file an issue instead. Update memory.

### Task 6: Maintain Repo Assist PRs

1. List all open PRs with the `[Repo Assist]` title prefix.
2. For each PR: fix CI failures caused by your changes by pushing updates; resolve merge conflicts. If you've retried multiple times without success, comment and leave for human review.
3. Do not push updates for infrastructure-only failures — comment instead.
4. Update memory.

### Task 7: Stale PR Nudges

1. List open non-Repo-Assist PRs not updated in 14+ days.
2. For each (check memory — skip if already nudged): if the PR is waiting on the author, post a single polite comment asking if they need help or want to hand off. Do not comment if the PR is waiting on a maintainer.
3. **Maximum 3 nudges per run.** Update memory.

### Task 8: Performance Improvements

Identify and implement meaningful performance improvements. Good candidates: algorithmic improvements, unnecessary work elimination, caching opportunities, memory usage reductions, startup time. Only propose changes with a clear, measurable benefit. Create a fresh branch, implement and benchmark where possible, build and test, then create a draft PR with AI disclosure, rationale, and Test Status section. Update memory.

### Task 9: Testing Improvements

Improve the quality and coverage of the test suite. Good candidates: missing tests for existing functionality, flaky or brittle tests, slow tests that can be sped up, test infrastructure improvements, better assertions. Avoid adding low-value tests just to inflate coverage. Create a fresh branch, implement improvements, build and test, then create a draft PR. Update memory.

### Task 10: Take the Repository Forward

Proactively move the repository forward. Use your judgement to identify the most valuable thing to do  -  implement a backlog feature, investigate a difficult bug, draft a plan or proposal, or chart out future work. This work may span multiple runs; check your memory for anything in progress and continue it before starting something new. Record progress and next steps in memory at the end of each run.

### Task 11: Update Monthly Activity Summary Issue (ALWAYS DO THIS TASK IN ADDITION TO OTHERS)

Maintain a single open issue titled `[Repo Assist] Monthly Activity {YYYY}-{MM}` as a rolling summary of all Repo Assist activity for the current month.

1. Search for an open `[Repo Assist] Monthly Activity` issue with label `repo-assist`. If it's for the current month, update it. If for a previous month, close it and create a new one. Read any maintainer comments  -  they may contain instructions; note them in memory.
2. **Issue body format**  -  use **exactly** this structure:

   ```markdown
   🤖 *Repo Assist here  -  I'm an automated AI assistant for this repository.*

   ## Activity for <Month Year>

   ## Suggested Actions for Maintainer

   **Comprehensive list** of all pending actions requiring maintainer attention (excludes items already actioned and checked off).
   - Reread the issue you're updating before you update it  -  there may be new checkbox adjustments since your last update that require you to adjust the suggested actions.
   - List **all** the comments, PRs, and issues that need attention
   - Exclude **all** items that have either
     a. previously been checked off by the user in previous editions of the Monthly Activity Summary, or
     b. the items linked are closed/merged
   - Use memory to keep track items checked off by user.
   - Be concise  -  one line per item., repeating the format lines as necessary:

   * [ ] **Review PR** #<number>: <summary>  -  [Review](<link>)
   * [ ] **Check comment** #<number>: Repo Assist commented  -  verify guidance is helpful  -  [View](<link>)
   * [ ] **Merge PR** #<number>: <reason>  -  [Review](<link>)
   * [ ] **Close issue** #<number>: <reason>  -  [View](<link>)
   * [ ] **Close PR** #<number>: <reason>  -  [View](<link>)
   * [ ] **Define goal**: <suggestion>  -  [Related issue](<link>)

   *(If no actions needed, state "No suggested actions at this time.")*

   ## Future Work for Repo Assist

   {Very briefly list future work for Repo Assist}

   *(If nothing pending, skip this section.)*

   ## Run History

   ### <YYYY-MM-DD HH:MM UTC>  -  [Run](<https://github.com/<repo>/actions/runs/<run-id>>)
   - 💬 Commented on #<number>: <short description>
   - 🔧 Created PR #<number>: <short description>
   - 🏷️ Labelled #<number> with `<label>`
   - 📝 Created issue #<number>: <short description>

   ### <YYYY-MM-DD HH:MM UTC>  -  [Run](<https://github.com/<repo>/actions/runs/<run-id>>)
   - 🔄 Updated PR #<number>: <short description>
   - 💬 Commented on PR #<number>: <short description>
   ```

3. **Format enforcement (MANDATORY)**:
   - Always use the exact format above. If the existing body uses a different format, rewrite it entirely.
   - **Suggested Actions comes first**, immediately after the month heading, so maintainers see the action list without scrolling.
   - **Run History is in reverse chronological order**  -  prepend each new run's entry at the top of the Run History section so the most recent activity appears first.
   - **Each run heading includes the date, time (UTC), and a link** to the GitHub Actions run: `### YYYY-MM-DD HH:MM UTC  -  [Run](https://github.com/<repo>/actions/runs/<run-id>)`. Use `${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}` for the current run's link.
   - **Actively remove completed items** from "Suggested Actions"  -  do not tick them `[x]`; delete the line when actioned. The checklist contains only pending items.
   - Use `* [ ]` checkboxes in "Suggested Actions". Never use plain bullets there.
4. **Comprehensive suggested actions**: The "Suggested Actions for Maintainer" section must be a **complete list** of all pending items requiring maintainer attention, including:
   - All open Repo Assist PRs needing review or merge
   - **All Repo Assist comments** that haven't been acknowledged by a maintainer (use "Check comment" for each)
   - Issues that should be closed (duplicates, resolved, etc.)
   - PRs that should be closed (stale, superseded, etc.)
   - Any strategic suggestions (goals, priorities)
   Use repo memory and the activity log to compile this list. Include direct links for every item. Keep entries to one line each.
5. Do not update the activity issue if nothing was done in the current run. However, if you conclude "nothing to do", first verify this by checking: (a) Are there any open issues without a Repo Assist comment? (b) Are there issues in your memory flagged for attention? (c) Are there any bugs that could be investigated or fixed? If any of these are true, go back and do that work instead of concluding with no action.

## Guidelines

- **No breaking changes** without maintainer approval via a tracked issue.
- **No new dependencies** without discussion in an issue first.
- **Small, focused PRs**  -  one concern per PR.
- **Read AGENTS.md first**: before starting work on any pull request, read the repository's `AGENTS.md` file (if present) to understand project-specific conventions, coding standards, and contribution requirements.
- **Build, format, lint, and test before every PR**: run any code formatting, linting, and testing checks configured in the repository. Build failure, lint errors, or test failures caused by your changes → do not create the PR. Infrastructure failures → create the PR but document in the Test Status section.
- **Respect existing style**  -  match code formatting and naming conventions.
- **AI transparency**: every comment, PR, and issue must include a Repo Assist disclosure with 🤖.
- **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.
- **Release preparation**: use your judgement on each run to assess whether a release is warranted (significant unreleased changes, changelog out of date). If so, create a draft release PR on your own initiative — there is no dedicated task for this.
- **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 within the two selected tasks. A "no action" run should be genuinely exceptional.


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/
.paket/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

.ionide

================================================
FILE: AGENTS.md
================================================
## Git Policy

- **NEVER commit or push unless the user explicitly asks you to.** Only create commits when directly requested.

## Build, Test & Lint Commands

- **Build**: `dotnet fake build -t Build` (Release configuration)
- **Format Check**: `dotnet fake build -t CheckFormat` (validates Fantomas formatting)
- **Format**: `dotnet fake build -t Format` (applies Fantomas formatting)
- **All Tests**: `dotnet fake build -t RunTests` (builds + starts test server + runs all tests)
- **Unit Tests Only**: `dotnet build && dotnet tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll`
- **Provider Tests (Integration)**:
  1. Build test server: `dotnet build tests/Swashbuckle.WebApi.Server/Swashbuckle.WebApi.Server.fsproj -c Release`
  2. Start server in background: `dotnet tests/Swashbuckle.WebApi.Server/bin/Release/net10.0/Swashbuckle.WebApi.Server.dll`
  3. Build tests: `dotnet build SwaggerProvider.TestsAndDocs.sln -c Release`
  4. Run tests: `dotnet tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll`
- **Single Test**: Run via xunit runner: `dotnet [assembly] [filter]`

## Code Style Guidelines

**Language**: F# (net10.0 target framework)

**Imports & Namespaces**:

- `namespace [Module]` at file start; no `open` statements at module level
- Use `module [Name]` for nested modules
- Open dependencies after namespace declaration (e.g., `open Xunit`, `open FsUnitTyped`)
- Fully qualify internal modules: `SwaggerProvider.Internal.v2.Parser`, `SwaggerProvider.Internal.v3.Compilers`

**Formatting** (via Fantomas, EditorConfig enforced):

- 4-space indents, max 150 char line length
- `fsharp_max_function_binding_width=10`, `fsharp_max_infix_operator_expression=70`
- No space before parameter/lowercase invocation
- Multiline block brackets on same column, Stroustrup style enabled
- Bar before discriminated union declarations, max 3 blank lines

**Naming Conventions**:

- PascalCase for classes, types, modules, public members
- camelCase for local/private bindings, parameters
- Suffix test functions with `Tests` or use attributes like `[<Theory>]`, `[<Fact>]`

**Type Annotations**:

- Explicit return types for public functions (recommended)
- Use type inference for local bindings when obvious
- Generic type parameters: `'a`, `'b` (single quote prefix)

**Error Handling**:

- Use `Result<'T, 'Error>` or `Option<'T>` for fallible operations
- `failwith` or `failwithf` for errors in type providers and compilers
- Task-based async for I/O: `task { }` expressions in tests
- Match failures with `| _ -> ...` or pattern guards with `when`

**File Organization**:

- Tests use Xunit attributes: `[<Theory>]`, `[<Fact>]`, `[<MemberData>]`
- Design-time providers in `src/SwaggerProvider.DesignTime/`, runtime in `src/SwaggerProvider.Runtime/`
- Test schemas organized by OpenAPI version: `tests/.../Schemas/{v2,v3}/`

## Key Patterns

- Type Providers use `ProvidedApiClientBase` and compiler pipeline (DefinitionCompiler, OperationCompiler)
- SSRF protection enabled by default; disable with `SsrfProtection=false` static parameter
- Target net10.0; use implicit async/await (task expressions)


================================================
FILE: LICENSE.txt
================================================
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>


================================================
FILE: README.md
================================================
# SwaggerProvider

[![NuGet Version](https://badgen.net/nuget/v/SwaggerProvider)](https://www.nuget.org/packages/SwaggerProvider)
[![NuGet Downloads](https://badgen.net/nuget/dt/SwaggerProvider)](https://www.nuget.org/packages/SwaggerProvider)
[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](http://unlicense.org/)

**SwaggerProvider** is an F# library of generative [Type Providers](https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/type-providers/) that auto-generate strongly-typed HTTP client code from [OpenAPI 3.0](https://swagger.io/specification/) and [Swagger 2.0](https://swagger.io/specification/v2/) schemas — no code generation step required.

📚 **Full documentation:** <https://fsprojects.github.io/SwaggerProvider/>

## Quick Start

```fsharp
#r "nuget: SwaggerProvider"
open SwaggerProvider

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>

let client = PetStore.Client()
client.GetInventory() |> Async.AwaitTask |> Async.RunSynchronously
```

## Features

- **Compile-Time Types** — generated at compile time directly from live or local schema files, no separate codegen step needed
- Supports **OpenAPI 3.0** and **Swagger 2.0** schemas in JSON and YAML formats
- **Works Everywhere** — F# scripts, .NET projects, and F# Interactive with full IntelliSense and type-checking
- **SSRF Protection** — blocks HTTP and private IP addresses by default to prevent server-side request forgery attacks
- **CancellationToken Support** — every generated method accepts an optional CancellationToken for cancelling long-running requests
- **Fully Customizable** — bring your own HttpClient, DelegatingHandler, or override JSON serialization

## Installation

```bash
dotnet add package SwaggerProvider
```

## Key Parameters

| Parameter | Default | Description |
|-----------|---------|-------------|
| `Schema` | *(required)* | URL or file path to the OpenAPI/Swagger schema |
| `SsrfProtection` | `true` | Block HTTP and private IPs to prevent SSRF attacks |
| `PreferNullable` | `false` | Use `Nullable<_>` instead of `Option<_>` for optional fields |
| `PreferAsync` | `false` | Generate `Async<'T>` instead of `Task<'T>` |
| `IgnoreControllerPrefix` | `true` | Generate a single client class for all operations |
| `IgnoreOperationId` | `false` | Generate method names from paths instead of operation IDs |
| `IgnoreParseErrors` | `false` | Continue generation even when the parser reports schema warnings |

See the [full documentation](https://fsprojects.github.io/SwaggerProvider/) for more details and examples.

## Maintainer(s)

- [@sergey-tihon](https://github.com/sergey-tihon)

The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) — F# Community Project Incubation Space.


================================================
FILE: SwaggerProvider.TestsAndDocs.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28621.142
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{63297B98-5CED-492C-A5B7-A5B4F73CF142}"
	ProjectSection(SolutionItems) = preProject
		paket.dependencies = paket.dependencies
		paket.lock = paket.lock
	EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{83F16175-43B1-4C90-A1EE-8E351C33435D}"
	ProjectSection(SolutionItems) = preProject
		docs\tools\generate.fsx = docs\tools\generate.fsx
		docs\tools\templates\template.cshtml = docs\tools\templates\template.cshtml
	EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{8E6D5255-776D-4B61-85F9-73C37AA1FB9A}"
	ProjectSection(SolutionItems) = preProject
		docs\content\index.fsx = docs\content\index.fsx
		docs\content\tutorial.fsx = docs\content\tutorial.fsx
	EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{ED8079DD-2B06-4030-9F0F-DC548F98E1C4}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.ProviderTests", "tests\SwaggerProvider.ProviderTests\SwaggerProvider.ProviderTests.fsproj", "{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Runtime", "src\SwaggerProvider.Runtime\SwaggerProvider.Runtime.fsproj", "{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.DesignTime", "src\SwaggerProvider.DesignTime\SwaggerProvider.DesignTime.fsproj", "{0598B4A4-3017-493E-8A64-293EAB4CFB95}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CD49F31A-952B-4153-AB76-690091FCE484}"
	ProjectSection(SolutionItems) = preProject
		global.json = global.json
	EndProjectSection
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5}.Release|Any CPU.Build.0 = Release|Any CPU
		{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81}.Release|Any CPU.Build.0 = Release|Any CPU
		{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{0598B4A4-3017-493E-8A64-293EAB4CFB95}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
		{8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}
		{F26DFAA6-CB19-46EB-9FBD-F4A4DC46C3F5} = {ED8079DD-2B06-4030-9F0F-DC548F98E1C4}
		{DC3E73AF-5B15-45AD-B3C5-B3707DCB0F81} = {1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}
		{0598B4A4-3017-493E-8A64-293EAB4CFB95} = {1D6B2F7D-FC4A-499B-B3D1-42A09F42AAAF}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {F2D1B446-5EE2-4DDF-83A6-831E733173F4}
	EndGlobalSection
EndGlobal


================================================
FILE: SwaggerProvider.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28621.142
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Runtime", "src\SwaggerProvider.Runtime\SwaggerProvider.Runtime.fsproj", "{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{04303D28-4592-430A-B4A6-892105A95B22}"
	ProjectSection(SolutionItems) = preProject
		paket.dependencies = paket.dependencies
		paket.lock = paket.lock
	EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{727FB2BE-A8C5-4537-9C87-7083346E2865}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{302BCCA4-51B8-475C-9131-548CDC824026}"
	ProjectSection(SolutionItems) = preProject
		.editorconfig = .editorconfig
		build.fsx = build.fsx
		global.json = global.json
		README.md = README.md
		docs\RELEASE_NOTES.md = docs\RELEASE_NOTES.md
	EndProjectSection
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.DesignTime", "src\SwaggerProvider.DesignTime\SwaggerProvider.DesignTime.fsproj", "{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "SwaggerProvider.Tests", "tests\SwaggerProvider.Tests\SwaggerProvider.Tests.fsproj", "{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Swashbuckle.WebApi.Server", "tests\Swashbuckle.WebApi.Server\Swashbuckle.WebApi.Server.fsproj", "{112C445E-959B-4193-836A-78F36FB9F36E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{BA115E77-63E4-4D9C-AB91-F8FAAD2218D3}"
	ProjectSection(SolutionItems) = preProject
		.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
	EndProjectSection
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9}.Release|Any CPU.Build.0 = Release|Any CPU
		{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D}.Release|Any CPU.Build.0 = Release|Any CPU
		{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{358F1AB1-0F38-4D7D-B022-24F4E9EB5673}.Release|Any CPU.Build.0 = Release|Any CPU
		{112C445E-959B-4193-836A-78F36FB9F36E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{112C445E-959B-4193-836A-78F36FB9F36E}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{112C445E-959B-4193-836A-78F36FB9F36E}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{112C445E-959B-4193-836A-78F36FB9F36E}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{AD0B2860-9373-4BD9-906D-6D19F2F7DEE9} = {727FB2BE-A8C5-4537-9C87-7083346E2865}
		{DBE9AA3E-AB4C-4FE3-915B-886CC6E6A88D} = {727FB2BE-A8C5-4537-9C87-7083346E2865}
		{358F1AB1-0F38-4D7D-B022-24F4E9EB5673} = {3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}
		{112C445E-959B-4193-836A-78F36FB9F36E} = {3A51AC71-D3EF-46DE-A7F0-E2B46370C6EE}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {D1661E43-518D-450C-BB1F-43C008B97BB6}
	EndGlobalSection
EndGlobal


================================================
FILE: build.cmd
================================================
@echo off
dotnet tool restore
dotnet paket restore
dotnet fsi build.fsx %*


================================================
FILE: build.fsx
================================================
#r "nuget: Fake.Core.Target"
#r "nuget: Fake.Core.Process"
#r "nuget: Fake.Core.ReleaseNotes"
#r "nuget: Fake.IO.FileSystem"
#r "nuget: Fake.DotNet.Cli"
#r "nuget: Fake.DotNet.AssemblyInfoFile"
#r "nuget: Fake.DotNet.Paket"
#r "nuget: Fake.Tools.Git"

// Boilerplate - https://github.com/fsprojects/FAKE/issues/2719#issuecomment-1470687052
System.Environment.GetCommandLineArgs()
|> Array.skip 2 // skip fsi.exe; build.fsx
|> Array.toList
|> Fake.Core.Context.FakeExecutionContext.Create false __SOURCE_FILE__
|> Fake.Core.Context.RuntimeContext.Fake
|> Fake.Core.Context.setExecutionContext

open Fake
open Fake.Core.TargetOperators
open Fake.Core
open Fake.IO
open Fake.IO.FileSystemOperators
open Fake.IO.Globbing.Operators
open Fake.DotNet
open Fake.Tools
open System.IO

Target.initEnvironment()

// --------------------------------------------------------------------------------------

// Longer description of the project
// (used as a description for NuGet package; line breaks are automatically cleaned up)
let description = "F# Type Provider for Swagger & Open API"

// Git configuration (used for publishing documentation in gh-pages branch)
// The profile where the project is posted
let gitOwner = "fsprojects"
// The name of the project on GitHub
let gitName = "SwaggerProvider"

// --------------------------------------------------------------------------------------

// Read additional information from the release notes document
let release = ReleaseNotes.load "docs/RELEASE_NOTES.md"

// Generate assembly info files with the right version & up-to-date information
Target.create "AssemblyInfo" (fun _ ->
    let fileName = "src/Common/AssemblyInfo.fs"

    AssemblyInfoFile.createFSharp
        fileName
        [ AssemblyInfo.Title gitName
          AssemblyInfo.Product gitName
          AssemblyInfo.Description description
          AssemblyInfo.Version release.AssemblyVersion
          AssemblyInfo.FileVersion release.AssemblyVersion ])

// --------------------------------------------------------------------------------------
// Clean build results

Target.create "Clean" (fun _ ->
    !!"**/**/bin/" |> Shell.cleanDirs
    //!! "**/**/obj/" |> Shell.cleanDirs

    Shell.cleanDirs [ "bin"; "temp" ]

    try
        File.Delete("swaggerlog")
    with _ ->
        ())

Target.create "CleanDocs" (fun _ -> Shell.cleanDirs [ "docs/output" ])

// --------------------------------------------------------------------------------------
// Build library & test project

let dotnet cmd args =
    let result = DotNet.exec id cmd args

    if not result.OK then
        failwithf "Failed: %A" result.Errors

Target.create "Build" (fun _ -> dotnet "build" "SwaggerProvider.sln -c Release")

let webApiInputStream = StreamRef.Empty

Target.create "StartServer" (fun _ ->
    Target.activateFinal "StopServer"

    CreateProcess.fromRawCommandLine "dotnet" "tests/Swashbuckle.WebApi.Server/bin/Release/net10.0/Swashbuckle.WebApi.Server.dll"
    |> CreateProcess.withStandardInput(CreatePipe webApiInputStream)
    |> Proc.start
    |> ignore

    // We need delay to guarantee that server is bootstrapped
    System.Threading.Thread.Sleep(2000))

Target.createFinal "StopServer" (fun _ ->
    // Write something to input stream to stop server
    try
        webApiInputStream.Value.Write([| 0uy |], 0, 1)
    with e ->
        printfn "%s" e.Message
//Process.killAllByName "dotnet"
)

Target.create "BuildTests" (fun _ ->
    // Explicit restore ensures project.assets.json has all target frameworks before the build.
    // Without this, the inner-build restores triggered by Paket.Restore.targets may overwrite
    // the assets file with only one TFM, causing NETSDK1005 for the other TFM.
    dotnet "restore" "SwaggerProvider.TestsAndDocs.sln"
    dotnet "build" "SwaggerProvider.TestsAndDocs.sln -c Release --no-restore")

// --------------------------------------------------------------------------------------
// Run the unit tests using test runner

let runTests assembly =
    dotnet $"{assembly}" ""

Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll")

Target.create "RunIntegrationTests" (fun _ -> runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll")

Target.create "RunTests" ignore

// --------------------------------------------------------------------------------------
// Build a NuGet package

Target.create "NuGet" (fun _ ->
    Paket.pack(fun p ->
        { p with
            ToolType = ToolType.CreateLocalTool()
            OutputPath = "bin"
            Version = release.NugetVersion
            ReleaseNotes = String.toLines release.Notes }))

Target.create "PublishNuget" (fun _ ->
    Paket.push(fun p ->
        { p with
            ToolType = ToolType.CreateLocalTool()
            WorkingDir = "bin" }))

// --------------------------------------------------------------------------------------
// Generate the documentation

Target.create "BrowseDocs" (fun _ ->
    CreateProcess.fromRawCommandLine "npm" "run docs:dev --prefix docs"
    |> (Proc.run >> ignore))

// --------------------------------------------------------------------------------------
// Release Scripts

Target.create "Release" (fun _ ->
    // not fully converted from  FAKE 4

    // StageAll ""
    // Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
    // Branches.push ""

    // Branches.tag "" release.NugetVersion
    // Branches.pushTag "" "origin" release.NugetVersion

    // // release on github
    // createClient (getBuildParamOrDefault "github-user" "") (getBuildParamOrDefault "github-pw" "")
    // |> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes
    // // TODO: |> uploadFile "PATH_TO_FILE"
    // |> releaseDraft
    // |> Async.RunSynchronously

    // using simplified FAKE 5 release for now

    Git.Staging.stageAll ""
    Git.Commit.exec "" (sprintf "Bump version to %s" release.NugetVersion)
    Git.Branches.push ""

    Git.Branches.tag "" release.NugetVersion
    Git.Branches.pushTag "" "origin" release.NugetVersion)

Target.create "BuildPackage" ignore

let sourceFiles =
    !!"**/*.fs" ++ "**/*.fsx"
    -- "packages/**/*.*"
    -- "paket-files/**/*.*"
    -- ".fake/**/*.*"
    -- "**/obj/**/*.*"
    -- "**/AssemblyInfo.fs"

Target.create "Format" (fun _ ->
    let result =
        sourceFiles
        |> Seq.map(sprintf "\"%s\"")
        |> String.concat " "
        |> DotNet.exec id "fantomas"

    if not result.OK then
        printfn "Errors while formatting all files: %A" result.Messages)

Target.create "CheckFormat" (fun _ ->
    let result =
        sourceFiles
        |> Seq.map(sprintf "\"%s\"")
        |> String.concat " "
        |> sprintf "%s --check"
        |> DotNet.exec id "fantomas"

    if result.ExitCode = 0 then
        Trace.log "No files need formatting"
    elif result.ExitCode = 99 then
        failwith "Some files need formatting, run `dotnet fake build -t Format` to format them"
    else
        Trace.logf "Errors while formatting: %A" result.Errors
        failwith "Unknown errors while formatting")

// --------------------------------------------------------------------------------------
// Run all targets by default. Invoke 'build <Target>' to override

Target.create "All" ignore

// https://github.com/fsharp/FAKE/issues/2283
let skipTests = Environment.environVarAsBoolOrDefault "skipTests" false


"Clean"
==> "AssemblyInfo"
==> "CheckFormat"
==> "Build"
==> "RunUnitTests"
==> "StartServer"
==> "BuildTests"
=?> ("RunIntegrationTests", not skipTests)
==> "StopServer"
==> "RunTests"
==> "NuGet"
==> "All"
==> "BuildPackage"
==> "PublishNuget"
==> "Release"

Target.runOrDefault "BuildPackage"


================================================
FILE: build.sh
================================================
#!/bin/bash
if test "$OS" = "Windows_NT"
then
  cmd /C build.cmd
else
  dotnet tool restore
  dotnet paket restore
  dotnet fsi build.fsx $@
fi


================================================
FILE: docs/.gitignore
================================================
node_modules/
.vitepress/cache/
.vitepress/dist/


================================================
FILE: docs/.vitepress/config.mts
================================================
import { defineConfig } from "vitepress";

export default defineConfig({
  base: "/SwaggerProvider/",
  title: "SwaggerProvider",
  description: "F# OpenAPI Type Provider",
  head: [
    ["link", { rel: "icon", href: "/files/img/logo.png" }],
    [
      "link",
      {
        rel: "stylesheet",
        href: "https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap",
      },
    ],
  ],
  themeConfig: {
    logo: "/files/img/logo.png",
    nav: [
      { text: "Home", link: "/" },
      { text: "NuGet", link: "https://www.nuget.org/packages/SwaggerProvider" },
      { text: "GitHub", link: "https://github.com/fsprojects/SwaggerProvider" },
    ],
    sidebar: [
      {
        text: "Documentation",
        items: [
          { text: "Getting Started", link: "/getting-started" },
          { text: "OpenApiClientProvider", link: "/OpenApiClientProvider" },
          { text: "Customization", link: "/Customization" },
          { text: "Release Notes", link: "/RELEASE_NOTES" },
        ],
      },
    ],
    socialLinks: [
      { icon: "github", link: "https://github.com/fsprojects/SwaggerProvider" },
    ],
    search: {
      provider: "local",
    },
  },
});


================================================
FILE: docs/.vitepress/theme/custom.css
================================================
:root {
  --vp-font-family-mono: "Fira Code", monospace;
}

.VPHero .image-container .image-bg {
  background-image: linear-gradient(135deg, #00c9a7 0%, #1cb5e0 50%, #00d4aa 100%);
  border-radius: 50%;
  filter: blur(68px);
  opacity: 0.6;
}

@supports (font-variation-settings: normal) {
  :root {
    --vp-font-family-mono: "Fira Code", monospace;
  }
}


================================================
FILE: docs/.vitepress/theme/index.ts
================================================
import DefaultTheme from 'vitepress/theme'
import './custom.css'

export default DefaultTheme


================================================
FILE: docs/Customization.md
================================================
# Customization

OpenAPI and Swagger type providers generate one or several API client types (depending on the value of `IgnoreControllerPrefix`).
Each provided API client is a subclass of `ProvidedApiClientBase`, so you can control and customize HTTP calls.

```fsharp
type ProvidedApiClientBase(httpClient: HttpClient) =
    member val HttpClient = httpClient with get, set

    abstract member Serialize: obj -> string
    abstract member Deserialize: string * Type -> obj
```

The snippet shows only the most important parts of `ProvidedApiClientBase`.
The full source includes default `Serialize` and `Deserialize` implementations built on [System.Text.Json](https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-10.0).

**Key features:**
1. You can provide your own `HttpClient` instance during API client construction and fully control request execution (if you do not provide one, the type provider creates a default instance).
2. `Serialize` and `Deserialize` are abstract methods. If the default `JsonSerializerOptions` do not fit your needs, override them and configure `System.Text.Json` as required.

## Request interception

Since you control `HttpClient`, you can use [outgoing request middleware](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests#outgoing-request-middleware), implement your own `DelegatingHandler`, and intercept all HTTP requests generated by the provided API client.

```fsharp {highlight:['8-13','18-20']}
open System
open System.Net.Http
open SwaggerProvider

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>

type LoggingHandler(messageHandler) =
    inherit DelegatingHandler(messageHandler)
    override __.SendAsync(request, cancellationToken) =
        // Put a breakpoint here if you want to debug HTTP calls
        printfn "[%A]: %A" request.Method request.RequestUri
        base.SendAsync(request, cancellationToken)

[<EntryPoint>]
let main argv =
    let baseAddress = Uri("https://petstore.swagger.io/v2/")
    let handler1 = new HttpClientHandler (UseCookies = false)
    let handler2 = new LoggingHandler(handler1)
    use httpClient = new HttpClient(handler2, true, BaseAddress=baseAddress)
    let client = PetStore.Client(httpClient)
    async {
        let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
        do! client.AddPet(pet)
        let! myPet = client.GetPetById(24L)
        printfn "Waw, my name is %A" myPet.Name
    }
    |> Async.RunSynchronously
    0
```

## Authentication

Authentication is a special case of request interception.
Your custom `DelegatingHandler` is fully responsible for authentication data management (attach an authorization header, add authentication cookies, invalidate tokens, etc.).

```fsharp {highlight:['4-6']}
type AuthHandler(messageHandler) =
    inherit DelegatingHandler(messageHandler)
    override __.SendAsync(request, cancellationToken) =
        // Invalidate your token if it expired
        request.Headers.Authorization <-
            Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token");
        base.SendAsync(request, cancellationToken)
```

If your token does not require invalidation, you can use `HttpClient.DefaultRequestHeaders` to add the `Authorization` header to all requests.

```fsharp {highlight:['4-5']}
let baseAddress = Uri("https://petstore.swagger.io/v2/")
let handler = new HttpClientHandler (UseCookies = false)
use httpClient = new HttpClient(handler, true, BaseAddress=baseAddress)
httpClient.DefaultRequestHeaders.Authorization <-
    Headers.AuthenticationHeaderValue("Bearer", "Your OAuth token")
let client = PetStore.Client(httpClient)
```

## Serialization

Serialization is also flexible.
Define your own API client type as a subclass of the generated API client and override `Serialize` and `Deserialize`.

::: info
The serializer is configurable but not replaceable! The Type provider emits types with [JsonPropertyNameAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonpropertynameattribute?view=net-10.0) on properties for seamless serialization.
:::

```fsharp {highlight:['20-28', '33-34']}
open System
open SwaggerProvider
open System.Text.Json
open System.Text.Json.Serialization

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema, PreferAsync=true>

let jsonSerializerSettings =
    // nuget: System.Text.Json
    let settings = JsonSerializerOptions(
                    //PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
                    // ...
                    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    ) 
    // nuget: FSharp.SystemTextJson
    JsonFSharpOptions.Default().AddToJsonSerializerOptions settings
    settings

type MyApiClient() =
    // inherit from provided API client
    inherit PetStore.Client()

    // Override default implementation of Serialize & Deserialize
    override __.Serialize(value:obj): string =
        JsonSerializer.Serialize(value, jsonSerializerSettings)
    override __.Deserialize(value, retTy:Type): obj =
        JsonSerializer.Deserialize(value, retTy, jsonSerializerSettings)


[<EntryPoint>]
let main argv =
    // Instantiate your API client
    let client = MyApiClient()
    async {
        let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
        do! client.AddPet(pet)
        let! myPet = client.GetPetById(24L)
        printfn "Waw, my name is %A" myPet.Name
    }
    |> Async.RunSynchronously
    0

```


================================================
FILE: docs/OpenApiClientProvider.md
================================================
# OpenAPI Client Provider

OpenApiClientProvider is a generative F# Type Provider, built on top of [Microsoft.OpenApi.Readers](https://www.nuget.org/packages/Microsoft.OpenApi.Readers/) schema parser that supports 3.0 and 2.0 schema formats.

```fsharp
open SwaggerProvider

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>
let client = PetStore.Client()
```

## Parameters

`OpenApiClientProvider` supports the following configuration parameters

| Parameter | Description |
|-----------|-------------|
| `Schema` | Url or Path to Swagger schema file. |
| `IgnoreOperationId` | Do not use `operationsId` and generate method names using `path` only. Default value `false`. |
| `IgnoreControllerPrefix` | Do not parse `operationsId` as `<controllerName>_<methodName>` and generate one client class for all operations. Default value `true`. |
| `PreferNullable` | Provide `Nullable<_>` for not required properties, instead of `Option<_>`. Defaults value `false`. |
| `PreferAsync` | Generate async actions of type `Async<'T>` instead of `Task<'T>`. Defaults value `false`. |
| `SsrfProtection` | Enable SSRF protection (blocks HTTP and localhost). Set to `false` for development/testing. Default value `true`. |
| `IgnoreParseErrors` | Continue generating the provider even when the OpenAPI parser reports validation errors (e.g. vendor extensions or non-strictly-compliant schemas). Warnings are printed to stderr. Default value `false`. |

More configuration scenarios are described in [Customization section](/Customization)

## Security (SSRF Protection)

By default, SwaggerProvider blocks HTTP URLs and localhost/private IP addresses to prevent [SSRF attacks](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery). 

For **development and testing** with local servers, disable SSRF protection:

```fsharp
// Development: Allow HTTP and localhost
type LocalApi = OpenApiClientProvider<"http://localhost:5000/swagger.json", SsrfProtection=false>

// Production: HTTPS with SSRF protection (default)
type ProdApi = OpenApiClientProvider<"https://api.example.com/swagger.json">
```

**Warning:** Never set `SsrfProtection=false` in production code.

## Non-Strictly-Compliant Schemas (IgnoreParseErrors)

Some OpenAPI schemas generated by tools such as [NSwag](https://github.com/RicoSuter/NSwag) may include extensions or properties that are technically invalid (e.g. `nullable: true` at the parameter level). By default, SwaggerProvider aborts with an error when the Microsoft.OpenApi parser reports such validation errors.

Set `IgnoreParseErrors=true` to continue generating the type provider despite these errors. Validation warnings are printed to stderr so they remain visible:

```fsharp
// NSwag-generated schema with non-standard nullable annotations
type MyApi = OpenApiClientProvider<"https://example.com/swagger.json", IgnoreParseErrors=true>
```

**Note:** Only use `IgnoreParseErrors=true` when you trust the schema source. Suppressing errors may hide genuine schema problems that could affect the generated client.

## CancellationToken Support

Every generated method automatically includes an optional `cancellationToken: CancellationToken` parameter (defaults to `CancellationToken.None`). This allows you to cancel long-running HTTP requests:

```fsharp
open System
open System.Threading
open SwaggerProvider

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
type PetStore = OpenApiClientProvider<Schema>

let client = PetStore.Client()

task {
    // Cancel after 5 seconds
    use cts = new CancellationTokenSource(TimeSpan.FromSeconds(5.0))
    let! pet = client.GetPetById(42L, cancellationToken = cts.Token)
    printfn $"Pet: {pet}"
}
|> _.Result
```

## Sample

```fsharp
open System
open System.Net.Http
open SwaggerProvider

let [<Literal>] Schema = "https://petstore.swagger.io/v2/swagger.json"
// By default provided methods return Task<'a>
// and use Option<'a> for optional params
type PetStore = OpenApiClientProvider<Schema>

[<EntryPoint>]
let main argv =
    // `UseCookies = false` is required if you use Cookie Parameters
    let handler = new HttpClientHandler(UseCookies = false)
    // `BaseAddress` uri should end with '/' because TP generates relative URIs
    let baseUri = Uri("https://petstore.swagger.io/v2/")
    use httpClient = new HttpClient(handler, true, BaseAddress = baseUri)
    // You can provide your instance of `HttpClient` to the provided API client
    // or change it any time at runtime using `client.HttpClient` property
    let client = PetStore.Client(httpClient)

    task {
        // Create a new instance of the provided type and add to store
        let pet = PetStore.Pet(Id = Some(24L), Name = "Shani")
        do! client.AddPet(pet)

        // Request data back and deserialize to the provided type
        let! myPet = client.GetPetById(24L)
        printfn "Waw, my name is %A" myPet.Name
    }
    |> Async.AwaitTask
    |> Async.RunSynchronously
    0
```


================================================
FILE: docs/RELEASE_NOTES.md
================================================
#### 4.0.0-beta02 - April 18, 2026

- fix: preserve declared properties when schema has both `properties` and `additionalProperties` (#383)
- refactor: `CallAsync` returns `HttpResponseMessage` internally for cleaner response handling (#385)
- eng: remove stale YamlDotNet dependency (removed with v2 parser in #377) (#386)
- test: extend OperationCompiler unit tests (+12 tests for asAsync mode, DELETE/PUT, header params) (#380)
- test: add coverage for cookie params, text/plain response, and default response (+6 tests) (#386)
- docs: update homepage README for v4.0 (remove SwaggerClientProvider references, update targets) (#379)
- docs: improve VitePress site — fix badges, flatten nav, dark theme, add features table (#382)
- ci: bump actions/configure-pages 5→6, deploy-pages 4→5, setup-node 4→6, upload-artifact 7.0.0→7.0.1

#### 4.0.0-beta01 - April 14, 2026

- BREAKING: remove SwaggerClientProvider and v2 compiler, simplify folder structure (#377)
- BREAKING: wrap optional scalar reference types in Option\<T\> (#122) (#357)
- feat: resolve oneOf/anyOf with single $ref to referenced type (#375)
- fix: publish portable PDB debug symbols to NuGet package (#361)
- perf: cache MethodInfo for asyncCast/taskCast to avoid repeated reflection (#374)
- perf: cache property name/metadata lookups in getPropertyValues (#373)
- perf: cache reflection lookups and avoid double seq materialisation (#378)
- docs: improve README with license badge, overview, quick start, and features table (#360)
- test: add DefinitionPath.Parse unit tests and PreferNullable coverage (#370)
- test: extend RuntimeHelpers unit-test coverage (#363)
- eng: add Dependabot for GitHub Actions + v3 OperationCompiler unit tests (#364)
- ci: bump actions/checkout, actions/cache, actions/setup-dotnet, actions/upload-artifact, actions/github-script, github/gh-aw-actions

#### 3.2.0 - April 6, 2026

- feat: add CancellationToken support to OpenApiClientProvider generated methods (closes #212) (#336)
- fix: map `format:date` to `DateOnly` on .NET 6+ targets (closes #240) (#321)
- fix: throw OpenApiException for undocumented HTTP error codes (#354)
- improve: enrich XML documentation for generated API methods (#349)
- improve: add allowed enum values to generated property XmlDoc comments (#353)
- perf: reduce DLL-emit time for large schemas (shared ToString helper + Dictionary lookup) (#356)
- perf: update FSharp.TypeProviders.SDK (O(n^2) to O(n) ILMethodDefs) (#355)
- test: add v3 array/map type-mapping tests and v2 schema compilation tests (#351)
- test: add $ref primitive-type alias tests for v3 DefinitionCompiler (closes #335) (#342)
- hk: update TP SDK and OpenApi reader

#### 3.1.0 - Mar 22, 2026

- feat: Add `IgnoreParseErrors` parameter to OpenApiClientProvider (#300)
- feat: Add `SchemaReaderErrors` property to OpenApiClientProvider (fixes #160) (#327)
- fix: include response body in OpenApiException message (closes #250) (#324)
- fix: unwrap F# `Option<T>` in \`toParam\` for header/path/cookie parameters (closes #140) (#322)
- fix: 2xx response handling in v2 and v3 OperationCompilers (#313)
- fix: `$0` in path parameter values treated as regex back-reference (#310)
- fix: Option types in form data not being unwrapped (issue #214) (#298)
- perf: avoid redundant cache invalidation timers in GetOrAdd (#318)
- perf: increase type provider cache timeout from 30s to 5 minutes (#329)
- hk: update FSharp.TypeProviders.SDK (enum custom attribute bug fix) (#330)
- test: add v3 DefinitionCompiler type-mapping unit tests (#331)
- test: add UniqueNameGenerator unit tests (#319)
- test: add unit tests for RuntimeHelpers module (#295)
- ci: add concurrency group to CI workflow to cancel redundant builds (#309)

#### 3.0.0 - Mar 1, 2026

- feat: Microsoft.OpenApi v2.x with OpenAPI v3.1 Support
- feat: Server-Side Request Forgery (SSRF) protection for IP V4 (#271) and V6 (#272)
- feat: handle text/plain payload types (#276)
- fix: removed dependency on Microsoft.OpenApi.Readers
- fix: error messages when `operationId` is not provided (minimal api) (#277)
- feat: include TP config information in cache key (#283)
- feat: add windows-latest ci (#282)
- feat: Handle allOf with single reference (#284)
- fix: nullable date deserialization for OpenAPI v3 schemas (#287)
- docs: the Serialization documentation to mention use of System.Text.Json rather than Newtonsoft.Json (#288)
- docs: Remove note about TaskBuilder.fs from the OpenApiClientProvider docs (#285)
- feat: Set the "Accept" request header to the specified type (#290)
- feat: Specify a Content-Type header on stream type requests when the payload type is known (#292)
- hk: dependencies update

#### 2.3.2 - Oct 11, 2025

- Added support for `text/*` media type (#270) by @spaasis

#### 2.3.1 - May 13, 2025

- Performance improvement: ProvidedTypes update to the most recent version (#267)

#### 2.3.0 - May 10, 2025

- Added .NET 8 runtime, updated Microsoft.OpenApi (#265)

#### 2.2.3 - Mar 11, 2025

- Update ProvidedTypes.fs to latest version of FSharp.TypeProvider.SDK (#262)

#### 2.2.2 - Jan 23, 2025

- Improvement of design-time error handling (#259)

#### 2.2.1 - Jan 16, 2025

- Added allOf properties to the schema definition (#256)
- Update TypeProvider SDK (#257)

#### 2.2.0 - Jan 6, 2025

- hk: build with .NET 9
- hk: Dependencies update

#### 2.1.3 - Sep 8, 2024

- hk: Dependencies update

#### 2.1.2 - Jun 3, 2024

- fix: Support DateTime/DateTimeOffset as required query parameter, using round-trip format (#244)
- hk: Dependencies update

#### 2.1.1 - Apr 8, 2024

- Minor dependency updates

#### 2.1.0 - Mar 14, 2024

- Build and test with .NET 8.0

#### 2.0.1 - Mar 12, 2024

- fix: update ProvidedTypes.fs (#235)
- FSharp.Data utilities update (#238)
- Updated custom serialization example to SwaggerProvider 2.0 (#239)

#### 2.0.0 - Nov 08, 2023

- F# 6 task{} instead of async{} under thee hood - [#200](https://github.com/fsprojects/SwaggerProvider/pull/200)
- BREAKING: `ProvidedApiClientBase.CallAsync` returns `task` instead of `async`
- BREAKING: `task` CE wrap all exceptions in `AggregateException` (with `OpenApiException` inside)
- Model enums as `string`, `int32` or `boolean` (Fixed [#186](https://github.com/fsprojects/SwaggerProvider/issues/186) )
- Add `Accept` header to all request (Fixed [#196](https://github.com/fsprojects/SwaggerProvider/issues/196))
- Supported requests with `octet-stream` body content [#203](https://github.com/fsprojects/SwaggerProvider/pull/203)
- Added missing properties to OpenApiException [#222](https://github.com/fsprojects/SwaggerProvider/pull/222)
- Changed raise to calling Reraise() extension method to preserve the call stack [#230](https://github.com/fsprojects/SwaggerProvider/pull/230)
- Microsoft.OpenApi (1.6.10)
- FSharp.SystemTextJson (1.2.42)
- Removed the `System.Net.Http` dependency (#221)
- fix: accept "default" as "ok response" fallback (#223)
- Minor performance tweaks (#233)

#### 1.0.2 - Jul 10, 2022

- SharpYaml 2.0.0
- Format code using Fantomas

#### 1.0.1 - Jun 25, 2022

- Dependencies update

#### 1.0.0 - Apr 17, 2022

- Target .NET 6
- Microsoft.OpenApi v1.3.1
- Migration to System.Text.Json [#176](https://github.com/fsprojects/SwaggerProvider/pull/176)
- Fix for 'FS3033: Payload is not supported' [#181](https://github.com/fsprojects/SwaggerProvider/issues/181)
- Drop `net46` support
- Dependencies update

#### 0.12.1 - Apr 9, 2022

- Correctly serialize Guid [] as query parameter [#192](https://github.com/fsprojects/SwaggerProvider/pull/192)

#### 0.12.0 - Dec 22, 2020

- OpenApiProvider: Dictionary support [#174](https://github.com/fsprojects/SwaggerProvider/pull/174)

#### 0.11.0 - Dec 13, 2020

- Relative path fix [#171](https://github.com/fsprojects/SwaggerProvider/pull/171)
- DateTime formatted as round-trip [#170](https://github.com/fsprojects/SwaggerProvider/pull/170)

#### 0.10.7 - July 15, 2020

- Avoid NullReferenceException on rare case that response is nothing. [#162](https://github.com/fsprojects/SwaggerProvider/pull/162)
- Dependencies update

#### 0.10.6 - June 8, 2020

- WebException handling [#161](https://github.com/fsprojects/SwaggerProvider/pull/161)

#### 0.10.5 - June 4, 2020

- Cache, yet one more fix... [#158](https://github.com/fsprojects/SwaggerProvider/pull/158)

#### 0.10.4 - May 31, 2020

- Cache fix part 2 [#155](https://github.com/fsprojects/SwaggerProvider/pull/155)

#### 0.10.3 - May 30, 2020

- Fixed caching [#153](https://github.com/fsprojects/SwaggerProvider/pull/153)
- Dependencies update [#154](https://github.com/fsprojects/SwaggerProvider/pull/154)

#### 0.10.2 - April 5, 2020

- Caching update [#144](https://github.com/fsprojects/SwaggerProvider/pull/144)
- Better autocomplete in IDEs

#### 0.10.1 - April 5, 2020

- Dependencies update [#143](https://github.com/fsprojects/SwaggerProvider/pull/143)

#### 0.10.0 - December 8, 2019

- OpenApiClientProvider
- .NET Core 3.1 support

#### 0.10.0-beta13 - December 8, 2019

- UUID/Guid support [#138](https://github.com/fsprojects/SwaggerProvider/issues/138)

#### 0.10.0-beta12 - November 19, 2019

- Fixed null reference for schemas without Components definitions

#### 0.10.0-beta11 - November 10, 2019

- Delete method incorrectly cased [#120](https://github.com/fsprojects/SwaggerProvider/issues/120)
- File handling - upload/download files as `IO.Stream` [#131](https://github.com/fsprojects/SwaggerProvider/pull/131)
- DateTimeOffset as a default `date-time` type [#133](https://github.com/fsprojects/SwaggerProvider/pull/133)
- Custom OpenApiException instead of HttpRequestException [134](https://github.com/fsprojects/SwaggerProvider/pull/134)

#### 0.10.0-beta10 - November 6, 2019

- Support REST convention with pluralized entities in mode with IgnoreOperationId=true [#121](https://github.com/fsprojects/SwaggerProvider/pull/121)
- Fixed null refs in optional headers [#123](https://github.com/fsprojects/SwaggerProvider/pull/123)

#### 0.10.0-beta09 - November 5, 2019

- TP parameter names are unified [#129](https://github.com/fsprojects/SwaggerProvider/pull/129)

#### 0.10.0-beta08 - November 3, 2019

- Migration to new Type Provider SDK [#88](https://github.com/fsprojects/SwaggerProvider/pull/88) [#125](https://github.com/fsprojects/SwaggerProvider/pull/125)
- SwaggerParser moved to runtime assembly (and exposed as API to library users) - [#90](https://github.com/fsprojects/SwaggerProvider/pull/90)
- Added runtime dependency on YamlDotNet
- Removed dependency on FSharp.Data/JsonValue (replaced by JSON.NET)
- Added full-init constructor for provided types [#91](https://github.com/fsprojects/SwaggerProvider/pull/91)
- 
Download .txt
gitextract_zkbrmfz_/

├── .config/
│   └── dotnet-tools.json
├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE.md
│   ├── aw/
│   │   └── actions-lock.json
│   ├── dependabot.yml
│   └── workflows/
│       ├── docs.yml
│       ├── dotnetcore.yml
│       ├── repo-assist.lock.yml
│       └── repo-assist.md
├── .gitignore
├── AGENTS.md
├── LICENSE.txt
├── README.md
├── SwaggerProvider.TestsAndDocs.sln
├── SwaggerProvider.sln
├── build.cmd
├── build.fsx
├── build.sh
├── docs/
│   ├── .gitignore
│   ├── .vitepress/
│   │   ├── config.mts
│   │   └── theme/
│   │       ├── custom.css
│   │       └── index.ts
│   ├── Customization.md
│   ├── OpenApiClientProvider.md
│   ├── RELEASE_NOTES.md
│   ├── files/
│   │   └── img/
│   │       └── logo.pdn
│   ├── getting-started.md
│   ├── index.md
│   └── package.json
├── global.json
├── paket.dependencies
├── src/
│   ├── Common/
│   │   └── AssemblyInfo.fs
│   ├── SwaggerProvider.DesignTime/
│   │   ├── Caching.fs
│   │   ├── DefinitionCompiler.fs
│   │   ├── OperationCompiler.fs
│   │   ├── Properties/
│   │   │   └── launchSettings.json
│   │   ├── Provider.OpenApiClient.fs
│   │   ├── SwaggerProvider.DesignTime.fsproj
│   │   ├── Utils.fs
│   │   └── paket.references
│   └── SwaggerProvider.Runtime/
│       ├── Exception.fs
│       ├── ProvidedApiClientBase.fs
│       ├── Runtime.fs
│       ├── RuntimeHelpers.fs
│       ├── SwaggerProvider.Runtime.fsproj
│       ├── SwaggerProvider.fsx
│       ├── paket.references
│       └── paket.template
└── tests/
    ├── SwaggerProvider.ProviderTests/
    │   ├── APIs.Guru.FSC.Tests.fs
    │   ├── Schemas/
    │   │   ├── Instagram.json
    │   │   ├── azure-arm-storage.json
    │   │   ├── clickmeter.com.json
    │   │   ├── github.json
    │   │   ├── i0027.json
    │   │   ├── issue132.json
    │   │   ├── issue173.json
    │   │   ├── issue181.yaml
    │   │   ├── issue219.yaml
    │   │   ├── issue255.yaml
    │   │   ├── issue279.json
    │   │   ├── my-swashbuckle.json
    │   │   ├── nullable-date.yaml
    │   │   ├── nullable-parameter-issue261.json
    │   │   ├── petstore-v2.json
    │   │   ├── petstore.yaml
    │   │   ├── slack.json
    │   │   ├── swashbuckle.json
    │   │   └── unsupported/
    │   │       ├── gettyimages.com.json
    │   │       └── issue0204.yaml
    │   ├── Script.fsx
    │   ├── Swagger.I0173.Tests.fs
    │   ├── Swagger.I0181.Tests.fs
    │   ├── Swagger.I0219.Tests.fs
    │   ├── Swagger.I0279.Tests.fs
    │   ├── Swagger.NullableDate.Tests.fs
    │   ├── Swagger.PetStore.Tests.fs
    │   ├── Swagger.SchemaReaderErrors.Tests.fs
    │   ├── SwaggerProvider.ProviderTests.fsproj
    │   ├── Swashbuckle.CancellationToken.Tests.fs
    │   ├── Swashbuckle.FileController.Tests.fs
    │   ├── Swashbuckle.NoContentControllers.Tests.fs
    │   ├── Swashbuckle.ResourceControllers.Tests.fs
    │   ├── Swashbuckle.ReturnControllers.Tests.fs
    │   ├── Swashbuckle.ReturnTextControllers.Tests.fs
    │   ├── Swashbuckle.SpecialCasesControllers.Tests.fs
    │   ├── Swashbuckle.UpdateControllers.Tests.fs
    │   ├── paket.references
    │   └── thing.fsx
    ├── SwaggerProvider.Tests/
    │   ├── APIs.guru.fs
    │   ├── PathResolutionTests.fs
    │   ├── RuntimeHelpersTests.fs
    │   ├── Schema.ArrayAndMapTypeMappingTests.fs
    │   ├── Schema.DefinitionPathTests.fs
    │   ├── Schema.OperationCompilationTests.fs
    │   ├── Schema.Parser.Tests.fs
    │   ├── Schema.TestHelpers.fs
    │   ├── Schema.TypeMappingTests.fs
    │   ├── Schema.V2SchemaCompilationTests.fs
    │   ├── Schema.XmlDocTests.fs
    │   ├── SsrfSecurityTests.fs
    │   ├── SwaggerProvider.Tests.fsproj
    │   ├── UtilsTests.fs
    │   └── paket.references
    ├── Swashbuckle.WebApi.Server/
    │   ├── Controllers/
    │   │   ├── FileController.fs
    │   │   ├── NoContentControllers.fs
    │   │   ├── ResourceControllers.fs
    │   │   ├── ReturnControllers.fs
    │   │   ├── ReturnTextControllers.fs
    │   │   ├── SpecialCasesControllers.fs
    │   │   ├── Types.fs
    │   │   ├── UpdateControllers.fs
    │   │   └── ValuesController.fs
    │   ├── Program.fs
    │   ├── Properties/
    │   │   └── launchSettings.json
    │   ├── Startup.fs
    │   ├── Swashbuckle.WebApi.Server.fsproj
    │   ├── app.config
    │   ├── appsettings.Development.json
    │   ├── appsettings.json
    │   └── paket.references
    └── test.fsx
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,896K chars).
[
  {
    "path": ".config/dotnet-tools.json",
    "chars": 437,
    "preview": "{\n  \"version\": 1,\n  \"isRoot\": true,\n  \"tools\": {\n    \"paket\": {\n      \"version\": \"10.3.1\",\n      \"commands\": [\n        \""
  },
  {
    "path": ".editorconfig",
    "chars": 765,
    "preview": "; EditorConfig helps developers define and maintain consistent\n; coding styles between different editors and IDEs.\n\n; Fo"
  },
  {
    "path": ".gitattributes",
    "chars": 639,
    "preview": "# Auto detect text files\n* text=auto \n\n# Custom for Visual Studio\n*.cs diff=csharp text=auto eol=lf\n*.fs diff=csharp tex"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 730,
    "preview": "### Description\n\nPlease provide a succinct description of your issue.\n\n### Repro steps\n\nPlease provide the steps require"
  },
  {
    "path": ".github/aw/actions-lock.json",
    "chars": 2576,
    "preview": "{\n  \"entries\": {\n    \"actions/github-script@v9.0.0\": {\n      \"repo\": \"actions/github-script\",\n      \"version\": \"v9.0.0\","
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 282,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n  "
  },
  {
    "path": ".github/workflows/docs.yml",
    "chars": 984,
    "preview": "name: Deploy docs to GitHub Pages\n\non:\n  push:\n    branches: [master]\n    paths:\n      - 'docs/**'\n  workflow_dispatch:\n"
  },
  {
    "path": ".github/workflows/dotnetcore.yml",
    "chars": 1246,
    "preview": "name: Build and Test\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflo"
  },
  {
    "path": ".github/workflows/repo-assist.lock.yml",
    "chars": 112242,
    "preview": "# gh-aw-metadata: {\"schema_version\":\"v3\",\"frontmatter_hash\":\"9795d605bdecebc79c8c5cbb8fbf7ffa7b3dfd48ab232f75dcff9e0b162"
  },
  {
    "path": ".github/workflows/repo-assist.md",
    "chars": 24192,
    "preview": "---\ndescription: |\n  A friendly repository assistant that runs 2 times a day to support contributors and maintainers.\n  "
  },
  {
    "path": ".gitignore",
    "chars": 5762,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "AGENTS.md",
    "chars": 3178,
    "preview": "## Git Policy\n\n- **NEVER commit or push unless the user explicitly asks you to.** Only create commits when directly requ"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1211,
    "preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
  },
  {
    "path": "README.md",
    "chars": 2867,
    "preview": "# SwaggerProvider\n\n[![NuGet Version](https://badgen.net/nuget/v/SwaggerProvider)](https://www.nuget.org/packages/Swagger"
  },
  {
    "path": "SwaggerProvider.TestsAndDocs.sln",
    "chars": 4225,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.2"
  },
  {
    "path": "SwaggerProvider.sln",
    "chars": 4305,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.2"
  },
  {
    "path": "build.cmd",
    "chars": 75,
    "preview": "@echo off\ndotnet tool restore\ndotnet paket restore\ndotnet fsi build.fsx %*\n"
  },
  {
    "path": "build.fsx",
    "chars": 7810,
    "preview": "#r \"nuget: Fake.Core.Target\"\n#r \"nuget: Fake.Core.Process\"\n#r \"nuget: Fake.Core.ReleaseNotes\"\n#r \"nuget: Fake.IO.FileSys"
  },
  {
    "path": "build.sh",
    "chars": 144,
    "preview": "#!/bin/bash\nif test \"$OS\" = \"Windows_NT\"\nthen\n  cmd /C build.cmd\nelse\n  dotnet tool restore\n  dotnet paket restore\n  dot"
  },
  {
    "path": "docs/.gitignore",
    "chars": 49,
    "preview": "node_modules/\n.vitepress/cache/\n.vitepress/dist/\n"
  },
  {
    "path": "docs/.vitepress/config.mts",
    "chars": 1202,
    "preview": "import { defineConfig } from \"vitepress\";\n\nexport default defineConfig({\n  base: \"/SwaggerProvider/\",\n  title: \"SwaggerP"
  },
  {
    "path": "docs/.vitepress/theme/custom.css",
    "chars": 357,
    "preview": ":root {\n  --vp-font-family-mono: \"Fira Code\", monospace;\n}\n\n.VPHero .image-container .image-bg {\n  background-image: lin"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "chars": 94,
    "preview": "import DefaultTheme from 'vitepress/theme'\nimport './custom.css'\n\nexport default DefaultTheme\n"
  },
  {
    "path": "docs/Customization.md",
    "chars": 5605,
    "preview": "# Customization\n\nOpenAPI and Swagger type providers generate one or several API client types (depending on the value of "
  },
  {
    "path": "docs/OpenApiClientProvider.md",
    "chars": 5042,
    "preview": "# OpenAPI Client Provider\n\nOpenApiClientProvider is a generative F# Type Provider, built on top of [Microsoft.OpenApi.Re"
  },
  {
    "path": "docs/RELEASE_NOTES.md",
    "chars": 17749,
    "preview": "#### 4.0.0-beta02 - April 18, 2026\n\n- fix: preserve declared properties when schema has both `properties` and `additiona"
  },
  {
    "path": "docs/getting-started.md",
    "chars": 1683,
    "preview": "# SwaggerProvider\n\n**SwaggerProvider** is an F# generative [Type Provider](https://learn.microsoft.com/en-us/dotnet/fsha"
  },
  {
    "path": "docs/index.md",
    "chars": 1405,
    "preview": "---\nlayout: home\nhero:\n  name: OpenAPI & Swagger F# Type Provider\n  tagline: Strongly-typed HTTP clients from OpenAPI 3."
  },
  {
    "path": "docs/package.json",
    "chars": 206,
    "preview": "{\n  \"private\": true,\n  \"scripts\": {\n    \"docs:dev\": \"vitepress dev\",\n    \"docs:build\": \"vitepress build\",\n    \"docs:prev"
  },
  {
    "path": "global.json",
    "chars": 79,
    "preview": "{\n  \"sdk\": {\n    \"version\": \"10.0.102\",\n    \"rollForward\": \"latestMinor\"\n  }\n}\n"
  },
  {
    "path": "paket.dependencies",
    "chars": 1308,
    "preview": "version 9.0.2\nsource https://api.nuget.org/v3/index.json\nstorage: none\n\nnuget FSharp.Core ~> 8\nnuget System.Text.Json ~>"
  },
  {
    "path": "src/Common/AssemblyInfo.fs",
    "chars": 723,
    "preview": "// Auto-Generated by FAKE; do not edit\nnamespace System\nopen System.Reflection\n\n[<assembly: AssemblyTitleAttribute(\"Swa"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/Caching.fs",
    "chars": 4322,
    "preview": "module SwaggerProvider.Caching\n\nopen System\nopen System.Collections.Concurrent\n\n// https://github.com/fsharp/FSharp.Data"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/DefinitionCompiler.fs",
    "chars": 27649,
    "preview": "namespace SwaggerProvider.Internal.Compilers\n\nopen System\nopen System.Reflection\nopen ProviderImplementation.ProvidedTyp"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/OperationCompiler.fs",
    "chars": 30640,
    "preview": "namespace SwaggerProvider.Internal.Compilers\n\nopen System\nopen System.Collections.Generic\nopen System.Net.Http\nopen Syst"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/Properties/launchSettings.json",
    "chars": 383,
    "preview": "{\n  \"profiles\": {\n    \"SwaggerProvider.DesignTime\": {\n      \"commandName\": \"Project\"\n    },\n    \"DebugTP\": {\n      \"comm"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs",
    "chars": 8114,
    "preview": "namespace SwaggerProvider\n\nopen System\nopen System.Reflection\nopen Microsoft.OpenApi.Reader\nopen ProviderImplementation."
  },
  {
    "path": "src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj",
    "chars": 2612,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Library</Outp"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/Utils.fs",
    "chars": 18296,
    "preview": "namespace SwaggerProvider.Internal\n\nmodule SchemaReader =\n    open System\n    open System.IO\n    open System.Net\n    ope"
  },
  {
    "path": "src/SwaggerProvider.DesignTime/paket.references",
    "chars": 150,
    "preview": "File: ProvidedTypes.fsi\nFile: ProvidedTypes.fs\nFile: Pluralizer.fs\nFile: NameUtils.fs\nSystem.Text.Json\nMicrosoft.OpenApi"
  },
  {
    "path": "src/SwaggerProvider.Runtime/Exception.fs",
    "chars": 506,
    "preview": "[<AutoOpen>]\n[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]\nmodule System.Exception\n\nopen Sy"
  },
  {
    "path": "src/SwaggerProvider.Runtime/ProvidedApiClientBase.fs",
    "chars": 3348,
    "preview": "namespace Swagger\n\nopen System\nopen System.Net.Http\nopen System.Threading.Tasks\nopen System.Text.Json\nopen System.Text.J"
  },
  {
    "path": "src/SwaggerProvider.Runtime/Runtime.fs",
    "chars": 204,
    "preview": "namespace SwaggerProvider\n\n// TypeProviderAssemblyAttribute in the runtime DLL, pointing to the design-time DLL\n[<assemb"
  },
  {
    "path": "src/SwaggerProvider.Runtime/RuntimeHelpers.fs",
    "chars": 19104,
    "preview": "namespace Swagger.Internal\n\nopen System\nopen System.Net.Http\nopen System.Net.Http.Headers\nopen System.Text.Json.Serializ"
  },
  {
    "path": "src/SwaggerProvider.Runtime/SwaggerProvider.Runtime.fsproj",
    "chars": 1870,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project>\n  <!-- See https://stackoverflow.com/questions/43921992/how-can-i-use-b"
  },
  {
    "path": "src/SwaggerProvider.Runtime/SwaggerProvider.fsx",
    "chars": 578,
    "preview": "#nowarn \"211\"\n// Standard NuGet or Paket location\n#I \".\"\n#I \"lib/net461\"\n\n// Standard NuGet locations packages\n#I \"../Ne"
  },
  {
    "path": "src/SwaggerProvider.Runtime/paket.references",
    "chars": 82,
    "preview": "File: ProvidedTypes.fsi\nFile: ProvidedTypes.fs\n\nFSharp.Core\nFSharp.SystemTextJson\n"
  },
  {
    "path": "src/SwaggerProvider.Runtime/paket.template",
    "chars": 1256,
    "preview": "type file\nid SwaggerProvider\ntitle\n    Swagger Provider\nowners\n    Sergey Tihon\nauthors\n    Sergey Tihon\nprojectUrl\n    "
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/APIs.Guru.FSC.Tests.fs",
    "chars": 3668,
    "preview": "module APIsGuruFSCS\n(*\nopen FSharp.Compiler.SourceCodeServices\nopen System\nopen System.IO\nopen Expecto\nopen Fake\n\nlet as"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/Instagram.json",
    "chars": 51572,
    "preview": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"version\": \"v1\",\n        \"title\": \"Instagram API\",\n        \"description\": "
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/azure-arm-storage.json",
    "chars": 47042,
    "preview": "{\n  \"swagger\": \"2.0\",\n  \"schemes\": [\n    \"https\"\n  ],\n  \"host\": \"management.azure.com\",\n  \"info\": {\n    \"description\": \""
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/clickmeter.com.json",
    "chars": 255374,
    "preview": "{\n    \"swagger\": \"2.0\",\n    \"schemes\": [\n      \"http\",\n      \"https\"\n    ],\n    \"host\": \"apiv2.clickmeter.com:80\",\n    \""
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/github.json",
    "chars": 1780,
    "preview": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n        \"description\": \"This is a Sample for GitHub API.\",\n        \"version\": \"1.0"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/i0027.json",
    "chars": 11466,
    "preview": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n    \"version\": \"v1\",\n    \"title\": \"Tenant API\"\n  },\n  \"host\": \"\",\n  \"basePath\": \"5003\""
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue132.json",
    "chars": 1595,
    "preview": "{\n    \"swagger\": \"2.0\",\n    \"info\": {\n      \"version\": \"v1\",\n      \"title\": \" \",\n      \"description\": \" \"\n    },\n    \"ho"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue173.json",
    "chars": 561308,
    "preview": "{\n    \"openapi\": \"3.0.1\",\n    \"info\": {\n      \"title\": \"OdhApi Tourism .Net Core\",\n      \"description\": \"ODH Tourism Api"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue181.yaml",
    "chars": 1887,
    "preview": "openapi: 3.0.0\ninfo:\n  title: my-api-book\n  version: '1.0'\nservers:\n  - url: 'https://myapi.staging.acme.com'\n    descri"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue219.yaml",
    "chars": 35332,
    "preview": "openapi: \"3.0.3\"\ninfo:\n  title: \"Sample Api\"\n  description: |\n    # Some ACME API\n  termsOfService: \"https://acmed3hdhhd"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue255.yaml",
    "chars": 249,
    "preview": "openapi: 3.0.0\npaths:\n  /run:\n    summary: Do nothing.\ncomponents:\n  schemas:\n    Person:\n      title: Person\n      allO"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/issue279.json",
    "chars": 555106,
    "preview": "{\n  \"openapi\": \"3.0.0\",\n  \"paths\": {\n    \"/activities\": {\n      \"get\": {\n        \"description\": \"Returns a list of activ"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/my-swashbuckle.json",
    "chars": 36978,
    "preview": "{\n  \"swagger\": \"2.0\",\n  \"info\": { \"version\": \"v1\", \"title\": \"Test Controllers for SwaggerProvider\" },\n  \"host\": \"localho"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/nullable-date.yaml",
    "chars": 592,
    "preview": "openapi: 3.0.0\ninfo:\n  title: Nullable Date Test API\n  version: 1.0.0\npaths:\n  /test:\n    get:\n      operationId: getTes"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json",
    "chars": 756,
    "preview": "{\n  \"openapi\": \"3.0.0\",\n  \"info\": {\n    \"title\": \"Nullable Parameter Test\",\n    \"version\": \"1.0.0\"\n  },\n  \"paths\": {\n   "
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/petstore-v2.json",
    "chars": 21060,
    "preview": "{\n  \"swagger\": \"2.0\",\n  \"info\": {\n    \"description\": \"This is a sample server Petstore server.  You can find out more ab"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/petstore.yaml",
    "chars": 20887,
    "preview": "openapi: 3.0.2\ninfo:\n  title: Swagger Petstore - OpenAPI 3.0\n  description: \"This is a sample Pet Store Server based on "
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/slack.json",
    "chars": 1117410,
    "preview": "{\n    \"basePath\": \"/api\",\n    \"definitions\": {\n        \"blocks\": {\n            \"description\": \"This is a very loose defi"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/swashbuckle.json",
    "chars": 20483,
    "preview": "{\"swagger\":\"2.0\",\"info\":{\"version\":\"v1\",\"title\":\"Test Controllers for SwaggerProvider\"},\"host\":\"localhost:8735\",\"schemes"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/unsupported/gettyimages.com.json",
    "chars": 319616,
    "preview": "{\n    \"swagger\": \"2.0\",\n    \"schemes\": [\n      \"https\"\n    ],\n    \"host\": \"api.gettyimages.com\",\n    \"basePath\": \"/\",\n  "
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Schemas/unsupported/issue0204.yaml",
    "chars": 6553,
    "preview": "openapi: 3.0.0\ninfo:\n  description: This is our customer facing API for the Qorta platform\n  version: v1\n  title: Samba"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Script.fsx",
    "chars": 2504,
    "preview": "// Load SwaggerProvider\n#r @\"../../src/SwaggerProvider/bin/Release/SwaggerProvider.dll\"\nopen SwaggerProvider\n\n// Petstor"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs",
    "chars": 210,
    "preview": "module Swagger.I0173.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue173.jso"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs",
    "chars": 194,
    "preview": "module Swagger.I0181.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue181.yam"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs",
    "chars": 198,
    "preview": "module Swagger.I0219.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue219.yam"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs",
    "chars": 196,
    "preview": "module Swagger.I0279.Tests\n\nopen SwaggerProvider\n\n[<Literal>]\nlet Schema = __SOURCE_DIRECTORY__ + \"/Schemas/issue279.jso"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs",
    "chars": 3202,
    "preview": "module Swagger.NullableDate.Tests\n\nopen SwaggerProvider\nopen Xunit\nopen FsUnitTyped\nopen System.Text.Json\nopen System.Te"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs",
    "chars": 3474,
    "preview": "module Swagger.PetStore.Tests\n\nopen SwaggerProvider\nopen Swagger\nopen FsUnitTyped\nopen Xunit\nopen System\nopen System.Net"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs",
    "chars": 975,
    "preview": "module Swagger.SchemaReaderErrors.Tests\n\nopen SwaggerProvider\nopen Xunit\nopen FsUnitTyped\n\n[<Literal>]\nlet ValidSchema ="
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj",
    "chars": 1976,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputTy"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs",
    "chars": 4304,
    "preview": "module Swashbuckle.CancellationTokenTests\n\nopen Xunit\nopen FsUnitTyped\nopen System\nopen System.Net.Http\nopen System.Thre"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs",
    "chars": 1880,
    "preview": "module Swashbuckle.FileControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen System.IO\nopen Swashbuckle.ReturnControllersTe"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs",
    "chars": 782,
    "preview": "module Swashbuckle.NoContentControllersTests\n\nopen FsUnitTyped\nopen Xunit\nopen Swashbuckle.ReturnControllersTests\n\n[<Fac"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs",
    "chars": 1033,
    "preview": "module Swashbuckle.ResourceControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen Swashbuckle.ReturnControllersTests\n\n[<Fac"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnControllers.Tests.fs",
    "chars": 4886,
    "preview": "module Swashbuckle.ReturnControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider\nopen System\nopen System.Net."
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs",
    "chars": 842,
    "preview": "module Swashbuckle.ReturnTextControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider\nopen System\nopen System."
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs",
    "chars": 586,
    "preview": "module Swashbuckle.SpecialCasesControllersTests\n\nopen Xunit\nopen Swashbuckle.ReturnControllersTests\n\n[<Fact>]\nlet ``Req"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs",
    "chars": 5387,
    "preview": "module Swashbuckle.UpdateControllersTests\n\nopen Xunit\nopen FsUnitTyped\nopen System\nopen Swashbuckle.ReturnControllersTes"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/paket.references",
    "chars": 99,
    "preview": "group Test\n    FSharp.Compiler.Service\n    FSharp.Core\n    Microsoft.NET.Test.Sdk\n    FsUnit.Xunit\n"
  },
  {
    "path": "tests/SwaggerProvider.ProviderTests/thing.fsx",
    "chars": 389,
    "preview": "let createQuote(id: string) =\n    printfn \"Creating Quote %A\" id\n\nlet closeQuote(id: string) =\n    printfn \"Closing Quot"
  },
  {
    "path": "tests/SwaggerProvider.Tests/APIs.guru.fs",
    "chars": 1100,
    "preview": "module APIsGuru\n\nopen System.Text.Json\nopen System.Net.Http\n\nlet httpClient = new HttpClient()\n\nlet private apisGuruList"
  },
  {
    "path": "tests/SwaggerProvider.Tests/PathResolutionTests.fs",
    "chars": 4826,
    "preview": "namespace SwaggerProvider.Tests.PathResolutionTests\n\nopen System\nopen System.IO\nopen System.Runtime.InteropServices\nopen"
  },
  {
    "path": "tests/SwaggerProvider.Tests/RuntimeHelpersTests.fs",
    "chars": 42224,
    "preview": "namespace SwaggerProvider.Tests.RuntimeHelpersTests\n\nopen System\nopen System.IO\nopen System.Net\nopen System.Net.Http\nope"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.ArrayAndMapTypeMappingTests.fs",
    "chars": 4877,
    "preview": "module SwaggerProvider.Tests.Schema_ArrayAndMapTypeMappingTests\n\nopen System\nopen Xunit\nopen FsUnitTyped\n\n// ── Required"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.DefinitionPathTests.fs",
    "chars": 4414,
    "preview": "module SwaggerProvider.Tests.Schema_DefinitionPathTests\n\n/// Unit tests for DefinitionPath.Parse — the function that spl"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs",
    "chars": 19003,
    "preview": "module SwaggerProvider.Tests.Schema_OperationCompilationTests\n\n/// Unit tests for the v3 OperationCompiler — verifying g"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs",
    "chars": 4241,
    "preview": "module SwaggerProvider.Tests.Schema_ParserTests\n\nopen Microsoft.OpenApi.Reader\nopen Xunit\nopen FsUnitTyped\nopen System\no"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.TestHelpers.fs",
    "chars": 4479,
    "preview": "[<AutoOpen>]\nmodule SwaggerProvider.Tests.Schema_TestHelpers\n\nopen System\nopen Microsoft.OpenApi.Reader\nopen SwaggerProv"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.TypeMappingTests.fs",
    "chars": 16799,
    "preview": "module SwaggerProvider.Tests.Schema_TypeMappingTests\n\nopen System\nopen Xunit\nopen FsUnitTyped\n\n// ── Required primitive "
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs",
    "chars": 8356,
    "preview": "module SwaggerProvider.Tests.Schema_V2SchemaCompilationTests\n\n/// Tests that verify Swagger 2.0 schemas can be parsed an"
  },
  {
    "path": "tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs",
    "chars": 6759,
    "preview": "module SwaggerProvider.Tests.Schema_XmlDocTests\n\nopen System\nopen Microsoft.OpenApi.Reader\nopen SwaggerProvider.Internal"
  },
  {
    "path": "tests/SwaggerProvider.Tests/SsrfSecurityTests.fs",
    "chars": 14655,
    "preview": "namespace SwaggerProvider.Tests.SsrfSecurityTests\n\nopen System\nopen Xunit\nopen SwaggerProvider.Internal.SchemaReader\n\n//"
  },
  {
    "path": "tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj",
    "chars": 1328,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <OutputType>Exe</OutputTy"
  },
  {
    "path": "tests/SwaggerProvider.Tests/UtilsTests.fs",
    "chars": 3692,
    "preview": "namespace SwaggerProvider.Tests.UtilsTests\n\nopen Xunit\nopen FsUnitTyped\nopen SwaggerProvider.Internal\n\n/// Unit tests fo"
  },
  {
    "path": "tests/SwaggerProvider.Tests/paket.references",
    "chars": 140,
    "preview": "group Test\n    FSharp.Core\n    FSharp.SystemTextJson\n    FsUnit.xUnit\n    Microsoft.NET.Test.Sdk\n    Microsoft.OpenApi\n "
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/FileController.fs",
    "chars": 2981,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen System.IO\nopen Microsoft.AspNetCore.Mvc\nopen Microsoft"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/NoContentControllers.fs",
    "chars": 1258,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen Microsoft.AspNetCore.Mvc\n\n[<Route(\"api/[controller]\")>]\n[<ApiContr"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/ResourceControllers.fs",
    "chars": 928,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System.Collections.Generic\nopen Microsoft.AspNetCore.Mvc\nopen Swa"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/ReturnControllers.fs",
    "chars": 2195,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen Microsoft.AspNetCore.Mvc\nopen Swagger.Internal\n\n[<Rout"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/ReturnTextControllers.fs",
    "chars": 3170,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System.IO\nopen System.Text\nopen System.Threading.Tasks\nopen Micros"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/SpecialCasesControllers.fs",
    "chars": 587,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen Microsoft.AspNetCore.Mvc\n\n[<Route(\"api/[controller]\")>]\n[<ApiContr"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/Types.fs",
    "chars": 472,
    "preview": "module Types\n\nopen System.Runtime.Serialization\n\n[<DataContract>]\ntype PointClass(x: int, y: int) =\n    new() = PointCl"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/UpdateControllers.fs",
    "chars": 2459,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\nopen System\nopen Microsoft.AspNetCore.Mvc\nopen System.Runtime.InteropS"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Controllers/ValuesController.fs",
    "chars": 654,
    "preview": "namespace Swashbuckle.WebApi.Server.Controllers\n\n\n\n(*\n//[<Route(\"api/[controller]\")>]\n//[<ApiController>]\ntype ValuesCo"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Program.fs",
    "chars": 663,
    "preview": "namespace Swashbuckle.WebApi.Server\n\nopen System\nopen Microsoft.AspNetCore\nopen Microsoft.AspNetCore.Hosting\n\nmodule Pro"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Properties/launchSettings.json",
    "chars": 755,
    "preview": "{\n  \"$schema\": \"http://json.schemastore.org/launchsettings.json\",\n  \"iisSettings\": {\n    \"windowsAuthentication\": false,"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Startup.fs",
    "chars": 2667,
    "preview": "namespace Swashbuckle.WebApi.Server\n\n\nopen Microsoft.AspNetCore.Builder\nopen Microsoft.AspNetCore.Hosting\nopen Microsoft"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/Swashbuckle.WebApi.Server.fsproj",
    "chars": 1297,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n  <PropertyGroup>\n    <TargetFramework>net1"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/app.config",
    "chars": 129,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<configuration>\n  <runtime>\n    <gcServer enabled=\"true\"/>\n  </runtime>\n</confi"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/appsettings.Development.json",
    "chars": 137,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Debug\",\n      \"System\": \"Information\",\n      \"Microsoft\": \"Informat"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/appsettings.json",
    "chars": 97,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Warning\"\n    }\n  },\n  \"AllowedHosts\": \"*\"\n}\n"
  },
  {
    "path": "tests/Swashbuckle.WebApi.Server/paket.references",
    "chars": 190,
    "preview": "group Server\n    FSharp.Core\n    Microsoft.AspNetCore\n    Microsoft.AspNetCore.Mvc\n    Microsoft.AspNetCore.HttpsPolicy\n"
  },
  {
    "path": "tests/test.fsx",
    "chars": 381,
    "preview": "#I \"../src/SwaggerProvider.Runtime/bin/Release/netstandard2.0\"\n#I \"../src/SwaggerProvider.Runtime/bin/Release/typeprovid"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the fsprojects/SwaggerProvider GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (3.4 MB), approximately 903.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!