v0.9.2 — Plugin peer dep fix + Firestore remote-host phase 2
Highlights
- Critical fix for fresh installs on Windows — bundled plugins now load instead of being silently dropped at handshake (#1920 / #1921).
- Mobile remote channel (phase 1 + 2) — a mobile app can now list a workspace's collections, browse records with pagination, view feeds and pinned shortcuts, and start a chat via a Firestore command channel (#1909, #1914, #1918, #1922).
- Share as zip (phase 1–3) — download any HTML artifact, markdown page, or wiki page as a self-contained zip with all referenced assets inlined (#1892, #1901, #1907, #1910).
- Mermaid diagrams inside markdown now render as diagrams instead of raw code fences (#1906).
- Session role continuity across
/switchand HTTP/connect— bridge chat sessions no longer lose their role when reconnected (#1893, #1895, #1905). - Wiki engine extracted into
@mulmoclaude/core/wikiso mulmoclaude, mulmoserver, and downstream tools share one implementation (#1875, #1876). - New CI gate — the launcher's
package.json, the rootpackage.json, and every plugin'speerDependenciesare now checked for drift on every PR (#1923).
📦 npm: mulmoclaude@0.9.2
📖 Full changelog: docs/CHANGELOG.md
Fixes #1920.
Bundled npm launcher — critical fix for fresh installs
mulmoclaude@0.9.1 pinned gui-chat-protocol@0.4.0 in the launcher, but the bundled form-plugin, markdown-plugin, and spotify-plugin still declared peerDependencies.gui-chat-protocol: ^0.3.0. npm papered over the conflict with a silent ERESOLVE overriding peer dependency override — then the plugins failed their runtime handshake against the newer protocol and were dropped from the registered plugin set entirely.
Most visibly on Windows 11: fresh installs surfaced [plugins/preset] loaded requested=4 succeeded=1 at startup, followed by mcp__mulmoclaude__handlePermission not found at runtime. Waiting after startup did not help (this was distinct from the previously-fixed tools/list race in #1712).
Changes:
- All 8 workspace plugins (
form,markdown,spotify,email,recipe-book,bookmarks,debug,edgar) bumped theirgui-chat-protocolpeer dep from^0.3.0to^0.4.0with a patch bump. - The launcher (
packages/mulmoclaude) updated its@mulmoclaude/*deps to the new plugin versions. - New CI gate (#1923) enforces three invariants on every PR:
- root
package.jsonand launcherpackage.jsoncommon deps have identical version ranges, - launcher
@mulmoclaude/*/@mulmobridge/*ranges satisfy the workspace source version, - bundle-target plugin
peerDependenciesare satisfied by the launcher's pins (the #1920 class of bug).
- root
- Skill hardening (#1924) —
publish-mulmoclaudenow pins the public npm registry explicitly.
Massive thanks to @drippinghydrangea-a11y for the extremely detailed reproduction, including the npm view output that pinpointed the peer-dep gap — that report cut the diagnosis time from days to hours.
Tracking: #1920. PRs: #1921, #1923, #1924.
Mobile remote — Firestore command channel (phase 1 + 2)
A companion mobile app (mulmoserver) can now connect to a MulmoClaude workspace and drive it via a command channel that runs over Firestore. Commands live under users/{uid}/hosts/mulmoclaude/commands and are isolated per user by the standard request.auth.uid == uid rule.
- Phase 1a (#1909) — login UI, presence heartbeat (60 s), and the host runner lifecycle (
connect/disconnect, atomic status transitions, listener death → offline reconciliation). - Phase 1b (#1914) —
listCollectionshandler + popover auto-close on connect / disconnect. - Phase 2 — data handlers (#1918) — read-only, paginated handlers so the mobile remote can render a workspace on a phone:
getCollection(slug, offset?, limit?)→ collection detail + a page of records + total.getFeed(slug, offset?, limit?)→ same shape asgetCollection(a feed is aLoadedCollection), so the mobile UI reuses one card renderer.listShortcuts()→ the user's pinned launcher shortcuts.listFeeds()→ feed registry with retrieval kind / schedule / last-fetch time.
- Pagination is mandatory because Firestore caps a single command document at 1 MiB;
limitis clamped to[1, 200](default 50). startChathandler (#1922) — the mobile remote can start a chat session, targeting either a collection or a specific record. Rejects unknown slugs before spawning; refuses feeds (no slash-command surface); validates slug / itemId as whitespace-free string tokens.
Share as zip (phase 1–3)
Any HTML artifact / markdown page / wiki page can now be downloaded as a self-contained zip with every referenced asset inlined — no more "broken link on the recipient's machine."
- Phase 1 (#1892) — bundle an HTML artifact + its assets (images, CSS, JS) into one zip.
- Phase 1b (#1901) — Download (zip) button in the HTML view.
- Phase 1c (#1907) — Download (zip) in the file-explorer HTML preview.
- Phase 3 (#1910) — markdown pages and wiki pages export as self-contained HTML zips, so a shared markdown note travels with its images and diagrams intact.
Markdown & Mermaid
- Mermaid fenced blocks now render as diagrams (#1906, tracking #1904) — writing
```mermaidin any markdown-rendered surface (chat, wiki, markdown plugin) draws the diagram instead of showing raw source. - Quoted labels + HTML in SVG labels (#1917, tracking #1916) — fixed a double-encoding bug that made
<foo>in Mermaid labels arrive at the renderer as<foo>; also unlocked HTML fragments inside labels for richer diagrams.
Wiki engine extracted into shared core
#1875 extracted the pure wiki engine (parse, link resolution, backlinks, snapshot policy) into @mulmoclaude/core/wiki. #1876 followed up by extracting the fs / YAML server read-engine into @mulmoclaude/core/wiki/server. mulmoclaude, mulmoserver, and any downstream tool now consume one implementation instead of duplicating it — future wiki features land in one place and every consumer picks them up.
Sessions & chat
- Bridge chat turns serialize per external chat (#1879, tracking #1878) — two rapid messages from the same external chat no longer race each other into the same session.
/switchpreserves session role (#1893, tracking #1888) — reconnecting an existing chat via/switchno longer resets its role to the default.- HTTP
/connectresolves target session's role (#1895, tracking #1894) — when a bridge reconnects a chat by session ID, the role is looked up server-side instead of being redeclared client-side. /connectrejects unsafechatSessionId(#1905) — defense-in-depth follow-up to #1895 — early reject at the handler entry point with a matching test.chat-indexsummaries use Sonnet with a wider input window (#1884) — better summaries for long chats.- Session query counter + "long-running 24 h+" filter (#1885) — a per-user query counter and a filter to isolate multi-day sessions from the picker.
- Exclude scheduler sessions from long-running filter (#1887, tracking #1886) — background scheduler-triggered sessions no longer clutter the long-running view.
CHAT_DIRsourced fromWORKSPACE_DIRS(#1903, tracking #1902) — one single source of truth for the chat directory path.
Collections
- Canonical
dataPaththreaded into ingest + action seed prompts (#1897, tracking #1891) — action templates and ingest steps now receive the collection's canonicaldataPathinstead of re-deriving it, with cross-platform (Windows POSIX) + ReDoS defenses in the sanitiser.
Accounting
- Any month-end can be the fiscal year end (#1890) — previously locked to quarter-end months; now any month.
CI, docs, and housekeeping
- Duplicate close-comments on auto-triaged PRs suppressed (#1871, follow-up to #1869).
publish-mulmoclaudeskill pins the public npm registry (#1924) — avoids install-time picking up a scope-override registry.- Routine dependency + tooling updates: #1872, #1873, #1877, #1919.
Known cosmetic issue
npx mulmoclaude@0.9.2 --version will print mulmoclaude 0.9.1 — the version string was hardcoded in bin/mulmoclaude.js at build time. The actual package is 0.9.2 (all runtime behaviour is correct). #1925 makes the CLI read the version from package.json at runtime so the two can never drift again; the next release will pick it up.