session.prompt() resolves to void; the reply lives in session.state.messages.
The dream route was awaiting its return value, so parsing crashed with
"Cannot read properties of undefined (reading 'match')" once the dream
completed. Extract the assistant text post-prompt and fail soft on
non-string input in extractDreamProcessorResult.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pre-existing local modifications that had been sitting in the
working tree across this session, neither produced by the recovery /
fallback work in adjacent commits. Committing them so the tree is clean.
- packages/dashboard/app/components/SettingsModal.css
Removes one trailing blank line at end-of-file. No semantic change.
- packages/dashboard/app/components/__tests__/ListView.test.tsx
Drops one test case ("shows NodeHealthDot for selected bulk node
override", 15 lines) from the "ListView - Bulk Selection" describe
block. The test asserted that selecting a bulk node override
rendered a `.status-dot--online` indicator in the DOM. Sibling tests
(option labels, batchUpdateTaskModels invocation) are preserved.
Likely debris from the FN-2729 NodeHealthDot work that didn't survive
one of the in-flight squash merges; the underlying behavior is still
exercised by the kept tests.
Verified: pnpm --filter @fusion/dashboard test ListView passes
(125/125), so the removed assertion isn't load-bearing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the AI commit-body generator (introduced in 52928ff5e) to the
existing dedicated title-summarization model lane, and updates the
settings UI so users understand the model is now used for two
short-summary jobs instead of just one. Also de-duplicates the
project-scope settings UI which was exposing the same model setting in
two places.
Engine (merger.ts):
- aiGenerateCommitBody now prefers settings.titleSummarizerProvider /
titleSummarizerModelId over the merger's default model. The
summarization lane is the right tier for this work — small, fast,
cheap. Falls back to the default merger model when the summarization
lane is unset.
Dashboard (SettingsModal.tsx):
- MODEL_LANES summarization lane label updated:
"Title Summarization Model" → "Title and Git Commit Message
Summarization Model". Helper text updated to mention the dual purpose
(auto-generated task titles + fallback merge commit message bodies).
This change flows through automatically to BOTH the global model
lanes view and any project-scope rendering of MODEL_LANES.
- Removed the duplicate summarization picker from the project-scope
Model Lanes section: previously it appeared once under Model Lanes
AND once under "AI Summarization". Now lives only in the dedicated
picker so users have a single source of truth in project scope.
- The dedicated picker section heading + description rewritten:
"AI Summarization" → "AI Title and Git Commit Message Summarization",
with a paragraph explaining both jobs the model performs.
- Inner dropdown label updated for consistency.
Tests + checks: engine 2887/2887 pass, dashboard typecheck clean,
workspace lint clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Resolve merge conflicts in InlineCreateCard and QuickEntryBox using the existing node picker UX
- Replace ad-hoc node status rendering with NodeHealthDot in task creation surfaces
- Keep advanced quick-create controls and portal-based dropdown behavior intact
- Preserve related dashboard styling and tests included in the staged squash
Fusion-Task-Id: FN-2729
Self-review of the recovery cascade surfaced three issues; this commit
addresses all of them.
1. AI didn't actually receive the safety constraint under Layer 3.
The previous commit logged the safety preamble to the task log via
`store.logEntry`, but the merge agent doesn't read task log entries as
prompt context — so the AI was running blind. The "no silent
re-introduction of main's deletions" guarantee was therefore relying
*entirely* on the deterministic verification gate (test + build),
which is correct as a backstop but doesn't help the AI produce a
correct first attempt.
Fixed by threading `preMergeRebaseFallthrough` through
`MergeAttemptParams` → `executeMergeAttempt` → `runAiAgentForCommit` →
`MergePromptParams` → `buildMergePrompt`, where it now injects an
explicit "⚠️ Pre-merge rebase recovery exhausted" preamble at the top
of the user prompt with three concrete rules:
- Prefer main's deletion when branch re-adds removed lines
- Prefer main's version on ambiguous hunks
- Call `fn_report_build_failure` rather than commit a regression
Also includes the original rebase failure message (truncated) so the
AI has diagnostic context.
The truncated-context retry path also forwards the preamble — it's the
safety constraint, not bulk context, so we keep it even when stripping
diff stat / commit log to fit the window.
2. Layer 2's branch-restore could fail with "uncommitted changes".
When a cherry-pick midway through Layer 2's replay fails, the worktree
is in a half-applied state with conflicts in the index. The previous
restore did `git checkout <branch>` (no -f) followed by
`git reset --hard <originalSha>`. The plain checkout would refuse with
"would overwrite local changes" if there were unmerged paths,
preventing the reset from running and leaving the branch at the
half-replayed tip.
Fixed by reordering: hard-reset to the captured original SHA first
(this clears index/working tree of any cherry-pick state), then
`git checkout -f <branch>` to ensure HEAD points at the named branch,
then a final hard-reset to the original SHA as belt-and-suspenders.
Worst case the worktree is at the original branch tip — never worse
than where Layer 2 started.
3. Pre-existing unrelated lint error blocking workspace lint.
`packages/dashboard/src/server.ts` had an unused `resolve` import from
`node:path` left behind by a recent refactor that extracted
`PACKAGE_VERSION` into its own file. The user explicitly asked to
clean it up so workspace lint passes. One-line drop.
Tests + checks:
- Engine: 2886 / 2886 pass (added safety preamble didn't break any
existing prompt-content assertions)
- Core: 3120 / 3120 pass
- Workspace lint: clean
- Engine typecheck: clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Default Cloudflare remote access to Quick Tunnel mode in settings documentation
- Replace the Quick Tunnel checkbox with an Advanced (Named Tunnel) details disclosure in SettingsModal
- Auto-sync quick tunnel state from the details open/close state while preserving named tunnel field editing
- Update SettingsModal tests to cover the new advanced-toggle behavior and persisted quick tunnel payload
Fusion-Task-Id: FN-2916
- Add attachment-first chat compose flow with paperclip picker, drag-and-drop, and paste support in ChatView input
- Render pending attachment preview chips with per-file remove actions and drag-over visual affordance
- Display sent message attachments with image/file presentation and accessible focus/interaction styling
- Update ChatView tests and icon mocks to cover attachment-only sends, file selection, and preview behavior
Fusion-Task-Id: FN-2911
- fix(FN-2914): remove divider line between close and shortcuts buttons in terminal
- feat(FN-2902): merge fusion/fn-2902
- chore(release): v0.8.3
- Update changeset
- fix(tui): swap 3/4 panel hotkeys so they match the help text
- fix(tui): always show auth token and report accurate macOS memory usage
- chore(release): v0.8.2
- feat(FN-2895): merge fusion/fn-2895
Fusion-Task-Id: FN-2914
Lead with Project Name, then Project Directory. Move setup-mode toggle
(existing vs clone) and the repository URL field into Advanced Settings
so the default path is one question — pick a folder, name it, register —
without the welcome blurb and mode picker getting in the way.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove btn-icon styling from ChatView render toggle controls and apply dedicated borderless toggle styling
- Update ChatView and QuickChatFAB behavior so quick chat streaming state is preserved when resuming sessions
- Add regression tests for QuickChatFAB and useQuickChat to cover resume and streaming-state handling
Fusion-Task-Id: FN-2906
- 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
- Render merge strategy descriptions behind expandable disclosure sections in Settings modal
- Add dedicated disclosure styling and update task form expectations for the new copy structure
- Extend Settings modal tests to cover disclosure toggling and merge-description visibility
- Improve model onboarding API key action layout on mobile by stretching form width and aligning button placement
The FN-2869 merge resolution claimed to keep this block removed but
the diff actually re-added it, so it started showing up on the task
details "definition" tab again.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Keep the GitHub import modal open after successful issue or PR import instead of auto-closing
- Reset selected issue/PR after import so the Import action disables until a new selection is made
- On mobile, return from preview to list view after a successful import for faster repeated imports
- Expand GitHubImportModal tests to cover stay-open behavior, selection reset, mobile view reset, and stabilized auto-load button assertions
Surface the Default Model selector directly after the authenticated
provider list so users see it without scrolling past the disclosures.
Hydration of the previously-saved default on reopen was already in
place — this just relocates the existing block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>