This branch establishes test scaffolding for rooms functionality across core and dashboard, adding test plans, room-specific test files for ChatView, AgentMentionPopup, QuickChatFAB, and core chat routes/stores, while also updating AgentMentionPopup with enhanced room-aware behavior and QuickChatFAB
Fusion-Task-Id: FN-3812
Merges FN-3884 chat scroll anchoring — ChatView now re-scrolls to the latest message when reopened or when activation transitions occur, with a bounded bottom-anchor helper preventing layout-shift overshoots. QuickChatFAB was updated to wire the new anchoring behavior, and both components gained com
Fusion-Task-Id: FN-3884
Added a `mentionMatching.ts` utility to normalize agent mention filtering across the codebase, fixing the handling of handles containing underscores. Updated `AgentMentionPopup`, `ChatView`, and `QuickChatFAB` to use the new utility, with corresponding tests added including a new `mentionMatching.te
Fusion-Task-Id: FN-3809
Chat UX improvements land first: bottom-snap scrolling behavior is wired into both `ChatView` and `QuickChatFAB`, with comprehensive test coverage added for the components and their underlying hooks; stale-closure bugs in the `useChat` and `useQuickChat` queue-flush handlers are also patched. Roadna
Fusion-Task-Id: FN-3771
The previous fix introduced a regression: handledMobileSendRef /
handledMobileActionRef was set in onPointerDown/onTouchStart but only
cleared in onClick. preventDefault() on pointer/touch events suppresses
the synthesized click on iOS Safari, so the ref stayed true forever
after the first tap — every subsequent tap (quick OR long press) hit
the new dedupe guard and silently bailed.
Now both handlers schedule a 500ms setTimeout to self-clear the ref
alongside their action. That covers the full pointerdown/touchstart/
click burst from one tap while still letting the next user tap go
through.
Applied to: ChatView send button, QuickChat send button, QuickChat
stop button.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The ChatView and QuickChat send/stop buttons each had both an
onPointerDown and an onTouchStart handler invoking the action. On a
quick mobile tap both fire, so handleSend / handleSendMessage /
stopStreaming ran twice in rapid succession. The second invocation
closed the first's SSE stream (streamRef.current.close()), the server
treated that as a cancel via beginGeneration, and the chat ended with
no output — exactly matching the reported "tap silently fails, long
press works" symptom (long press happened to suppress one of the two
events).
Both handlers now early-return when the existing handledMobile*Ref
flag is already set, so only the first event for a given tap fires the
action. The send button additionally gets touch-action: manipulation
(removes the click delay that lets the textarea blur win the race) and
an expanded invisible hit area via ::before so slightly-off taps don't
land on the surrounding textarea and dismiss the keyboard without
sending.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge implements FN-3603, adding jump-to-latest controls for the chat view and improving mobile bubble width layout, with corresponding CSS updates in ChatView and QuickChatFAB components. It also includes documentation for the new mobile chat controls, a fix for workspace lint regex escaping,
Fusion-Task-Id: FN-3603
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>
Merges FN-3244's three-step hardening of the mobile FAB drag path, adding regression tests and finalizing TypeScript typing. Includes FN-3296's tokenized typography for agent health reasons, FN-3014's documented recovery semantics for the research system, and related CLI/dashboard work that improves
Fusion-Task-Id: FN-3244
This merge lands v0.15.0 with two major features: a slash-triggered quick chat skill menu (FN-3119, 8 steps covering skill discovery state, trigger matcher, input wiring, skill menu rendering, styles, local help assistant, and tests) and plugin dashboard views (FN-3079, FN-3066) with dependency grap
Fusion-Task-Id: FN-3119
This merge lands v0.14.2, a release focused on plugin system improvements and UI refinements. The plugin SDK gains a new `plugin-loader` and `plugin-runner` module with cached contribution accessors, plus an event bridge overhaul in the Claude CLI integration. On the dashboard side, the agent log vi
Fusion-Task-Id: FN-3187
The merge adds a `/clear` command to both the Chat view and Quick Chat that clears transient chat state on session resets, with tests for all new hooks and components. It also persists session banner dismissals via a new `useSessionBannerPref` hook, adds a hide-banner setting, and preserves planning
Fusion-Task-Id: FN-3062
This merge completes the session-first quick chat FAB flow (Step 5), restores the quick chat hook after fixing a styling regression, and fixes heartbeat prompt composition for autonomous agents. It also adds the planning mode question display with new-session reset, introduces new Droid CLI settings
Fusion-Task-Id: FN-3058
The mobile QuickChat panel was unusable on iOS Safari: the input bar
rendered off-screen, the soft keyboard often did not open on FAB tap,
the panel slid up out of view on the second input focus, and the
header pill overflowed when the model name was long.
- The FAB JSX no longer emits inline right/bottom styles on mobile,
and the mobile media query pins every edge with !important so the
panel cannot be dragged off-screen by the desktop draggable hook.
- Body scroll is locked while the panel is open via overflow:hidden
on <html> and <body>, and the document is reset to scroll 0 on
open. This prevents iOS from leaking residual scroll into the
fixed-positioned panel between opens.
- An always-mounted, offscreen stealth input claims the iOS soft
keyboard inside the FAB click gesture (the real composer input is
initially `disabled` waiting for the chat session, and iOS will
not open the keyboard for a disabled input). Focus is transferred
synchronously to the real input once it becomes enabled.
- The composer input intercepts touchstart on mobile and re-focuses
with `preventScroll: true`, suppressing iOS's default focus-and-
scroll behavior that was shifting visualViewport.offsetTop and
sliding the panel up off-screen on a refocus.
- A useLayoutEffect mirrors visualViewport.height onto the panel as
--vv-height directly via the DOM, bypassing React state to avoid
the per-event reconciliation lag that read as visual jank during
the keyboard slide-in. On blur, the variable is cleared and a
short suppress window (~450ms) prevents iOS's mid-dismiss reports
from clobbering the regrowth, so the panel snaps back to full
height immediately while the keyboard finishes sliding down on
top of it.
- The model-tag pill in the header collapses to the provider icon
when the tag would otherwise exceed ~12 characters on mobile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge brings multiple substantial features: new research extension tools wired through the AI engine (with full test coverage and documentation), legacy routines agentId backward compatibility with migration paths, migration of experimental remote settings to the global scope, Nerd Font glyph a
Fusion-Task-Id: FN-2996
This merge adds an AgentLogViewer component, improves the NewAgentDialog and QuickChatFAB with mobile keyboard awareness and custom model dropdowns, and introduces insight tools in the CLI extension with tightened typing and comprehensive test coverage. The theme system receives enhancements in `use
Fusion-Task-Id: FN-3041
This merge adds research settings to the settings modal and dashboard (FN-2839, FN-3029), implements a dashboard font scale setting with persistence and documentation (FN-3027), refactors AgentDetailView with a new AgentLogViewer CSS module (FN-2839), and improves NewAgentDialog with custom model dr
Fusion-Task-Id: FN-3027
Workflow-step REVISE retries, pause→todo handoffs, and the
context-overflow fresh-session requeue were all routing tasks back to
`todo` before returning to `in-progress`. The default reopen-to-todo
path reset every step to pending and rewrote PROMPT.md checkboxes, so
each retry restarted from step 0 even when earlier steps had already
been done — the symptom seen on FN-2978, where every workflow REVISE
or pause cycle wiped the task's progress.
- Add `preserveResumeState` to `TaskStore.moveTask`. When set, skip
`resetAllStepsToPending` + `resetPromptCheckboxes` and keep
`worktree` and `executionStartedAt` so the resumed run reattaches to
the same checkout. `status`, `error`, and `blockedBy` still clear.
- Use it on the workflow-rerun bounce, the three pause-graceful
handoffs, and the context-overflow requeue. The agent-terminated
pause path still discards (it nukes worktree+branch by design).
- Context-overflow requeue clears `sessionFile` synchronously in the
awaited `updateTask` immediately before `moveTask`, so the next
dispatch cannot reopen the saturated session via a stale pointer.
- `fn_task_update` no longer silently regresses `done`/`skipped` steps
to `in-progress`, no longer captures a stale rewind checkpoint when
it does, and tells the agent honestly when a regression is ignored.
- Mobile chat keyboard: ChatView/QuickChatFAB gate layout on the new
`keyboardOpen` flag so focused-input + viewport-shrink iOS cases
still adjust when the computed overlap is zero.
Tests:
- New `preserveResumeState` coverage in store.test.ts; updated
workflow-rerun + pause-graceful assertions in executor.test.ts.
- Restructured the previously-flaky "routes exhausted prompt-mode
workflow hard failures" test to drive the bounce inline; passes in
isolation and in the wider workflow/pause/context sweep (59/59).
- Added regression tests in ChatView.test.tsx and QuickChatFAB.test.tsx
for the iOS last-resort `keyboardOpen=true, keyboardOverlap=0` case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each agent now gets its own .fusion/agents/<id>/HEARTBEAT.md procedure
file instead of sharing a single project-wide file. A one-shot
migration in AgentStore.init() re-points existing agents off the legacy
shared path and copies the legacy file's contents into each agent's
new per-agent location so operator edits are preserved.
The HeartbeatTriggerScheduler now phase-aligns the first tick to
lastHeartbeatAt + intervalMs so a process restart resumes each agent's
existing schedule rather than waiting up to a full interval before
firing again. Overdue ticks fire promptly within a small jitter window
to avoid a thundering herd at boot.
Also fixes three pre-existing QuickChatFAB test failures introduced by
739e899b5: auto-select default model now switches to model mode whether
or not agents are present, the model tag only renders in model mode,
and one test scopes its option lookup to role="option" to disambiguate
the in-header tag from the dropdown entry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Pre-select the global default (or first available) model on first open so
users can chat without manually picking from the dropdown.
- Bump specificity of the new-chat (+) button styles so the CTA bg/text
applies instead of being overridden by the header's .btn-icon rule.
- Focus the message input on panel open via rAF.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Inline grouped tool-call rendering in chat surfaces and update summary logic for clearer aggregation
- Refine chat, quick FAB, settings, and agents UI styles/behavior with matching test coverage updates
- Extend dashboard TUI state/controller flow with status and shortcut improvements
- Update engine and dashboard route handling related to agent runs, settings memory sync, and remote access adapters
Fusion-Task-Id: FN-2926
- Keep active streaming responses alive when resuming an existing quick chat session instead of resetting stream state
- Update useQuickChat session-resume logic to only restart waiting indicators when appropriate
- Adjust QuickChatFAB waiting indicator behavior so it reflects real in-flight assistant activity
- Add focused hook and component tests covering same-session resume and waiting-indicator regressions
Fusion-Task-Id: FN-2904
- Wire onRetryTask from App through Board/Column/WorktreeGroup/ListView into TaskCard
- Add a Retry button with loading/disabled state to failed task error boxes in TaskCard
- Update failed-card styles to use design tokens and add retry button visual states
- Add TaskCard tests covering retry visibility, callback invocation, loading, and error toast behavior
- Add a patch changeset for @runfusion/fusion documenting the dashboard retry shortcut
- Allow session initialization to retry when the same target key is selected but no active session exists
- Gate duplicate-init short-circuit behind activeSession/sessionsLoading so model-mode startup can recover
- Expand the effect dependency list to track session readiness inputs used by the retry guard
- Extend /models API responses to include optional defaultProvider/defaultModelId from global settings, including empty and error paths
- Update QuickChatFAB to prefer the configured default model on load and fall back to first-model selection only when no agents exist
- Move quick chat model tag/title-wrap inline styles into QuickChatFAB.css using dashboard design tokens
- Add QuickChatFAB tests covering default-model auto-selection with and without agents and legacy behavior when no default is configured
Update-check frequency (end-to-end)
- Add `updateCheckFrequency: "manual" | "on-startup" | "daily" | "weekly"`
to GlobalSettings (default: "daily").
- Backend `performUpdateCheck` honors the frequency: TTL = day/week,
`manual` returns cache or empty without hitting npm, `on-startup`
refreshes once per process lifetime then serves cache. `/refresh`
route forces network regardless.
- Settings → Updates surfaces a working `<select>` for the cadence,
disabled when auto-checks are off entirely.
- Tests: 4 new cases covering ttlForFrequency mapping, weekly window,
manual semantics, on-startup once-per-process behavior.
TUI update notice
- Read cached update result synchronously on TUI startup. When an
update is available, render a yellow notice line on the splash and
a colored ● next to the version in the status bar.
Settings modal header polish
- Add "Star on GitHub" pill (icon + Star + cached star count from the
GitHub API, 1h localStorage TTL) and "Help" button (opens project
Discussions). Both link to the Runfusion/Fusion repo.
- Star button auto-hides after the user clicks it (intent = star),
tracked in localStorage `fusion:github-star-clicked`.
- Settings → General gets a "Show Star on GitHub button" checkbox so
users can hide it preemptively. New global setting
`showGitHubStarButton: boolean` (default true) gates rendering.
More resizable modals
- Task Detail modal: 85vh default, resize: both, persisted via
useModalResizePersist (key `fusion:task-detail-modal-size`).
- Quick Chat FAB: full 8-direction resize (4 corners + 4 edges) via
pointer-event handlers; persisted to
`fusion:quick-chat-size-<projectId>`. Each handle has the right
cursor + role="separator" for accessibility.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add a shared useMobileKeyboard hook that tracks visualViewport overlap on mobile browsers
- Apply keyboard overlap CSS variables to QuickChatFAB so fullscreen mobile panels resize above the virtual keyboard
- Apply the same keyboard-aware sizing to ChatView mobile thread layout and auto-scroll messages when keyboard opens
- Expand ChatView, QuickChatFAB, and hook test coverage for mobile keyboard detection and viewport-resize behavior
- Remove generic btn btn-icon classes from quick chat render toggles so component-specific visibility styles apply
- Increase toggle icon size and adjust default muted color for clearer eye/eye-off affordance in assistant messages
- Add explicit focus-visible ring styling for keyboard accessibility on the render toggle control
- Extend QuickChatFAB regression coverage to assert class usage, SVG icon presence, and plain/rendered toggle state transitions
- Add panel resize state and pointer-driven drag handling to QuickChatFAB
- Wire resize behavior into component layout so desktop users can adjust panel dimensions
- Style resize handles and interaction affordances in QuickChatFAB.css
- Expand QuickChatFAB tests to cover resize lifecycle, constraints, and persistence behavior