Skip to content

Commit d4cf8d6

Browse files
AThraenclaude
andauthored
feat(release): publish to Chocolatey on release (#49)
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 <noreply@anthropic.com>
1 parent ed37e64 commit d4cf8d6

8 files changed

Lines changed: 273 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
3+
<metadata>
4+
<id>codeshellmanager</id>
5+
<version>__VERSION__</version>
6+
<packageSourceUrl>https://github.com/umage-ai/CodeShellManager/tree/main/.chocolatey</packageSourceUrl>
7+
<owners>umage.ai</owners>
8+
<title>CodeShellManager</title>
9+
<authors>umage.ai</authors>
10+
<projectUrl>https://umage.ai/products/code-shell-manager/</projectUrl>
11+
<iconUrl>https://raw.githubusercontent.com/umage-ai/CodeShellManager/main/src/CodeShellManager/Assets/app.ico</iconUrl>
12+
<copyright>Copyright (c) 2025 umage.ai</copyright>
13+
<licenseUrl>https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE</licenseUrl>
14+
<requireLicenseAcceptance>false</requireLicenseAcceptance>
15+
<projectSourceUrl>https://github.com/umage-ai/CodeShellManager</projectSourceUrl>
16+
<docsUrl>https://github.com/umage-ai/CodeShellManager#readme</docsUrl>
17+
<bugTrackerUrl>https://github.com/umage-ai/CodeShellManager/issues</bugTrackerUrl>
18+
<tags>codeshellmanager terminal claude claude-code wpf conpty xterm ai coding-agent admin</tags>
19+
<summary>Multi-terminal host for Claude Code and other CLI coding agents on Windows.</summary>
20+
<description><![CDATA[
21+
**CodeShellManager** is a Windows desktop app for running multiple AI coding agents side-by-side — Claude Code, Codex, GitHub Copilot, or any CLI tool — in a tabbed and grid-layout terminal host. Built with WPF, xterm.js, and Windows ConPTY for full pseudo-terminal fidelity.
22+
23+
## Features
24+
25+
* Multi-terminal grid — up to 18 sessions simultaneously in configurable layouts
26+
* Sleep & wake — park sessions without losing them
27+
* Full-text search across every session, ever (SQLite FTS5)
28+
* Per-project notepad, alert detection, git status, session rename, auto-resume
29+
* SSH remote sessions, session history, configurable launch commands
30+
* Tray icon with balloon notifications
31+
32+
## Requirements
33+
34+
* Windows 10 (1903+) or Windows 11
35+
* [Microsoft Edge WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) (pre-installed on Windows 11)
36+
]]></description>
37+
<releaseNotes>https://github.com/umage-ai/CodeShellManager/releases/tag/v__VERSION__</releaseNotes>
38+
</metadata>
39+
<files>
40+
<file src="tools\**" target="tools" />
41+
</files>
42+
</package>

.chocolatey/tools/LICENSE.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
From: https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE
2+
3+
MIT License
4+
5+
Copyright (c) 2025 umage.ai
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.

.chocolatey/tools/VERIFICATION.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
VERIFICATION
2+
3+
Verification is intended to assist Chocolatey moderators and end-users in
4+
verifying that this package's contents are authentic.
5+
6+
This Chocolatey package downloads the official signed MSI installer from the
7+
matching CodeShellManager GitHub Release:
8+
9+
https://github.com/umage-ai/CodeShellManager/releases
10+
11+
The MSI is built and signed by GitHub Actions from the source in
12+
https://github.com/umage-ai/CodeShellManager (see .github/workflows/build.yml)
13+
using Azure Trusted Signing — publisher: umage.ai.
14+
15+
To verify the package independently:
16+
17+
1. Note the embedded download URL and SHA256 checksum in
18+
tools\chocolateyinstall.ps1 (variables $url64 and $checksum64).
19+
20+
2. Download the same MSI directly from the GitHub Release page above.
21+
22+
3. On Windows, compute the SHA256 of the downloaded file:
23+
24+
Get-FileHash -Algorithm SHA256 .\CodeShellManager-<version>-Setup.msi
25+
26+
The output should match the $checksum64 value in chocolateyinstall.ps1.
27+
28+
4. Optionally inspect the Authenticode signature on the MSI — it should be
29+
issued to "umage.ai" via Microsoft's Azure Trusted Signing service.
30+
31+
The bundled LICENSE.txt is a verbatim copy of the project license, also
32+
available at:
33+
34+
https://github.com/umage-ai/CodeShellManager/blob/main/LICENSE
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
$ErrorActionPreference = 'Stop'
2+
3+
$packageName = 'codeshellmanager'
4+
$toolsDir = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
5+
6+
# These placeholders are replaced by .github/workflows/chocolatey.yml at pack time
7+
# with the version-pinned MSI URL and its SHA256 from the GitHub Release.
8+
$url64 = '__URL64__'
9+
$checksum64 = '__CHECKSUM64__'
10+
11+
$packageArgs = @{
12+
packageName = $packageName
13+
unzipLocation = $toolsDir
14+
fileType = 'msi'
15+
url64bit = $url64
16+
softwareName = 'CodeShellManager*'
17+
checksum64 = $checksum64
18+
checksumType64 = 'sha256'
19+
silentArgs = '/qn /norestart /l*v "$($env:TEMP)\$($packageName).$($env:chocolateyPackageVersion).MsiInstall.log"'
20+
validExitCodes = @(0, 3010, 1641)
21+
}
22+
23+
Install-ChocolateyPackage @packageArgs
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
$ErrorActionPreference = 'Stop'
2+
3+
$packageName = 'codeshellmanager'
4+
$softwareName = 'CodeShellManager*'
5+
6+
# Discover the install record (MSI product code) registered for the
7+
# installed CodeShellManager and uninstall via msiexec.
8+
$key = Get-UninstallRegistryKey -SoftwareName $softwareName
9+
10+
if ($key.Count -eq 1) {
11+
$packageArgs = @{
12+
packageName = $packageName
13+
fileType = 'msi'
14+
silentArgs = "$($key.PSChildName) /qn /norestart"
15+
validExitCodes = @(0, 3010, 1605, 1614, 1641)
16+
file = ''
17+
}
18+
Uninstall-ChocolateyPackage @packageArgs
19+
}
20+
elseif ($key.Count -eq 0) {
21+
Write-Warning "$packageName has already been uninstalled by other means."
22+
}
23+
elseif ($key.Count -gt 1) {
24+
Write-Warning "$($key.Count) matches found!"
25+
Write-Warning "To prevent accidental data loss, no programs will be uninstalled."
26+
Write-Warning "Please alert package maintainer the following keys were matched:"
27+
$key | ForEach-Object { Write-Warning "- $($_.DisplayName)" }
28+
}

.github/workflows/chocolatey.yml

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
name: Publish to Chocolatey
2+
3+
# Packs and pushes a Chocolatey package wrapping the signed MSI from a GitHub Release
4+
# to community.chocolatey.org.
5+
# - `release` event fires automatically when CI / Release publishes the GitHub Release.
6+
# - `workflow_dispatch` lets us re-publish a past version (used for the first
7+
# submission once this workflow exists on main).
8+
#
9+
# Requires repo secret CHOCO_API_KEY (from https://community.chocolatey.org/account)
10+
# scoped to push for package id `codeshellmanager`.
11+
12+
on:
13+
release:
14+
types: [released]
15+
workflow_dispatch:
16+
inputs:
17+
tag:
18+
description: 'Release tag to publish (e.g. v0.5.0)'
19+
required: true
20+
type: string
21+
22+
permissions:
23+
contents: read
24+
25+
jobs:
26+
publish:
27+
runs-on: windows-latest
28+
steps:
29+
- uses: actions/checkout@v6
30+
31+
- name: Resolve tag and version
32+
id: ver
33+
shell: pwsh
34+
run: |
35+
$tag = '${{ inputs.tag }}'
36+
if (-not $tag) { $tag = '${{ github.event.release.tag_name }}' }
37+
if (-not $tag) { Write-Error 'No release tag resolved.'; exit 1 }
38+
$version = $tag.TrimStart('v')
39+
"tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
40+
"version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
41+
Write-Host "Publishing tag=$tag version=$version"
42+
43+
- name: Download signed MSI from GitHub Release
44+
shell: pwsh
45+
env:
46+
GH_TOKEN: ${{ github.token }}
47+
run: |
48+
$tag = '${{ steps.ver.outputs.tag }}'
49+
$version = '${{ steps.ver.outputs.version }}'
50+
$msiName = "CodeShellManager-$version-Setup.msi"
51+
New-Item -ItemType Directory -Force -Path artifact | Out-Null
52+
gh release download $tag --repo umage-ai/CodeShellManager --pattern $msiName --dir artifact
53+
if (-not (Test-Path "artifact\$msiName")) {
54+
Write-Error "MSI $msiName not found in release $tag."
55+
exit 1
56+
}
57+
Write-Host "Downloaded artifact\$msiName"
58+
59+
- name: Template version, URL, and checksum into package
60+
shell: pwsh
61+
run: |
62+
$version = '${{ steps.ver.outputs.version }}'
63+
$msiName = "CodeShellManager-$version-Setup.msi"
64+
$url64 = "https://github.com/umage-ai/CodeShellManager/releases/download/v$version/$msiName"
65+
$sha256 = (Get-FileHash "artifact\$msiName" -Algorithm SHA256).Hash.ToLowerInvariant()
66+
Write-Host "URL: $url64"
67+
Write-Host "SHA256: $sha256"
68+
69+
$installPs1 = '.chocolatey/tools/chocolateyinstall.ps1'
70+
(Get-Content $installPs1 -Raw).
71+
Replace('__URL64__', $url64).
72+
Replace('__CHECKSUM64__', $sha256) |
73+
Set-Content -Path $installPs1 -NoNewline
74+
75+
$nuspec = '.chocolatey/codeshellmanager.nuspec'
76+
(Get-Content $nuspec -Raw).
77+
Replace('__VERSION__', $version) |
78+
Set-Content -Path $nuspec -NoNewline
79+
80+
Write-Host '--- chocolateyinstall.ps1 ---'
81+
Get-Content $installPs1
82+
Write-Host '--- codeshellmanager.nuspec ---'
83+
Get-Content $nuspec
84+
85+
- name: choco pack
86+
shell: pwsh
87+
run: |
88+
choco pack .chocolatey/codeshellmanager.nuspec --out artifact
89+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
90+
Get-ChildItem artifact\*.nupkg
91+
92+
- name: choco push
93+
shell: pwsh
94+
env:
95+
CHOCO_API_KEY: ${{ secrets.CHOCO_API_KEY }}
96+
run: |
97+
$version = '${{ steps.ver.outputs.version }}'
98+
$nupkg = "artifact/codeshellmanager.$version.nupkg"
99+
if (-not (Test-Path $nupkg)) {
100+
Write-Error "Expected nupkg not found: $nupkg"
101+
exit 1
102+
}
103+
choco push $nupkg --source https://push.chocolatey.org/ --api-key $env:CHOCO_API_KEY
104+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
105+
106+
- name: Upload built nupkg as workflow artifact
107+
if: always()
108+
uses: actions/upload-artifact@v4
109+
with:
110+
name: codeshellmanager-chocolatey-${{ steps.ver.outputs.version }}
111+
path: artifact/*.nupkg
112+
if-no-files-found: warn

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ The tag value overrides the csproj `<Version>` at publish time (`-p:Version=` fl
263263

264264
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.
265265

266+
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.
267+
266268
## Known Conventions
267269

268270
- All WPF color literals use Catppuccin Mocha hex values — do not introduce system colors

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[![Build](https://github.com/umage-ai/CodeShellManager/actions/workflows/build.yml/badge.svg)](https://github.com/umage-ai/CodeShellManager/actions/workflows/build.yml)
44
[![Latest Release](https://img.shields.io/github/v/release/umage-ai/CodeShellManager?label=download&cacheSeconds=3600)](https://github.com/umage-ai/CodeShellManager/releases/latest)
55
[![winget](https://img.shields.io/winget/v/UmageAI.CodeShellManager?label=winget)](https://winstall.app/apps/UmageAI.CodeShellManager)
6+
[![Chocolatey](https://img.shields.io/chocolatey/v/codeshellmanager?label=chocolatey)](https://community.chocolatey.org/packages/codeshellmanager)
67
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
78

89
> **🌐 [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
4950

5051
Future updates pick up automatically with `winget upgrade UmageAI.CodeShellManager` (or `winget upgrade --all`).
5152

53+
### Chocolatey
54+
55+
```powershell
56+
choco install codeshellmanager
57+
```
58+
59+
Upgrade with `choco upgrade codeshellmanager` (or `choco upgrade all`).
60+
5261
### Download from Releases
5362

5463
1. Go to [**Releases**](https://github.com/umage-ai/CodeShellManager/releases/latest)

0 commit comments

Comments
 (0)