`notice` is `events.find(...)` which returns `undefined` (not `null`)
when no match. `waitFor(() => expect(...).not.toBeNull())` exited
immediately because `undefined !== null` — the test never actually
waited for the api mock to resolve. Sometimes the followup assertions
happened to land after the events fetched (test passed by luck);
sometimes they ran while notice was still undefined and the assertions
failed.
Switched all five waitFor sites to `.toBeDefined()` so they actually
block on the events-fetch resolution.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Repository Status panel now answers "what is the actual state of my
project root vs the integration branch?" so operators can be sure of
the picture even when the Merge Advance Notice banner is dismissed.
GET /api/git/status accepts ?extended=1 and returns additional optional
fields:
- integrationBranch + integrationBranchSource (settings|origin-head|fallback)
- integrationTipSha / originIntegrationTipSha
- aheadOfIntegration / behindIntegration (HEAD vs local integration tip)
- aheadOfOriginIntegration / behindOriginIntegration (local tip vs origin)
- dirtyDetails {staged, modified, untracked, conflicted, sample}
- indexStaleVsHead (surfaces the FN-INDEX-DESYNC scenario)
- stashCount
- recentMergeAdvances: up to 5 merge:integration-ref-advance events
joined with merge:auto-sync outcomes; needsAction flag flips when
auto-sync didn't successfully bring this worktree forward
GitManagerModal renders all of it:
- Existing cards get sub-text: branch shows "not on <integration>",
Working Tree shows staged/modified/untracked/conflicted breakdown
- Second row: Integration branch + source, HEAD-vs-integration,
local-vs-origin, stash count
- Yellow warning panel when indexStaleVsHead surfaces the merger's
stale-index situation with a recovery hint
- Recent integration-branch advances list, color-coded by needsAction,
shows the per-advance auto-sync outcome so operators can audit
even after dismissing the banner
All fetchGitStatus calls in GitManagerModal switched to extended:true.
Other callers unaffected — extra fields are optional.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Broaden mobile media query to include (max-height: 480px) so landscape
phones (which exceed 768 CSS px wide) still render the bottom nav and
mobile board layout instead of desktop horizontally-scrollable columns.
- Guard useMobileKeyboard against pinch-zoom (vv.scale > 1) — Android
Chrome ignores user-scalable=no, and a focused textarea + zoom was
false-positiving keyboard-open and hiding MobileNavBar.
- Read documentElement.clientHeight instead of stale window.innerHeight
when computing keyboard overlap (Android multi-window can leave
innerHeight cached at a wildly different value than the actual layout
viewport — observed 2848 while html was 797).
- Add interactive-widget=resizes-content to the viewport meta so Android
Chrome shrinks the layout viewport with the soft keyboard, matching iOS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migrated dashboard component CSS from hardcoded `rgba()` values to design token variables across nine components including `CustomModelDropdown`, `CliBinaryPanel`, and `CliBinaryInstallBanner`, with test coverage added for the affected components.
Fusion-Task-Id: FN-4016
The merge adds the `fusion-plugin-even-cards` workspace plugin with board card endpoints and auth support, refactors agent action gating classifications into a unified `gating-classifications.ts` module, refreshes review state on manual triggers, repoints roadmap type imports to the plugin package,
Fusion-Task-Id: FN-3753
The merge adds a pull split-button in the GitManager modal that lets users choose between a regular `git pull` and a `git pull --rebase`, with styling and test coverage for the menu interactions and API payload. It also fixes plugin toggle rendering (FN-3723) and adds a release note for plugin insta
Fusion-Task-Id: FN-3724
Merges FN-3623 stash diff inspection system (backend contract, GitManagerModal viewing UI with new API route and tests) and FN-3088 dependency graph hover/selection highlighting. The stash diff work dominates the commit count and touches the core GitManagerModal, while the graph plugin gains new hig
Fusion-Task-Id: FN-3623
- Add mesh task replication plumbing in core store/types with node-aware task creation metadata
- Expose dashboard and mesh API route coverage for replicated task creation and sync behavior
- Restore independent scrolling in Git Manager changes list and prevent Scripts modal scroll regressions
- Expand tests across core, dashboard routes, API, and CLI extension insights for the new behavior
Fusion-Task-Id: FN-3631
This merge delivers five major themes: a large mobile chat UX pass (viewport-aware GitManager CSS, compact tool-call layout, keyboard-safe modals, and iterative fixes for the send-button double-fire behavior), a complete refactor of the TaskDetailModal test suite from a 6745-line monolith into eight
Fusion-Task-Id: FN-3614
- Add mobile-only Git Manager layout rules so changes lists and sections can shrink without horizontal page scrolling
- Wrap section header actions and file rows at narrow widths while preserving readable file names and controls
- Extend GitManagerModal CSS regression coverage for mobile wrapping selectors
- Add core mobile modal test assertions for wrapped actions/rows and bounded section width
- Add a patch changeset for @runfusion/fusion documenting the mobile overflow fix
Fusion-Task-Id: FN-3367
Fixes ScriptsModal CSS by adding a fallback value for the undefined `--bg-surface` token, preventing broken styling when the token isn't defined in the current theme.
Fusion-Task-Id: FN-3245
- Add global `touch-action: manipulation` on html/body to reduce gesture-triggered zoom
- Set mobile input font-size to 16px for terminal, nodes, and scripts modal form fields
- Extend mobile CSS regression tests to assert the global touch-action rule
The Settings, Workflow Steps, Automations (and friends) modals all carried
desktop `min-width: 480-520px` constraints from the resize work. On phones
that pushed them off-screen, and the overlay's 10vh top padding plus a
fractional `height: 80vh` left awkward gaps top and bottom.
Apply the same `@media (max-width: 768px)` full-screen-sheet treatment
that File Browser already had to every resize-aware modal: drop the
overlay padding, set width/height to `100vw`/`100dvh`, zero out the
min-* / max-* constraints, and disable `resize` (touchscreens can't grab
the corner grip anyway).
Also tightened the existing File Browser and GitHub Import overrides to
match (`min-width: 0`, `min-height: 0`, `resize: none`).
For TaskDetailModal the mobile rules go inside the existing first
`@media (max-width: 768px)` block to keep the FN-1331 detail-body
padding regression test happy (it captures from the first 768px media
query greedily).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Modal resize + size persistence
- Extract `useModalResizePersist` hook (ResizeObserver + localStorage),
apply to Files, Git Manager, GitHub Import, Workflow Steps, Automations
(ScheduledTasks), and Settings modals. Each gets `resize: both`, sane
min/max constraints, and a unique storage key.
- Bump default heights so the modals feel less cramped (Git: 92vh,
Workflow/Automation: 80vh, Settings: 80vh / 1100px).
Scrollbar theme
- Add a global `*::-webkit-scrollbar*` + `scrollbar-color` rule in
styles.css so chat, document, system stats, file browser, usage
indicator, etc. inherit the theme. Existing per-component overrides
(.board, .column-body, .settings-sidebar, planning modal) still win.
Document view
- Collapse "Show hidden" toggle and search input onto the same row as
the Project Files / Task Documents segmented control. Stack again
below 768px.
Mailbox / Todos
- Match Todos header treatment to the Mailbox header (typography,
padding, border).
- Add top spacing above Mailbox Inbox/Outbox/Agents tab bar so the
vertical gaps balance.
Settings
- Wider, resizable, persisted Settings modal.
- Project Models description and Authentication panel get proper
horizontal padding.
- Reorder project sidebar so "General" is first.
- Plugins page: clean margins, integrate refresh button, exclude
bundled runtimes from the "Installed Plugins" list (they were
appearing twice — once erroring, once in their own section).
- New "Updates" panel with auto-check toggle + "Check now" button
(frequency control noted as needing a backend schema field).
Background sessions
- Fix stale "AI N" / planning-icon badge: `handleDeleted` in
`useBackgroundSessions` now writes a tombstone, advances the
timestamp guard, and broadcasts completion so the cross-tab
sync store stops resurrecting the deleted session on the next
merge tick. Added regression test.
- Re-fetch list on SSE reconnect so terminal events fired during a
network blip don't get permanently lost.
System stats
- Refresh button uses correct single class (was getting both `btn`
and `btn-icon`, which conflicted on padding/border).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add running-state visual treatment to routine cards, including spinner icon and running class styling
- Capture manual run results in ScheduledTasksModal and pass transient inline output/error to each RoutineCard
- Clear pending inline output when routine data refresh catches up or when leaving/switching routine views
- Expand dashboard tests to cover loader icon, running class, and inline run output rendering
- Restructure ScheduledTasksModal header markup to support updated title and actions grouping
- Add automation toolbar styling updates in ScriptsModal.css to match the new modal header layout
- Update ScheduledTasksModal tests to assert the revised header structure and action placement
All three were declared as 100vw/100dvh on mobile but the .modal-overlay
default still applied 10vh top padding, leaving them pushed below the
viewport edge with a sliver of overlay showing on top. Override
.modal-overlay:has(.X) to drop padding and stretch to fill, and explicitly
zero out border/radius/margin on the modal itself so the sheet truly
covers the screen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sweep 1 of the styles.css split. Rules where the desktop counterpart already
lived in a component CSS file have been moved out of the global mobile @media
block in styles.css and appended to the matching component file's mobile
block. styles.css 4551 → 4488.
Affected components: Header, AgentsView, DocumentsView, ListView, QuickChatFAB,
QuickEntryBox, ScriptsModal, TaskDetailModal, TerminalModal, WorkflowResultsTab.
Truly global mobile rules (input font-size for iOS auto-zoom, html/body
overflow, root safe-area padding, base .btn touch targets, bare element
selectors) intentionally stay in styles.css. The remaining bulk of the mobile
block (settings, auth, board/card, inline-create) cannot move yet because
their desktop rules are still in styles.css — those will fall out as part of
the cards and settings extraction sweeps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Move misclassified .mesh-topology, .connect-node, .nodes-view-topology, .node-status-indicator, and pulse-warning keyframe from AgentReflectionsTab.css to NodesView.css; relocate node-related mobile @media rules from SettingsSyncLog.css so NodesView renders standalone
- Add missing CSS import on GitManagerModal so its .gm-* styles load without depending on ScriptsModal being mounted
- Bump desktop max-widths for FileBrowser, Terminal, GitManager, GitHubImport, and WorkflowStepManager modals; raise selector specificity to .modal.X so the base .modal { width: 480px } can't win the cascade
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add a new /api/git/diff/file endpoint with path and staged query handling, including validation and untracked-file diff support
- Introduce fetchGitFileDiff API client wiring and update GitManagerModal to load diffs for selected staged/unstaged file rows
- Improve file-row UX with active/focus styling, keyboard activation, and guarded async diff loading/error states
- Expand dashboard route and modal tests to cover per-file diff behavior, query validation, and stage/unstage interaction isolation
Split app/styles.css from ~40k lines down to ~4.5k. Created 56 co-located
component CSS files in app/components/, each imported by its owning .tsx.
The remainder of styles.css holds genuinely global rules (design tokens,
.btn/.card/.modal/.form-input primitives, cross-component @media overrides).
- Lazy-load 13 heavy views (AgentsView, RoadmapsView, NodesView, etc.) via
React.lazy + Suspense; prefetch all chunks on idle so first navigation is
instant. Initial JS bundle: 1.58 MB → 1.16 MB (-26%). Initial CSS bundle:
635 kB → 471 kB (-26%); the rest splits into 13 per-view chunks.
- Add app/test/cssFixture.ts exposing loadAllAppCss() + loadAllAppCssBaseOnly()
so CSS regression tests load the full per-component bundle (mirroring Vite
source order). Migrate 30+ tests off direct readFileSync('../styles.css').
- Enable test.css: { include: [/.+/] } in vitest.config.ts so component CSS
imports actually inject styles in jsdom (fixes getComputedStyle assertions).
- Add ESLint rule (no-restricted-syntax) banning direct styles.css reads in
dashboard test files; points at loadAllAppCss() instead.
- Restore lost utility classes (.text-muted, .text-secondary, .text-dim,
.form-input) and rescue dropped chat tool-call rules into QuickChatFAB.css.
- Mobile fixes along the way: scroll containment for view containers
(min-height:0 + -webkit-overflow-scrolling), QuickChatFAB full-screen on
mobile (with safe-area-inset for iOS home bar), AgentsView single-row
header layout, ActivityLogModal close button on right, model-combobox
z-index above the mobile quick-chat panel.
- Bug fix: SkillsView toggle was display:none which hid the input from the
accessibility tree; replaced with the visually-hidden pattern so screen
readers + getByRole still find the checkbox.
- Bug fix: standalone Delete button in TaskDetailModal for triage-column
tasks (Actions dropdown is hidden in triage state, so previously no way
to delete a freshly-created task without status change first).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>