diff --git a/.github/RELEASE_CHECKLIST.md b/.github/RELEASE_CHECKLIST.md index 1fe08b216..f7fba6713 100644 --- a/.github/RELEASE_CHECKLIST.md +++ b/.github/RELEASE_CHECKLIST.md @@ -32,6 +32,10 @@ Create or update the GitHub Release body before publishing the release. Use Engl - [macOS Intel](https://github.com/Astro-Han/pawwork/releases/download/vX.Y.Z/pawwork-mac-x64.dmg) - [Windows](https://github.com/Astro-Han/pawwork/releases/download/vX.Y.Z/pawwork-win-x64.exe) +## App Update Notice + +- Short product-facing sentence for the in-app post-update modal. Do not include download links, PR numbers, verification details, or maintenance-only notes. + ## Highlights - User-facing changes, bug fixes, or packaging fixes. diff --git a/bun.lock b/bun.lock index 94b7af5a3..486c07c10 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "0.2.5", + "version": "0.2.6", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -80,7 +80,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "0.2.5", + "version": "0.2.6", "dependencies": { "@opencode-ai/util": "workspace:*", "effect": "catalog:", @@ -141,7 +141,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "0.2.5", + "version": "0.2.6", "bin": { "opencode": "./bin/opencode", }, @@ -384,7 +384,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "0.2.5", + "version": "0.2.6", "dependencies": { "@opencode-ai/shared": "workspace:*", "zod": "catalog:", diff --git a/packages/app/package.json b/packages/app/package.json index 6953bb264..8341a4cec 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "0.2.5", + "version": "0.2.6", "description": "", "type": "module", "exports": { diff --git a/packages/app/src/context/highlights.test.ts b/packages/app/src/context/highlights.test.ts index c5d9d113c..616a46a79 100644 --- a/packages/app/src/context/highlights.test.ts +++ b/packages/app/src/context/highlights.test.ts @@ -2,12 +2,12 @@ import { describe, expect, test } from "bun:test" import { loadReleaseHighlights } from "./highlights" describe("loadReleaseHighlights (GitHub Releases API)", () => { - test("synthesizes a single PawWork highlight from the release body", () => { + test("reads the app-facing update notice section from the release body", () => { const payload = [ { tag_name: "v0.2.3", name: "v0.2.3", - body: "Fixed first-message crash\n- bumped Minimax-M2.5\n", + body: "## Downloads\n\n- [macOS](https://example.com/app.dmg)\n\n## App Update Notice\n\nFixed first-message crash\n", }, ] const highlights = loadReleaseHighlights(payload, "0.2.3", "0.2.2") @@ -18,11 +18,11 @@ describe("loadReleaseHighlights (GitHub Releases API)", () => { }) }) - test("skips markdown headings and strips bullet markers on the first summary line", () => { + test("skips markdown headings and strips bullet markers inside the app update notice section", () => { const payload = [ { tag_name: "v0.3.0", - body: "## Desktop\n\n- Added dark theme\n- Fixed dock icon\n", + body: "## Downloads\n\n- [macOS](https://example.com/app.dmg)\n\n## App Update Notice\n\n### Desktop\n\n- Added dark theme\n- Fixed dock icon\n\n## Verification\n\n- CI passed\n", }, ] const highlights = loadReleaseHighlights(payload, "0.3.0", "0.2.3") @@ -31,12 +31,34 @@ describe("loadReleaseHighlights (GitHub Releases API)", () => { test("truncates long summaries with an ellipsis", () => { const long = "a".repeat(300) - const payload = [{ tag_name: "v1.0.0", body: long }] + const payload = [{ tag_name: "v1.0.0", body: `## App Update Notice\n\n${long}` }] const highlights = loadReleaseHighlights(payload, "1.0.0", "0.9.0") expect(highlights[0].description.endsWith("…")).toBe(true) expect(highlights[0].description.length).toBe(201) }) + test("does not guess from downloads when the app update notice section is missing", () => { + const payload = [ + { + tag_name: "v0.2.6", + body: "## Downloads\n\n- [macOS Apple Silicon](https://github.com/Astro-Han/pawwork/releases/download/v0.2.6/pawwork-mac-arm64.dmg)\n\n## Highlights\n\n- Maintenance fixes\n", + }, + ] + expect(loadReleaseHighlights(payload, "0.2.6", "0.2.5")).toHaveLength(0) + }) + + test("stops app update notice parsing at empty same-level headings", () => { + const payload = [ + { + tag_name: "v0.2.6", + body: "## App Update Notice\n\n- Fixed update notices\n\n##\n\n- [macOS](https://example.com/app.dmg)\n", + }, + ] + const highlights = loadReleaseHighlights(payload, "0.2.6", "0.2.5") + expect(highlights).toHaveLength(1) + expect(highlights[0].description).toBe("Fixed update notices") + }) + test("returns no highlights when the body is empty or only headings", () => { const payload = [{ tag_name: "v0.2.4", body: "# Title only\n\n## Heading only\n" }] expect(loadReleaseHighlights(payload, "0.2.4", "0.2.3")).toHaveLength(0) diff --git a/packages/app/src/context/highlights.tsx b/packages/app/src/context/highlights.tsx index e5f8b9550..c3184a885 100644 --- a/packages/app/src/context/highlights.tsx +++ b/packages/app/src/context/highlights.tsx @@ -61,8 +61,25 @@ function parseHighlight(value: unknown): Highlight | undefined { return { title, description, media } } -function summarizeBody(body: string): string | undefined { - const lines = body +function findAppUpdateNotice(body: string): string | undefined { + const lines = body.split(/\r?\n/) + const start = lines.findIndex((line) => /^#{2,6}\s+App Update Notice\s*$/i.test(line.trim())) + if (start === -1) return + + const headingLevel = lines[start].trim().match(/^#+/)?.[0].length ?? 2 + const section = lines.slice(start + 1) + const end = section.findIndex((line) => { + const heading = line.trim().match(/^(#{1,6})(?:\s|$)/) + return heading !== null && heading[1].length <= headingLevel + }) + return (end === -1 ? section : section.slice(0, end)).join("\n") +} + +function summarizeAppUpdateNotice(body: string): string | undefined { + const notice = findAppUpdateNotice(body) + if (!notice) return + + const lines = notice .split(/\r?\n/) .map((line) => line.trim()) .filter((line) => line.length > 0 && !line.startsWith("#")) @@ -97,7 +114,7 @@ function parseRelease(value: unknown): ParsedRelease | undefined { const body = getText(value.body) if (tag && body) { - const summary = summarizeBody(body) + const summary = summarizeAppUpdateNotice(body) if (summary) { return { tag, diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 017bfb5d0..19b8e81a5 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "0.2.5", + "version": "0.2.6", "type": "module", "license": "Apache-2.0", "homepage": "https://pawwork.ai", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 7467dd725..8740bb122 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "0.2.5", + "version": "0.2.6", "name": "opencode", "type": "module", "license": "Apache-2.0", diff --git a/packages/util/package.json b/packages/util/package.json index 032ee49fe..02ea683cd 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "0.2.5", + "version": "0.2.6", "private": true, "type": "module", "license": "Apache-2.0",