Skip to content

Commit cb62ea8

Browse files
Feed real changelog into the updater notes and show them in-app
The in-app "a new version is available" prompt showed only a version number, and latest.json's `notes` carried the workflow's generic install template — the actual changelog only ever appeared on the GitHub release page, edited in by hand after the fact. Now CHANGELOG.md is the single source of truth. The release workflow extracts the section matching the tag (portable awk, so it runs on the macOS and Windows runners too) and passes it as tauri-action's releaseBody, which is also what lands in latest.json's `notes`. The update banner renders update.body, so the prompt says what changed. Download links and Gatekeeper/SmartScreen help stay out of the changelog — they're appended to the GitHub page after publishing, so they never clutter the in-app notes. RELEASING.md documents the new flow. Takes effect on the next tagged release; nothing about the published v0.10.1 changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent a50a3ad commit cb62ea8

4 files changed

Lines changed: 119 additions & 35 deletions

File tree

.github/workflows/release.yml

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,39 @@ jobs:
3535
steps:
3636
- uses: actions/checkout@v4
3737

38+
- name: Extract release notes for this tag
39+
# The single source of truth for "what changed" is CHANGELOG.md. We pull
40+
# out the section whose heading matches the tag and hand it to
41+
# tauri-action as the release body — which is also what tauri-action
42+
# writes into latest.json's `notes`, i.e. what the in-app updater shows.
43+
# Runs on every matrix platform (bash is available on all three runners)
44+
# so each job produces an identical body and latest.json stays consistent.
45+
id: notes
46+
shell: bash
47+
run: |
48+
ver="${GITHUB_REF_NAME}"
49+
# Print the lines under `## <tag>` up to the next `## ` heading, with
50+
# leading and trailing blank lines trimmed but internal ones kept.
51+
# Done inside awk so it needs nothing beyond POSIX (no tac/GNU sed) —
52+
# this step also runs on the macOS and Windows runners.
53+
body="$(awk -v head="## $ver" '
54+
$0 == head { grab=1; next }
55+
grab && /^## / { exit }
56+
grab {
57+
if ($0 ~ /[^[:space:]]/) { while (pending-- > 0) print ""; pending=0; print; started=1 }
58+
else if (started) { pending++ }
59+
}
60+
' CHANGELOG.md)"
61+
if [ -z "$body" ]; then
62+
echo "::warning::no CHANGELOG.md section for $ver — using a fallback line"
63+
body="See the release page for what's new in ${ver}."
64+
fi
65+
{
66+
echo "body<<__NOTES_EOF__"
67+
echo "$body"
68+
echo "__NOTES_EOF__"
69+
} >> "$GITHUB_OUTPUT"
70+
3871
- name: Install Linux system dependencies
3972
if: matrix.platform == 'ubuntu-22.04'
4073
run: |
@@ -93,26 +126,13 @@ jobs:
93126
with:
94127
tagName: ${{ github.ref_name }}
95128
releaseName: "Field Notes ${{ github.ref_name }}"
96-
releaseBody: |
97-
Download an installer for your platform below.
98-
99-
**macOS:** not yet notarized — on first launch, **right-click the app and
100-
choose Open** to get past Gatekeeper.
101-
102-
If you still have a problem opening it, use the **"Open Anyway"** setting:
103-
1. Try to open the app and dismiss the warning dialog.
104-
2. Open the **Apple menu** and select **System Settings**.
105-
3. Click **Privacy & Security** in the left sidebar.
106-
4. Scroll to the **Security** section — you'll see a message that the app was blocked.
107-
5. Click **Open Anyway**, enter your Mac's login password, and click **OK**.
108-
109-
**Windows:** download the `-setup.exe` installer. It isn't code-signed yet, so
110-
SmartScreen may warn on first launch — click **More info → Run anyway**.
111-
112-
**Linux:** use the .AppImage (portable), or the .deb / .rpm for your distro.
113-
114-
The Companion and text-import features run a model locally — the app guides
115-
you through installing Ollama and downloading one on first use.
129+
# The changelog section for this tag, from the step above. This is the
130+
# release body AND `latest.json`'s `notes`, so the in-app updater prompt
131+
# now shows what actually changed. Download links and Gatekeeper /
132+
# SmartScreen help are deliberately NOT here — they'd be noise in the
133+
# app; they're added to the GitHub release page after publishing
134+
# (see RELEASING.md).
135+
releaseBody: ${{ steps.notes.outputs.body }}
116136
releaseDraft: true
117137
# The updater reads /releases/latest/download/latest.json, and GitHub's
118138
# "latest" excludes prereleases. So marking a v*-beta / v*-rc tag as a

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!-- SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 -->
2+
# Changelog
3+
4+
User-facing notes, one section per released version. The release workflow reads
5+
the section whose heading matches the tag (`## vX.Y.Z`) and uses it as the
6+
release body — which is also what lands in `latest.json` and what the in-app
7+
"a new version is available" prompt shows. So: write for the person who will
8+
read it inside the app, keep it to what changed, and don't put download links
9+
or Gatekeeper/SmartScreen help here (those are added to the GitHub release page
10+
after publishing — see RELEASING.md).
11+
12+
The heading must be exactly `## vX.Y.Z`, matching the tag. Newest on top.
13+
14+
## v0.10.1
15+
16+
- **You can see when your phone has paired.** Setting up phone access used to
17+
give no feedback — you showed the QR code, scanned it, and then guessed. Now a
18+
green "Paired successfully" light appears the moment your phone first connects.
19+
It confirms a phone has paired since you turned phone access on (not that one
20+
is connected this second), and resets when you turn phone access off. Phone
21+
access is unchanged otherwise: off by default, tailnet-only, code on every
22+
request.
23+
24+
## v0.10.0
25+
26+
- **The Companion stays responsive.** It no longer locks the window while it
27+
thinks (worst on the first message, when the model loads), and the model
28+
pre-loads when you open the Companion so the first reply comes back at normal
29+
speed. Same fix for Import from text.
30+
- **It's honest about your hardware.** The app checks whether your machine can
31+
run the model you picked and says so plainly — before a multi-gigabyte
32+
download, and again using real reply speed once you've chatted.
33+
- **Import from text actually works now.** It reads any format, pulls out every
34+
dose, and uses each substance's standard name so the interaction checker
35+
recognises it. The screen shows everything it found for review.
36+
- **A first-run choice for the Companion**, asked once on a fresh install.
37+
- **Send feedback in one click** — a Settings card opens a prefilled GitHub
38+
issue in your browser. Nothing is sent from the app itself.

RELEASING.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ npm install --package-lock-only # syncs package-lock.json
3333
Also update `ROADMAP.md` (mark shipped items with the version) and `README.md`
3434
(the feature list) if features shipped.
3535

36+
## 2a. Write the changelog section (before tagging)
37+
38+
Add a `## vX.Y.Z` section to the top of **`CHANGELOG.md`** with the user-facing
39+
"what's new", written for the person reading it **inside the app**. The release
40+
workflow extracts this exact section and uses it as the release body — which is
41+
also what goes into `latest.json` and what the in-app "a new version is
42+
available" prompt now shows. So keep it to what changed; **no** download links
43+
or Gatekeeper/SmartScreen help here (those go on the GitHub page in step 4).
44+
45+
The heading must be exactly `## vX.Y.Z`, matching the tag, or the build falls
46+
back to a generic one-liner (and logs a warning).
47+
3648
## 3. Tag
3749

3850
Work lands on `main` first (merge feature branches, make sure CI-relevant
@@ -49,19 +61,23 @@ git push origin main vX.Y.Z
4961
**prerelease**, which keeps it away from `/releases/latest` and therefore away
5062
from everyone's auto-updater. Plain tags become the update everyone is offered.
5163

52-
## 4. Write the release notes
64+
## 4. Round out the GitHub release page
5365

54-
The workflow fills the draft with a generic install-instructions template — CI
55-
can't know what changed. Replace it before (or right after) publishing:
66+
The workflow already fills the draft body with the `CHANGELOG.md` section from
67+
step 2a — that part is done, and it's what `latest.json` and the in-app prompt
68+
carry. What the changelog deliberately leaves out is the web-page furniture, so
69+
**append** it to the draft body (don't replace what's there):
5670

57-
1. **What's new** — the actual changes, written for end users.
58-
2. **Downloads table** — direct links to the five files a human wants
71+
1. **Downloads table** — direct links to the files a human wants
5972
(`_x64-setup.exe`, `.msi`, `_universal.dmg`, `.AppImage`, `.deb`, `.rpm`).
6073
Asset URLs follow the pattern:
6174
`https://github.com/sparkly-quasar/field-notes/releases/download/vX.Y.Z/<asset-name>`
62-
3. **First-launch notes** — SmartScreen (Windows) and Gatekeeper (macOS)
75+
2. **First-launch notes** — SmartScreen (Windows) and Gatekeeper (macOS)
6376
workarounds, since installers are unsigned.
6477

78+
Keep this download/first-launch furniture **out of `latest.json`** — it lives
79+
only on the web page. That's why it's appended here rather than in `CHANGELOG.md`.
80+
6581
Constraints worth knowing:
6682

6783
- **Assets cannot be grouped, reordered, or renamed.** GitHub shows a flat

src/routes/+page.svelte

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,14 +1555,22 @@
15551555
<main>
15561556
{#if update && !updateDismissed}
15571557
<div class="update-banner">
1558-
<span>A new version <strong>v{update.version}</strong> of Field Notes is available.</span>
1559-
{#if updateBusy}
1560-
<span class="muted small">{updateMsg}</span>
1561-
{:else}
1562-
<span class="row-actions">
1563-
<button class="primary small-btn" onclick={installUpdate}>Install &amp; restart</button>
1564-
<button class="ghost small-btn" onclick={() => (updateDismissed = true)}>Later</button>
1565-
</span>
1558+
<div class="update-head">
1559+
<span>A new version <strong>v{update.version}</strong> of Field Notes is available.</span>
1560+
{#if updateBusy}
1561+
<span class="muted small">{updateMsg}</span>
1562+
{:else}
1563+
<span class="row-actions">
1564+
<button class="primary small-btn" onclick={installUpdate}>Install &amp; restart</button>
1565+
<button class="ghost small-btn" onclick={() => (updateDismissed = true)}>Later</button>
1566+
</span>
1567+
{/if}
1568+
</div>
1569+
{#if update.body?.trim()}
1570+
<!-- The changelog section for this version, straight from latest.json.
1571+
Shown as plain text (not rendered as markdown) — it's short and the
1572+
Markdown-ish dashes read fine as-is. -->
1573+
<p class="update-body">{update.body.trim()}</p>
15661574
{/if}
15671575
</div>
15681576
{/if}
@@ -2885,7 +2893,9 @@ Peak was intense and connected; gentle comedown by 1am. Drank lots of water, no
28852893
.dose-class.caution { color: var(--caution); }
28862894
.dose-class.danger { color: var(--danger); font-weight: 600; }
28872895
.dose-class.muted { color: var(--muted); }
2888-
.update-banner { display: flex; flex-wrap: wrap; align-items: center; gap: 0.8rem; justify-content: space-between; border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: 10px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; font-size: 0.9rem; }
2896+
.update-banner { border: 1px solid var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: 10px; padding: 0.6rem 0.9rem; margin-bottom: 1rem; font-size: 0.9rem; }
2897+
.update-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.8rem; justify-content: space-between; }
2898+
.update-body { margin: 0.6rem 0 0.1rem; padding-top: 0.5rem; border-top: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); color: var(--muted); font-size: 0.83rem; line-height: 1.5; white-space: pre-wrap; max-height: 11rem; overflow-y: auto; }
28892899
.ai-log { max-height: 150px; overflow: auto; background: color-mix(in srgb, var(--ink) 6%, transparent); border-radius: 8px; padding: 0.6rem; font-size: 0.75rem; line-height: 1.4; white-space: pre-wrap; word-break: break-word; color: var(--muted); margin: 0.2rem 0 0; }
28902900
.import-panel { border: 1px solid var(--line); border-radius: 12px; padding: 1rem; margin: 0.6rem 0 1rem; display: flex; flex-direction: column; gap: 0.6rem; }
28912901
.import-text { font: inherit; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 0.7rem; resize: vertical; width: 100%; box-sizing: border-box; }

0 commit comments

Comments
 (0)