· Version 0.2.4

Novelist 0.2.4 — image hosting and one-click publishing

Two new core features: upload local images in your Markdown to your image host of choice (Qiniu / OSS / S3·R2 / imgur / sm.ms / Custom), and publish the active document to Ghost / WordPress / Medium with one click. Plus a batch of daily-workflow polish.

0.2.4 is a major release. It finally pulls the last step of writing — getting the piece off your disk and onto the internet — into the editor. Local images in your Markdown can be uploaded straight to your own image host, and the finished document can be published to Ghost / WordPress / Medium without juggling four browser tabs.

Image hosting

Six built-in providers plus a minimal “Custom HTTP” endpoint:

  • Qiniu Kodo — HMAC-SHA1 upload-token, multipart POST
  • Aliyun OSS — HMAC-SHA1 header signature, virtual-hosted PUT
  • Amazon S3 — manual SigV4 path-style PUT (works with Cloudflare R2 and MinIO via endpoint override)
  • imgur — Client-ID Bearer
  • sm.ms — optional API token, with image_repeated dedup handling
  • Custom — multipart POST with optional Bearer; response URL read from url or data.url

Entry points:

  • Settings → Image Hosts panel: list, add/edit/delete, set active default; per-host Test button (uploads a 1×1 PNG to verify credentials without leaving noisy artifacts).
  • Right-click any inline image with a local path → Upload to host — replaces the Markdown URL in place.
  • Palette command Upload all local images: iterates the document’s image refs, uploads each sequentially, applies all URL replacements in a single CodeMirror transaction, reports partial failures via toast.
  • Optional auto-on-paste / auto-on-drop — off by default. When enabled, every pasted or dropped image immediately uploads to the active host.

For bucket-style hosts, object keys are date-prefixed automatically: {yyyy}/{mm}/{dd}/{8-char-blake3}-{sanitized-name}.{ext} — keeps the remote bucket organized and collision-free.

Credential safety: plaintext credentials live only in global settings. Per-project configs can only override the active-host pointer, so secrets never leak into project files that might be tracked by git.

One-click publishing

Four publish platforms, each as a self-contained adapter:

  • Ghost — Admin API key signed as a 5-min HS256 JWT, posts via ?source=html so we send HTML and Ghost converts to Lexical server-side
  • WordPress (self-hosted) — Application Passwords (HTTP Basic), full REST tag-name → ID resolution with auto-create, raw-body media upload
  • WordPress.com — OAuth2 personal access token (Bearer), same REST shape with a /sites/<id> prefix
  • Medium — legacy Integration Token Bearer; native Markdown body, max 3 tags. Note: Medium removed the Integration Token UI in late 2024; the API still accepts pre-existing tokens, but new users typically can’t generate one.

Entry points:

  • Top-right Share button in the editor → Upload Local Images to… + one Publish to entry per configured channel (mweb-style — single discoverable entry point).
  • Publish dialog with mweb-shaped fields: title (auto-prefilled from the document’s H1), tags (chip input), excerpt, slug (auto kebab-case), per-platform status dropdown, drag-drop cover image. Inline error on failure with retry; success banner with Open in browser.

Pre-publish image upload: local images in the body are uploaded to the publish target’s own media endpoint and rewritten in the submitted body. So publishing to Ghost doesn’t require a third-party CDN at all. If you’d rather everything route through your own image host, run Upload Local Images to… explicitly first.

No publish history tracking: every publish creates a new post. Republishing an edited document creates duplicates that you prune manually on the platform side; front-matter ID writeback is intentionally out of scope for 0.2.4.

Conversion path: Ghost / WordPress / WordPress.com use Pandoc Markdown → HTML; Medium consumes Markdown natively.

UX polish

  • Bilingual command palette — Cmd+Shift+P now shows the active-locale label large with the alternate-locale label as a small subscript below; the search matcher hits both. A Chinese-locale user can find Toggle Outline by typing either outline or 大纲.
  • Double-click to rename in the file tree — double-clicking a file row opens inline rename. Folders still toggle expansion. Rename input renders inline under the renamed node (used to render at the top of the sidebar).
  • Right-side panel shortcuts moved to Cmd+Shift+1/2/3/4 — outline, draft, snapshot, stats. Easier chord than Cmd+Alt. macOS users may need to disable system screenshot shortcuts (Cmd+Shift+3/4). Toggle-template stays on Cmd+Alt+5 (Cmd+Shift+5 is the macOS screenshot toolbar).
  • Drag files from the sidebar into a pane or split-right zone — while dragging, the editor area shows two drop overlays (active pane + right-edge “split right” gutter); dropping opens the file in that pane. Tab bars accept the same payload.
  • Wrap long file names — new Settings → Editor toggle keeps long file names on multiple lines instead of truncating to an ellipsis.
  • Edge-mounted sidebar toggle — collapse/reopen the sidebar from a small ◁ / ▷ button on the resize handle, in addition to the existing keyboard shortcut.
  • Editor max-width is a slider + numeric input (480–9999px) instead of a fixed dropdown.
  • Filename macros for new files{yyyy}, {mm}, {dd}, {HH}, {MM}, {ss} are expanded in the new-file template, with live previews under the setting.
  • Searchable Settings dialog — top filter narrows visible panels and rows by label, hint, or keyword (Chinese aliases included).
  • Publish dialog polish — paste-from-clipboard, Ghost tag autocomplete, redesigned pill-grid tag picker, native clipboard read, Test button that actually hits the platform, edit button + secret-reveal in credential rows, fully localized.
  • {title}-only filename template — the new-file template now accepts {title} without a {N} slot (renders Untitled.md, then Untitled 2.md, Untitled 3.md on collision; H1 auto-rename replaces the whole stem). Typo tokens like {cN} or {Title} are still rejected so a misspelt placeholder doesn’t silently become literal text.
  • Sort sidebar by creation timeCreated (newest) / Created (oldest) alongside the existing modified-time options. Filesystems without birth time fall back to mtime.
  • Command-palette shortcut chip uses the UI font — Apple modifier symbols (⇧⌘⌥⌃) match the stroke weight of the letter next to them.
  • Settings checkbox rows align with the first text line — the wrap-filenames row used to float above the baseline; it now lines up.
  • Sidebar folder right-click adds Expand All / Collapse All — recursive (whole subtree), lazy-loaded BFS expand; collapse keeps the child cache so re-expand is instant. The same items also appear in the empty-area sidebar menu (operates on project root).

Changed

  • Filename now follows the H1 heading on every save (was first-save only). Manually renaming a file detaches the sync. See spec docs/superpowers/specs/2026-05-12-h1-filename-ongoing-sync-design.md.
  • {title} in the new-file template implicitly opts in to H1 rename-on-save. The dedicated Sync filename with H1 on save checkbox is gone — its intent is now expressed by whether the template contains {title}. The shipped default (第{N}章-{title}) keeps the behavior on; remove {title} to opt out.
  • Sibling-aware new-file naming is always on. The Detect chapter pattern from folder checkbox is gone — inferNextName always reads the folder so {N} slots pick the next free number; templates without {N} are unaffected.

Fixed

  • Filename-macro tooltip (the ? next to the default-template field) opens rightward, so content no longer clips against the panel’s left edge.
  • Numeric sidebar sort orders 第九 < 第十 < 第十一, and no longer misplaces files whose Chinese number is followed by extra characters like 第十章终稿.md.
  • In-project search is now Unicode case-insensitive and emits UTF-16 offsets, so highlights land on the right glyphs for CJK and Latin-with-diacritic queries; empty queries short-circuit instead of scanning the project.
  • File watcher refreshes the right parent on rename/delete on Windows + macOS, emits a separate directory-changed event, polls every 15s as a fallback — no more ghost rows after a rename done in another window or by an external tool. .canvas and .kanban files now open via the same external open-file path as Markdown.
  • Plain folders without .novelist/project.toml stay global-scoped — previously the app tried to write view settings into folders it had no project file in.
  • Save (Cmd+S) on a clean tab still runs the H1 → file-name auto-rename check when no edits since the last save introduced a new H1.
  • External links open via tauri-plugin-shell instead of the default WebKit navigation, so they actually open in the system browser.
  • Pandoc auto-discovery + user override — no longer relies on the previously-bundled Pandoc binary; falls back to PATH probing with a manual override in Settings → Editor.

Security

  • Template zip import is now done via the zip crate (instead of shelling out to unzip), rejects symlinks, NUL bytes, path-traversal entries, and caps the archive at 2048 entries / 50 MiB uncompressed. Template ids are validated to [a-z0-9-]{1,96} before they reach the filesystem.
  • WebDAV sync validates remote file paths before downloading — absolute paths, .. components, and dotfile-prefixed components are rejected, so a hostile server can’t write above the project root.

Platform

  • macOS bundle declares CFBundleLocalizations for en and zh-Hans via the newly bundled core/Info.plist, so Chinese users get localized application menus and system dialogs.

Removed

  • Run Release Benchmark command — internal diagnostic, not user-facing. The regular performance benchmark stays available.
  • Settings → Editor → Sync filename with H1 on save checkbox — the gate moved to the filename template (use {title}). Stored auto_rename_from_h1 values in existing project configs are still parsed but no longer consulted.
  • Settings → Editor → Auto-detect chapter pattern from folder checkbox — sibling-aware naming is now unconditional.

Notes for developers

  • The tauri-specta codegen pipeline is currently broken upstream (specta-serde rejects skip_serializing_if on existing ProjectConfig fields). New IPC commands and types in 0.2.4 are patched into app/lib/ipc/commands.ts manually. The file remains @ts-nocheck so it’s type-safe at the consumer level. A follow-up release will restore auto-generation.
  • E2E coverage for the new image-host and publish UIs is deferred. Rust + frontend unit coverage is comprehensive (over 1500 tests total); manual smoke-testing covers the UI surfaces for 0.2.4.

Also

Download 0.2.4