Fix winget packaging

paydii committed Aug 31, 2026 at 18:02 UTC 2e1ee71ce454dca248e338b3ec625bee2f5c4217
5 files changed +182 -15
.agents/AGENTS.md
+6 -2
@@ -283,8 +283,12 @@ Three of these need credentials or a one-time manual step before they work:
283 - Scoop needs a `getsigit/scoop-bucket` repo and a `SCOOP_BUCKET_TOKEN` secret, mirroring the
284 Homebrew tap setup.
285 - winget needs a `WINGET_TOKEN` (PAT with `public_repo`) so `wingetcreate` can fork
286 - `microsoft/winget-pkgs`. The workflow only handles *updates*; the first submission has to be made
287 - by hand with `wingetcreate new`, since a package must exist before it can be updated.
286 + `microsoft/winget-pkgs`. It is passed as `WINGET_CREATE_GITHUB_TOKEN` rather than `--token`,
287 + which wingetcreate warns can leak the token into logs. `wingetcreate update` only works on a
288 + package that already exists in `microsoft/winget-pkgs`, so the workflow checks the
289 + `manifests/g/getSigit/siGitCode` path first and falls back to rendering
290 + `packaging/winget/*.yaml.in` and running `wingetcreate submit` for a first submission. That
291 + fallback runs once, then every later release takes the `update` path.
292 - The AUR needs `AUR_USERNAME`, `AUR_EMAIL`, and `AUR_SSH_PRIVATE_KEY`. It publishes `sigit-bin`
293 (a prebuilt binary) so Arch users are not compiling the on-device inference stack to install a
294 CLI.
.github/workflows/release-winget.yml
+112 -13
@@ -2,14 +2,17 @@ name: winget Release
2
3 # Dispatched by release-github.yml once the release and its checksums exist.
4 #
5 -# This workflow only handles *updates*. winget manifests live in
6 -# microsoft/winget-pkgs, and a package has to exist there before it can be
7 -# updated, so the very first submission is a one-time manual step:
5 +# winget manifests live in microsoft/winget-pkgs, and `wingetcreate update`
6 +# only works on a package that is already there. So this workflow branches:
7 #
9 -# wingetcreate new https://github.com/getsigit/sigit/releases/download/vX.Y.Z/sigit-win-amd64.exe
8 +# - package already in winget-pkgs -> `wingetcreate update`, which rewrites
9 +# the URLs and re-hashes the installers for us.
10 +# - package not there yet -> render the manifests in packaging/winget/ and
11 +# `wingetcreate submit` them as a new package.
12 #
11 -# answering `portable` for the installer type and `smbCloud.siGitCode` for the
12 -# package identifier. Every release after that is automated here.
13 +# The second path only runs once, but keeping it here means a first release
14 +# does not need someone to sit at a Windows box running `wingetcreate new`
15 +# interactively.
16 on:
17 workflow_dispatch:
18 inputs:
@@ -22,7 +25,7 @@ permissions:
25
26 env:
27 REPO: getsigit/sigit
25 - PACKAGE_IDENTIFIER: smbCloud.siGitCode
28 + PACKAGE_IDENTIFIER: getSigit.siGitCode
29
30 jobs:
31 submit-winget-manifest:
@@ -31,22 +34,118 @@ jobs:
34 runs-on: windows-latest
35
36 steps:
34 - - name: Resolve tag and version
37 + - name: Check out repository
38 + uses: actions/checkout@v6
39 +
40 + - name: Resolve tag, version and release date
41 id: release
42 shell: bash
43 + env:
44 + GH_TOKEN: ${{ github.token }}
45 run: |
46 TAG="${{ github.event.inputs.tag }}"
47 VERSION="${TAG#v}"
48 + # wingetcreate wants ReleaseDate as YYYY-MM-DD.
49 + DATE=$(gh release view "$TAG" --repo "$REPO" --json publishedAt --jq '.publishedAt[0:10]')
50
51 echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
52 echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
53 + echo "date=${DATE}" >> "$GITHUB_OUTPUT"
54 +
55 + - name: Check whether the package is already in winget-pkgs
56 + id: exists
57 + shell: bash
58 + env:
59 + GH_TOKEN: ${{ github.token }}
60 + run: |
61 + # manifests are filed under the lowercased first letter of the
62 + # publisher, e.g. manifests/g/getSigit/siGitCode.
63 + PUBLISHER="${PACKAGE_IDENTIFIER%%.*}"
64 + NAME="${PACKAGE_IDENTIFIER#*.}"
65 + FIRST=$(echo "${PUBLISHER:0:1}" | tr '[:upper:]' '[:lower:]')
66 + PATH_IN_REPO="manifests/${FIRST}/${PUBLISHER}/${NAME}"
67 +
68 + if gh api "repos/microsoft/winget-pkgs/contents/${PATH_IN_REPO}" >/dev/null 2>&1; then
69 + echo "Found ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting an update."
70 + echo "found=true" >> "$GITHUB_OUTPUT"
71 + else
72 + echo "No ${PACKAGE_IDENTIFIER} at ${PATH_IN_REPO}; submitting it as a new package."
73 + echo "found=false" >> "$GITHUB_OUTPUT"
74 + fi
75 +
76 + - name: Render manifests for a first submission
77 + if: steps.exists.outputs.found == 'false'
78 + shell: bash
79 + env:
80 + GH_TOKEN: ${{ github.token }}
81 + run: |
82 + TAG="${{ steps.release.outputs.tag }}"
83 + VERSION="${{ steps.release.outputs.version }}"
84 +
85 + mkdir -p artifacts manifests
86 +
87 + gh release download "$TAG" \
88 + --repo "$REPO" \
89 + --pattern "sigit-win-*.exe.sha256" \
90 + --dir artifacts/
91 +
92 + # The schema wants 64 hex characters; the community validation
93 + # pipeline writes them uppercase, so match that.
94 + SHA_AMD64=$(tr -d '[:space:]' < artifacts/sigit-win-amd64.exe.sha256 | tr '[:lower:]' '[:upper:]')
95 + SHA_ARM64=$(tr -d '[:space:]' < artifacts/sigit-win-arm64.exe.sha256 | tr '[:lower:]' '[:upper:]')
96 +
97 + RELEASE_DATE="${{ steps.release.outputs.date }}"
98 +
99 + for template in packaging/winget/*.yaml.in; do
100 + out="manifests/$(basename "$template" .in)"
101 + sed \
102 + -e "s|@VERSION@|${VERSION}|g" \
103 + -e "s|@TAG@|${TAG}|g" \
104 + -e "s|@REPO@|${REPO}|g" \
105 + -e "s|@SHA_AMD64@|${SHA_AMD64}|g" \
106 + -e "s|@SHA_ARM64@|${SHA_ARM64}|g" \
107 + -e "s|@RELEASE_DATE@|${RELEASE_DATE}|g" \
108 + "$template" > "$out"
109 +
110 + echo "--- ${out} ---"
111 + cat "$out"
112 + done
113 +
114 + - name: Download wingetcreate
115 + shell: pwsh
116 + run: Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
117 +
118 + - name: Submit new package
119 + if: steps.exists.outputs.found == 'false'
120 + shell: pwsh
121 + env:
122 + # wingetcreate reads the token from this variable. Passing it as
123 + # --token instead makes the tool warn that the token can end up in
124 + # logs, which on a shared runner is not a warning worth ignoring.
125 + WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
126 + run: |
127 + if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
128 + Write-Error "WINGET_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
129 + }
130 +
131 + $version = "${{ steps.release.outputs.version }}"
132 +
133 + # --no-open because the runner has no browser to open the PR in.
134 + .\wingetcreate.exe submit manifests `
135 + --prtitle "New package: $env:PACKAGE_IDENTIFIER version $version" `
136 + --no-open
137 +
138 + if ($LASTEXITCODE -ne 0) {
139 + Write-Error "wingetcreate submit failed with exit code $LASTEXITCODE"
140 + }
141
142 - name: Submit manifest update
143 + if: steps.exists.outputs.found == 'true'
144 shell: pwsh
145 env:
47 - WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
146 + WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }}
147 run: |
49 - if (-not $env:WINGET_TOKEN) {
148 + if (-not $env:WINGET_CREATE_GITHUB_TOKEN) {
149 Write-Error "WINGET_TOKEN is not set. It needs a PAT with public_repo scope so wingetcreate can fork microsoft/winget-pkgs and open the manifest PR."
150 }
151
@@ -54,8 +153,6 @@ jobs:
153 $version = "${{ steps.release.outputs.version }}"
154 $base = "https://github.com/${env:REPO}/releases/download/$tag"
155
57 - Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe
58 -
156 # The trailing |x64 and |arm64 tell wingetcreate which installer
157 # entry each URL replaces. Without them it guesses from the file
158 # name, and "sigit-win-amd64.exe" is not a spelling it recognises.
@@ -63,8 +160,10 @@ jobs:
160 --version $version `
161 --urls "$base/sigit-win-amd64.exe|x64" "$base/sigit-win-arm64.exe|arm64" `
162 --release-notes-url "https://github.com/${env:REPO}/releases/tag/$tag" `
163 + --release-date "${{ steps.release.outputs.date }}" `
164 + --prtitle "Update $env:PACKAGE_IDENTIFIER to version $version" `
165 --submit `
67 - --token $env:WINGET_TOKEN
166 + --no-open
167
168 if ($LASTEXITCODE -ne 0) {
169 Write-Error "wingetcreate failed with exit code $LASTEXITCODE"
packaging/winget/getSigit.siGitCode.installer.yaml.in new
+18
@@ -0,0 +1,18 @@
1 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json
2 +PackageIdentifier: getSigit.siGitCode
3 +PackageVersion: @VERSION@
4 +InstallerType: portable
5 +# `Commands` is what winget names the shim it drops on PATH. The release
6 +# assets are sigit-win-<arch>.exe, but the command has to be `sigit`.
7 +Commands:
8 + - sigit
9 +ReleaseDate: "@RELEASE_DATE@"
10 +Installers:
11 + - Architecture: x64
12 + InstallerUrl: https://github.com/@REPO@/releases/download/@TAG@/sigit-win-amd64.exe
13 + InstallerSha256: @SHA_AMD64@
14 + - Architecture: arm64
15 + InstallerUrl: https://github.com/@REPO@/releases/download/@TAG@/sigit-win-arm64.exe
16 + InstallerSha256: @SHA_ARM64@
17 +ManifestType: installer
18 +ManifestVersion: 1.6.0
packaging/winget/getSigit.siGitCode.locale.en-US.yaml.in new
+40
@@ -0,0 +1,40 @@
1 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json
2 +PackageIdentifier: getSigit.siGitCode
3 +PackageVersion: @VERSION@
4 +PackageLocale: en-US
5 +Publisher: getSigit
6 +PublisherUrl: https://sigit.si/
7 +PublisherSupportUrl: https://github.com/@REPO@/issues
8 +PackageName: siGit Code
9 +PackageUrl: https://code.sigit.si
10 +License: Apache-2.0
11 +LicenseUrl: https://github.com/@REPO@/blob/main/LICENSE
12 +Copyright: Copyright 2026 PT Sigit Mitra Bangun
13 +ShortDescription: siGit Code, an AI coding agent that runs on your machine.
14 +Description: |-
15 + siGit Code is a local coding agent. It runs on your machine, not someone
16 + else's. No API keys, no cloud round-trips, no subscription.
17 +
18 + It works two ways from the same binary. Zed and other ACP-compatible
19 + editors start it over stdio and talk the Agent Client Protocol to it. Run
20 + it from a terminal and you get an interactive chat UI instead. On Windows
21 + it speaks ACP; the full-screen terminal UI is Unix-only.
22 +
23 + Inference runs on-device against a GGUF model, or against siGit Code Cloud
24 + or any OpenAI-compatible endpoint you point it at.
25 +Moniker: sigit
26 +Tags:
27 + - acp
28 + - agent
29 + - ai
30 + - cli
31 + - coding-agent
32 + - developer-tools
33 + - llm
34 + - terminal
35 +ReleaseNotesUrl: https://github.com/@REPO@/releases/tag/@TAG@
36 +Documentations:
37 + - DocumentLabel: Readme
38 + DocumentUrl: https://github.com/@REPO@/blob/main/README.md
39 +ManifestType: defaultLocale
40 +ManifestVersion: 1.6.0
packaging/winget/getSigit.siGitCode.yaml.in new
+6
@@ -0,0 +1,6 @@
1 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json
2 +PackageIdentifier: getSigit.siGitCode
3 +PackageVersion: @VERSION@
4 +DefaultLocale: en-US
5 +ManifestType: version
6 +ManifestVersion: 1.6.0