- Add a new dashboard TUI renderer with logs, system, utilities, stats, and settings sections
- Wire runDashboard to auto-enable TUI in TTY sessions with reactive task/agent updates and utility keybindings
- Keep non-TTY behavior unchanged by falling back to the existing plain-text startup output
- Add CLI tests and docs for TUI behavior, keyboard shortcuts, and auth/usage guidance
- Ensure dashboard WebSocket auth checks respect --no-auth consistently
findLandedTaskCommit only fell back to scanning all of HEAD on git-log
exceptions. When the bounded base..HEAD range is valid but empty — e.g.
the merger fast-forward-rebased the task branch and set baseCommitSha
to the new HEAD, or later commits moved HEAD past the merge — recovery
silently returned null and re-queued the merge even though the commit
had already landed. Add an empty-stdout fallback that re-scans HEAD,
with a regression test covering the FN-2221 scenario.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a new worktree setting that fetches the configured remote and rebases
the task branch onto the latest default-branch tip before the merger attempts
to merge it back. Catches concurrent pushes from other collaborators or
fusion workers on other hosts before they surface as merge conflicts —
anything the rebase can't fast-forward flows into the existing smart/AI
resolve pipeline (attempts 1–3) rather than needing new handling.
- `settings.worktreeRebaseBeforeMerge` (bool, default true) — gates the step.
- `settings.worktreeRebaseRemote` (string, default "") — which remote to
fetch; empty falls back to git's configured remote for the default branch,
then to the sole remote if there's only one, then to "origin".
- Rebase runs inside the task's worktree; failure aborts and falls through
to the merge cascade. Rebase errors are warn-logged but never throw.
- Dashboard SettingsModal Worktrees section now has a toggle for the setting
plus a remote dropdown populated from `/api/git/remotes/detailed`. The
dropdown defaults to "Use git default" so no explicit selection is needed
on first configure.
Also aligns the Last/Next heartbeat spans on the agent list card — both now
share the `.agent-heartbeat-last, .agent-heartbeat-next, .agent-heartbeat-saving`
font-size rule with a consistent line-height and inline-flex alignment so
the labels don't drift vertically when they share a row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three orthogonal fixes bundled together so they re-land as a unit after
earlier worktree-based reverts kept wiping them individually.
1. `--no-auth` flag now actually disables auth. Previously a stale
FUSION_DAEMON_TOKEN in .env silently re-armed bearer-token auth despite
the CLI flag. Added a `noAuth` option to ServerOptions; auth-middleware's
isDaemonAuthActive/getDaemonToken short-circuit to false/undefined when
set; CLI plumbs opts.noAuth through both createServer call sites.
2. Workflow review failures no longer reset every completed step. Previously
a single CSS nit from a workflow reviewer could drag 5+ already-approved
steps back through plan review, code review, and re-execution because
determineRevisionResetStart fuzzy-matched feedback tokens against step
names. handleWorkflowRevisionRequest, handleWorkflowStepFailure, and
sendTaskBackForFix now call a new reopenLastStepForRevision helper that
flips only the last non-pending step back to pending (with currentStep
rewind via a newly-accepted updateTask field) — all earlier done steps
stay done, and the agent applies the feedback as an in-place patch per
the updated PROMPT.md instructions. determineRevisionResetStart stays
exported as @deprecated so existing unit tests still link.
3. Heartbeat scheduling is now state-driven. Previously a non-ephemeral
agent with a stale runtimeConfig.enabled=false on disk would never tick
and the Pause/Resume button couldn't arm the timer without also flipping
that hidden flag. HeartbeatTriggerScheduler's watchAgentLifecycle now
registers on transitions into active/running and clears on transitions
out; the tick and assignment-trigger guards key off state + ephemeral
classification. InProcessRuntime's created/updated listeners and startup
scan mirror the same semantics. runtimeConfig.enabled is only retained
for ephemeral (task-worker) opt-out.
Tests updated: agent-heartbeat.test.ts — one test renamed from "skips
registration when enabled is false" (obsolete behavior) to
"registers regardless of the legacy enabled flag"; 4 assignment-watching
tests now pass a realistic `state: "active"` on mock agents. 207 heartbeat
tests + 330 executor tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add display:flex and flex-direction:column to .setup-wizard-modal for scroll containment
- Ensure .setup-wizard-content has flex:1, min-height:0, overflow-y:auto for internal scrolling
- Protect header/footer with flex-shrink:0 to prevent collapse
- Add regression test coverage for viewport-safe layout contract
- Preserve mobile full-screen modal behavior
agentHealth.tsx:
- Drop the "Disabled" label and isHeartbeatEnabled helper. Server-side
heartbeat scheduling is driven by agent.state (active/running = armed),
not by the legacy runtimeConfig.enabled flag, so surfacing "Disabled" for
agents with a stale flag on disk was misleading.
- Replace the elapsed > heartbeatTimeoutMs check with elapsed > 2× effective
interval (with a 60s floor). heartbeatTimeoutMs is the per-run work budget,
not a between-tick freshness window; using it made any agent configured
with a multi-minute+ interval show Unresponsive the moment it got more
than 60s old. The effective interval resolver now falls back to the
server-side 1h default, so agents never configured via the dropdown and
agents with an explicit interval get consistent treatment, differing only
by scheduled cadence.
AgentDetailView.tsx:
- Remove Stop buttons from active/paused/running/error (mirrors the earlier
AgentsView cleanup — Pause/Resume/Retry cover reversible transitions,
Delete stays on idle/terminated for teardown).
- Add a "Next Heartbeat" info row alongside "Last Heartbeat" for ticking
agents (active/running), computed as lastHeartbeatAt + effective interval.
Tests rewritten to cover the new semantics; dropped 14 obsolete cases that
were pinned to the old heartbeatTimeoutMs-based check and the "Disabled"
branch. 42 agentHealth tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The compact board view was a duplicate of the list view with fewer affordances
— no heartbeat dropdown, no Last/Next indicators, and its own copy of the
action buttons that kept drifting out of sync with the list view's. Drop it
entirely and migrate any saved "board" preference to "list" on load.
- Remove Board toggle button (LayoutGrid icon) and the "board" state value.
- Remove the entire board rendering branch.
- Simplify getStateCardClass to the single "agent-card" prefix.
- Remove unused LayoutGrid import.
Tree and Org Chart views remain unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove Stop buttons from active/paused/running/error in both grid and list
views; Pause/Resume/Retry cover the reversible transitions and Delete stays
available on idle/terminated for teardown. Matches the existing shape of
AgentDetailView after the earlier cleanup.
- Drop the redundant interval badge next to the heartbeat dropdown — the
selected <option> already shows the current value.
- Add a "Next: HH:MM:SS" indicator alongside "Last:" for active/running
agents, derived from lastHeartbeatAt + configuredIntervalMs (full timestamp
in the tooltip). Paused/idle/error/terminated agents show Last only since
there's no scheduled next tick.
- Remove now-unused Square and Heart icon imports.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HeartbeatMonitor.executeHeartbeat() now checks if resolved task is done/archived
and exits before session creation with reason 'task_closed'
- When stale task came from persisted agent.taskId, clears the linkage to prevent
repeated stale activations
- HeartbeatTriggerScheduler.watchAssignments() now skips assignment callback dispatch
when assigned task is done/archived (when taskStore is available)
- Added comprehensive tests for stale-task activation guard behavior
Backup automation now emits `npx runfusion.ai backup --create` so scheduled
backups work for users on the zero-install path where `fn` is not on PATH.
`runfusion.ai` also exposes `fn` and `fusion` bins, so `npm i -g runfusion.ai`
puts them on PATH (npm does not link dep bins globally). Alias only defaults
to the dashboard when invoked as `runfusion.ai` / `runfusion`; `fn` / `fusion`
forward args verbatim so bare `fn` still prints help.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add global settings schema/types fields for persisted dashboard session state (selected project and node)
- Refactor NodeContext and current-project hooks to read/write project and node selection via global settings instead of project-local state
- Update App wiring to use the new selection flow across dashboard startup and switching behavior
- Add and expand dashboard tests for NodeContext, useCurrentProject, and view-state persistence behavior
- DevServerView.preview.test.tsx: drop manual-preview-override assertion
(the component hard-codes isManualPreviewOverride=false under the new
session model, so the badge is always "Auto"), provide both legacy and
current-API fields from createDevServerHookState, and mirror
embedContext into blockReason in createPreviewEmbedState so the
fallback panel picks up the reason text under the new destructure.
- runtime-adapter.test.ts: skip the createSession / promptWithFallback /
describeModel blocks with a TODO — the adapter loads pi.js via
CommonJS require() which vi.mock does not intercept, so the mocked
module is never actually installed. Needs a dynamic import seam
before these can run; tracking separately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace public logo.svg with the header ring+swoosh geometry to keep branding consistent
- Refresh icon-192.png and icon-512.png assets to match the updated dashboard mark
- Add PWA tests that validate logo.svg structure and ensure install icon files exist
- Document favicon/PWA brand alignment expectations in the dashboard README
- Add canonical DevServer session types for commands, runtime state, logs, and preview metadata
- Introduce session-scoped API helpers for list/create/get/start/stop/restart/delete operations under /api/devserver
- Add log history, preview URL, command detection, and SSE stream URL helpers for session-based endpoints
- Preserve migration compatibility by falling back to legacy /api/dev-server endpoints and normalizing legacy responses
- Move inline styles from AgentListModal and AgentGenerationModal into token-based stylesheet classes
- Polish NewAgentDialog step-zero layout, role grid, and AI generation button/summary presentation
- Improve AgentImportModal result stat visual hierarchy and semantic status coloring
- Expand dashboard modal CSS coverage with sectioned rules and mobile-specific refinements
- Update component and stylesheet tests to assert new class usage and modal responsive behavior
- Add ExecutionMode type contracts and executionMode field to core task interfaces
- Persist executionMode through SQLite schema mappings and TaskStore read/write paths
- Validate executionMode in dashboard route handlers and API request handling
- Expand core and dashboard test coverage for executionMode persistence and route behavior
- Replace inline agent state badge and card colors with state-specific CSS classes across list, board, tree, and org chart views
- Add reusable AgentEmptyState with create-agent CTA and wire it into all empty agent view modes
- Polish agents controls and metrics presentation in AgentsView/AgentMetricsBar with corresponding stylesheet token updates
- Extend dashboard tests for agent CSS classes, metrics bar behavior, list view rendering, and mobile view coverage
- Add a patch changeset for @gsxdsm/fusion describing the agent view UX improvements
- Migrate mission, milestone-slice, and subtask breakdown flows to shared ai-session-diagnostics logging
- Add a planning-flow guardrail test that fails on raw console.* diagnostics across planning modules
- Update mission and subtask breakdown tests to use structured diagnostics sink hooks instead of console spies
- Keep backward-compatible diagnostics test hooks and reset injected sinks to avoid cross-test leakage
- Extend core task types/store and dashboard API route handling to persist task reviewLevel
- Add review level controls to TaskForm, NewTaskModal, and TaskDetailModal flows
- Improve workflow step selector presentation in WorkflowResultsTab and styles for clearer review settings UX
- Document the new review level behavior and add route/form/modal tests to cover create and edit scenarios
- Add a reusable scoped diagnostics contract for AI session flows with typed levels and structured context
- Add sink injection hooks to capture and reset diagnostics output in tests without console monkey-patching
- Add nonfatal and nonfatalAsync wrappers that log failures via errorFromException and continue execution
- Add comprehensive Vitest coverage for scope isolation, sink behavior, error serialization, and non-fatal semantics
- Add Markdown/Raw rendering toggle support to DocumentsView and TaskDocumentsTab for consistent document preview behavior
- Reuse workflow-style toggle UX and markdown CSS patterns to align with existing dashboard design conventions
- Add comprehensive tests for DocumentsView and TaskDocumentsTab toggle interactions and rendering states
- Update dashboard guide documentation to describe the new Markdown/Raw toggle behavior
- Fetch unread inbox messages whenever messageStore is available, not only wake-on-message triggers
- Include pending messages in execution prompts for task and no-task heartbeat runs across timer, assignment, and on-demand sources
- Extend heartbeat messaging tests to cover run-wide mailbox prefetch and read-marking behavior
- Document heartbeat mailbox checking semantics and messageResponseMode behavior in agents docs
- Replace Header mailbox badge class with existing header-badge style token
- Trigger model loading when the dialog opens instead of only on initial mount
- Guard NewAgentDialog effects with isOpen to avoid late async state updates after close/unmount
- Update AgentsView dialog tests to await settled UI state before asserting controls
- Harden NewAgentDialog tests with async act/waitFor patterns around render, reopen, and fetch side effects
The bearer-token middleware was mounted globally on the Express app, so
the initial GET /?token=<token> request for index.html was rejected with
401 before the frontend JS could even load and capture the token from
the URL. The server-side query-string fallback only accepts fn_token=,
while the banner URL uses ?token= (which only the frontend captures), so
the bootstrap request had no valid auth path.
Fix: gate auth on /api/* only. The SPA shell (index.html, /assets/*,
favicon) is public — it contains no secrets, and the frontend auth.ts
module captures the token into localStorage and installs a fetch wrapper
that injects Authorization: Bearer on every /api/* call.
Also: add .env / .env.local to .gitignore so local FUSION_DAEMON_TOKEN
values don't accidentally get committed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-release polish. Two related changes bundled because they both land the
project on public-release footing:
Dashboard auth
- fn dashboard now gates the HTTP API + terminal/badge WebSockets behind a
bearer token by default. Token resolution order: --token flag,
FUSION_DASHBOARD_TOKEN env, FUSION_DAEMON_TOKEN env (back-compat), or an
auto-generated fn_<32 hex>. --no-auth disables. The startup banner prints
a click-to-open URL with ?token=<token> embedded.
- Auth middleware now also accepts fn_token=<token> as a query-string
fallback so EventSource and WebSocket clients (which can't set custom
headers) still authenticate.
- setupTerminalWebSocket / setupBadgeWebSocket now refuse unauthenticated
upgrades with a proper 401 + socket close.
- Frontend: new auth.ts module captures ?token= off the URL into
localStorage (key fn.authToken), strips it from the visible URL via
replaceState, and installs a window.fetch wrapper that injects
Authorization: Bearer <token> on every same-origin /api/* request.
EventSource/WebSocket URL builders (api.ts, sse-bus.ts, useTerminal,
useBadgeWebSocket) route through appendTokenQuery().
MIT license
- LICENSE file at repo root.
- license: "MIT" on root package.json and every packages/*/package.json,
plus description/bugs metadata on the CLI package.
Docs
- docs/cli-reference.md documents --token / --no-auth / FUSION_DASHBOARD_TOKEN
and the click-to-open auth flow.
- docs/getting-started.md, docs/docker.md, README.md point at the new flow
and the CLI reference section.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the engine restarts mid-step, an in-progress step may have already
passed plan + code review but not yet been flipped to done by the agent's
next task_update call. Previously, the next executor pass re-entered the
step and replayed both reviews — measured at 5-20 min of pure waste per
restart (observed in FN-2215 Step 1 and FN-2207 Step 6).
recoverApprovedStepsOnResume scans the task log for any in-progress step
whose most recent "code review Step N: APPROVE" entry is newer than its
most recent "Step N → pending" transition, and marks those steps done
before execute() runs. Safely skips steps that were reset after approval
(e.g. by a workflow revision) or only received REVISE verdicts.
Called from both the engine-restart path (resumeOrphaned) and the
unpause path, matching the two places the task log shows as vulnerable
to this race.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add stateDerived metadata to AgentHealthStatus to indicate when health text only mirrors agent.state
- Update getAgentHealthStatus to set stateDerived consistently across terminated, error, paused, running, heartbeat, idle, and disabled paths
- Update AgentDetailView, AgentListModal, and AgentsView to render icon-only health badges when labels are state-derived while preserving full labels via title tooltips
- Expand agentHealth tests with explicit stateDerived assertions and a table-driven semantics suite for representative states
- Extend isEphemeralAgent to treat metadata.internal agents as internal system agents
- Add legacy fallback detection for executor agents named verification-agent with no reportsTo
- Update AgentsView list and org tree filtering to honor the Show system agents toggle
- Add regression coverage in core and dashboard tests for default filtering and includeEphemeral visibility
- Move the assigned agent badge out of the card header into a dedicated metadata row below task details
- Add a new .card-agent-row container to control spacing and alignment for the badge block
- Update .card-agent-badge styling to use token-aligned pill radius and color-mix backgrounds while removing monospace/fixed-width conventions
- Expand TaskCard agent badge tests to verify new DOM placement and enforced badge style rules
- Update the dashboard dev-server API client for compatibility with multiple backend response shapes
- Refine useDevServer polling and SSE lifecycle handling to improve status/action reliability
- Gate dev server navigation in header/mobile overflow and fix mobile preview header wrapping styles
- Expand DevServerView and useDevServer test coverage with isolated mocks and log/status assertions
- Document the devServerView experimental feature flag in settings reference
- Add typed dev server models and constants for configs, session state, runtime metadata, and bounded log history
- Add JSON persistence helpers for .fusion/devserver.json with tolerant parsing and session reconstruction
- Add dev command auto-detection across root and workspace package.json scripts with framework inference and priority sorting
- Implement DevServerManager lifecycle controls, preview URL detection, port probing fallback, and singleton manager helpers
- Add Vitest coverage for devserver types, detection/persistence behavior, and manager lifecycle/events
- Add preview embed diagnostics with richer error classification and fallback state handling
- Improve PreviewIframe and DevServerView retry UX for timeout and iframe failure states
- Adjust preview layout/styles to prevent clipping and header overflow while keeping fallback panels centered
- Expand dashboard tests to cover fallback transitions, retry flows, and responsive CSS behavior
- Add usePreviewEmbed hook to derive preview embed URLs and availability state
- Add PreviewIframe component with iframe load/error wiring and deduplicated error callbacks
- Integrate preview panel actions, fallback messaging, and embedded iframe rendering in DevServerView
- Expand test coverage for usePreviewEmbed, PreviewIframe, and DevServerView preview integration scenarios
- Display heartbeat interval and timeout in seconds while persisting runtimeConfig in milliseconds
- Convert derived and persisted heartbeat values before dirty-state comparison so unchanged settings keep Save Settings disabled
- Update heartbeat validation minimums, placeholders, and hints to align with seconds-based inputs
- Expand AgentDetailView tests for pre-filled values, unchanged-state save disabling, validation, and payload conversion