Skip to content

feat: add tar.gz Linux target and simplify AUR PKGBUILD#133

Merged
adibhanna merged 5 commits into
ZenNotes:release/v2.4.0from
Lund1337:feature/linux-tarball-release
Jun 16, 2026
Merged

feat: add tar.gz Linux target and simplify AUR PKGBUILD#133
adibhanna merged 5 commits into
ZenNotes:release/v2.4.0from
Lund1337:feature/linux-tarball-release

Conversation

@Lund1337

Copy link
Copy Markdown
Contributor

Verified

Tarball produced by npm run dist:linux (ZenNotes-2.3.0-linux-x64.tar.gz):

Confirmed resources/arch-extras exists with desktop file + icons

tar -tzf ZenNotes-2.3.0-linux-x64.tar.gz | grep -i arch-extras

LICENSE present at tarball root

tar -tzf ZenNotes-2.3.0-linux-x64.tar.gz | grep -i license

chrome_crashpad_handler ships with correct execute permissions (-rwxr-xr-x)

tar -tvzf ZenNotes-2.3.0-linux-x64.tar.gz | grep crashpad

Note: sha256sums in .SRCINFO / PKGBUILD still reference the old AppImage hash.

@Lund1337
Lund1337 requested a review from adibhanna as a code owner June 12, 2026 12:29

@adibhanna adibhanna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice direction — moving the AUR -bin package off AppImage extraction onto a plain tarball is the right call, and dropping the whole --appimage-extract + chmod dance (#70/#74/#92) is justified since tar preserves permissions. I verified the two load-bearing assumptions and they hold:

  • Top-level tar dir — electron-builder's tar() sets prefix: path.basename(outFile, ".tar.gz"), so the archive's top folder is exactly ZenNotes-<ver>-linux-x64, matching the PKGBUILD's _extracted. ✅
  • Symlink targetexecutableName: "ZenNotes" means the binary is named ZenNotes, so /usr/bin/zennotes → /opt/zennotes-bin/ZenNotes and Exec=zennotes are correct. ✅

A few blocking items before merge:

1. Scope the new extraResources/extraFiles to linux

extraFiles (LICENSE) and the new arch-extras extraResources entries are added at the global build level, so they ship in the mac and win builds too. On macOS extraFiles copies into ZenNotes.app/Contents/, leaving a stray Contents/LICENSE at the bundle root — and this app notarizes (afterSign: scripts/notarize.cjs), where unexpected top-level files in Contents/ are a common signing/notarization failure. The Linux .desktop + 8 PNG icons inside the mac/win installers are also pure bloat. Please move both new blocks under "linux" (electron-builder supports per-platform extraFiles/extraResources).

2. pkgver 2.3.0 points at a tarball that doesn't exist

The v2.3.0 release only has .AppImage, .deb, and .pacman — the tar.gz is produced by this PR, so …/releases/download/v2.3.0/ZenNotes-2.3.0-linux-x64.tar.gz 404s and makepkg can't fetch the source. The PKGBUILD/.SRCINFO need to target the first release that actually ships the tarball (the next release), not 2.3.0.

3. sha256sums still reference the old AppImage hash

As you noted, f7f6a67b… is the v2.2.0 AppImage hash. Needs regenerating with updpkgsums against the real published tarball — gated on #2, since the asset has to exist first.

Minor

  • You verified chrome_crashpad_handler is -rwxr-xr-x; the main ZenNotes binary's exec bit is equally load-bearing for launch — worth a quick tar -tvzf … | grep -E '/ZenNotes$' to confirm.
  • The removed PKGBUILD comments captured real context (#70/#74/#92). A one-liner noting "tar.gz preserves perms, so the chmod workarounds are gone" would keep that history.

@Lund1337

Copy link
Copy Markdown
Contributor Author

Addressed review feedback:

  1. Scoped to linux — moved extraResources (arch-extras) and extraFiles (LICENSE) from top-level build into the linux block
  2. pkgver bumped to 2.4.0 — the tar.gz will ship with the next release, not 2.3.0
  3. Added comment in PKGBUILD
# tar.gz preserves permissions (unlike squashfs extraction)
# chmod workarounds from #70/#74/#92 are no longer needed.
  1. Verified ZenNotes binary permissions-rwxr-xr-x 0/0 206339288 2026-06-12 16:30 ZenNotes-2.3.0-linux-x64/ZenNotes with command:
tar -tvzf ZenNotes-2.3.0-linux-x64.tar.gz | grep -E '/ZenNotes$'   

sha256sums still needs updpkgsums when the release is published — gated on the release shipping the tar.gz artifact.

@Lund1337
Lund1337 force-pushed the feature/linux-tarball-release branch from 4e1b961 to b3a0342 Compare June 12, 2026 14:41
@Lund1337
Lund1337 requested a review from adibhanna June 12, 2026 14:42
adibhanna and others added 5 commits June 12, 2026 10:06
- Add tar.gz to electron-builder Linux targets
- Include desktop file icons via arch-extras in extraResources + LICENSE
- Rewrite PKGBUILD to use tar.gz instead of AppImage extraction
@Lund1337
Lund1337 force-pushed the feature/linux-tarball-release branch from b3a0342 to b49d227 Compare June 12, 2026 15:54
@adibhanna
adibhanna changed the base branch from main to release/v2.4.0 June 16, 2026 23:07
@adibhanna
adibhanna merged commit 028e72a into ZenNotes:release/v2.4.0 Jun 16, 2026
@adibhanna adibhanna mentioned this pull request Jun 19, 2026
adibhanna added a commit that referenced this pull request Jun 19, 2026
* docs: update in-app help for v2.4.0

Document CSV databases (how-to + core concept + database-grid shortcuts),
the comments keyboard flow (Mod+Alt+M, Mod+Shift+C, panel j/k/e/r/d), the
always-on Alt+H/J/K/L pane-focus motions, a new Palettes and pickers
shortcut section, and the expanded theme family list in Appearance.

* Fix tab scroll position restore (#127)

* Fix calendar date note detection (#131)

* Add configurable daily and weekly note patterns (#77)

Daily and weekly notes can use date-pattern tokens (yyyy, MM, MMM, dd, EEE, ww, ...) for both the directory and the title/filename, with a locale for localized month and weekday names. Literal text is single-quoted, e.g. 'Daily Notes'/yyyy/MM-MMM.

Recognition re-formats each note's recovered date and accepts it only when it round-trips, so any token combination resolves -- including titles that encode the day via ISO week + weekday (yyyy-'W'ww-EEE) rather than day-of-month. Changing a pattern snapshots the previous one so existing notes stay recognized, and a Reset to defaults control restores the directory, naming, and locale.

Closes #77

* Fix duplicated hover text on sidebar icons (#141)

IconBtn rendered its label through both the native title attribute and a custom hover bubble, so macOS showed the tooltip text twice. Drop the redundant native title; the styled bubble and aria-label remain, matching the editor toolbar's tooltip pattern.

* docs: add #77 feature and #141 fix to v2.4.0 release notes

* Keep release notes local-only (stop tracking docs/releases)

Release notes and launch copy are personal/local working docs, not repo content. Untrack the v2.4.0 notes (the file stays on disk) and gitignore docs/releases/ so they can't be committed again.

* Fix blank Window menu items on macOS (#154)

Electron 41 no longer supplies default text for the macOS tab roles (toggleTabBar, selectNextTab, selectPreviousTab, mergeAllWindows), so the Window menu rendered them as blank rows that thinned out on repeat opens. Give each role an explicit label so the rows render their text.

* Fix sidebar header not reflecting the remote vault (#153)

In remote mode the sidebar header showed vault.name -- the server-side vault folder (e.g. "workspace") -- while the vault switcher names the same vault after the connection profile the user created (e.g. "Home"). The header label and its color/initial badge therefore disagreed with the switcher. Bind the header to the current switcher entry's name so the label and badge stay in sync with the dropdown; fall back to vault.name when there is no current entry.

* Fix switching from a remote workspace back to a local vault

openLocalVault bailed out when the target path equaled the current vault.root, without checking workspaceMode. In remote mode vault.root is the server-reported path, and a localhost server reports the served folder's real on-disk path -- which equals the local vault's own path. Switching back to that local vault was therefore mistaken for reopening the current vault and silently did nothing. Only short-circuit when already in local mode on the same root.

* Fix hint mode in the tasks and tags views (#151)

2.3.0 moved hint mode to <leader>h, but VimNav bailed out of the tasks/tags
tabs for every key except the old standalone `f`, so the leader -- and
therefore hint mode and every other leader command -- was dead there. Let
leader input through in those panels; VimNav now arms and consumes the leader
before TasksView can see it, so <leader>h works and Space-to-toggle falls back
to x (Space still toggles for anyone who remapped their leader off Space).

While the hint overlay is open, the tasks/tags handlers (list, calendar, kanban)
now yield every key to it, so hint labels that collide with panel keys (j/k/x/o,
Esc) are no longer stolen.

Also stop Esc from closing the tasks and tags tabs. They are tabs like any note
tab, so Esc now only clears an active filter and leaves the tab open; close with
:q, the header button, or the OS shortcut.

* Fix remapped pane-focus shortcuts colliding with the editor (#124)

Remapping the pane-focus shortcuts (global.focusPane*) onto a key CodeMirror also binds -- e.g. Ctrl-h (delete char) or Ctrl-k (kill line) -- ran both: the bubble-phase window handler fired *after* CodeMirror had already executed its command, so the key deleted text and moved focus. Handle these shortcuts in the capture phase and consume the event so the editor never sees a key bound to focus. The handler bails while Settings, a palette, or a modal is open so it can't steal keys from the keybinding recorder.

Also fix sidebar->pane navigation: focusPaneOrEdgePanel always moved geometrically from activePaneId, so pressing focus-right from the sidebar jumped from the last active pane and skipped the pane next to the sidebar. When focus is on a horizontal edge panel, move relative to that panel and land on the edge-most pane when crossing into the editor.

* Add Vim yank-to-clipboard and yank highlight; fix Linux clipboard hints (#144)

On Linux the editor's right-click menu hardcoded Mac hints ("⌘X" etc.), and the Ctrl clipboard keys collided with codemirror-vim's own Ctrl bindings (Ctrl+A increment, Ctrl+V visual block, Ctrl+X decrement), so they appeared broken.

- Menu hints now derive from formatKeyToken('Mod+...'), showing Ctrl on Linux/Windows and ⌘ on macOS.

- New 'Yank to system clipboard' Vim setting (clipboard=unnamed): yank/delete/change to the unnamed register also copy to the OS clipboard, while vim's Ctrl bindings keep working. Implemented by wrapping codemirror-vim's register controller (created once, so the patch is stable). Default off.

- Highlight on yank (like nvim's vim.highlight.on_yank): the yanked range briefly flashes. The range is read from the editor selection, which codemirror-vim sets to the operator range while the yank runs.

* Let Space reach Vim while a command awaits an argument (#147)

VimNav's capture-phase leader handling armed on Space even while codemirror-vim was mid-command in the focused editor. After f/t/F/T/r (or an operator/count) the next key is the command's argument, so r<Space> (replace with space) and f<Space> (find next space) instead opened the which-key leader UI.

Add isVimAwaitingArgument() -- true when codemirror-vim has a partial command buffered (inputState.keyBuffer) or expects a literal next char (expectLiteralNext) -- and skip arming the leader when the editor is focused and awaiting an argument, so Space falls through to codemirror-vim. The leader still works at rest.

* Ship a complete macOS app icon (.icns) (#165)

electron-builder auto-generated the macOS icon from build/icon.png, producing an .icns that omitted the standard 32x32 (@1x) and 1024x1024 representations. Add a canonical build/icon.icns (all 10 Apple iconset sizes, built from the 1024 source) and point mac.icon at it, so future builds carry a complete icon for every consumer. The reported Raycast case is most likely a stale Raycast icon cache -- the bundle icon is correct and renders in Spotlight/Finder -- but a complete .icns rules out a strict icon reader.

* docs: refresh in-app help for the Tasks/Tags keyboard changes

Reflect the keyboard updates shipped this release: hint mode is <leader>h (was shown as f), the Tasks view toggles with x (Space is the leader), Esc clears the filter rather than closing the tab, and the leader works in the Tasks/Tags views. Adds the <Space> h entry to the Vim command list.

* Show editor ex-command errors inline instead of a blocking alert (#173)

Running an ex command with a bad argument (e.g. :mv trash) reported the error with window.alert. In an Electron renderer that native dialog blurs CodeMirror, and after dismissing it the editor never regained focus -- in Vim mode the user could no longer type.

Route the :mv/:move, :e/:edit, and :new error paths through a non-blocking, in-editor notification (cm.openNotification) -- the same red bottom-of-editor message codemirror-vim uses for its own errors -- so the editor keeps focus. Falls back to alert + refocus when the editor notification is unavailable.

* Sort sidebar folders/notes/assets by name numerically (#168)

Sidebar folders rendered in on-disk/insert order and were never name-sorted, so folders named with numeric/char prefixes only fell into place after a restart (a fresh load), and a folder created mid-session appeared last. Note and asset name sorting also used a plain locale compare, so '10 Foo' sorted above '2 Foo'.

Add a shared naturalCompare() (numeric-aware, case-insensitive) and use it for folder children (sorted at render time, so new folders land in place immediately) and for the note/asset Name sort modes in the sidebar tree and note list.

* Skip unreadable files/dirs in the server vault scan (#159)

The server's ListNotes and ListFolders walked the vault with filepath.WalkDir and returned the error for anything except os.ErrNotExist, so the first permission-denied entry aborted the whole scan -- a vault copied in with root-owned files while the container runs as a non-root user showed up empty, and fixing some files only revealed those. ListAssets already tolerated permission errors; notes and folders did not.

Add a shared isSkippableWalkErr helper (skips ErrNotExist and ErrPermission) and use it in all three list functions, so unreadable entries are skipped and the rest of the vault still loads.

* Fix zen CLI opening two windows on cold start (#178)

* Add WYSIWYG live-preview editor (tables, blocks, vim tables)

Render markdown in Edit mode (live preview), ported from the WYSIWYG work in
PR #185 (author: songgnqing) — excluding that PR's breaking database restructure:

- Tables as an editable grid (cm-table) + action menu (cm-table-menu)
- Blockquote bars, list bullets, horizontal rules (cm-wysiwyg-blocks)
- Hashtag chips (cm-hashtags), wikilink rendering (cm-wikilink-render)
- Fenced-code cards + language flair (cm-code-block-flair, cm-code-block-font)
- Strikethrough across all editor highlight styles (#187)
- Task lines: marker hidden when rendered, raw source on the active line (Obsidian-style)

Vim-navigable tables: a block cursor over the current character with
h/l/w/b/e/0/$ motions, i/a/I/A editing, j/k row moves, and an `m` action menu.

Wired via wysiwygExtensions() in the live-preview compartment, gated by the
livePreview setting. 400 app-core tests green.

* Render Obsidian-style callouts in Edit mode

Detect `> [!type] title` blockquotes and render them as colored cards matching
the Preview palette (note/info=blue, tip/hint/success=green, warning/warn=yellow,
danger/error=red, quote=grey). The typed title shows bold (custom title, or the
capitalized type name when none); the `[!type]` token is hidden off the line and
revealed when the cursor is on the header for editing.

Also fixes nested lists inside callouts/blockquotes breaking out of the box
(re-add the box padding on top of the list hanging-indent) and de-italicizes
callout body text to match plain blockquotes.

* Add vim editing to WYSIWYG table cells

In a table cell (Vim mode), beyond h/l/w/b/e/0/$ navigation:

- Editing operators: x, D, C, and operator-pending dd/cc, dw/cw, d$/c$, d0, db.
- Char-wise visual mode (v) with motions + text objects, then d/c/y; rendered
  as a themed overlay (not a native selection, which CodeMirror would mirror
  across cells and show in the OS color).
- Text objects: viw/vaw, vi"/va", vi(/va) (and operators diw/ciw/ca", …),
  via a pure, unit-tested textObjectRange (word/quote/bracket).
- Undo/redo: u and Ctrl-r route to the editor history (committing the pending
  cell edit first).
- Esc in normal mode is a no-op (was jumping out below the table); leave via
  j/k at the edges.
- Cells disable native selection in view mode (re-enabled while editing), so
  the only highlight is the themed visual overlay.

* Close the window on Cmd+W when no tab is open (#192)

`global.closeActiveTab` (Cmd+W / Ctrl+W) called closeActiveNote(), which
returns early when there's no active note — so on an empty window (all tabs
closed) nothing happened and the window never closed. In vim mode Ctrl+W was
also always reserved for the `<C-w>` pane prefix, swallowing the empty-window
case on Linux.

Now: when no tab is open, close the window via window.zen.windowClose(); and
only reserve Ctrl+W for vim when a tab is actually open (an empty window has
no pane to navigate), so Cmd+W / Ctrl+W closes the window on macOS and Linux,
vim on or off.

* Keep the reference-link definition colon visible in Edit mode (#188)

The `:` in a reference-style definition (`[label]: url`) parses as a LinkMark,
which the live-preview plugin hides along with inline-link brackets — so the
colon disappeared in Edit mode, leaving a broken-looking `[label] url`. Skip
hiding LinkMarks whose parent is LinkReference; inline-link brackets (parent
Link/Image) still hide as before. Preview was already correct (the definition
is consumed and the reference link resolves).

* Show images/PDFs in a capital-cased Inbox folder (#186)

On a case-insensitive filesystem (macOS/Windows), an inbox folder stored
as `Inbox/` (or any system folder with non-canonical casing) made the
file browser hide its images and PDFs while still showing its notes.

The vault walk's `realpath` (symlink-loop detection) resolves to the
on-disk case, so both note and asset paths come back as `Inbox/...`.
Notes still appeared because the walk assigns `folder: 'inbox'`
authoritatively, but assets carry no folder field and the renderer's
`folderForVaultRelativePath` matched system folders case-sensitively,
dropping the capital path to `null` -> hidden.

Make the renderer classify and strip system-folder prefixes
case-insensitively (`folderForVaultRelativePath`, `assetPathWithinFolder`,
`notePathWithinFolder`), so a capital `Inbox/` behaves exactly like
`inbox/` and notes + their sibling assets group into the same subpath.
The real on-disk path is preserved for file ops, keeping this correct on
case-sensitive Linux.

Adds renderer unit coverage plus an end-to-end test wiring the real
main-process listAssets/listNotes to the real renderer classifier.

* Stop logging an error when an open database is deleted

Deleting a database (or any client removing the .csv) left the renderer
trying to re-read the gone file: the watcher's delete event called
syncDatabaseFromDisk, and nothing ever removed the database from state or
closed its tab, so DatabaseView kept re-requesting it. Each attempt threw
"Database not found" from the open-database IPC handler, which Electron
logs as "Error occurred in handler for 'vault:open-database'".

- The open-database handler now returns null for a missing database
  (a stale tab outliving its file is not exceptional); real parse/
  permission errors still throw.
- loadDatabase / syncDatabaseFromDisk treat null as "gone" and forget the
  database, closing its tab (both the database-tab and .csv asset-tab
  forms) instead of looping on a missing file.
- The watcher's delete event proactively forgets the database, and
  openDatabase won't open a tab for one that no longer exists.

Covers live deletes, a stale tab restored on startup, and external
deletes. Adds store tests for all three.

* Don't trigger actions on the Enter that confirms an IME conversion (#183)

When typing with an IME (e.g. Japanese), pressing Enter to confirm a
conversion also fired our own keydown handlers — committing a rename,
selecting a search result, blurring a field, etc. — because the handlers
never checked whether a composition was in progress.

Add a shared `isImeComposing(e)` helper (standard `isComposing` flag plus
the legacy `keyCode === 229` fallback, for both React synthetic and raw
DOM events) and guard every text-entry "Enter confirms" handler: the
rename prompt and breadcrumb rename, all search/command palettes,
database inline renames (view/field/cell/group/tag), settings fields and
the combobox picker, the remote-profile and directory-picker modals,
quick-capture result pickers, and the tasks filter and Kanban column
rename. While composing, these now let the IME own Enter/Arrows/Tab; a
fresh Enter still confirms once composition ends.

Pure-navigation handlers and modifier combos (e.g. Cmd+Enter) are left
as-is, and the onboarding handler already bailed on editable targets.

* Don't let the file watcher hang the server where inotify is restricted (#179)

In an unprivileged LXC container, inotify on a bind-mounted vault can wedge
the process (unkillable, host volume locked) rather than returning an error,
and errors from fsw.Add() were silently discarded so a restricted
environment failed invisibly.

- Add ZENNOTES_DISABLE_WATCHER=1 → a no-op watcher (no fsnotify handle, no
  tree walk, no inotify syscalls). The vault is still fully served; only
  live auto-refresh stops. This is the reliable escape hatch on restricted
  hosts because it never makes the syscalls that hang.
- New watcher.StartOrDisabled is used at startup and on vault switch: if the
  watcher can't be created it logs a warning and falls back to the no-op
  watcher instead of log.Fatal / failing the switch.
- Surface fsw.Add failures: the initial walk counts and logs them once (with
  a pointer to ZENNOTES_DISABLE_WATCHER), and watching a newly created
  directory logs on error.

Document the variable and a "container hangs and won't stop" troubleshooting
entry in the Docker how-to. Adds tests for the no-op watcher.

* Make a database a self-contained .base folder

A database is now one folder, `<Name>.base/`, holding `data.csv`, `schema.json`
(the sidecar), and its record-page notes as `.md` files. The folder is the
database: rename/move/trash are plain folder operations and record-page paths
in the schema are stored relative to it, so nothing needs path rewriting.

The sidebar renders a `.base` folder as a database — database icon, title
without the suffix, click opens the grid, expand reveals its record pages — and
the folder menu renames/deletes it as a database. The database header title is
editable (double-click) and renames the folder, rehoming the open grid tab.

Walks treat a `.base` folder as one unit: the desktop lists it as a database
and its record pages as notes, but hides data.csv/schema.json from notes,
folders, and assets; the MCP server hides the folder; the self-hosted Go server
hides it entirely (databases are desktop-only). A legacy loose `<Name>.csv`
plus co-located `.csv.base.json` (with record notes under `<Name>/`) is
migrated to the new layout on vault open — idempotent, and only for managed
databases (a plain CSV is left alone).

Also fixes a couple of grid rough edges: a new/blank row no longer collapses
shorter than filled rows, and the rename input is sized to the title.

Adds shared-path, main-process (folder ops + migration + walk), and Go-server
tests.

* Add back/forward nav and restyle the tab bar (from #185)

Back/forward history navigation: ◀ ▶ buttons in the tab-bar header (wired to
the existing jump history, dimmed when there's nothing to go to) plus
`global.historyBack`/`historyForward` shortcuts bound to Alt+←/Alt+→ on every
platform (VS Code-style); vim's Ctrl+O/Ctrl+I history nav is unchanged.

Restyle the workspace tabs from rounded "browser pills" to flat, full-height
VS Code-style segments: right-border separators, no rounded tops, the active
tab filled with an accent ring, inactive tabs muted with hover. The close
button stays on the active tab and reveals on hover for the rest, and the
active tab scrolls into view when switching among many tabs.

* Unify assets under assets/ + add an Assets view (from #185)

Assets are no longer mixed with notes: they live in a top-level `assets/`
folder. A `migrateLooseAssets` step runs on vault open and moves loose
root-level attachments plus the legacy `attachements/`/`_assets/` dirs into
`assets/`, skipping any basename collision so existing `![[…]]`/`![](…)`
embeds keep resolving (the resolver falls back to a unique basename). Notes
and `.base` databases are never touched. New imports — including pasted
images — now land in `assets/`.

A dedicated Assets view (the `zen://assets` tab + a sidebar entry) browses
every asset in one place, with filter, open, and delete. The desktop main,
MCP server, and self-hosted Go server all recognize `assets/` (reserved
root); the Go server lists from it. Asset migration runs on the desktop.

Adds migration tests and updates the paste-image tests for the new target.

* Assets view: usage + actions + table layout, and nav polish

Assets view:
- Show "used in N" / "unused" per asset, computed from a new per-note
  assetEmbeds field (captures ![[asset]] and ![](path) embeds, which note
  metadata previously dropped) resolved via the same relative-path +
  unique-basename logic embeds render with. The note-meta cache version is
  bumped so it rebuilds with the new field on first open.
- Right-click context menu: Open, Copy embed, Reveal in file manager,
  Rename…, Move to Trash.
- Reorganized the list into an aligned table (header + shared grid columns,
  right-aligned numeric fields, whole-row click, hover-reveal delete).
- Fix a restore crash: the zen://assets tab is now treated as a virtual tab,
  so it's never loaded from disk as a note (ENOENT on relaunch).

Nav polish:
- Move the sidebar toggle up next to back/forward (shown when the sidebar is
  hidden); drop the redundant toggles from the breadcrumb, database, and
  assets headers.
- Anchor the leftmost toolbar tooltips to the button's left edge so
  "Show sidebar"/"Go back" no longer clip at the window edge.

* Fix Vim/normal-mode key interaction in list views

The Trash/Archive/Tasks/Tags/Quick Notes views register global capture-phase keydown handlers that fired single-key shortcuts straight through open confirm dialogs and context menus — Enter bypassed the delete-confirm and repeated Enter kept deleting — and ignored the Vim-mode setting entirely.

- Add isAppOverlayOpen() so the views stand down while a prompt/confirm modal or context menu owns the keyboard.
- Gate the single-key Vim shortcuts (j/k/x/d/gg/G/o/r/Space/1-3) behind vimMode; only arrows/Enter/Escape navigate when Vim is off.

Reported by songgenqing.

* Add markdown snippet auto-close in the editor

Type an inline delimiter (`**` `__` `~~` ``` `==` `[[` `%%`) then Space to wrap the cursor, or a fence (``````, `~~~`, `$$`) then Enter to expand a block with the cursor inside. Skips already-closed pairs, closing fences, and escaped delimiters.

Gated by a new 'Markdown snippets' setting (Settings → Writing, default on) and only active while typing — Vim off or Vim insert mode, never normal/visual mode. Wired into every editor surface via one shared helper.

Ported from community PR #185 (songgenqing).

* Add Flatpak packaging (#145)

* Add GitHub Sponsors username to FUNDING.yml

* docs: add GitHub Sponsors link to README

* Add Flatpak packaging

Adds packaging/flatpak/ mirroring the existing AUR packaging. The
manifest downloads the official AppImage from the GitHub release and
extracts it at build time (--appimage-extract, no FUSE required), then
installs the unpacked Electron app against the Flatpak Electron base app
and launches it through zypak.

Flatpak ships a self-contained runtime, so it avoids the host FUSE /
system-library issues that keep the AppImage from starting on Fedora
Atomic, minimal installs and some Arch variants (same class of problem
as #65).

Includes the flatpak-builder manifest, zypak launcher, desktop entry,
AppStream metainfo and a README documenting build and release-bump
steps.

---------

Co-authored-by: Adib Hanna <adibhanna@gmail.com>

* feat: add tar.gz Linux target and simplify AUR PKGBUILD (#133)

Add a tar.gz electron-builder Linux target that bundles the desktop file, icons, and LICENSE (via extraResources/extraFiles), and rewrite the AUR PKGBUILD to repackage that tarball instead of extracting the AppImage — dropping the chmod workarounds behind #70/#74/#92 (tar.gz preserves permissions). Fixes #103.

Tarball layout verified end-to-end against an electron-builder build.

* packaging(aur): SKIP sha256 until the v2.4.0 tarball is published

The rewritten PKGBUILD/.SRCINFO still carried the old v2.x AppImage sha256, which matches nothing now that the source is the tar.gz. The v2.4.0 tarball doesn't exist until release time, so there's no artifact to hash — use SKIP as a placeholder. `updpkgsums` pins the real checksum against the uploaded release asset before publishing to AUR.

* ci(aur): skip makepkg build until the release asset is published

The AUR check runs makepkg -s, which downloads the source tarball. The PKGBUILD points at the upcoming release's tarball (v2.4.0), which 404s until that release is cut — so the check failed for a non-bug reason. Probe the source URL first: when the asset isn't published yet, skip the build/lint with a notice (still validating PKGBUILD metadata + .SRCINFO sync); the full build runs once the release exists.

* feat: [[Note#heading]] wikilinks — resolve, jump to heading, autocomplete (#196)

`[[Note#heading]]` was matched as a note literally named "Note#heading", so
it never resolved — the connections tab even offered to create it. The whole
heading-link experience now works:

- resolveWikilinkTarget (and suggestCreateNotePath) strip the #heading / ^block
  anchor, so [[Note#heading]] resolves to Note everywhere (editor click,
  connections, backlinks) and 'create from link' makes a valid Note.md.
- Clicking, and `gd`, on [[Note#heading]] now scroll to the heading — shared
  openWikilinkHeading() → openNoteAtOffset — in both the editor and the preview.
- Typing [[Note# autocompletes that note's headings ([[# uses the current note).
- Ctrl+Y accepts the highlighted completion (Vim-style); Tab accepts a note
  link but keeps the caret inside [[…]] so you can chain into a #heading.

Tests: wikilinks.test.ts (resolution / anchor / create-path, incl. the
/Untitled#test edge case) and cm-wikilinks.test.ts (heading autocomplete).

* feat(ui): add middle-click to close tabs

* packaging(nix): add Nix/NixOS flake and packages (#149)

Adds a root flake plus packaging/nix/ with separate desktop and server
packages that build ZenNotes from source, a dev shell, and install docs.
Linux packaging only — no application-code changes.

Co-authored-by: Krysteq <justkrysteq@proton.me>

* fix: set quick capture window title

* fix: Ctrl+D and other emacs chords work in Vim mode on macOS

CodeMirror's defaultKeymap binds the emacs-style control chords
(Ctrl-d/a/e/f/b/v/h/k/o/t/p/n) as macOS-only bindings, and its key
handler outranks the Vim plugin's — so on macOS those chords ran the
emacs action (Ctrl-d deleted a character) instead of the Vim motion
(<C-d> half-page down). Ctrl-u, which has no emacs binding, already
worked, hence the up/down asymmetry. Linux/Windows were unaffected.

Add vimAwareDefaultKeymap(): in Vim mode the emacs chords are stripped
so Vim handles them natively; with Vim off they're kept (standard macOS
editing keys). Applied to every Vim-capable editor surface — the main
editor (dynamic via a compartment, so toggling Vim mode updates it live),
quick capture, floating/external/template editors, and the pinned
reference pane.

* feat: render comment bodies as Markdown

Comment bodies in the comments panel rendered as raw text, so Markdown a
user typed (## headings, lists, **bold**, `code`) showed as literal
source. They now render as sanitized Markdown via the same renderMarkdown
pipeline the preview uses, with a compact `comment-prose` variant that
scales headings and block spacing down to fit the narrow comment card.
The input stays a plain textarea (you type Markdown source).

* feat: focus the title field when creating a note from the sidebar

Creating a note from the sidebar (the note-list "+" button, the folder
context menu, and the empty-area menu) dropped the cursor straight into
the body with the name left as "Untitled", so it had to be renamed
afterward. These paths now pass focusTitle: true — matching the command
palette's "New Note" — so focus lands on the title input with "Untitled"
selected; Enter then moves to the body. Daily/weekly notes,
wikilink-create, and trash-restore are intentionally unchanged.

* fix: warn when inbox-mode vault hides root-level notes (#195)

An Obsidian-style vault whose notes live at the root (and in custom
folders) showed up empty when ZenNotes opened it in "inbox" mode — the
scan only walks inbox/quick/archive/trash, so top-level content was
silently hidden. This commonly happened when a flaky first directory
read (iCloud-backed, symlinked folders) fell back to the inbox default.

Add a sidebar banner that detects the mismatch — vault in inbox mode but
its root holds markdown/non-system folders that only root mode surfaces
(rootContentHiddenByInboxMode in the main process, exposed over a new
IPC) — and offers a one-click "Switch to Vault root". Replaces the silent
empty vault with a clear, actionable message.

The banner lives in the sidebar (the unified layout's note tree), not the
retired NoteList column. Refreshed on vault open and after settings
changes. Covered by vault.test.ts cases.

* feat: per-folder accent colors

Folders can now be given a preset accent color (10-color palette) from the
sidebar context menu — "Change color…" / "Reset color" — alongside the
existing folder icons. The color tints the folder's icon and name and stays
readable in every state: a colored row that's selected uses a faint accent
tint + ring instead of the saturated fill, so same-hue text doesn't vanish.

Stored as `folderColors: Record<"folder:subpath", FolderColorId>` on
VaultSettings (persisted to .zennotes/vault.json via the existing
setVaultSettings — no new IPC), keyed exactly like folderIcons and rewritten
in lock-step on folder rename/delete/duplicate (main process + store).

* feat: copy the whole note as Markdown

Add a "Copy Note as Markdown" command (command palette) plus a Vim leader
binding (Space l y, under the note-actions group) that copies the active
note's full Markdown source — including unsaved edits — to the clipboard.

Wired through a copyActiveNoteAsMarkdown store action, registered as the
remappable vim.leaderCopyMarkdown keymap, surfaced in the leader-l
which-key hint, and documented in the in-app help.

* feat: Excalidraw drawings as a first-class file type

Adds `.excalidraw` drawings alongside notes and databases:
- Listed in the sidebar (not as assets), with the real Excalidraw icon;
  they open in an embedded, lazy-loaded @excalidraw/excalidraw editor that
  loads/saves the scene JSON and follows the app's light/dark theme.
- Create from the sidebar ("New drawing" in the folder and empty-area
  menus) and from the breadcrumb. Rename and move preserve the
  `.excalidraw` extension instead of turning a drawing into a .md note.
- The drawing header hides Markdown-only controls (edit/split/preview,
  connections, comments, outline, PDF export), keeping archive + trash.
- New vault:create-excalidraw IPC (desktop); the web build degrades until
  the Go server learns to list/create drawings.

Also adds a breadcrumb create menu: right-click — or press `m` while a
crumb is focused (e.g. via hint mode) — any folder crumb to create a new
note / drawing / folder in that folder.

* feat(server): Excalidraw drawings on the self-hosted/web build

Brings the desktop's `.excalidraw` support to the Go server so drawings
work on the self-hosted and web client:
- ListNotes includes `.excalidraw` files (shown in the sidebar); ListAssets
  excludes them so they aren't treated as attachments.
- readMeta/ReadNote skip Markdown parsing for drawings — a scene's hex
  color (e.g. #1971c2) no longer registers as a #tag, and the raw JSON
  never leaks into the excerpt.
- Rename, move, duplicate, and move-between-folders preserve the
  `.excalidraw` extension instead of turning a drawing into a .md note.
- New CreateExcalidraw method + POST /excalidraw/create endpoint, backing
  the web bridge's existing createExcalidraw call (which previously 404'd).
- Root-mode detection recognizes a vault of only drawings; full-text search
  stays .md-only (drawings remain findable by title).

Tests: vault listing/create/rename-move parity + an end-to-end HTTP test
(login → POST /api/excalidraw/create → appears in /api/notes).

* feat: Favorites + Notion-style sidebar reorganization

Favorites — pin notes and folders to the top of the sidebar:
- Right-click a note or subfolder → Add/Remove from Favorites, or press the
  Vim leader binding `<leader> l s` on the active note (which-key + remappable).
- A FAVORITES section lists them with their real icons; click or Vim-Enter to
  open. Stored per-vault in VaultSettings.favorites (note path or folder key).
- Favorites survive note rename/move and folder rename, and are pruned on
  folder delete (rewrite logic lives in the store; the Go server carries
  favorites through folder ops so the web client persists them too).

Sidebar reorganized into clear labeled sections (Notion-style):
- FAVORITES (top), QUICK ACCESS (Tasks / Quick Notes / Daily+Weekly), NOTES
  (the tree), TAGS (flows after the notes), and SYSTEM (Archive / Trash /
  Assets) pinned to the bottom.
- The header `+` now opens a create menu for every supported type (note,
  drawing, template, database, folder) instead of only a note.
- Fix: Vim j/k now stops on Daily/Weekly note rows (they were missing
  navigation indices); Assets is Vim-activatable; removed stray top margin
  that made the gap above Daily Notes uneven; dropped the Tags chevron.

* feat(sync): foundation for bidirectional synced vaults

Lays the groundwork for a third workspace mode, `synced` — a local vault
that bidirectionally syncs with a server hub — while leaving `local` and the
thin-client `remote` modes untouched. No user-facing behavior yet.

Server (M2):
- GET /api/sync/manifest returns {path, hash, size, mtime} per note/.excalidraw
  for content-addressed diffing. sha256 hashes are cached in the existing
  note-meta-cache (keyed by mtime+size, version bumped 1->2), so an unchanged
  vault answers from stat() calls alone. supportsSyncManifest capability added.
- Refactored the notes walk into a shared collectNoteFiles(). Tests for hash
  stability/change, database+internal exclusion, and the HTTP endpoint (auth).

Desktop plumbing (M1):
- WorkspaceMode / WindowWorkspaceMode gain 'synced'; PersistedConfig gains
  syncedVaults[] (root + server profile + conflict policy + asset mode) with a
  normalizer. WindowVaultRegistry.setSyncedVault treats synced as disk-backed
  (shares the chokidar watcher) with an onLocalChange fan-out hook for the
  engine. store.workspaceModeFrom handles synced.

Reconcile core (M3, pure):
- Three-way diff (local/remote/base content hashes): push, pull, bidirectional
  delete-propagation, keep-both conflicts, first-sync union merge, hash-only
  (clock-skew-safe) decisions. 16 unit tests cover every decision-table row.

* feat(sync): the bidirectional sync engine (M3 I/O)

Builds the background replicator on top of the pure reconcile core:
- sync-state.ts — per-device base snapshot at .zennotes/sync-state.json
  (atomic writes, intent log for crash recovery).
- scan-local.ts — walks/hashes local note/.excalidraw files, mirroring the
  server's collectNoteFiles (inbox/root + quick/archive/trash, excluding
  databases, hidden, .zennotes).
- conflict.ts — keep-both conflict-copy naming ("Note (conflict <dev> <ts>).md").
- engine.ts — debounced, single-flight reconcile loop triggered by the local
  watcher fan-out, the server /api/watch WS, and a periodic backstop; executes
  push/pull/delete/converge/conflict via the existing RemoteServerClient with
  atomic, path-safe local writes. Offline/error/conflict status surface.
- RemoteServerClient.getSyncManifest(); SyncManifestEntry + SyncStatus types.

Verified: 22 unit tests (reconcile decision table + an end-to-end engine test
against an in-memory server over real local files: first-sync union merge,
pull, push, delete-propagation, keep-both conflict with no data loss,
idempotency). Not yet wired into app startup (next: activation + status UI).

* feat(sync): app integration — activation, IPC, and status UI (M3+M4)

Wires the sync engine into the running app:
- index.ts activation: a synced vault opens disk-backed (all file ops stay
  local — isRemoteWorkspaceActive stays false) plus a background SyncEngine,
  started from loadCurrentVaultFromConfig and torn down when switching to
  local/remote. setSyncedVaultForWindow mirrors setVaultForWindow; the local
  watcher fan-out (onLocalChange) drives the engine.
- New IPC: sync:get-status / now / on-status / attach-server / detach-server /
  open-vault, exposed through preload + the ZenBridge interface; the web bridge
  gets inert stubs (the browser is itself the thin client).
- Store: syncStatus slice, onSyncStatus subscription + initial fetch, and
  syncNow / attachSyncServer / detachSyncServer actions.
- UI: a cloud sync-status button in the sidebar header (synced / syncing /
  offline / error + a conflict badge; click to sync now) and vault-menu items
  to "Back up & sync to <server>" (attach a local vault) or "Stop syncing".

Typechecks clean across all packages; 36 desktop/sync tests + app-core tests
green; web builds. Runtime not yet exercised end-to-end (next: assets, then
databases/comments/settings, then the conflict-resolution UI).

* feat(sync): full-vault coverage — databases, comments, settings, assets (M5+M6)

Unifies all syncable content under one manifest instead of notes-only:
- Server: Manifest() now walks collectSyncFiles() — the whole vault tree
  (notes, drawings, databases, assets, comments, vault.json) excluding only the
  per-device sync-state, the meta cache, dotfiles, unrelated dot-dirs, and temp
  files. New POST /api/sync/write (multipart) writes raw bytes to an exact path
  for binary files (Vault.WriteSyncFile, atomic + size-capped).
- Client: scanLocalVault() walks the whole tree to match (also removing the
  earlier inbox/root-mode parity concern). The engine classifies each path as
  text (.md/.excalidraw/.json/.csv/.txt) — transferred via writeNote/readNote —
  or binary, transferred byte-for-byte via writeSyncFile/readSyncFile. Conflict
  copies handle both. Databases (CSV/JSON), comments, and settings are text, so
  they sync through the existing endpoints with no special-casing.

Tests: 25 sync unit tests (added binary push/pull byte-equality, databases/
comments/settings sync, and a never-sync guard for sync-state/meta-cache); the
server manifest test now asserts syncables-in / internal-out. All green;
typechecks + web build clean.

Note: assets sync as a full mirror for now; the lazy on-demand fetch is a
follow-up optimization.

* feat(sync): conflict-resolution UI (M7)

When the sidebar sync indicator shows kept-both conflicts, clicking it opens a
resolver listing each conflict copy with its original. Per conflict the user can
open either version, adopt the copy's content into the original ("Use the copy's
version"), or discard the copy — all via normal vault ops that then sync. The
engine gains dismissConflict() + a sync:dismiss-conflict IPC to clear a resolved
entry from the status list; the store adds resolveSyncConflict(keepMine|keepTheirs)
and an originalFromConflictPath() helper.

Completes the synced-vault feature end to end: notes, drawings, databases,
comments, settings, and assets sync bidirectionally with keep-both conflicts, a
live status indicator, attach/detach, and conflict resolution. Typechecks +
tests + web build all green. Ready for live testing.

* Revert the synced-vaults work (M1–M7) — will revisit

Reverts the five feat(sync) commits (731abb7, 757098a, aa22df5, 4fd805b,
a38ce62): the server sync manifest + binary write endpoint, the desktop sync
engine, app activation/IPC/status UI, full-vault coverage, and the conflict UI.

The bidirectional-sync direction needs more design/validation before it ships,
so it's parked. The work remains in history and can be restored later by
reverting this commit (or cherry-picking those SHAs).

* feat(web): databases on the web client (desktop/web parity)

Databases now work in the web client, reusing the exact same shared TS logic
the desktop uses so the on-disk format is identical across platforms.

- Server (apps/server/internal/vault/vault.go): ListFolders now lists `.base`
  database folders (then stops descending), mirroring the desktop — that one
  divergence was why databases never reached the web sidebar. ListNotes and
  ListAssets still hide the internals. Test updated.
- Web bridge (apps/web/src/bridge/http-bridge.ts): implemented the 8 database
  methods (open/writeRows/writeSchema/create/createRecordPage/rename/list) over
  HTTP, reusing @shared/database-csv + @shared/databases (parseCsv, parseRows,
  serializeRows, inferFields, buildDefaultViews, path helpers). Reads/writes use
  the existing generic /notes/read|write endpoints; `.base` folders are created/
  renamed via the folder endpoints — no new server endpoints, no Go
  re-implementation, so CSV/schema parity is guaranteed.

Drawings already worked end-to-end on web (no change). Verified: web typecheck +
build, app-core tests (shared CSV unchanged), Go vault/httpserver tests.

* feat: daily-note task calendar, vim calendar control, and Notion-style sidebar

Tasks calendar
- Daily-note tasks get an implicit due date (the note's date) so they
  surface on the right day without writing due: tokens; gated by the new
  "Tasks are due on the note's date" setting.
- Add, move, reschedule, and delete tasks directly from the calendar,
  creating the daily note on demand when needed.
- Drag a task to another day (pointer-based) with a move-vs-set-due choice.
- Optional "Roll over unfinished tasks to today" (Obsidian-style).
- Week agenda under the month grid in the sidebar calendar panel.

Vim keyboard
- Full keyboard control of the big Tasks calendar and the sidebar calendar
  panel: h/j/k/l day nav, Tab to pick a task, x/e/dd/m/</>/T/a actions,
  gg/G, [/] month, gt today.

Sidebar
- Notion-style restyle (soft active highlight, roomier rows, muted icons).
- Per-folder/note/database icon + color customization with inline reset.
- Folder hover-chevron and aligned rows.

Editor
- "Task" slash command; calendar hidden on quick notes.

Settings + docs
- New daily-notes task settings (server round-trips them as *bool).
- Help docs for the tasks calendar and daily-note settings.

* fix: don't reorganize loose files in an existing Obsidian vault (#202)

Pointing ZenNotes at an existing Obsidian vault silently relocated every
loose root-level non-md file — images, PDFs, and Obsidian `.canvas` files —
into `assets/` on first open (the loose-asset migration), which a user
reported as "a number of different files were changed that I made no edits
to."

A vault with an `.obsidian/` directory is managed by another app, so its
loose files are the user's own, not ZenNotes' legacy attachments. Skip the
root-level relocation step in that case; the legacy ZenNotes attachment dirs
(which never exist in such a vault) stay handled, so the former-ZenNotes
upgrade path is unchanged.

Adds end-to-end integrity tests that wire the real main-process vault I/O and
the real renderer store for the reporter's exact shape (root mode, nested
folders, spaces in filenames, symlinked `~/sync` root): notes never
cross-wire content, pure navigation writes nothing to disk, edits autosave to
only the edited file, and external watcher changes land under the right path.

* fix: make standard Markdown links clickable (#201)

Standard `[text](target)` links didn't navigate the way `[[wikilinks]]` do:
internal note links opened as broken asset tabs (the asset enhancer tagged
every relative link with a zen-asset URL), and external links — especially a
scheme-less domain like `[site](google.com)` — did nothing.

Now, across the preview pane, the editor live preview, and `gd`:

- `[text](Note.md)` and relative paths (`../x.md`, `#heading`) navigate to the
  note, resolved relative to the current note.
- `[site](https://…)` and bare domains (`google.com`, `www.x.com/path`) open in
  the browser; a scheme-less domain is promoted to https.
- In the editor a plain click follows a rendered link (cursor outside it),
  mirroring wikilinks; clicking a link the cursor is inside edits it. Cmd/Ctrl-
  click always follows. Markdown links now show the pointer cursor on hover.
- `.md` and external links are no longer mis-tagged as vault assets.

New pure module `internal-links.ts` (resolveInternalNoteHref / externalLinkUrl /
markdownLinkAt / extractLinkAtCursor) shared by all surfaces, with unit tests
and a regression test that note/external links aren't tagged as assets.

* feat: live-sync database fields to record-page frontmatter + tidy metadata card

The database table is the source of truth for a record's properties, and a
record page's frontmatter is a derived "metadata" mirror. Previously the
frontmatter was only re-mirrored when the page was opened, so editing a cell or
adding a field in the table left an already-open record page stale.

Now table changes (a cell value, an added/renamed/removed field) re-mirror the
frontmatter of any open record page live, preserving its body; pages that
aren't open are still synced lazily on next open. The existing database
write-guards keep this from looping through the file watcher.

Also redesign the in-editor frontmatter rendering: instead of small grey text
it reads as a compact properties card — a subtle rounded container, the `---`
fences hidden into quiet rounded edges, and each key shown as a muted label
beside its value.

* feat: Notion-style selection toolbar with formatting + shortcuts

Selecting text in the editor now pops up a floating bubble toolbar: a
"Turn into" block menu (Text, Heading 1–3, bulleted/numbered/to-do lists,
quote, code), inline formatting (bold, italic, strikethrough, highlight,
code, math), a link, and a comment. The footer shows the focused/hovered
action's keyboard shortcut on the popup itself.

Inline formats also have keyboard shortcuts that work on every platform,
in or out of Vim mode — handled in VimNav's window-capture pass so they
beat Vim's own Ctrl chords on Linux/Windows, with `Mod` resolving to ⌘ on
macOS and Ctrl elsewhere: ⌘B bold, ⌘I italic, ⌘E code, ⌘K link, ⇧⌘S
strikethrough, ⇧⌘H highlight, ⇧⌘M math.

The toolbar is fully keyboard-navigable: `Mod+/` focuses it, then the
arrows — or h/j/k/l in Vim mode — move row-aware (h/l across the format
row, j/k between it and "Turn into"); Enter applies, Esc returns to text.
`l`/→ on "Turn into" opens its submenu.

New pure `cm-format` commands (toggleWrap / wrapLink / setBlockType) with
unit tests; new toolbar icons; in-app Help updated.

* fix: recognize tags in any script — Cyrillic, CJK, etc. (#205)

Hashtags required an ASCII letter to start (`#[a-zA-Z]…`, with `\w` for the
rest), so `#тест`, `#ошибка`, `#标签` and other non-Latin tags were never
recognized and rendered as plain text.

Make the tag character classes Unicode-aware everywhere — first char `\p{L}`
(a letter in any script), rest letters/digits/`_`/`-`/`/` — keeping behavior
otherwise identical (a heading `# x` still isn't a tag; a hex colour like
`#1971c2` still isn't, since the first char must be a letter). Updated in
lockstep across the preview, editor pills, inline render, live sidebar
extraction, tag rename, the desktop scanner + MCP, shared task tags, and the
Go server so desktop and the self-hosted/web client stay byte-for-byte.

Adds regression tests: the editor renders Cyrillic/CJK tags as pills, and the
Go scanner extracts them.

* chore(release): prep v2.4.0 — version bump, green typecheck, packaging

- Bump all package versions 2.3.0 → 2.4.0.
- Fix the typecheck gate (was red, would fail CI build:prod):
  - Add RemoteServerClient.createExcalidraw — a real fix: creating a drawing
    while connected to a self-hosted server called a method that didn't exist.
  - Add the now-required `assetEmbeds` field to older NoteMeta test fixtures.
- release.yml: upload `*.tar.gz` so the AUR source asset is published (was built
  then dropped by the upload glob).
- Flatpak: add the 2.4.0 metainfo release entry and point the AppImage URL at
  v2.4.0 (sha256 pinned at release once the asset exists).

---------

Co-authored-by: Weslley Almeida <weslleyalmeida6@gmail.com>
Co-authored-by: Lund <59971256+Lund1337@users.noreply.github.com>
Co-authored-by: Victor Ribeiro <victruu@outlook.com>
Co-authored-by: Raihan Adam <hallwack.id@gmail.com>
Co-authored-by: Krysteq <justkrysteq@proton.me>
Co-authored-by: dannrs <danniramdhani@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish a plain Linux tar.gz for cleaner Arch packaging

2 participants