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