Two related bugs let two in-progress tasks share a single
.worktrees/<name> directory:
1. The dashboard POST /tasks/:id/move route promoted tasks to
in-progress without allocating a fresh worktree path, so a queued
task carrying a stale worktree field from a prior preserveResumeState
requeue could land in-progress on a directory already held by another
active task.
2. moveTask({preserveResumeState:true}) kept the worktree pointer on
requeue. When the on-disk checkout was later removed or reassigned,
the next dispatch collided with a worktree the scheduler had handed
to another task.
moveTask now releases the worktree pointer on every reopen-to-todo hop
(branch is kept so committed progress survives via git worktree add
<path> <branch>). A new preserveWorktree option opts internal bounces
out of the release. moveTask also accepts an allocateWorktree callback
that runs under a new cross-task allocation lock in TaskStore, so two
concurrent moves cannot pick the same name from a stale snapshot. Both
the manual-move route and the scheduler dispatch path flow through the
allocator and share the lock.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The logout flow had two bugs causing credentials to reappear immediately:
1. The codebase has two separate auth storage Proxy chains:
- createFusionAuthStorage (engine, for agents)
- mergeAuthStorageReads (CLI, for dashboard UI)
Neither had a logout trap, so supplemental credentials from
~/.claude/.credentials.json were never excluded after logout.
2. The upstream AuthStorage.hasAuth() checks environment variables
(ANTHROPIC_API_KEY), which always returns true regardless of logout.
Fix: Add loggedOutProviders tracking to both Proxy chains. All query
traps (has, hasAuth, get, getAll, list, getApiKey) return false/undefined
for logged-out providers instead of delegating to the underlying storage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drops "terminated" from AGENT_STATES. The agent lifecycle now runs through
idle | active | running | paused | error. paused (carrying a pauseReason)
absorbs every former terminated use case — manual stop, heartbeat run
termination, spawned-child cleanup. Run status (agentRuns.status) is
unchanged: "terminated" stays a valid run-status value.
AGENT_VALID_TRANSITIONS allows direct any→idle transitions so resetAgent
no longer needs the intermediate hop.
Stack-wide:
- core/agent-store: lastError clearing + resetAgent simplified.
- engine/agent-heartbeat, executor, in-process-runtime: terminated state
writes → paused; halt-state listener fires on paused/error.
- dashboard: AgentsView/AgentListModal/AgentDetailView lose the Terminated
badge/option/state-block; agent pickers no longer filter terminated;
agentHealth drops the Terminated branch; routes/state cast widened to
the new AgentState union.
Tests across core and engine updated to assert paused for AgentState and
left "terminated" intact for run-status assertions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge adds three major features: an eval domain (`eval-store.ts`, `eval-types.ts`) with persistence schema for evaluation data; a plugin dashboard view registry with navigation integration for third-party dashboard extensions; and GitHub source metadata traceability that locks and enforces issu
Fusion-Task-Id: FN-3513
req.on("close") was firing for healthy SSE connections in this
Node/Express setup, which cancelled the in-flight agent the client was
still listening to and made even msg #1 fail after a fresh reload.
Keep the beginGeneration (no dispose) change from the same commit —
that one's correct.
Closing the QuickChat browser tab mid-response left the backend agent
running with no listener. The `activeGenerations` slot persisted and the
next message's freshly-opened CLI SessionManager raced against the
lingering agent on the same session file, so the model produced no
output for the new prompt.
- POST /chat/sessions/:id/messages now calls cancelGeneration on
req.on("close") if the response hasn't ended yet, so disconnects stop
the agent promptly.
- beginGeneration only aborts the prior controller; it no longer
disposes the prior agent. Disposing pre-emptively could yank the CLI
process out from under the new generation's session opened on the
same file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After stopping a streaming chat reply, the next message would appear
sent but show no Stop button or "Connecting…" indicator. The cancel
broadcast from the prior generation was leaking into the new SSE
subscription and immediately marking it as errored.
Each `chatManager.sendMessage` now allocates a per-generation id;
`ChatStreamManager` only delivers tagged broadcasts to subscribers
from the matching generation. `sendMessage`'s cleanup also stops
deleting a newer generation's `activeGenerations` slot when an older
one finally unwinds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge adds done-payload snapshot handling across the chat system (FN-3430), normalizing how final assistant messages are preserved and consumed in the dashboard hooks, plus it normalizes dashboard mailbox and user identity for inter-agent messaging (FN-3484) and introduces plugin workflow step
Fusion-Task-Id: FN-3430
This merge normalizes dashboard user identity and mailbox messaging (FN-3484, 4 steps), adds workflow step execution for plugins (FN-3490), and updates the restart integration store mock for plugin templates (FN-3096). Core changes touch the message store and store modules with identity normalizatio
Fusion-Task-Id: FN-3484
Merged CSS changes that apply tokenized sizing and focus styles to InsightsView and DesktopModeChooser components, with the majority of changes in InsightsView.css.
Fusion-Task-Id: FN-3471
Completes the commit body rendering in expanded git views within `GitManagerModal`, including updated component implementation and tests. The dashboard git routes and modal component now properly display full commit body content.
Fusion-Task-Id: FN-3301
This merge adds Docker node provisioning infrastructure with API routes for provisioning lifecycle, Docker node management, and failure-state handling, along with corresponding test coverage for onboarding, lifecycle, and error flows. It also introduces planning session rewind capability with a moda
Fusion-Task-Id: FN-3116
This merge delivers four major features: a planning session rewind system (FN-3447, steps 1–4) with a new backend route for rolling back sessions, modal back-action wiring, and updated typing; workspace verification gates (FN-3385) for agent prompt editing; an agents view org chart spacing rework (F
Fusion-Task-Id: FN-3447
The merge stabilizes a test case in the NodeDetailModal test file related to the docker config modal's recreate indicator, correcting an assertion that was causing intermittent failures.
Fusion-Task-Id: FN-3114
Adds a regression test sentinel in the engine's in-process runtime test suite to guard against runtime guard behavior regressions (FN-3324).
Fusion-Task-Id: FN-3324
Test FN-3314 completes its final step by refining an auth route assertion in the agents routes test, ensuring the test accurately validates the expected behavior.
Fusion-Task-Id: FN-3314
Fixes FN-3112: Updates NodesView CSS to use tokenized border-radius and transition values from the design system instead of hardcoded pixel values, ensuring consistency with the dashboard's established token variables.
Fusion-Task-Id: FN-3112
Fixes task detail modal danger/error styling by switching to token-based CSS variables for consistent theming across dark and light modes.
Fusion-Task-Id: FN-3350
This merge adds a changeset for feature FN-3349 (in-review retry behavior) and delivery documentation to the `@runfusion/fusion` package.
Fusion-Task-Id: FN-3349
When running multiple projects (e.g., primary + fitness-app), on-demand
agent heartbeat triggers from the dashboard silently created zombie run
records that never executed. The agent appeared "running" but produced
no logs, no system prompt, no execution prompt.
Root cause: the dashboard routes used a single HeartbeatMonitor bound to
whichever project initialized first. For agents in other projects,
isHeartbeatMonitorForProject() returned false, causing either a 400
error or a fallback to agentStore.startHeartbeatRun() which only creates
a record without executing.
Fix: add resolveHeartbeatMonitor() which looks up the correct engine's
HeartbeatMonitor via engineManager by matching the scoped store's root
directory. Update POST /agents/:id/runs, POST /agents/:id/heartbeat,
POST /agents/:id/runs/stop, and triggerCommentWakeForAssignedAgent to
use the resolved monitor instead of the single static one.
ClosesRunfusion/Fusion#31
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Orca <help@stably.ai>
Merges FN-3336 to recover chat streaming state on page reload — adds `isGenerating()` and `getGeneratingSessionIds()` to `ChatManager`, enriches the session API to surface active-streaming sessions, and makes `useChat` and `useQuickChat` hooks restore the `isGenerating` flag when loading existing se
Fusion-Task-Id: FN-3336
The merge lands the mesh configuration system (FN-3111) with type definitions, a `MeshConfigGenerator` service using a new `DockerClientService.recreateContainer()` method, and backend API routes for managing Docker-based mesh nodes. It also adds a "New Chat" button to the ChatView header on desktop
Fusion-Task-Id: FN-3111
Merges FN-3110 to add Docker provisioning support across the stack: TypeScript types and DockerProvisioningService in core, API routes in dashboard for provisioning operations, a useDockerProvisioning hook for frontend integration, and a DockerProvisioningStatus UI component — all covered by unit an
Fusion-Task-Id: FN-3110
This merge adds Docker connectivity management to Fusion (FN-3109), introducing a Docker client service in `@fusion/core` with typed interfaces for daemon connection configuration (host, socket path, TLS). The dashboard gains a `DockerTargetSelector` component for choosing between local socket and T
Fusion-Task-Id: FN-3109
Adds a resolved planning model display to the planning modal by introducing a new `/api/models/resolve` endpoint, wiring it through the legacy API, and updating the modal to show the final resolved model alongside its source (FN-3120).
Fusion-Task-Id: FN-3120
The planning modal's draft sync only updated SQLite, never the in-memory
session, so Start Planning ran the agent against whatever fragment was
typed before the first 500ms debounce and silently dropped everything
after. Drafts that survived a backend restart couldn't be started at
all (lazy rebuild was missing for the start path), reopened drafts left
the textarea empty, and the model override the user picked at create
time was forgotten on reopen — Start Planning would silently use the
project default instead.
This change rehydrates initialPlan from SQLite in startExistingSession,
flushes the latest text from the request body before reading it back,
lazy-rebuilds the in-memory session from the persisted row when needed,
and round-trips the model override through inputPayload so reopen
restores it into modal state. Sidebar drafts now render a derived
preview (from inputPayload, never persisted as title) so multiple
drafts are distinguishable while editing, and summarizeDraftTitle fires
on textarea blur and modal close — gated on status rather than title
content so blur-then-edit still refreshes rather than locking to the
first snapshot.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add managed Docker node API client/routes, onboarding hook, and NodesView integration with new onboarding modal UX
- Refine Add Node, mobile nav, agent/node detail, and onboarding-related component styling/interaction flows
- Expand dashboard/core/cli test coverage for onboarding flows, node routes, insights persistence, and mobile regressions
- Add CLI/plugin packaging updates including bundled dependency-graph install and plugin schema initialization support
Fusion-Task-Id: FN-3108
`git diff --no-index` exits 1 when files differ — that's the success case for synthetic untracked-file diffs, not an error. Use spawn directly so we can resolve on exit 0 or 1, independent of how callers (or test mocks) wrap execFile / promisify.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce a draft lifecycle for planning sessions: typing into the
PlanningModeModal textarea now creates a server-side draft after a
300ms debounce, persisted with status='draft' so the user's in-flight
plan survives modal close/reopen and shows up immediately in the
session list.
- planning.ts: new createDraftSession path; persistSession status
union widened to include 'draft'; Session gains an explicit title
field so subsequent updates don't clobber it.
- register-planning-subtask-routes.ts: wires the createPlanningDraft
POST endpoint that the modal calls on debounce.
- ai-session-store.ts: tracks the draft status across queries so the
session list and locks behave the same as any active session.
- legacy.ts: client wrapper for createPlanningDraft.
- PlanningModeModal styling, tests, and ModalReentry coverage updated
for the new flow.
- docs/architecture.md notes the expanded ai_sessions.status lifecycle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge ships several feature and infrastructure improvements across the codebase. Task title validation is strengthened in triage with stricter rejection of malformed titles and preference for prompt-declared titles (FN-3056), while task creation now preserves priority settings (FN-3210). The Mi
Fusion-Task-Id: FN-3056
- Add scheduler logic to create dependency-linked follow-up tasks when actionable PR feedback remains after a PR is merged or closed
- Update engine runtime/project wiring to support manual PR create flows and branch publish behavior for fusion/<task-id>
- Add dashboard route coverage for manual PR creation/linking behavior and corresponding engine/runtime tests
- Document manual PR branch conventions and follow-up behavior in task management and dashboard docs
Fusion-Task-Id: FN-3202
This merge implements a "preserve progress" option for task resets across the system. FN-3185 adds a `preserveProgress` flag to `moveTask` that keeps status/history when resetting tasks back to `todo`, with required explicit confirmation dialogs to prevent accidental resets. The feature is wired thr
Fusion-Task-Id: FN-3185
Defaults to true so existing behaviour (dashboard probes PATH for `fn` /
`fusion` and surfaces install / version-mismatch states) is unchanged.
When the user toggles it off in Settings → General → CLI Binary:
- `GET /system/fn-binary/status` short-circuits before `detectFnBinary()`
and returns `state: "skipped"`. No `<bin> --version` subprocess is
spawned at all, so an outdated globally-installed CLI cannot run as a
side effect of opening the dashboard.
- The install banner is hidden when `state` is `"skipped"`.
- `POST /system/fn-binary/install` rejects with HTTP 409 since install
is the user action that the status check informs.
- The Settings UI gains a checkbox under the existing CLI binary panel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The dashboard task-edit route destructured every editable body field
except priority, so changing priority via the task-detail modal was
silently dropped before reaching store.updateTask. Wire priority
through with isTaskPriority validation (null resets to default).
Without this fix the priority-aware triage/scheduler/merge ordering
shipped previously had no effect for tasks edited in the dashboard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This merge introduces a new Todo Planning mode for task creation, wiring the entrypoint through the dashboard and CLI, accompanied by a new `PlanningModeModal` component and associated tests. It also makes peer exchange shutdown deterministic in the engine, improves rate limiting for the planning fl
Fusion-Task-Id: FN-3064
The merge delivers three major features: a droid CLI path reconciliation extension that resolves workspace path mismatches for spawned agents, session-first quick chat with improved heartbeat prompts and a dramatically simplified QuickChatFAB component, and canonical agent asset directory naming wit
Fusion-Task-Id: FN-3033
Merges FN-2982 Step 3: adds model filtering for the droid-cli settings API, fixes planning mode question display and new-session reset in the dashboard, and adds test coverage for droid-cli settings and model route registration.
Fusion-Task-Id: FN-2982
This merge lands v0.12.0 with two major features: a droid-cli provider integration adding auth routes, status endpoints, and a settings toggle hook for controlling CLI-based authentication, plus a new experimental agent onboarding modal with a create-agent form. The release also stabilizes engine st
Fusion-Task-Id: FN-2981
Merges FN-3049 to replace all runtime dynamic imports of `@fusion/engine` with static imports that esbuild can inline into the CLI bundle, preventing the known regression where the published `npm i -g @runfusion/fusion` silently failed at the import site. Also ships FN-3024, adding an experimental a
Fusion-Task-Id: FN-3049
Added a new `droid-cli-probe` module to the dashboard package with test coverage, implementing a CLI probe capability for the droid system.
Fusion-Task-Id: FN-2979