Commit Graph

372 Commits

Author SHA1 Message Date
Fusion
9057421112 feat(FN-3091): add plugin view remount routing test coverage
Adds test coverage for plugin view remount routing behavior in the App component.

Fusion-Task-Id: FN-3091
2026-05-07 08:49:18 -07:00
Fusion
1a0124c5da feat(FN-3080): document graph navigation canonicalization in plugin authori
Adds documentation for graph navigation canonicalization (FN-3080) covering plugin authoring and dashboard usage, along with a changeset for the `@runfusion/fusion` package release.

Fusion-Task-Id: FN-3080
2026-05-06 22:59:51 -07:00
gsxdsm
c9bbd7d43e fix(dashboard): parse Codex reset_at as epoch ms or seconds
Codex returns weekly window reset_at in milliseconds in some cases,
which was being multiplied by 1000 and producing nonsensical reset
countdowns and pace calculations. Route through _parseResetTimestamp
so both formats work, and add a regression test.

Also tightens comments in useMobileKeyboard / ChatView around why
visualViewport scroll events skip offsetTop updates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 22:17:35 -07:00
Fusion
ad60886794 fix(FN-3624): harden mobile chat keyboard layout behavior
- Update ChatView keyboard spacer styling to keep viewport layout stable on mobile
- Adjust ChatView viewport handling logic to better align chat body with keyboard transitions
- Add ChatView regression tests covering mobile layout and keyboard interaction scenarios
- Add useMobileKeyboard hook tests to lock keyboard metric behavior and prevent regressions

Fusion-Task-Id: FN-3624
2026-05-06 21:55:22 -07:00
gsxdsm
8ec6c1086f Revert "fix(dashboard): lazy-init useMobileKeyboard so remount has no stale render"
This reverts commit 3f5d01f4d4.
2026-05-06 21:41:16 -07:00
gsxdsm
3f5d01f4d4 fix(dashboard): lazy-init useMobileKeyboard so remount has no stale render
When ChatView remounted (e.g. tab switch with keyboard still up), the
hook started with keyboardOpen=false and corrected itself only after
the effect ran. That single stale-state render briefly unhid the
executor status bar, which appeared as a blank pane covering half the
input box before the next state update settled it.

useState initializers now call getKeyboardMetrics() lazily on first
render so the very first paint already reflects the live keyboard
state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:38:50 -07:00
gsxdsm
9a35f4f006 fix(dashboard): add rAF stability poll for keyboard re-snapshot
Tab/page switches with the keyboard up sometimes still left the
chat-thread anchored wrong because the timed re-reads (50/200/500ms)
missed the actual settlement frame on slower devices.

updateWithTail now also kicks off a rAF poll that re-reads metrics
each frame until offsetTop is stable for 2 consecutive frames or 1.5s
elapses. Combined with the extended timed tail (now adds 1000/1500ms),
this should catch both fast and slow iOS settlement paths without
indefinite polling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:36:31 -07:00
Fusion
46f3ac2114 feat(FN-3618): surface provider icons in settings and dropdowns
Completes Step 3 of FN-3618 by surfacing AI provider icons throughout the Settings modal and model dropdowns, updating both the component styles and adding integration and unit tests to cover the new icon display behavior.

Fusion-Task-Id: FN-3618
2026-05-06 21:36:31 -07:00
gsxdsm
81e47e50eb fix(dashboard): re-snapshot keyboard metrics on focusin and page restore
Switching away from the chat view and back left the hook with stale
metrics — keyboardOpen was false at remount even though the system
keyboard was still visible, so the .chat-thread transform never
re-applied and the message list anchored too high. focusin and
synchronous reads also captured offsetTop mid-transition.

Adds a tail of delayed re-reads (50ms, 200ms, 500ms) on focusin,
visibilitychange, and pageshow so iOS has time to settle before the
final snapshot is taken.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:16:33 -07:00
gsxdsm
21b01f8f56 fix(dashboard): pin --vv-offset-top to resize/focus, ignore pan scrolls
iOS fires visualViewport scroll events at 60fps during a pan with the
keyboard up. Routing those through React state and into the .chat-thread
translateY(--vv-offset-top) transform amplified the pan into a visible
judder + ~300px shift + body background exposure.

useMobileKeyboard now uses two listeners: a full update (resize +
focusin/focusout) that re-snapshots all metrics including offsetTop, and
a scroll-only update that updates only height/keyboardOpen. offsetTop
is therefore frozen between keyboard open/close events — the transform
correctly compensates for iOS's initial visualViewport shift on focus
without following pan-time movement.

Restores the translateY anchor (so the thread isn't off-screen on
first focus) while keeping the swipe-jitter fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:58:04 -07:00
Fusion
d791fa90ab feat(FN-3608): update dashboard chat documentation
Updated the dashboard chat documentation in the user guide with a minor addition.

Fusion-Task-Id: FN-3608
2026-05-06 19:55:55 -07:00
Fusion
2140148fe2 feat(FN-3609): split TaskDetailModal tests into focused suites
This merge splits the monolithic TaskDetailModal test file into six focused test suites (rendering, attachments/tabs, definition/actions, inline-editing/integrations, models/progress/workflow, responsive/dependencies), adds a changeset for the test isolation baseline, fixes chat SSE optimistic echo

Fusion-Task-Id: FN-3609
2026-05-06 16:05:44 -07:00
gsxdsm
cd845d39be perf(merger): skip redundant in-merge verification and lockfile-stable installs
Two cuts to wasted work in the merge verification loop:

1. After the in-merge fix agent runs, fingerprint the working tree
   (`git diff HEAD` + `git status --porcelain`, sha256). If the post-fix
   fingerprint matches pre-fix and is non-empty, the agent didn't actually
   change anything — re-running the same failing command can only yield
   the same failure, so log and report the attempt as unsuccessful without
   paying the test/build cost. Empty fingerprints (snapshot tooling failed)
   fall through to the existing re-run path so we never silently swallow a
   real fix.

2. Inside `syncDependenciesForMerge`, hash the active lockfile and compare
   against `node_modules/.fusion-install-marker` (written after each
   successful install). When they match, skip `pnpm install
   --frozen-lockfile` even if `package.json` is staged. Covers the common
   case where `package.json` changes but the lockfile doesn't, and
   amortizes install across auto-recovery re-enqueues that hit the same
   worktree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 12:24:57 -07:00
gsxdsm
9087239078 chore(dashboard): drop dead reportDashboardPerf client and its log file
The /_perf/dashboard-load server route no longer exists, so every
reportDashboardPerf() call was a silently-swallowed 404. Remove the helper
in legacy.ts plus its five call sites in App.tsx / useProjects.ts (the
companion console.log lines stay), and drop the dashboard-perf.log entry
from the test-isolation runtime ignore list since nothing writes that file
anymore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 12:14:26 -07:00
Fusion
f499f10818 feat(FN-3564): isolate plugin loader test state to prevent cross-test conta
Refactored plugin-loader tests and implementation to isolate plugin test contamination, improving test independence in `@fusion/core`.

Fusion-Task-Id: FN-3564
2026-05-06 02:14:05 -07:00
gsxdsm
b312ca4122 fix(dashboard): null WebSocket handlers before close to stop terminal tab doubling
Creating a new terminal tab caused every pty data chunk (including
keystroke echo) to render twice in xterm. The connect-effect's
`contextChanged` dep flips true→false in the same render cycle as
the new connection: the effect re-runs, React calls cleanup which
closed the still-CONNECTING WS without nulling its handlers, then
connect() opens a fresh WS. The ghost socket's onmessage continued
firing on the shared `onDataCallbacksRef` Set, delivering each chunk
twice (and producing the "WebSocket is closed before the connection
is established" warning). Null onopen/onmessage/onclose/onerror in
both cleanup() and connect()'s pre-close branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 00:05:55 -07:00
Timothy Laurent
2746015fc7 test(dashboard): add regression tests for quick chat init fixes
Six new tests covering the three bugs fixed in the previous commit:

- Retry limit: stops showing toasts after 3 consecutive failures,
  resets counter on success
- Skip flag: startFreshSession sets/clears skipNextSessionInitRef,
  creates new session even when existing one exists
- Ref stability: switchSession reads activeSession from ref so it
  correctly detects "same session" and skips re-initialization

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 16:43:54 -07:00
Timothy Laurent
5e5b40079a fix(dashboard): prevent quick chat init race condition and infinite retry loop
Three interacting bugs caused "Failed to initialize chat" toast spam and
prevented fresh session creation:

1. Race condition in handleCreateFreshSession — setting chatMode/
   selectedAgentId before startFreshSession triggered the session-init
   useEffect, which called switchSession and resumed the old session
   instead of creating a new one. Fixed with skipNextSessionInitRef.

2. Infinite retry loop — shouldRetrySessionInit retried indefinitely
   when initializeSession failed, producing unbounded toast spam.
   Fixed with a 3-retry cap (initRetryCountRef).

3. Cascading re-renders — switchSession depended on activeSession in
   its closure, getting a new identity on every state change and
   re-triggering the consumer's useEffect. Fixed by reading
   activeSession from a ref instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 16:31:49 -07:00
Timothy Laurent
ac74cb0d6d feat(FN-002): enable browser back-button navigation within the SPA dashboard
Previously the back button left the dashboard page entirely because
useNavigationHistory was only enabled for mobile viewports. Now it's
enabled for all viewports — desktop and mobile — so the browser back
button dismisses modals and reverts view changes within the SPA.

Changes:
- Enable useNavigationHistory for desktop (enabled: true instead of enabled: isMobile)
- Remove all isMobile ? historyAwareHandler : plainHandler ternaries
- Always use navigation-aware handlers (openDetailTask, openSettingsWithNav, etc.)
- Update JSDoc to reflect desktop support
2026-05-05 15:06:17 -07:00
Fusion
0aef085f13 feat(FN-3368): tighten research view test coverage and resolve dashboard ty
This merge introduces an eval automation domain store with persistence schema and a plugin dashboard view registry (FN-3512/FN-3513), adds scheduled eval batch architecture documentation (FN-3388), and includes substantial test coverage for Research routes and hooks (FN-3368 steps 1-3). The branch a

Fusion-Task-Id: FN-3368
2026-05-05 13:05:57 -07:00
Fusion
d7880c66b0 feat(FN-3157): add plugin dashboard view registry with nav integration
Merged FN-3157 to add a plugin dashboard views system, including a plugin view registry with lazy loading, navigation integration for Header and MobileNavBar, a usePluginDashboardViews hook with cache and refetch support, and tests covering the no-loader path. Also added documentation in `docs/PLUGI

Fusion-Task-Id: FN-3157
2026-05-05 12:14:20 -07:00
gsxdsm
b4a2e7a486 feat(chat): unify QuickChat backend path and consolidate render toggle
Backend
- chat.ts now routes both regular chat and QuickChat through
  createResolvedAgentSession instead of branching to createFnAgent for
  the no-runtime-hint case. This removes the divergent path where
  pi-ai's cleanupSessionResources(sessionId) could tear down resources
  the next generation depends on.
- sendMessage's finally only disposes the agent if it still owns the
  activeGenerations slot. A newer generation that has pre-empted us
  cleans up its own agent in its own finally — disposing here would
  yank the underlying CLI process out from under it.
- __setCreateFnAgent test helper now mirrors its mock into the
  createResolvedAgentSession slot so existing test setups still work
  after the unification.

Frontend
- Extract createChatStreamHandlers (RAF coalescing, accumulators,
  tool-call dedup, fallback handling) — useChat and useQuickChat were
  duplicating ~85 LOC each. Both now compose the shared factory.
- Move shared chat types into chatTypes.ts. The hooks re-export them
  for backward compatibility with existing consumers.
- Removed per-message Markdown/plain-text eye toggles. A single
  thread-level toggle in the chat header now flips every assistant
  bubble (including the streaming one) between rendered Markdown and
  plain text.
- Model-only chats hide the per-message agent identity row entirely;
  the model name is already in the thread header.

Tests
- Updated ChatView tests to reflect the new render-toggle contract
  (single header toggle drives all bubbles) and the model-only avatar
  suppression.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 11:04:48 -07:00
gsxdsm
ba6666fe5f fix: planning modal full-screen height on mobile
Two related bugs left the Planning Mode modal stuck at partial height on
mobile. useModalResizePersist replayed desktop-saved pixel dimensions
that overrode the mobile 100dvh rule, and React reconciled removed CSS
custom properties to empty string rather than calling removeProperty(),
which on iOS Safari defeated the var() fallback after keyboard dismiss.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 07:44:56 -07:00
Fusion
9e2a8006b9 feat(FN-3430): preserve and consume final assistant done payload
This merge adds done-payload snapshot handling across the chat system (FN-3430), normalizing how final assistant messages are preserved and consumed in the dashboard hooks, plus it normalizes dashboard mailbox and user identity for inter-agent messaging (FN-3484) and introduces plugin workflow step

Fusion-Task-Id: FN-3430
2026-05-05 06:42:18 -07:00
Fusion
c5e680db76 feat(FN-3466): add mutation coverage for agent view refreshes
Adds deterministic split-pane refresh behavior to the Agents views (AgentsView and AgentDetailView), with comprehensive test coverage for the mutation refreshes in the detail pane and the agents hook.

Fusion-Task-Id: FN-3466
2026-05-05 06:32:33 -07:00
Fusion
cdb64e008d feat(FN-3432): document chat streaming recovery guarantees in architecture
Added documentation for chat streaming recovery guarantees to the architecture docs.

Fusion-Task-Id: FN-3432
2026-05-05 00:11:02 -07:00
Fusion
b45b4dd17a feat(FN-3315): add test coverage for archived insights in three test suites
Adds test coverage for archived insights across the core store, `InsightsView` component, and `useInsights` hook — 156 lines of new tests covering FN-3315.

Fusion-Task-Id: FN-3315
2026-05-04 23:47:26 -07:00
Fusion
025eb7b3ae feat(FN-3398): update desktop README with multi-project setup and troublesh
The merge lands Step 7 of FN-3398, adding documentation and delivery artifacts across the mobile and desktop packages with updated READMEs, mobile-specific docs, and architecture references.

Fusion-Task-Id: FN-3398
2026-05-04 22:17:10 -07:00
Fusion
a0c1e5b982 feat(FN-3459): enable tool mode for heartbeat agent sessions
This merge enables heartbeat agents to use coding sessions with tool access (FN-3459). It adds heartbeat session prompt tests, updates the heartbeat executor to support tool mode, modifies dashboard node components and hooks, and includes a fix for a typecheck regression. A changeset is included for

Fusion-Task-Id: FN-3459
2026-05-04 21:21:22 -07:00
Fusion
783d834b91 feat(FN-3381): add skill detail panel with readable badges to agent detail
Adds readable skill badges to the agent detail view with an interactive detail panel, along with corresponding tests and utility functions. A typecheck fix for the dashboard docker config is included.

Fusion-Task-Id: FN-3381
2026-05-04 21:21:22 -07:00
Fusion
fccec582f4 feat(FN-3260): document static slot-host rendering contract
Documents the static slot-host rendering contract in `docs/PLUGIN_AUTHORING.md`, clarifying how plugins should interact with the rendering system.

Fusion-Task-Id: FN-3260
2026-05-04 21:21:22 -07:00
Fusion
e3011e9aca feat(FN-3362): add node detail modal with docker config routes
This merge delivers three focused changes: fixes the Git Manager modal mobile overflow (FN-3367) with new CSS, stabilizes the Docker config modal recreate indicator tests (FN-3114) with comprehensive new test coverage, and adds hook baseline cleanup tests (FN-3362). The changes span the core databas

Fusion-Task-Id: FN-3362
2026-05-04 19:17:16 -07:00
Fusion
8f0f9257ed feat(FN-3114): stabilize docker config modal recreate indicator test
The merge stabilizes a test case in the NodeDetailModal test file related to the docker config modal's recreate indicator, correcting an assertion that was causing intermittent failures.

Fusion-Task-Id: FN-3114
2026-05-04 19:05:48 -07:00
Fusion
cba93d0924 feat(FN-3264): add droid plugin, improve agent detail view, and fix researc
This merge adds Agent Detail view improvements including model favoriting, wires in the droid bundled plugin, updates mobile split layout with proper safe-area padding, and adds research task-view persistence with associated test coverage across Header, MobileNavBar, App, and view state hooks.

Fusion-Task-Id: FN-3264
2026-05-04 09:20:07 -07:00
Fusion
0237607d81 feat(FN-3014): document research recovery semantics
Documents research recovery semantics in the CLI reference and settings reference, adding 9 lines of documentation across both files.

Fusion-Task-Id: FN-3014
2026-05-04 09:20:07 -07:00
gsxdsm
986a928fa9 fix(dashboard): forward removeDependencyReferences flag in deleteTask
useTasks.deleteTask had a single-arg signature and dropped the options
object, so the modal's "remove dependency references" confirmation
flag never reached the API and deletion still failed with
TASK_HAS_DEPENDENTS. Forward options through the hook and widen the
matching taskOperations.deleteTask type in AppModals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 06:49:05 -07:00
Fusion
cc5c8c668b feat(FN-3112): tokenize NodesView border-radius and motion styles
Fixes FN-3112: Updates NodesView CSS to use tokenized border-radius and transition values from the design system instead of hardcoded pixel values, ensuring consistency with the dashboard's established token variables.

Fusion-Task-Id: FN-3112
2026-05-04 06:12:12 -07:00
Fusion
e9fcf3697d feat(FN-3344): preserve history state in deep-link close
Fixes deep-link close to preserve browser history state and adds comprehensive integration tests for the navigation history feature, covering App component and useDeepLink hook behavior.

Fusion-Task-Id: FN-3344
2026-05-04 02:23:04 -07:00
gsxdsm
bacc103e4e fix(FN-XXX): unify codex auth and chat fallback 2026-05-03 23:08:05 -07:00
Fusion
df21a4cc51 feat(FN-3344): add navigation history hook unit and integration tests
Merged test(FN-3344): added comprehensive unit and integration tests for the navigation history hook, covering 470 lines of test coverage across navigation state management, history tracking, and edge cases.

Fusion-Task-Id: FN-3344
2026-05-03 20:37:12 -07:00
gsxdsm
24528051f3 fix(dashboard): always restore scroll to 0 in useMobileScrollLock cleanup
When App-level activation triggers the lock from an input gaining focus,
iOS may have already scrolled the document by the time the lock effect
runs. Capturing that already-shifted scrollY and restoring it on release
left the dashboard pushed up after the keyboard dismissed (the inline-
edit case). Always snap to 0 instead — the dashboard has body{overflow:
hidden} so user-initiated scroll is always 0 anyway, and any non-zero
value at lock time is iOS-forced and should be reset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:45:18 -07:00
gsxdsm
e4572ef9ce fix(dashboard): treat keyboard as closed on blur instead of waiting for vv settle
useMobileKeyboard now requires a focused input for keyboardOpen=true (both
the chrome-overlap and iOS-gap paths). The moment an input blurs, the hook
reports keyboardOpen=false instead of waiting hundreds of ms for iOS's
visualViewport dismissal animation to settle.

This makes App-level mobileKeyboardOpen flip false instantly on blur, so
MobileNavBar reappears and project-content regains nav-bar padding in the
same frame. The ChatView composer (and TodoModal/PlanningModeModal) snap
to their post-keyboard layout in one move instead of crawling down with
iOS's keyboard slide.

Replaces the per-component 450ms suppress hack in ChatView (also dropped
in this commit) which couldn't reach the parent layout's nav padding
state and produced "below tab bar then snap up" jitter.

Adds a regression test and updates four existing tests that assumed
"vv shrinks → keyboard up" without focus (focus is now required).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:34:28 -07:00
gsxdsm
08aa64e314 fix(dashboard): mobile keyboard scroll lock, auto-reload hash, ChatView snap
- Add useMobileScrollLock hook using position:fixed body lock (Bootstrap/
  Headless UI/Stripe pattern) to prevent iOS Safari from shifting the
  document and visualViewport when an input inside a fixed-position modal
  is focused. Wire into 15 input-bearing modals plus ChatView, replacing
  ChatView's inline body-overflow effect.
- Widen computeBuildVersion in vite.config.ts to hash the entire app/ tree
  so the version-check poll actually notices rebuilds (FN-3333 follow-up;
  previously only main.tsx and package.json were hashed).
- ChatView: on input blur, suppress keyboard-aware sizing for 450ms while
  reserving mobile-nav-bar space, so the composer snaps to its final
  height in one move instead of crawling down with iOS's keyboard slide
  and then jumping again when the nav bar reappears.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 19:01:10 -07:00
Fusion
ba893b82bf feat(FN-3336): recover chat isGenerating state on session load to prevent U
Merges FN-3336 to recover chat streaming state on page reload — adds `isGenerating()` and `getGeneratingSessionIds()` to `ChatManager`, enriches the session API to surface active-streaming sessions, and makes `useChat` and `useQuickChat` hooks restore the `isGenerating` flag when loading existing se

Fusion-Task-Id: FN-3336
2026-05-03 16:51:01 -07:00
Fusion
6724cf5f19 feat(FN-3334): add auto-reload setting and fix worktree project resolution
Merged two features: FN-3334 introduces a new `autoReloadOnVersionChange` setting with a toggle in the Settings modal, version-check logic in the dashboard, and corresponding tests; FN-3335 fixes worktree project root resolution in `createFnAgent` and the skill resolver, with tests for both paths. S

Fusion-Task-Id: FN-3334
2026-05-03 16:26:47 -07:00
Fusion
0568d5d41b feat(FN-3110): add docker provisioning service, API routes, and status UI c
Merges FN-3110 to add Docker provisioning support across the stack: TypeScript types and DockerProvisioningService in core, API routes in dashboard for provisioning operations, a useDockerProvisioning hook for frontend integration, and a DockerProvisioningStatus UI component — all covered by unit an

Fusion-Task-Id: FN-3110
2026-05-03 14:10:11 -07:00
Fusion
b9b5c0873c feat(FN-3290): add changeset for modal keyboard isolation fix
Adds a patch changeset for FN-3290 documenting the modal keyboard isolation fix, ensuring the change is captured in the release changelog.

Fusion-Task-Id: FN-3290
2026-05-03 12:51:22 -07:00
Fusion
7f3fb7799d feat(FN-2999): harden research lifecycle with idempotent cancel/retry, SSE
Merges FN-2999 research hardening (idempotent cancel/retry routes, aligned SSE event wiring, and cleaned status handling in the core research store and orchestrator) plus UI improvements to AgentDetailView header actions and planning disclosure UX in the modal, with a CSS token fallback fix in Scrip

Fusion-Task-Id: FN-2999
2026-05-03 09:11:04 -07:00
Fusion
fca870f4f5 feat(FN-3109): add Docker connectivity service and target selector UI
This merge adds Docker connectivity management to Fusion (FN-3109), introducing a Docker client service in `@fusion/core` with typed interfaces for daemon connection configuration (host, socket path, TLS). The dashboard gains a `DockerTargetSelector` component for choosing between local socket and T

Fusion-Task-Id: FN-3109
2026-05-03 07:47:45 -07:00
Fusion
cc6c9abe61 feat(FN-3212): remove runtime memory-backend side-load, add regression test
Merged FN-3207, FN-3212, and FN-3242: removed runtime memory-backend side-loading in core, added comprehensive regression tests for QuickChat, chat routes, and SSE streams, and documented compact mobile chat dialogs in the dashboard guide. The refactor in `project-memory.ts` reduces complexity while

Fusion-Task-Id: FN-3212
2026-05-03 07:37:03 -07:00