Skip to content

v0.9.2 — Plugin peer dep fix + Firestore remote-host phase 2

Choose a tag to compare

@isamu isamu released this 02 Jul 06:04
db34062

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 /switch and HTTP /connect — bridge chat sessions no longer lose their role when reconnected (#1893, #1895, #1905).
  • Wiki engine extracted into @mulmoclaude/core/wiki so mulmoclaude, mulmoserver, and downstream tools share one implementation (#1875, #1876).
  • New CI gate — the launcher's package.json, the root package.json, and every plugin's peerDependencies are 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 their gui-chat-protocol peer dep from ^0.3.0 to ^0.4.0 with 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:
    1. root package.json and launcher package.json common deps have identical version ranges,
    2. launcher @mulmoclaude/* / @mulmobridge/* ranges satisfy the workspace source version,
    3. bundle-target plugin peerDependencies are satisfied by the launcher's pins (the #1920 class of bug).
  • Skill hardening (#1924) — publish-mulmoclaude now 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) — listCollections handler + 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 as getCollection (a feed is a LoadedCollection), 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; limit is clamped to [1, 200] (default 50).
  • startChat handler (#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 ```mermaid in 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 &lt;foo&gt;; 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.
  • /switch preserves session role (#1893, tracking #1888) — reconnecting an existing chat via /switch no longer resets its role to the default.
  • HTTP /connect resolves 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.
  • /connect rejects unsafe chatSessionId (#1905) — defense-in-depth follow-up to #1895 — early reject at the handler entry point with a matching test.
  • chat-index summaries 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_DIR sourced from WORKSPACE_DIRS (#1903, tracking #1902) — one single source of truth for the chat directory path.

Collections

  • Canonical dataPath threaded into ingest + action seed prompts (#1897, tracking #1891) — action templates and ingest steps now receive the collection's canonical dataPath instead 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-mulmoclaude skill 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.