From 42af0790ac7e325d12538ffe1ff028f1dba4641e Mon Sep 17 00:00:00 2001 From: Allan Thraen Date: Fri, 15 May 2026 11:24:52 +0200 Subject: [PATCH] feat(release): publish to Chocolatey on release Adds a .chocolatey/ package skeleton (codeshellmanager) and a new .github/workflows/chocolatey.yml that triggers on release: released (and workflow_dispatch for backfill). The workflow downloads the signed MSI from the GitHub Release, substitutes the version, MSI URL, and SHA256 into the nuspec + chocolateyinstall.ps1 placeholders, then choco pack + choco push to community.chocolatey.org using the CHOCO_API_KEY repo secret. Closes #42 Co-Authored-By: Claude Opus 4.7 --- .chocolatey/codeshellmanager.nuspec | 42 ++++++++ .chocolatey/tools/LICENSE.txt | 23 +++++ .chocolatey/tools/VERIFICATION.txt | 34 +++++++ .chocolatey/tools/chocolateyinstall.ps1 | 23 +++++ .chocolatey/tools/chocolateyuninstall.ps1 | 28 ++++++ .github/workflows/chocolatey.yml | 112 ++++++++++++++++++++++ CLAUDE.md | 2 + README.md | 9 ++ 8 files changed, 273 insertions(+) create mode 100644 .chocolatey/codeshellmanager.nuspec create mode 100644 .chocolatey/tools/LICENSE.txt create mode 100644 .chocolatey/tools/VERIFICATION.txt create mode 100644 .chocolatey/tools/chocolateyinstall.ps1 create mode 100644 .chocolatey/tools/chocolateyuninstall.ps1 create mode 100644 .github/workflows/chocolatey.yml diff --git a/.chocolatey/codeshellmanager.nuspec b/.chocolatey/codeshellmanager.nuspec new file mode 100644 index 0000000..dba8321 --- /dev/null +++ b/.chocolatey/codeshellmanager.nuspec @@ -0,0 +1,42 @@ + + + + codeshellmanager + __VERSION__ + https://github.com/umage-ai/CodeShellManager/tree/main/.chocolatey + umage.ai + CodeShellManager + umage.ai + https://umage.ai/products/code-shell-manager/ + https://raw.githubusercontent.com/umage-ai/CodeShellManager/main/src/CodeShellManager/Assets/app.ico + Copyright (c) 2025 umage.ai + https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE + false + https://github.com/umage-ai/CodeShellManager + https://github.com/umage-ai/CodeShellManager#readme + https://github.com/umage-ai/CodeShellManager/issues + codeshellmanager terminal claude claude-code wpf conpty xterm ai coding-agent admin + Multi-terminal host for Claude Code and other CLI coding agents on Windows. + + https://github.com/umage-ai/CodeShellManager/releases/tag/v__VERSION__ + + + + + diff --git a/.chocolatey/tools/LICENSE.txt b/.chocolatey/tools/LICENSE.txt new file mode 100644 index 0000000..33ded07 --- /dev/null +++ b/.chocolatey/tools/LICENSE.txt @@ -0,0 +1,23 @@ +From: https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE + +MIT License + +Copyright (c) 2025 umage.ai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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 OR COPYRIGHT HOLDERS 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. diff --git a/.chocolatey/tools/VERIFICATION.txt b/.chocolatey/tools/VERIFICATION.txt new file mode 100644 index 0000000..4e2a034 --- /dev/null +++ b/.chocolatey/tools/VERIFICATION.txt @@ -0,0 +1,34 @@ +VERIFICATION + +Verification is intended to assist Chocolatey moderators and end-users in +verifying that this package's contents are authentic. + +This Chocolatey package downloads the official signed MSI installer from the +matching CodeShellManager GitHub Release: + + https://github.com/umage-ai/CodeShellManager/releases + +The MSI is built and signed by GitHub Actions from the source in +https://github.com/umage-ai/CodeShellManager (see .github/workflows/build.yml) +using Azure Trusted Signing — publisher: umage.ai. + +To verify the package independently: + +1. Note the embedded download URL and SHA256 checksum in + tools\chocolateyinstall.ps1 (variables $url64 and $checksum64). + +2. Download the same MSI directly from the GitHub Release page above. + +3. On Windows, compute the SHA256 of the downloaded file: + + Get-FileHash -Algorithm SHA256 .\CodeShellManager--Setup.msi + + The output should match the $checksum64 value in chocolateyinstall.ps1. + +4. Optionally inspect the Authenticode signature on the MSI — it should be + issued to "umage.ai" via Microsoft's Azure Trusted Signing service. + +The bundled LICENSE.txt is a verbatim copy of the project license, also +available at: + + https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE diff --git a/.chocolatey/tools/chocolateyinstall.ps1 b/.chocolatey/tools/chocolateyinstall.ps1 new file mode 100644 index 0000000..f89ccdd --- /dev/null +++ b/.chocolatey/tools/chocolateyinstall.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = 'Stop' + +$packageName = 'codeshellmanager' +$toolsDir = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)" + +# These placeholders are replaced by .github/workflows/chocolatey.yml at pack time +# with the version-pinned MSI URL and its SHA256 from the GitHub Release. +$url64 = '__URL64__' +$checksum64 = '__CHECKSUM64__' + +$packageArgs = @{ + packageName = $packageName + unzipLocation = $toolsDir + fileType = 'msi' + url64bit = $url64 + softwareName = 'CodeShellManager*' + checksum64 = $checksum64 + checksumType64 = 'sha256' + silentArgs = '/qn /norestart /l*v "$($env:TEMP)\$($packageName).$($env:chocolateyPackageVersion).MsiInstall.log"' + validExitCodes = @(0, 3010, 1641) +} + +Install-ChocolateyPackage @packageArgs diff --git a/.chocolatey/tools/chocolateyuninstall.ps1 b/.chocolatey/tools/chocolateyuninstall.ps1 new file mode 100644 index 0000000..4b9d1cc --- /dev/null +++ b/.chocolatey/tools/chocolateyuninstall.ps1 @@ -0,0 +1,28 @@ +$ErrorActionPreference = 'Stop' + +$packageName = 'codeshellmanager' +$softwareName = 'CodeShellManager*' + +# Discover the install record (MSI product code) registered for the +# installed CodeShellManager and uninstall via msiexec. +$key = Get-UninstallRegistryKey -SoftwareName $softwareName + +if ($key.Count -eq 1) { + $packageArgs = @{ + packageName = $packageName + fileType = 'msi' + silentArgs = "$($key.PSChildName) /qn /norestart" + validExitCodes = @(0, 3010, 1605, 1614, 1641) + file = '' + } + Uninstall-ChocolateyPackage @packageArgs +} +elseif ($key.Count -eq 0) { + Write-Warning "$packageName has already been uninstalled by other means." +} +elseif ($key.Count -gt 1) { + Write-Warning "$($key.Count) matches found!" + Write-Warning "To prevent accidental data loss, no programs will be uninstalled." + Write-Warning "Please alert package maintainer the following keys were matched:" + $key | ForEach-Object { Write-Warning "- $($_.DisplayName)" } +} diff --git a/.github/workflows/chocolatey.yml b/.github/workflows/chocolatey.yml new file mode 100644 index 0000000..41ad678 --- /dev/null +++ b/.github/workflows/chocolatey.yml @@ -0,0 +1,112 @@ +name: Publish to Chocolatey + +# Packs and pushes a Chocolatey package wrapping the signed MSI from a GitHub Release +# to community.chocolatey.org. +# - `release` event fires automatically when CI / Release publishes the GitHub Release. +# - `workflow_dispatch` lets us re-publish a past version (used for the first +# submission once this workflow exists on main). +# +# Requires repo secret CHOCO_API_KEY (from https://community.chocolatey.org/account) +# scoped to push for package id `codeshellmanager`. + +on: + release: + types: [released] + workflow_dispatch: + inputs: + tag: + description: 'Release tag to publish (e.g. v0.5.0)' + required: true + type: string + +permissions: + contents: read + +jobs: + publish: + runs-on: windows-latest + steps: + - uses: actions/checkout@v6 + + - name: Resolve tag and version + id: ver + shell: pwsh + run: | + $tag = '${{ inputs.tag }}' + if (-not $tag) { $tag = '${{ github.event.release.tag_name }}' } + if (-not $tag) { Write-Error 'No release tag resolved.'; exit 1 } + $version = $tag.TrimStart('v') + "tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + "version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + Write-Host "Publishing tag=$tag version=$version" + + - name: Download signed MSI from GitHub Release + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + $tag = '${{ steps.ver.outputs.tag }}' + $version = '${{ steps.ver.outputs.version }}' + $msiName = "CodeShellManager-$version-Setup.msi" + New-Item -ItemType Directory -Force -Path artifact | Out-Null + gh release download $tag --repo umage-ai/CodeShellManager --pattern $msiName --dir artifact + if (-not (Test-Path "artifact\$msiName")) { + Write-Error "MSI $msiName not found in release $tag." + exit 1 + } + Write-Host "Downloaded artifact\$msiName" + + - name: Template version, URL, and checksum into package + shell: pwsh + run: | + $version = '${{ steps.ver.outputs.version }}' + $msiName = "CodeShellManager-$version-Setup.msi" + $url64 = "https://github.com/umage-ai/CodeShellManager/releases/download/v$version/$msiName" + $sha256 = (Get-FileHash "artifact\$msiName" -Algorithm SHA256).Hash.ToLowerInvariant() + Write-Host "URL: $url64" + Write-Host "SHA256: $sha256" + + $installPs1 = '.chocolatey/tools/chocolateyinstall.ps1' + (Get-Content $installPs1 -Raw). + Replace('__URL64__', $url64). + Replace('__CHECKSUM64__', $sha256) | + Set-Content -Path $installPs1 -NoNewline + + $nuspec = '.chocolatey/codeshellmanager.nuspec' + (Get-Content $nuspec -Raw). + Replace('__VERSION__', $version) | + Set-Content -Path $nuspec -NoNewline + + Write-Host '--- chocolateyinstall.ps1 ---' + Get-Content $installPs1 + Write-Host '--- codeshellmanager.nuspec ---' + Get-Content $nuspec + + - name: choco pack + shell: pwsh + run: | + choco pack .chocolatey/codeshellmanager.nuspec --out artifact + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + Get-ChildItem artifact\*.nupkg + + - name: choco push + shell: pwsh + env: + CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }} + run: | + $version = '${{ steps.ver.outputs.version }}' + $nupkg = "artifact/codeshellmanager.$version.nupkg" + if (-not (Test-Path $nupkg)) { + Write-Error "Expected nupkg not found: $nupkg" + exit 1 + } + choco push $nupkg --source https://push.chocolatey.org/ --api-key $env:CHOCO_API_KEY + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + - name: Upload built nupkg as workflow artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: codeshellmanager-chocolatey-${{ steps.ver.outputs.version }} + path: artifact/*.nupkg + if-no-files-found: warn diff --git a/CLAUDE.md b/CLAUDE.md index c53798b..f4b6f42 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -263,6 +263,8 @@ The tag value overrides the csproj `` at publish time (`-p:Version=` fl A second workflow, `.github/workflows/winget.yml`, fires on the `release: released` event and submits the signed MSI to microsoft/winget-pkgs as `UmageAI.CodeShellManager` via [vedantmgoyal9/winget-releaser](https://github.com/vedantmgoyal9/winget-releaser). It needs the repo secret `WINGET_TOKEN` (classic PAT, `public_repo` scope). The same workflow is `workflow_dispatch`-able with a `tag` input to backfill or retry a release. +A third workflow, `.github/workflows/chocolatey.yml`, also fires on `release: released` and publishes the signed MSI to community.chocolatey.org as `codeshellmanager`. It downloads the MSI from the GitHub Release, computes its SHA256, substitutes `__URL64__` / `__CHECKSUM64__` placeholders in `.chocolatey/tools/chocolateyinstall.ps1`, then runs `choco pack` and `choco push`. Needs the repo secret `CHOCO_API_KEY` (API key from a chocolatey.org account with push rights on the `codeshellmanager` id). Also `workflow_dispatch`-able with a `tag` input. The `.chocolatey/` folder holds the package skeleton (`codeshellmanager.nuspec`, `tools/chocolateyinstall.ps1`, `tools/chocolateyuninstall.ps1`, `tools/LICENSE.txt`, `tools/VERIFICATION.txt`); never commit a resolved URL or checksum into the install script — those placeholders are only substituted by the workflow at pack time. + ## Known Conventions - All WPF color literals use Catppuccin Mocha hex values — do not introduce system colors diff --git a/README.md b/README.md index 861b01c..ef1eb53 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build](https://github.com/umage-ai/CodeShellManager/actions/workflows/build.yml/badge.svg)](https://github.com/umage-ai/CodeShellManager/actions/workflows/build.yml) [![Latest Release](https://img.shields.io/github/v/release/umage-ai/CodeShellManager?label=download&cacheSeconds=3600)](https://github.com/umage-ai/CodeShellManager/releases/latest) [![winget](https://img.shields.io/winget/v/UmageAI.CodeShellManager?label=winget)](https://winstall.app/apps/UmageAI.CodeShellManager) +[![Chocolatey](https://img.shields.io/chocolatey/v/codeshellmanager?label=chocolatey)](https://community.chocolatey.org/packages/codeshellmanager) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) > **🌐 [umage.ai/products/code-shell-manager](https://umage.ai/products/code-shell-manager/)** — product page, screenshots, and latest news @@ -49,6 +50,14 @@ winget install UmageAI.CodeShellManager Future updates pick up automatically with `winget upgrade UmageAI.CodeShellManager` (or `winget upgrade --all`). +### Chocolatey + +```powershell +choco install codeshellmanager +``` + +Upgrade with `choco upgrade codeshellmanager` (or `choco upgrade all`). + ### Download from Releases 1. Go to [**Releases**](https://github.com/umage-ai/CodeShellManager/releases/latest)