Commit Graph

4194 Commits

Author SHA1 Message Date
gsxdsm
3df09883be 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
648c71e2a8 feat(FN-3619): preserve agent memory across import/export flows
- Extend agent company manifest contract to include memory payloads during export and parse
- Align dashboard agent import/export route generation to pass memory through unchanged
- Add parser, exporter, and route-level tests covering memory passthrough behavior
- Document memory import/export parity in agent and CLI documentation
Ref: Runfusion/Fusion#53

Fusion-Task-Id: FN-3619
2026-05-06 21:36:31 -07:00
Fusion
953ac8a886 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
94c93abf68 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
Fusion
a0fa7f7bc8 feat(FN-3423): show task branch metadata on cards
- Render Branch/Base chips in TaskCard when branch metadata is present
- Add responsive TaskCard styles for branch metadata chips using design tokens
- Expand TaskCard tests to cover branch/base rendering and memo comparator branch changes
- Remove unused ChatView focus-preservation refs/callback to resolve lint blockers
- Document branch metadata semantics in task-management docs

Fusion-Task-Id: FN-3423
2026-05-06 21:16:33 -07:00
Fusion
6de69a2ced feat(FN-3449): implement distributed task-id allocator with mesh API endpoi
Implements a distributed task-ID allocator with mesh networking endpoints for multi-project coordination (FN-3449), alongside substantial ChatView and GitManager mobile polish including improved iOS keyboard handling, rubber-band containment, scroll-drift fixes, and visual viewport stabilization. In

Fusion-Task-Id: FN-3449
2026-05-06 21:16:33 -07:00
gsxdsm
ec119677de fix(dashboard): lock ChatView composer with touch-action: none on textarea
A pan-y gesture on the focused textarea still triggered iOS auto-
scroll-into-view, lifting the composer up off-screen even with body
locked. touch-action: none on .chat-input-textarea blocks gesture-
driven panning entirely (tap-to-focus, typing, caret moves still
work) so the composer stays anchored. Trade-off: loses gesture-
scroll within the textarea once content exceeds max-height — minor
since textareas rarely exceed 6 lines in this composer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:02:22 -07:00
gsxdsm
4708e453ae 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
gsxdsm
d5858b44b9 fix(dashboard): drop translateY(--vv-offset-top) on ChatView mobile
The transform amplified jitter during iOS textarea swipes: visualViewport
scroll events updated --vv-offset-top rapidly, the transform followed,
and the thread juddered then shifted ~300px exposing the body background.
Removing the transform leaves the thread where iOS places it; the
height-shrink to var(--vv-height) still constrains it to the visible
area. Trade-off: on initial focus the thread anchor relies on iOS's
own viewport adjustment instead of explicit compensation, but that
beats the swipe-time jitter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:54:33 -07:00
Fusion
4d39e577fd feat(FN-3615): fix Codex weekly pace parsing
Fixed Codex weekly pace parsing in the usage tracking module, with corresponding test coverage added to verify the fix.

Fusion-Task-Id: FN-3615
2026-05-06 20:54:33 -07:00
gsxdsm
1258e471c1 fix(dashboard): contain iOS rubber-band on ChatView messages and composer
Three scoped overscroll fixes for the ChatView mobile keyboard-up case:

- .chat-messages: overscroll-behavior: contain so edge-swipes on the
  messages list don't bounce the parent / document.
- .chat-input-area: overscroll-behavior: contain so swipes on the
  composer footer don't escape upward.
- .chat-input-textarea: touch-action: pan-y + overscroll-behavior:
  contain so a vertical swipe started on the textarea stays inside
  the textarea (multi-line scroll still works) instead of
  rubber-banding the page and exposing the body background.

User-reported symptom: keyboard up + swipe up on the textarea edge,
the composer shakes and a gray box (body background) partially
covers it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:49:42 -07:00
Fusion
31f2998a8e feat(FN-3614): improve mobile keyboard handling in ChatView and GitManager
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
2026-05-06 20:48:50 -07:00
gsxdsm
a41157545d fix(dashboard): reset scroll on ChatView refocus to undo iOS drift
After dismissing and re-bringing up the mobile keyboard, iOS could
leave window.scrollY > 0 and visualViewport.offsetTop > 0. With
useMobileScrollLock then pinning body{position:fixed} relative to that
drifted scroll, the message thread anchored above the visible viewport
and a large blank area appeared below it.

handleInputFocus now resets window scroll to (0,0) on mobile in a
zero-delay timeout — late enough that iOS finishes its own
scroll-into-view first, but before useMobileScrollLock observes the
drifted state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:42:14 -07:00
gsxdsm
7b3a31ec3b fix(dashboard): keep keyboard up on send tap; hide status bar with keyboard
Two mobile chat regressions addressed together:

1) ChatView send button: preventDefault now fires on pointerdown for
   touch pointers, before iOS blurs the textarea. The previous
   onMouseDown.preventDefault was too late on iOS (mousedown is
   synthesized after touchend, by which point the keyboard has
   already started dismissing). Click still runs the action so quick
   taps remain reliable.

2) ExecutorStatusBar: hidden on mobile while keyboard is open,
   mirroring MobileNavBar. The bar is position:fixed against the
   layout viewport, which iOS leaves anchored below the keyboard;
   during a swipe/pan it would slide over the messages list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:34:35 -07:00
gsxdsm
f08c8ace24 revert(dashboard): undo imperative visualViewport write in ChatView
The imperative useLayoutEffect approach made mobile worse — first tap
flickered and didn't bring up the keyboard, while the original
swipe-overlap symptom remained. Restoring the previous React-state
flow until a better fix is identified. Removes the changeset that
shipped with the failed attempt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:29:12 -07:00
gsxdsm
72691c6fd6 fix(dashboard): write ChatView visualViewport vars imperatively
The mobile composer/footer slid over the message list when the user
swiped with the keyboard up. Cause: --vv-height / --vv-offset-top were
routed through React state via useMobileKeyboard, so on iOS — which
fires visualViewport scroll/resize on the same frame as its keyboard
animation — the .chat-thread translation lagged by one paint, visible
as the composer momentarily floating over messages.

Now those two vars are written imperatively in a useLayoutEffect
directly to the .chat-thread DOM node on every visualViewport event,
mirroring the working pattern at QuickChatFAB.tsx:1032-1052 (which
already works correctly on mobile). Only --keyboard-overlap (a
structural open/close signal, not per-frame) still flows through
React state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:25:38 -07:00
gsxdsm
bcfb4a3f62 fix(dashboard): keep mobile keyboard up when ChatView send button tapped
Re-add preventDefault on mousedown so the textarea doesn't blur when
the user taps send — keyboard stays up, no viewport reflow jumping
the input to the top of the screen. The action still runs on click
(which fires reliably from the iOS touch sequence even for quick
taps), so this preserves the previous fix's quick-tap reliability.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:19:28 -07:00
gsxdsm
0d3324ad95 fix(dashboard): make ChatView mobile send fire on quick tap
The mobile send button used pointerdown + touchstart with preventDefault
and a focus-preservation dance to keep the keyboard up while sending.
That path silently failed on quick taps on iOS — only a long press
registered. Switching to plain onClick (with touch-action: manipulation
to skip the click delay) fires reliably on tap. The soft keyboard may
dismiss on send now, which is a minor regression vs. the previous
intent but vastly preferable to silent failure.

QuickChat is unchanged because it already works on mobile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 20:15:30 -07:00
gsxdsm
ca047a714a Revert "fix(dashboard): stop mobile send-button double-fire that aborted chats"
This reverts commit 394b1a655a.
2026-05-06 20:02:02 -07:00
gsxdsm
beb0a1a189 Revert "fix(dashboard): self-clear mobile send/stop dedupe ref so subsequent taps work"
This reverts commit 27d6511af3.
2026-05-06 20:02:02 -07:00
gsxdsm
27d6511af3 fix(dashboard): self-clear mobile send/stop dedupe ref so subsequent taps work
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>
2026-05-06 19:59:38 -07:00
gsxdsm
394b1a655a fix(dashboard): stop mobile send-button double-fire that aborted chats
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>
2026-05-06 19:55:55 -07:00
Fusion
3819d48134 feat(FN-3574): add setup-aware built-in plugin rows
- Add built-in plugin catalog metadata and constants for shipped installable plugins
- Render a Built-in Plugins section with install, setup-required, and manage states
- Fetch and display plugin setup status, including setup install flow and status badges
- Add PluginManager CSS and tests covering built-in plugin install/setup behaviors

Fusion-Task-Id: FN-3574
2026-05-06 19:55:55 -07:00
Fusion
52c673a4cb feat(FN-3392): implement follow-up suggestion contract and policy system
Merges the evaluator follow-up suggestion system (FN-3392, Steps 1–5), which adds a normalized contract, provenance tracking, and lifecycle documentation for AI-generated follow-up tasks, alongside chat UI improvements including unread indicators in header and mobile nav, corrected message routing,

Fusion-Task-Id: FN-3392
2026-05-06 19:55:55 -07:00
Fusion
c95517af31 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
7dcdf0929f docs(FN-3608): update dashboard chat guide with mailbox tooling note
- Document that agent-backed chat sessions expose fn_send_message and fn_read_messages when MessageStore is available
- Clarify that model-only chat sessions continue to work without mailbox tools
- Complete the Step 4 dashboard chat documentation update

Fusion-Task-Id: FN-3608
2026-05-06 19:55:55 -07:00
Fusion
b9b6d06cad feat(FN-3622): add canonical task-detail timing calculations and stats pane
The merge lands three commits for FN-3622's canonical task timing calculations, adding `taskTiming.ts` logic and stats timing semantics to `TaskDetailModal` and `TaskTokenStatsPanel`, backed by regression tests across those panels and the root `test-changed.mjs` script. The remaining commits introdu

Fusion-Task-Id: FN-3622
2026-05-06 19:55:55 -07:00
Fusion
e7884370f2 fix(FN-3610): isolate test home for changed-package test runs
- Create a disposable HOME/USERPROFILE env for scripts/test-changed.mjs execution
- Run isolation guard checks with the same isolated env, including cache-hit no-op paths
- Clean up temp HOME after test execution to avoid residue
- Update test coverage and contributing docs for the shared isolation behavior

Fusion-Task-Id: FN-3610
2026-05-06 18:57:37 -07:00
Fusion
c44beada79 feat(FN-3606): correct chat-bound message routing and stabilize merger auto
Merger receives substantial hardening: autostash race-rescue with de-duplication, advisory observer for destructive operations, and subject-line preference for step headlines. The TUI gains a narrow log-split mode on System panel with proper back-navigation to the main pane. Chat header and mobile n

Fusion-Task-Id: FN-3606
2026-05-06 18:55:10 -07:00
Fusion
63492e18fd feat(FN-3605): keep mobile header identity and toggle inline in ChatView
The merge completes Step 2 of FN-3605 by refactoring the ChatView mobile header to preserve its visual identity while converting the toggle control to an inline layout, accompanied by corresponding tests.

Fusion-Task-Id: FN-3605
2026-05-06 18:50:59 -07:00
Fusion
d2b840bd92 feat(FN-3604): add chat unread indicator to header and mobile nav
Implements a chat unread indicator across the header and mobile nav bar, driven by a new unread-response tracker in the app state, with tests and a docs update for the feature.

Fusion-Task-Id: FN-3604
2026-05-06 18:47:25 -07:00
Fusion
dc95aa0357 feat(FN-3600): harden TaskDetailModal pause/unpause async assertions
Hardens async assertions in the task detail modal's pause/unpause action tests, improving test reliability for that interaction flow.

Fusion-Task-Id: FN-3600
2026-05-06 18:44:25 -07:00
Fusion
7fc7b7653f feat(FN-3599): align documentation with delivery process
Documentation delivery alignment completing Step 5 of FN-3369, updating the CLI reference, research docs, and research hardening preflight guide with consistent documentation delivery guidance across all three files.

Fusion-Task-Id: FN-3599
2026-05-06 18:40:52 -07:00
Fusion
fbf91c74a9 feat(FN-3596): unify board/list task ordering, split TaskDetailModal test m
The merge introduces a major TaskDetailModal test refactor (splitting a 6.7K-line monolith into five focused suites), significant merger improvements including autostash race-rescue, deduplication, and advisory logging for destructive operations, a new TUI narrow-mode log-split feature for the dashb

Fusion-Task-Id: FN-3596
2026-05-06 18:37:23 -07:00
gsxdsm
3ae9a85c9b fix(tui): ← returns to main pane from focused log split
Previously ← in the narrow log strip cycled the section (matching n/p),
which was disorienting once the user had drilled into the strip — they
expected ← to back out, not flip them to a different panel. Now ← from
a focused log strip clears the narrow-split sub-focus and returns to
the main pane (System / Stats / Utilities / Settings) where the user
can drag-select tokens or interact with the panel as usual. p/P still
cycle sections in all states; ↑ at the top of the strip and Esc
continue to work as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:31:19 -07:00
gsxdsm
e624dbb054 fix(tui): re-enable narrow log-split on System without losing UI
Bring back the bottom log strip on the System panel and make sure
nothing that lives in System is dropped when the strip steals rows:

- Render the [Enter] / [c] / drag-to-select hint unconditionally so
  shortcuts stay discoverable when the strip has sub-focus and System
  isn't the keyboard target. The split-aware focus border still tracks
  which pane the keyboard is wired to.
- Move URL and Token to their own full-width rows under the status-chip
  wrap row. Long token values now wrap onto multiple lines instead of
  being truncated or pushed off-panel — the auth token is always
  visible (and selectable) in full.
- Keep mouse reporting OFF whenever System is the active section, even
  when the log strip below has sub-focus, so click-drag selection of
  the token text continues to work.
- Update estimateSystemContentRows to mirror the new layout: greedy
  pack of small status chips, full-width URL / Token rows that wrap by
  ceil(width / inner), and an always-counted hint row. The dynamic
  split sizer now reserves enough rows for the panel in every state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:27:18 -07:00
gsxdsm
a217969b39 fix(tui): skip narrow log-split on System panel
System has interactive UI — Enter to open URL, [c] to copy auth token,
and click-drag for token selection — whose [Enter]/[c] hint row only
renders when the panel has focus. Auto-shifting focus into a bottom log
strip on ↓ hid that hint and removed a clear visual path back to the
panel for token operations. Restrict the auto-split to inert sections
(Stats / Utilities / Settings); System keeps the full single-pane view
it had before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:16:58 -07:00
gsxdsm
9b30711b43 feat(tui): split narrow main view to surface live logs
When the dashboard TUI collapses to single-pane mode (narrow width or
short terminal), show a horizontal log strip at the bottom of the screen
while the active section renders on top. The split is content-driven:
the top pane gets exactly the rows it needs to render its section
without truncating (computed from SystemPanel's chip wrap at the current
width, or each panel's known row count for Stats/Utilities/Settings),
and the log strip absorbs every remaining row to maximize log
visibility. Down-arrow shifts sub-focus into the log strip with the
same key bindings as the dedicated Logs section (j/k, Home/G, Enter to
expand, w to wrap, c to copy, f to filter, mouse wheel). Up-arrow at
the top of the strip or Esc returns focus to the main pane.
Right/Left/Tab continue to cycle sections, so the dedicated full-screen
Logs view is unchanged. The split auto-disables if the log strip would
get fewer than 6 rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:11:49 -07:00
gsxdsm
9a83117294 fix(merger): address code-review findings on autostash + observer
P0 — parsePorcelainZ rename/copy handling
  Git's -z porcelain emits `R  <new>\0<old>\0` for renames (and
  C for copies). The naive split-and-slice treated <old> as an
  independent dirty path, which made runObservedDestructiveSyncOp
  warn about phantom "cleared paths" whenever a rename was in
  flight. Now we detect R/C status and skip the trailing entry.

P1 — race-rescue loop unstages between attempts
  `git stash create` snapshots the index without clearing it, so
  iteration 2's `git add -A` would re-stage atop iteration 1's
  leftovers. Tree differences inside the loop then reflected stale
  staging rather than genuine new writes. Added a `git reset` at
  the top of each iteration so every attempt starts from a clean
  index baseline.

P1 — writeActiveMergerStatus is now atomic
  Switched from in-place writeFileSync to temp-file + renameSync.
  POSIX guarantees rename atomicity on the same filesystem, so a
  reader can no longer catch the file mid-flush and return a
  false-negative "no merger active" advisory.

P2 — Step regex em-dash clarity
  `[—\-:]` is functionally fine but obscures intent; switched to
  `(?:—|-|:)` so the em-dash branch is obvious. Added a test case
  for the em-dash separator.

New tests:
- parse-porcelain-z.test.ts (8 cases including renames + copies)
- em-dash case added to derive-subject-summary.test.ts

247/247 merger-suite tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:04:19 -07:00
gsxdsm
32f4d4fbff fix(merger): de-dupe race-rescue against primary stash path set
The race-rescue loop was firing on every merger run because
`git add -A && git stash create` does not clean the working tree —
files stay dirty post-stash, so a subsequent `snapshotDirtyFiles` saw
the SAME paths the primary stash had just captured and stashed them
again, producing identical-tree race-rescue duplicates (visible in
git stash list as `fusion-merger-autostash:FN-XXXX:race-rescue-0`
sitting next to its identical `fusion-merger-autostash:FN-XXXX:`).

Fix: list the path set captured by the primary stash via
`git stash show --name-only`, and only rescue paths in the current
dirty snapshot that are NOT in that set — those are genuine
late-dirty writes from concurrent dev edits or interleaved ops.
Also drop any rescue whose tree-SHA exactly equals the primary,
as a defensive belt-and-braces.

Existing duplicate race-rescue stashes are harmless (identical
content to their primaries) and can be dropped manually.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:57:42 -07:00
Fusion
9b56e521eb docs(FN-3421): document branch field plumbing architecture
- Document how branch field data flows through task lifecycle
- Clarify architecture-level plumbing responsibilities for branch metadata
- Capture Step 4 documentation updates in docs/architecture.md

Fusion-Task-Id: FN-3421
2026-05-06 17:54:23 -07:00
Fusion
f8fe57ea09 feat(FN-3594): split TaskDetailModal test monolith and improve mobile chat/
The merge brings TaskDetailModal test coverage in line with the project's testing standards by splitting the monolithic 6,745-line test file into five focused suites. It also delivers merger reliability improvements including headline-step subject preference, redundant-merge verification skipping, a

Fusion-Task-Id: FN-3594
2026-05-06 17:51:09 -07:00
gsxdsm
8a417a70b8 fix(merger): add active-merger advisory + observe destructive ops + log rescue stashes
- writeActiveMergerStatus: writes .git/.fusion-merger-active.json
  (taskId, pid, hostname, startedAt) at merge entry, deleted in finally.
  Not a lock — purely informational so dashboards / status lines /
  pre-Edit hooks can warn devs that rootDir is volatile during the run.
  readActiveMergerStatus(rootDir) is exported for consumers.
- runObservedDestructiveSyncOp: snapshot-before/after wrapper around
  destructive rootDir ops that are *supposed* to preserve unrelated
  working-tree edits. resetMergeWithWarn now uses it — any future
  silent wipe of dirty paths surfaces as an actionable warning instead
  of going unnoticed. Not applied to the autostash's own reset
  --hard / clean -fd; those are intentionally destructive and already
  protected by the race-rescue stash.
- Race-rescue stashes from stashUnrelatedRootDirChanges are now
  attached to the AutostashHandle and surfaced via store.logEntry so
  the recovery command lands on the task feed instead of only
  mergerLog.warn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:25:19 -07:00
gsxdsm
b81196e3a2 fix(merger): prefer step headline subject + add autostash race-rescue
- deriveDeterministicSubjectSummary now picks the lowest-numbered
  `complete Step N` headline (or the oldest commit) instead of the most
  recent commit, so trailing quality-gate revisions stop hijacking the
  squash-merge subject (FN-3617 landed as "align mailbox modal css..."
  when 4 of 5 commits were the actual Claude OAuth fix).
- AI subject + body system prompts in ai-summarize.ts now weight by
  commit theme rather than file size, so a small token cleanup that
  touches a large CSS file no longer dominates the summary.
- stashUnrelatedRootDirChanges adds a bounded re-snapshot loop after
  the primary stash is persisted but before \`git reset --hard\`. Any
  late-dirty paths (concurrent dev edits during a long merger run,
  parallel merger runs racing on rootDir, late test/build artifacts)
  get captured in labeled \`race-rescue-N\` stashes recoverable from
  \`git stash list\`, instead of being wiped by the destructive reset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:06:46 -07:00
Fusion
4dc4e25018 feat(FN-3592): exclude live fusion app paths from test isolation checks
Merges FN-3592 test isolation improvements: broadens the runtime ignore list in `check-test-isolation.mjs` to filter live Fusion app paths, fixes a lint violation in the script, and updates the agents lifecycle documentation. A patch changeset is included for the `@runfusion/fusion` package.

Fusion-Task-Id: FN-3592
2026-05-06 16:25:14 -07:00
Fusion
fb7d9b116b feat(FN-3617): align mailbox modal css with design tokens
Updated MailboxModal CSS to use design tokens instead of hardcoded values, and adjusted the co-located test to match.

Fusion-Task-Id: FN-3617
2026-05-06 16:14:29 -07:00
Fusion
f860d3d545 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
Fusion
c3b7a02644 feat(FN-3591): split TaskDetailModal test monolith into focused suites
The monolithic `TaskDetailModal` test suite (6,745 lines) was split into six focused test files covering attachments/tabs, definition/actions, inline editing/integrations, models/progress/workflow, rendering, and responsive/dependencies, with a shared test helpers module added for common utilities.

Fusion-Task-Id: FN-3591
2026-05-06 15:57:08 -07:00
Fusion
ed52c3dff3 test(FN-3591): split TaskDetailModal coverage into focused test suites
- Replace the monolithic TaskDetailModal test file with focused suites by behavior area
- Add shared TaskDetailModal test helpers to reduce duplication across suites
- Keep existing coverage while improving test isolation and maintainability
- Remove the legacy combined TaskDetailModal.test.tsx file

Fusion-Task-Id: FN-3591
2026-05-06 15:57:08 -07:00
Fusion
8dada75717 docs(FN-3589): document fn agent subcommand behavior
- Add dedicated CLI reference sections for fn agent stop/start/mailbox/export with usage, options, and behavior notes
- Document expected no-op and invalid-transition outputs for agent lifecycle commands
- Expand useful options matrix with agent import/export flags
- Add a doc contract test that asserts the new agent subcommand sections remain present

Fusion-Task-Id: FN-3589
2026-05-06 15:21:45 -07:00