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
Merges FN-3009 (remote settings migrated to global scope with updated schema and docs), FN-3034 (legacy routines compatibility layer: agentId backfill on load and schema validation for old format), and FN-3039 (Nerd Font glyph asset bundled into the terminal with CSS prioritization). Core settings s
Fusion-Task-Id: FN-3034
This merge migrates Fusion's settings architecture to a unified global scope (FN-3009), consolidating settings types, defaults, merge semantics, updater logic, and routing into a centralized system that aligns dashboard remote settings with global configuration. Secondary changes include adding the
Fusion-Task-Id: FN-3009
Merges two features: FN-3039 bundles a 2.5MB Nerd Font glyph asset into the dashboard and updates the terminal to prioritize the bundled font, improving icon rendering across environments; FN-3035 tightens insight tool type definitions and adds corresponding tests. The CLI extension gains new tools
Fusion-Task-Id: FN-3039
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
Fixes the insight tool filter typing in the CLI extension to use stricter types, preventing incorrect filter values from being passed through.
Fusion-Task-Id: FN-3035
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
This merge brings several enhancements across the dashboard and engine. Research settings are now fully integrated into the settings modal and exported for alias builds, including a new schema and dedicated resolver. The AgentDetailView receives a heartbeat markdown viewer modal and expanded styling
Fusion-Task-Id: FN-3029
This merge adds a new **Research Settings** section to the settings modal and dashboard (ResearchView), including a new schema, types, and resolver exported for dashboard alias builds, along with comprehensive tests and documentation updates. It also makes task review step fields editable in the Tas
Fusion-Task-Id: FN-3031
Adds `focus-visible` styling to action buttons in the AgentLogViewer component, improving keyboard accessibility for interactive button elements.
Fusion-Task-Id: FN-3037
This merge introduces a research settings system including new resolver functions in `@fusion/core`, a dedicated ResearchView in the dashboard with a full SettingsModal integration, and corresponding TypeScript types and schemas. Comprehensive unit tests cover routing resolution, research settings,
Fusion-Task-Id: FN-2839
Exports the research settings resolver from `@fusion/core` types to fix dashboard alias builds, ensuring the resolver is available when imported through the dashboard's module alias configuration.
Fusion-Task-Id: FN-2995
Adds a heartbeat markdown viewer modal to the AgentDetailView (FN-3030) with styling, tests, and documentation for the feature, while also rendering multi-sample theme swatches in the ThemeSelector component (FN-3028).
Fusion-Task-Id: FN-3030
ThemeSelector now renders multi-sample theme swatches with richer styling; tests were updated to match and the swatch contract is documented in the dashboard README.
Fusion-Task-Id: FN-3028
The vitest child-process guard wrapped exec/execFile without preserving the
`[util.promisify.custom]` symbol, so awaited `execAsync` resolved to a raw
stdout string instead of `{stdout, stderr}`. That single regression cascaded
through ~60 "failing" tests across cli, core, engine, and dashboard whose
production code was actually correct. Also relax the AI-CLI blocklist for
cheap introspection (--version/--help/which …), give SIGTERM'd subprocesses a
brief grace period before being flagged as "left running", fix a few real
test-side bugs uncovered along the way (executor mock step transitions, iOS
last-resort keyboard path, mission SSE replay tests racing with the real AI
agent), and convert dashboard route tests' dynamic `await import("../server.js")`
to static imports so first-test timings drop from 2–5s to <200ms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Nerd Font as the terminal font stack default with a migration to update existing user settings, updates the terminal and settings modals to reflect the new font choice, and includes corresponding tests plus a patch changeset for `@runfusion/fusion`.
Fusion-Task-Id: FN-3026
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>
Three coordinated fixes for the FN-2978 incident class — auto-requeues
that orphaned committed work and watchdog kills on long verification runs.
**Auto-requeue branch reuse** (executor.ts, worktree-pool.ts)
- executor.ts:1782 now uses `task.branch || fusion/<id>` so persisted
branches are honored on requeue. Previously the hardcoded fallback
always tried to re-create the original branch, hit a conflict with
the prior run's ref, and got suffix -2/-3. Other call sites already
honor task.branch — this aligns the worktree-acquisition path.
- worktree-pool.ts:181 prepareForTask now probes existing branches with
`git rev-parse --verify` and checks them out as-is. Falls through to
suffixed creation only when the branch is genuinely in use by another
live worktree. Previously force-reset with `checkout -B`, destroying
prior commits.
- New private reconcileStepsFromGitHistory walks `git log
baseCommitSha..HEAD` for `feat(FN-X): complete Step N` commits and
marks matching steps[] as done so resumes don't redo committed work.
**Manual reset endpoint + UI** (dashboard)
- POST /api/tasks/:id/reset (requires `confirm: true`) — clears worktree,
branch, all retry counters, resets steps[] to pending, moves to todo.
Distinct from /retry which is the soft-resume path.
- Reset button alongside Retry in TaskDetailModal with confirm dialog,
wired through useTasks → AppModals → API.
**fn_run_verification tool** (run-verification-tool.ts, executor.ts)
- New custom tool wrapping test/lint/build commands with a heartbeat
callback (per-line + 60s synthetic), 200KB head+tail output cap, hard
timeout with SIGTERM→SIGKILL escalation, and auto-bootstrap detection
for missing node_modules. Prevents the inactivity watchdog from
killing sessions during long compiles.
- Cross-platform via `shell: true` (Node picks /bin/sh on POSIX,
cmd.exe on Windows). Prompt section in EXECUTOR_SYSTEM_PROMPT and
EXECUTOR_PROMPT_TEXT instructs agents to prefer package-scoped
verification first and reserve workspace-scoped runs for final
integration.
**Tests** (64 passing)
- detect-pseudo-pause.test.ts (27 tests) — covers all 7 regex patterns,
structural fallback, FN-2978 regression text.
- reconcile-step-regex.test.ts (25 tests) — pins the commit-message
regex against a wide variant set.
- run-verification-command.test.ts (12 tests) — basic execution, output
capture, heartbeat callbacks, timeout, error handling. POSIX-specific
cases (multi-cmd `;`, `>&2`, `\$USER`) gated behind itPosix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds vitest coverage for validateCliPresenceAsync and validateCliAuthAsync,
verifying success paths, spawn-error paths, non-zero exit codes, and that
auth failures emit the expected warning. Pairs with the async/memoized
validation refactor in 442238196 that unblocks the dashboard event loop
on every chat send.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Agents sometimes end turns by asking permission instead of calling tools.
Add turn-ending rules to both executor prompts and runtime detection via
detectPseudoPause() to identify these stalls and issue targeted retry
prompts that correct the behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The merge hardens the cloudflared installation backend with fallback logic and architecture detection, updates the SettingsModal UI with clearer manual installation guidance, and adds comprehensive test coverage for the remote access routes including the new memory-based settings registration flow.
Fusion-Task-Id: FN-2977
Merges external Tailscale funnel detection (FN-2976) — adds types, detection logic, status inclusion, kill flow, and a dedicated UI panel for funnel processes started outside Fusion — alongside custom AI providers API routes and a new settings UI section (FN-2965).
Fusion-Task-Id: FN-2976
Merged v0.9.4 bringing custom AI providers to the dashboard — SettingsModal now surfaces provider configuration with an onboarding disclosure flow, backed by new API routes (`/custom-providers`) and comprehensive test coverage. The engine adds self-healing with a ghost-review fallback recovery path,
Fusion-Task-Id: FN-2965
The merge adds an inline version refresh control to the Settings modal with improved touch targets for better mobile usability, replacing a separate duplicate-updates check button. Changes span the SettingsModal component, its CSS styling, and new test coverage for the control behavior.
Fusion-Task-Id: FN-2974
Hoist agentStore to outer scope so the finally block can close it
before removing the temp dir, preventing leaked SQLite handles when
the test errors mid-try.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add recoverGhostReviewTasks as a final-fallback scan in the maintenance
loop. Catches any in-review task that fell through every more-specific
recovery scan and has been idle past taskStuckTimeoutMs, kicks it back
to todo with transient status cleared. Worktree state is intentionally
ignored — the executor recreates as needed. Preserves human-handoff and
active-merge statuses; rate-limited naturally by updatedAt refresh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace bare `feat(FN-XXXX): merge fusion/fn-XXXX` subjects with an
AI-generated summary describing what landed (e.g. `feat(FN-XXXX): add
webhook handler`). Calls the existing `summarizeCommitSubject` lane
alongside the body summarizer; falls back to `merge <branch>` when the
summarizer is disabled, unavailable, or returns nothing.
Default for `useAiMergeCommitSummary` flips to true so existing
projects without an explicit override pick up the new behavior. The
Settings UI already exposes the toggle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RoutineStore's constructor appends ".fusion" to its rootDir argument,
but InProcessRuntime was passing taskStore.getFusionDir() (already the
.fusion path), producing <projectRoot>/.fusion/.fusion/fusion.db. Pass
the project root instead, matching AutomationStore's construction.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `as const` annotation narrowed column to "in-progress" only, breaking
tsc build when the moveTask mock assigned "todo".
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>