Added the e2e tests I should have shipped with v0.5.2. Two Playwright specs exercise the drag-and-drop reorganization end-to-end: one drags a page onto a folder header, verifies both the file moves on disk AND the sidebar link href updates (watcher → refresh); the other drags into the root drop zone from root, verifies zero server calls (correct no-op). Both pass. 6/6 e2e overall.
Cursor feedback on draggable items: `cursor-grab` on hover, `cursor-grabbing` while actively dragging. Fixes the "it doesn't look draggable" feel — there was no visual cue that sidebar pages were pickupable.
v0.5.2Apr 21, 2026
Drag-and-drop page reorganization in the sidebar. Grab any page and drop it on a folder header to move it there. A "drop to move to root" zone appears at the top while you're dragging. Uses @dnd-kit (keyboard accessibility baked in — space to pick up, arrows to navigate, space again to drop).
New backend action type: `move`. Renames the .md file on disk (with cross-device fallback), refuses to clobber an existing destination, returns 404 if the source is missing. Covered by 5 new unit tests.
The UI piece was drafted by Gemini 3 Pro — drag-and-drop has enough edge cases (collision detection, keyboard coords, pointer activation distance to not block clicks) that it pays to hand that specific task to a model that's tuned for spatial React code.
v0.5.1Apr 21, 2026
Fix: sidebar now refreshes when a page is renamed/edited. ContentWatcher was skipping router.refresh() on /w/* routes to avoid stomping WikiView's state — but that also meant the layout (which renders the sidebar) never re-ran. Now it always calls router.refresh() AND dispatches the custom event; client views preserve their state, server trees pick up fresh data.
Action card rewrite: the terse "EDIT test +27 −2" is gone. Every tool call now includes a required `description` field — one plain-English sentence like "Rewrite the intro as a satire" or "Split Examples into its own page". That's the card's primary label; verb + slug + diff counts fall to a secondary metadata line.
System prompt updated to enforce descriptions. Cards are now scannable — you can tell three stacked edit proposals apart at a glance.
v0.5.0Apr 21, 2026
Architectural fix: wiki pages now render client-side. Was a Next.js server component going through ten cache layers (wiki cache, RSC cache, route cache, HTTP response cache, Chromium memory cache). Now it's a thin React component that fetches /api/page/:slug on mount and re-fetches on any file-watcher event. React re-renders in place. No reload, no navigation, no caches to invalidate.
After an AI Apply, the page updates instantly — the write is immediately visible with zero round-trip through Next's rendering pipeline. The entire class of "apply doesn't refresh" bugs is now structurally impossible.
Unified content-change signal: one custom window event (`mindos:content-changed`) carries the notification across all sources — Electron's chokidar watcher via IPC in packaged builds, the SSE dev watcher in browser preview. Client views subscribe once and react regardless of environment.
Manual refresh button now calls the WikiView's refetch directly (cheaper, cleaner) instead of a full document reload. Still falls back to reloadIgnoringCache when there's no view handler.
Playwright e2e suite passes 4/4 against the new architecture — including the specific scenario of "apply happens, no user-initiated reload, verify new content is visible within seconds".
v0.4.1Apr 21, 2026
Fix the apply-stays-stale bug at the actual root: the wiki cache is now invalidated BEFORE the disk write, not after. Previously the file watcher fired on the write, triggered a renderer reload, and that reload hit Next.js while the cache still held the old pages. Plus an optimistic client-side DOM swap for same-page edits — you see the new content instantly, no waiting for the server to re-render.
Stop button: while the AI is streaming, the Send button turns into a red Stop. Clicking aborts the in-flight request immediately (AbortController was already wired; just needed UI).
Model autocomplete from the provider itself: OpenRouter's 300+ model catalog is fetched from their /models API on mount, Ollama's locally-installed models come from /api/tags. You can type or pick anything; curated shortlist still surfaces at the top.
Manual refresh button in the page header (circular arrow next to the breadcrumb). Escape hatch when every other refresh path fails — forces a cache-busting reload.
v0.4.0Apr 21, 2026
Architectural: AI edits now use provider-native tool calls (edit_page, create_page, delete_page) instead of regex-parsed ```action fences. Claude 4.6/4.7, GPT-5, Gemini 3, and Ollama (gemma4:26b, qwen3-max) all support tools natively — the model sends structured JSON, we dispatch it directly. No more truncation mid-fence, no more hallucinated slugs: the schema constrains the call shape at the provider level.
Backward compatible: if a model still emits ```action blocks (older local models, non-tool-capable providers), the fence parser keeps working as a fallback alongside the tool-call path.
System prompt rewritten: shorter, instructs tools as the primary surface, mentions action-fences only as a "last resort".
Tests: 11 new cases for lib/tools.ts (parseToolCall, wire-shape conversions, ParsedAction bridge). 50 total pass.
v0.3.6Apr 21, 2026
The AI now gets an explicit list of pages that actually exist on disk in its system prompt — it stops proposing edits to pages that were never written (e.g. after a truncated create).
"page not found" on Apply is now recoverable: the review pane header shows a Create instead button when an edit lands on a missing slug. One click converts the action to create and applies it.
Page list auto-refreshes on any content change (file watcher event), so the AI stays grounded even after you reorganize your folder.
v0.3.5Apr 21, 2026
Fix: action cards no longer stuck on "streaming…" forever when the model ends mid-fence (context limit, network drop, Ollama stall). The chat now threads a live-streaming flag into each card: still coming in → pulsing "streaming…"; stream ended without a closing fence → red "truncated" tag. Review stays disabled in either case so you never apply a half-finished body.
Parser tests: four new coverage cases including end-of-stream without a trailing newline, a truncated header-only block, and a mixed finished+truncated pair. 39 tests pass (+4).
v0.3.4Apr 21, 2026
Fix: Apply now always shows the new content. location.reload() was getting served a stale response by an upstream cache for some users; switched to a cache-busting URL (?t=timestamp) that Chromium treats as a fresh navigation.
Motion: after Apply, the article now fades up + a thin accent bar sweeps left-to-right across the top of the page, so you see the swap happen instead of wondering if anything changed.
Action cards now show a diff summary next to the slug (+12 −3, etc.) — three "EDIT test" cards stacked in the chat are finally distinguishable at a glance.
Action cards animate in (gentle fade-up, 180ms) when the AI emits them, feels less like a paste.
v0.3.3Apr 21, 2026
Chat accepts images. Click the paperclip, drag-drop onto the chat panel, or just paste from clipboard. Up to 8 images per message (8 MB each), shown as thumbnails above the input with individual ✕ remove buttons.
Images are routed per-provider as multimodal content: inline base64 parts for Gemini (AI Studio), image_url parts for OpenRouter (works with Claude, GPT-5, Gemini 3 Pro, any vision-capable model), and Ollama's native images[] field (works with qwen3-max, gemma4, llava variants).
In-message thumbnails stay in the conversation afterwards so you can scroll back and see what you asked about.
Chat history persisted to localStorage drops images — only kept in-memory for the current session — to stay within the browser's 5 MB quota.
v0.3.2Apr 21, 2026
Fix (for real this time): Apply on an AI edit now reloads the page — v0.3.1 was using location.href = current path, which is a no-op in Chromium when the URL doesn't change. Swapped to location.reload() for edits; create still navigates to the new slug, delete goes home.
Action cards latch once resolved: after Apply or Discard, the card stays as "✓ Applied" / "Discarded" instead of re-offering the Review button on re-renders.
Chat panel is now a side-by-side column (Linear / Cursor style), not a fixed overlay. Opening it reflows the page into the remaining width; closing animates it to zero. No more content hidden under the chat.
Page area now scrolls internally inside <main> rather than the whole document. Sticky sidebar stays truly sticky.
Fix: AI configuration (provider, model, chat history, sidebar collapse state, theme / language) no longer resets on every launch. Root cause was the dynamic port — localStorage is origin-scoped and the port is part of the origin, so a new port each launch meant a new origin and empty storage. Now binds a stable port (50645) with fallback to a free one only on conflict.
Live file watcher: any .md file added, changed, or removed inside your content folder — by MindOS, vim, iCloud sync, git pull, whatever — reloads the current view within ~200ms. External edits no longer require an app restart.
Fix: applying an AI edit now always shows the result (was stuck on stale content in v0.3.0 due to a router-refresh quirk). Apply triggers an explicit re-navigation, and the file watcher belts-and-braces the refresh.
v0.3.0Apr 21, 2026
New AI review pane: clicking "Review →" on an edit/create/delete card swaps the document area for a full-width diff view (GitHub PR style). Chat stays pinned to the right — the page fades underneath.
Diff rendering: hunk-based with ±3 context lines, old/new line numbers, and word-level highlighting inside changed lines (you see the exact bytes that moved).
For `create` actions the pane renders the new page's markdown preview. For `delete`, the current page with a red overlay + where it's going in `.trash/`.
Keyboard: <kbd>a</kbd> apply · <kbd>d</kbd> discard · <kbd>esc</kbd> back. Apply animates with a brief green flush before closing.
Chat's action card is now compact — one line with the slug and a "Review →" button. Apply/Discard moved to the pane header so there's only ever one surface to act on.
v0.2.4Apr 20, 2026
Fix: auto-updater now actually works. The electron-updater package was missing from the bundle in v0.2.0 → v0.2.3, so "Check again" was silently doing nothing. It's properly in dependencies now and included in the ASAR. This is the one manual re-download — every release from here lands by itself.
Hardened the updater load path: if the dep is ever missing again, the UI shows an error state instead of staying stuck on "Up to date".
v0.2.3Apr 20, 2026
Sidebar reshuffled (Linear-style): removed the redundant "MindOS" header (window title already says it), footer becomes three stacked rows — big "+ New page" with ⌘N, search with ⌘K, then a compact icon strip (update dot · settings · reveal in Finder) with the page count.
New ⌘N shortcut opens the New page modal from anywhere.
Update dot becomes icon-only (hover / popover for details), matching the rest of the footer icon strip.
v0.2.2Apr 20, 2026
Fix: the Next.js server subprocess no longer shows as a separate "exec" tile in the macOS Dock. Switched from spawn(process.execPath) to Electron's utilityProcess.fork, which uses the Helper binary (LSUIElement: true).
v0.2.1Apr 20, 2026
Updater UX polish: amber dot for "update available", emerald for "ready to restart". Release notes render inline in both the toast and the sidebar popover.
Toast remembers dismissals per (state, version) — dismissing the "available" prompt doesn't suppress the later "ready to restart" one.
Trimmed the sidebar header (removed the "your mind in markdown" tagline — it's already in the window title).
Model suggestions refreshed: Qwen 3 Max + Qwen 3 Coder added on Ollama and OpenRouter. Claude Sonnet 4.6 is the default on OpenRouter.
v0.2.0Apr 20, 2026
Auto-updates — MindOS now polls for new releases in the background and offers Restart when one is ready. No more manual re-downloads.
API keys moved to Keychain (macOS) / libsecret (Linux). Previous localStorage keys are migrated on first launch, then wiped.