Part of the fix for #735 — top-level folder creation invisible in
multi-workspace mode. The primary route, where the create-folder flow
ignored the sidebar selection and always wrote to the legacy
`resolvedPath`, is fixed in #728 (selection-aware routing in
`handleCreateFolder` and `FolderTree`). This commit fixes the
complementary state-machine bug: the vault switcher could leave
`vaultPath` pointing at an unmounted vault, so any consumer that still
reads `vaultPath` would operate on a vault the user no longer sees.
The vault switcher tracks two related paths:
- `defaultWorkspacePath` — the workspace the user is currently "on"
(used as the destination for new notes, the graph default, etc.).
- `vaultPath` — the active vault the switcher tracks; read by the file
watcher, folder/view reloaders, and the active-vault fallback in the
folder loader.
Unchecking a vault in the switcher previously re-routed only
`defaultWorkspacePath` to another mounted vault, leaving `vaultPath`
pointing at the just-unmounted vault. The two paths drifted apart and
every downstream consumer that read `vaultPath` operated on stale
state — for example the folder loader's active-vault fallback (when
enabled) would silently re-introduce the unmounted vault into the
sidebar, and the file watcher would keep listening to it.
`applyMountedChange` now also calls `onSwitchVault(nextPath)` when the
unmounted vault is the active one, mirroring the existing reroute for
`defaultWorkspacePath`. After the change `vaultPath` and mounted state
stay consistent for every consumer.
`applyMountedChange` is extracted from `VaultMenu.tsx` to a sibling
helper module (`vaultMenuMountedChange.ts`) so it can be unit-tested
directly without tripping `react-refresh/only-export-components`.
Tests:
- New `VaultMenu.applyMountedChange.test.ts` covers the four reroute
permutations (default+active, active only, default only, neither),
the bail-out when no alternative mounted vault exists, and the
remount no-op.
Fixes: https://github.com/refactoringhq/tolaria/issues/735
Related: https://github.com/refactoringhq/tolaria/pull/728
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tolaria's MCP server is pure ESM with only standard `node:fs|path|http|child_process`
imports and pure-JS dependencies, so Bun can execute it identically to Node.
Until now `find_node()` was the single entry point for spawning the WebSocket
bridge and writing external AI tool config — users with Bun but no Node would
hit "node not found in PATH or common install locations" and lose access to MCP
tools entirely.
Introduce `find_mcp_runtime()` which returns the first verifying runtime,
preferring Node 18+ when present and falling back to Bun 1+. The generic
PATH and login-shell lookup helpers (`find_on_path`, `find_in_user_shell`,
`lookup_command`, `lookup_paths`) are now parameterised by command name so
both runtimes share the same machinery. Bun candidates cover `~/.bun/bin/bun`,
mise/asdf/proto shims, Homebrew, and `%USERPROFILE%\.bun\bin\bun.exe` on
Windows. The Codex CLI and Windows .cmd-shim resolution paths keep using the
strict `find_node()` since they specifically need Node.
`spawn_ws_bridge_with_paths`, `mcp_config_snippet`, and `register_mcp` now
resolve through `find_mcp_runtime` so the runtime that gets registered into
`~/.claude.json`, `~/.gemini/settings.json`, `~/.cursor/mcp.json`, etc.
matches the one actually present on the machine.
Locale copy updated from "nodeRequirement" to "runtimeRequirement" across
all 15 catalogs to reflect "Node.js 18+ or Bun 1+".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port the useful dynamic-vault MCP direction from Domenico Lupinetti's proposal into the current mounted-workspace model.
Durable external MCP registration is now vault-neutral, Node MCP resolves active mounted vaults from explicit env or Tolaria vaults.json, and vault context includes root AGENTS.md instructions per active vault.
Based-on: https://github.com/refactoringhq/tolaria/pull/603
Co-authored-by: Domenico Lupinetti <domenico@translated.net>