Skip to content

Commit 75d9553

Browse files
committed
chore(release): v0.1.2
- fix(ci): remove dead biome suppressions + non-null assertion to get lint green - feat(packaging): stable artifactName across platforms (-x64/-arm64 suffixes) - feat(release): SHA256SUMS + CycloneDX SBOM attached to each Release - feat(release): best-effort Snap build (isolated job, continue-on-error) - feat(packaging): Homebrew Cask + winget + Flathub manifest templates - feat(release): auto-bump jobs for Homebrew/winget (gated on secrets) - docs(readme): honest per-channel status for v0.1.x install surface - docs(website): SmartDownload reads version from package.json; new asset naming
1 parent f6052f7 commit 75d9553

25 files changed

Lines changed: 408 additions & 70 deletions

File tree

.github/workflows/release.yml

Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
run: pnpm typecheck
6262

6363
- name: Test
64-
run: pnpm -r test
64+
run: pnpm test
6565

6666
# ------------------------------------------------------------------
6767
# Changelog: build release notes from conventional commits.
@@ -175,12 +175,134 @@ jobs:
175175
if-no-files-found: error
176176
retention-days: 7
177177

178+
# ------------------------------------------------------------------
179+
# Snap: best-effort build of a .snap on ubuntu using snapcraft.
180+
# Isolated into its own job because snapcraft is heavyweight and
181+
# occasionally flakes on hosted runners; failure here should NOT
182+
# block the release (publish job does not `needs:` this one).
183+
# ------------------------------------------------------------------
184+
build-snap:
185+
name: Build Linux Snap (best-effort)
186+
needs: [gate]
187+
runs-on: ubuntu-latest
188+
continue-on-error: true
189+
env:
190+
RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }}
191+
steps:
192+
- uses: actions/checkout@v4
193+
with:
194+
ref: ${{ env.RELEASE_REF }}
195+
fetch-depth: 0
196+
197+
- name: Setup pnpm
198+
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
199+
200+
- name: Setup Node
201+
uses: actions/setup-node@v4
202+
with:
203+
node-version-file: .nvmrc
204+
cache: pnpm
205+
206+
- name: Install
207+
run: pnpm install --frozen-lockfile
208+
209+
- name: Install snapcraft + LXD
210+
# snapcraft itself handles most simple electron-builder builds via
211+
# `snap pack`, but recent electron-builder (post core22/core24) will
212+
# fall back to invoking snapcraft which needs LXD for its build
213+
# environment. Setting both up here keeps the step resilient.
214+
run: |
215+
sudo snap install snapcraft --classic
216+
sudo snap install lxd
217+
sudo lxd waitready --timeout=60
218+
sudo lxd init --auto
219+
220+
- name: Build workspace
221+
run: pnpm --filter '!@open-codesign/desktop' -r build
222+
223+
- name: Package snap
224+
working-directory: apps/desktop
225+
env:
226+
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
227+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
228+
run: pnpm exec electron-vite build && pnpm exec electron-builder --linux snap --publish never
229+
230+
- name: Upload snap artifact
231+
uses: actions/upload-artifact@v4
232+
with:
233+
name: installer-snap
234+
path: apps/desktop/release/*.snap
235+
if-no-files-found: warn
236+
retention-days: 7
237+
238+
# ------------------------------------------------------------------
239+
# Supply-chain: checksums + CycloneDX SBOM for the whole workspace.
240+
# Runs on one runner after all platform artifacts are uploaded.
241+
# ------------------------------------------------------------------
242+
provenance:
243+
name: Checksums + SBOM
244+
needs: [build, build-snap]
245+
runs-on: ubuntu-latest
246+
env:
247+
RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }}
248+
steps:
249+
- uses: actions/checkout@v4
250+
with:
251+
ref: ${{ env.RELEASE_REF }}
252+
fetch-depth: 0
253+
254+
- name: Setup pnpm
255+
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
256+
257+
- name: Setup Node
258+
uses: actions/setup-node@v4
259+
with:
260+
node-version-file: .nvmrc
261+
cache: pnpm
262+
263+
- name: Install
264+
run: pnpm install --frozen-lockfile
265+
266+
- name: Download all installers
267+
uses: actions/download-artifact@v4
268+
with:
269+
path: dist/
270+
merge-multiple: true
271+
272+
- name: Generate CycloneDX SBOM (workspace)
273+
uses: anchore/sbom-action@v0
274+
with:
275+
path: .
276+
format: cyclonedx-json
277+
output-file: dist/open-codesign-${{ github.event_name == 'push' && github.ref_name || inputs.tag }}-sbom.cdx.json
278+
279+
- name: Generate SHA256SUMS.txt
280+
working-directory: dist
281+
run: |
282+
shopt -s nullglob
283+
: > SHA256SUMS.txt
284+
for f in *; do
285+
[ -f "$f" ] && [ "$f" != "SHA256SUMS.txt" ] || continue
286+
sha256sum "$f" >> SHA256SUMS.txt
287+
done
288+
cat SHA256SUMS.txt
289+
290+
- name: Upload provenance artifacts
291+
uses: actions/upload-artifact@v4
292+
with:
293+
name: provenance
294+
path: |
295+
dist/SHA256SUMS.txt
296+
dist/open-codesign-*-sbom.cdx.json
297+
if-no-files-found: error
298+
retention-days: 7
299+
178300
# ------------------------------------------------------------------
179301
# Publish: create (or update draft) GitHub Release and attach files.
180302
# ------------------------------------------------------------------
181303
publish:
182304
name: Publish GitHub Release
183-
needs: [build, changelog]
305+
needs: [build, build-snap, changelog, provenance]
184306
runs-on: ubuntu-latest
185307
env:
186308
RELEASE_REF: ${{ github.event_name == 'push' && github.ref || format('refs/tags/{0}', inputs.tag) }}
@@ -221,3 +343,66 @@ jobs:
221343
fail_on_unmatched_files: false
222344
env:
223345
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
346+
347+
# ------------------------------------------------------------------
348+
# Homebrew Cask bump — opens a PR against OpenCoworkAI/homebrew-tap
349+
# with the new version + sha256 of the mac DMGs.
350+
# Skipped until HOMEBREW_TAP_TOKEN is set (see packaging/homebrew/README.md).
351+
# ------------------------------------------------------------------
352+
homebrew:
353+
name: Bump Homebrew Cask
354+
needs: [publish]
355+
runs-on: macos-latest
356+
if: github.event_name == 'push' && !contains(github.ref_name, '-')
357+
steps:
358+
- name: Guard on secret
359+
id: guard
360+
run: |
361+
if [ -z "${{ secrets.HOMEBREW_TAP_TOKEN }}" ]; then
362+
echo "skip=true" >> "$GITHUB_OUTPUT"
363+
echo "::notice::HOMEBREW_TAP_TOKEN not set — skipping Homebrew bump. See packaging/homebrew/README.md."
364+
else
365+
echo "skip=false" >> "$GITHUB_OUTPUT"
366+
fi
367+
368+
- name: Bump cask
369+
if: steps.guard.outputs.skip == 'false'
370+
# TODO: pin to commit SHA when flipping HOMEBREW_TAP_TOKEN on (Scorecard).
371+
uses: macauley/action-homebrew-bump-cask@v1
372+
with:
373+
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
374+
tap: OpenCoworkAI/homebrew-tap
375+
cask: open-codesign
376+
tag: ${{ github.ref_name }}
377+
force: false
378+
379+
# ------------------------------------------------------------------
380+
# winget manifest PR — submits to microsoft/winget-pkgs.
381+
# Skipped until WINGET_PAT is set (see packaging/winget/).
382+
# Requires initial manual submission of the manifest first.
383+
# ------------------------------------------------------------------
384+
winget:
385+
name: Submit winget manifest
386+
needs: [publish]
387+
runs-on: windows-latest
388+
if: github.event_name == 'push' && !contains(github.ref_name, '-')
389+
steps:
390+
- name: Guard on secret
391+
id: guard
392+
shell: bash
393+
run: |
394+
if [ -z "${{ secrets.WINGET_PAT }}" ]; then
395+
echo "skip=true" >> "$GITHUB_OUTPUT"
396+
echo "::notice::WINGET_PAT not set — skipping winget submission. See packaging/winget/."
397+
else
398+
echo "skip=false" >> "$GITHUB_OUTPUT"
399+
fi
400+
401+
- name: Release winget package
402+
if: steps.guard.outputs.skip == 'false'
403+
# TODO: pin to commit SHA when flipping WINGET_PAT on (Scorecard).
404+
uses: vedantmgoyal9/winget-releaser@v2
405+
with:
406+
identifier: OpenCoworkAI.OpenCoDesign
407+
installers-regex: '-x64-setup\.exe$|-arm64-setup\.exe$'
408+
token: ${{ secrets.WINGET_PAT }}

README.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,29 +99,30 @@ Your providers, models, and API keys import in one click — no copy-paste, no r
9999

100100
### 1. Install
101101

102-
**Package managers** (recommended):
102+
**Direct download** (v0.1.x) from [GitHub Releases](https://github.com/OpenCoworkAI/open-codesign/releases):
103103

104-
```sh
105-
# macOS — Homebrew
106-
brew tap OpenCoworkAI/tap
107-
brew install --cask open-codesign
104+
| Platform | File |
105+
|---|---|
106+
| macOS (Apple Silicon) | `open-codesign-*-arm64.dmg` |
107+
| macOS (Intel) | `open-codesign-*-x64.dmg` |
108+
| Windows (x64) | `open-codesign-*-x64-setup.exe` |
109+
| Windows (ARM64) | `open-codesign-*-arm64-setup.exe` |
110+
| Linux (x64) | `open-codesign-*-x64.AppImage` |
108111

109-
# Windows — winget
110-
winget install OpenCoworkAI.open-codesign
112+
Each release ships with `SHA256SUMS.txt` and a CycloneDX SBOM (`*-sbom.cdx.json`) so you can verify what you downloaded.
111113

112-
# Windows — Scoop
113-
scoop bucket add opencowork https://github.com/OpenCoworkAI/scoop-bucket
114-
scoop install opencowork/open-codesign
115-
```
114+
<details>
115+
<summary><b>Package managers</b> — status for v0.1.x</summary>
116116

117-
**Direct download** from [GitHub Releases](https://github.com/OpenCoworkAI/open-codesign/releases):
117+
| Manager | Command | Status |
118+
|---|---|---|
119+
| Homebrew Cask (macOS) | `brew install --cask opencoworkai/tap/open-codesign` | 🟡 Tap pending — manifest in [`packaging/homebrew/`](./packaging/homebrew/) |
120+
| winget (Windows) | `winget install OpenCoworkAI.OpenCoDesign` | 🟡 First submission pending — manifest in [`packaging/winget/`](./packaging/winget/) |
121+
| Flathub (Linux) | `flatpak install flathub ai.opencowork.codesign` | 🟡 Submission pending — manifest in [`packaging/flatpak/`](./packaging/flatpak/) |
122+
| Snap (Linux) | `snap install --dangerous open-codesign-*.snap` | 🟡 Attached to releases best-effort; Snap Store publish not yet wired |
118123

119-
| Platform | File |
120-
|---|---|
121-
| macOS (Apple Silicon) | `open-codesign-*-arm64.dmg` |
122-
| macOS (Intel) | `open-codesign-*.dmg` |
123-
| Windows (x64 / arm64) | `open-codesign-*-setup.exe` |
124-
| Linux | `open-codesign-*.AppImage` |
124+
Each release-time PR is auto-opened by CI once the corresponding tap/manifest/secret is provisioned — see each `packaging/*/README.md` for setup.
125+
</details>
125126

126127
> **v0.1 note:** installers are unsigned. macOS: right-click → Open, or run `xattr -d com.apple.quarantine /Applications/open-codesign.app` after install. Windows: SmartScreen → More info → Run anyway.
127128
> Want a verified build? Compile from source — see [CONTRIBUTING.md](./CONTRIBUTING.md).

README.zh-CN.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,29 +99,30 @@ Open CoDesign 把自然语言提示词变成精美的 HTML 原型、幻灯片或
9999

100100
### 1. 安装
101101

102-
**包管理器**推荐)
102+
**直接下载**v0.1.x)从 [GitHub Releases](https://github.com/OpenCoworkAI/open-codesign/releases)
103103

104-
```sh
105-
# macOS — Homebrew
106-
brew tap OpenCoworkAI/tap
107-
brew install --cask open-codesign
104+
| 平台 | 文件 |
105+
|---|---|
106+
| macOS(Apple Silicon)| `open-codesign-*-arm64.dmg` |
107+
| macOS(Intel)| `open-codesign-*-x64.dmg` |
108+
| Windows(x64)| `open-codesign-*-x64-setup.exe` |
109+
| Windows(ARM64)| `open-codesign-*-arm64-setup.exe` |
110+
| Linux(x64)| `open-codesign-*-x64.AppImage` |
108111

109-
# Windows — winget
110-
winget install OpenCoworkAI.open-codesign
112+
每个 release 附带 `SHA256SUMS.txt` 和 CycloneDX SBOM(`*-sbom.cdx.json`),可用于校验下载完整性。
111113

112-
# Windows — Scoop
113-
scoop bucket add opencowork https://github.com/OpenCoworkAI/scoop-bucket
114-
scoop install opencowork/open-codesign
115-
```
114+
<details>
115+
<summary><b>包管理器</b>——v0.1.x 状态</summary>
116116

117-
**直接下载**[GitHub Releases](https://github.com/OpenCoworkAI/open-codesign/releases)
117+
| 管理器 | 命令 | 状态 |
118+
|---|---|---|
119+
| Homebrew Cask(macOS)| `brew install --cask opencoworkai/tap/open-codesign` | 🟡 Tap 待建 —— 模板见 [`packaging/homebrew/`](./packaging/homebrew/) |
120+
| winget(Windows)| `winget install OpenCoworkAI.OpenCoDesign` | 🟡 首次提交待处理 —— 模板见 [`packaging/winget/`](./packaging/winget/) |
121+
| Flathub(Linux)| `flatpak install flathub ai.opencowork.codesign` | 🟡 Flathub 提交待处理 —— 模板见 [`packaging/flatpak/`](./packaging/flatpak/) |
122+
| Snap(Linux)| `snap install --dangerous open-codesign-*.snap` | 🟡 每次 release 尽力附带;尚未推到 Snap Store |
118123

119-
| 平台 | 文件 |
120-
|---|---|
121-
| macOS(Apple Silicon)| `open-codesign-*-arm64.dmg` |
122-
| macOS(Intel)| `open-codesign-*.dmg` |
123-
| Windows(x64 / arm64)| `open-codesign-*-setup.exe` |
124-
| Linux | `open-codesign-*.AppImage` |
124+
一旦配好对应的 tap / manifest / secret,CI 会在每次发版时自动开 PR —— 具体步骤见 `packaging/*/README.md`
125+
</details>
125126

126127
> **v0.1 说明:** 安装包暂未签名。macOS:右键 → 打开,或安装后在终端执行 `xattr -d com.apple.quarantine /Applications/open-codesign.app`。Windows:SmartScreen → 更多信息 → 仍要运行。
127128
> 需要已验证的构建?请从源码自行编译,参见 [CONTRIBUTING.md](./CONTRIBUTING.md)

apps/desktop/electron-builder.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ mac:
2222
hardenedRuntime: true
2323
gatekeeperAssess: false
2424
notarize: false
25+
artifactName: ${productName}-${version}-${arch}.${ext}
2526
target:
2627
- target: dmg
2728
arch: [arm64, x64]
@@ -47,6 +48,7 @@ dmg:
4748
path: /Applications
4849
win:
4950
icon: resources/icon.ico
51+
artifactName: ${productName}-${version}-${arch}-setup.${ext}
5052
target:
5153
- target: nsis
5254
arch: [x64, arm64]
@@ -55,7 +57,21 @@ nsis:
5557
allowToChangeInstallationDirectory: true
5658
linux:
5759
icon: resources/icon.png
60+
# Hardcode `x64` (not ${arch}) because electron-builder substitutes ${arch}
61+
# differently per Linux target convention (AppImage → x86_64, deb → amd64,
62+
# rpm → x86_64). SmartDownload.vue + Homebrew cask + Flatpak manifest all
63+
# reference `-x64.ext`; picking a fixed literal keeps them in sync. We
64+
# only ship one Linux arch, so this is safe until we add arm64.
65+
artifactName: ${productName}-${version}-x64.${ext}
5866
target:
5967
- target: AppImage
6068
arch: [x64]
69+
# Snap is built in a separate, best-effort CI step (see
70+
# .github/workflows/release.yml) because snapcraft on ubuntu-latest
71+
# is heavyweight and occasionally flakes. The target config below is
72+
# used when that step invokes `electron-builder --linux snap`.
6173
category: Graphics
74+
snap:
75+
grade: stable
76+
confinement: strict
77+
summary: Prompt → polished HTML prototypes, slide decks, and marketing assets.

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@open-codesign/desktop",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"private": true,
55
"type": "module",
66
"main": "./out/main/index.js",

apps/desktop/src/renderer/src/components/ModelSwitcher.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,13 @@ export function ModelSwitcher({ variant }: ModelSwitcherProps) {
6969
const providerLabel = activeProviderRow?.label ?? provider;
7070

7171
async function switchModel(model: string) {
72-
if (!window.codesign || model === currentModel) {
72+
if (!window.codesign || !provider || model === currentModel) {
7373
setOpen(false);
7474
return;
7575
}
7676
try {
7777
const next = await window.codesign.settings.setActiveProvider({
78-
provider: provider!,
78+
provider,
7979
modelPrimary: model,
8080
});
8181
setConfig(next);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-codesign",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"private": true,
55
"description": "Open-source AI design tool — prompt to interactive prototype, slide deck, and marketing assets. Multi-model, BYOK, runs on your laptop.",
66
"license": "Apache-2.0",

packages/artifacts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@open-codesign/artifacts",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"private": true,
55
"type": "module",
66
"main": "./src/index.ts",

packages/artifacts/src/parser.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ export function createArtifactParser() {
176176
* must hold back from `start` and wait for more input
177177
* - `none`: no candidate; caller may flush the entire buffer as text
178178
*/
179-
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: quote-aware tag scanning is inherently branchy; splitting hurts clarity
180179
function findOpenTag(buffer: string): OpenTagMatch {
181180
let from = 0;
182181
while (from <= buffer.length) {

0 commit comments

Comments
 (0)