Hermes / OpenClaw / Paperclip runtime cards in Settings now lazily
register themselves on first Save instead of failing with `Plugin
"fusion-plugin-...-runtime" not found`. The CLI also bundles each
runtime plugin (with @fusion/plugin-sdk inlined via esbuild) into
dist/plugins/<id>/bundled.js so npm/npx-installed Fusion can load them
without the workspace SDK dependency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes no-op `agents.filter((a) => true)` calls (a leftover from the
terminated AgentState refactor) flagged by eslint and updates affected
tests and fixtures so `terminated` is no longer referenced. Also:
- Deletes the duplicate `state === "paused"` render branch in
AgentListModal list view that produced two "Resume" buttons.
- Updates the AgentDetailView help text to reflect the current
deletable states ("idle or paused").
- Aligns the bundled-plugin-install test with the new auto-load
behavior for already-installed enabled plugins.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the engine boots, if an agent has the new
runMissedHeartbeatOnStartup flag enabled and lastHeartbeatAt is older
than its interval, fire one catch-up heartbeat through the existing
executeHeartbeat path. Default is off, so existing agents are
unchanged. Toggle exposed in the agent's Heartbeat Settings tab.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Only running shows green and error shows red; idle/active/paused share
the neutral gray border and badge across the agent list, board, and
org-chart views.
Co-Authored-By: Claude Opus 4.7 (1M context) <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>
- Run Now now optimistically stamps the agent's state to "running" before
the startAgentRun API call so the card reacts immediately. Rolls back on
error, mirroring the handleStateChange pattern.
- Whole .agent-card body is clickable (role=button, Enter/Space, focus ring)
and bails when the click landed on an action button, select, or the
role-icon so those keep their dedicated behaviors.
- Renamed the card's "View Details" button to "Details" and switched
.agent-card-actions to flex-wrap: nowrap so Run Now / Pause / Details
stay on one row regardless of card width.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related leaks in the agent lifecycle plus a refactor:
- Governance-skip paths in executeHeartbeat (budget/global-pause/engine-paused)
were leaving agents permanently stuck in `running` because they ran startRun
first and then short-circuited with skipStateTransition: true. Removed the
flag from those four paths so they flow through running → active. Added
HeartbeatMonitor.reconcileOrphanedRunningAgents() on start to recover any
rows already trapped in this state.
- Ephemeral task-workers piled up across runtime restarts because taskAgentMap
was in-memory only and the startup sweep ignored ephemerals with no taskId.
Now: spawn dedup via findAgentByName before create, on-disk fallback in
finalize when the in-memory map is empty, and the sweep deletes any
ephemeral not bound to an in-progress task.
- Extracted the lifecycle into EphemeralWorkerManager
(packages/engine/src/ephemeral-worker-manager.ts). InProcessRuntime drops
~140 lines and delegates via onTaskStart/onTaskComplete/onTaskError/
attachStateChangeListener/reconcileOrphaned. ChildProcessRuntime and
RemoteNodeRuntime inherit the fix because they delegate execution to a
worker that runs InProcessRuntime.
Durable assigned agents now return to `active` after task completion (was
`terminated` in the old contract).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add AgentErrorDetailsModal and wire agent list/detail views to open full error diagnostics while keeping inline errors compact
- Add line-number gutter toggle in FileEditor and Files modal with dashboard persistence coverage
- Align project memory scope guidance across core logic, CLI tool docs, and dashboard docs
- Add regression coverage for runtime plugin alias behavior and update related engine/heartbeat tests
- Include changesets for FN-3530 UI improvements and FN-3485 memory guidance updates
Fusion-Task-Id: FN-3530
- Clarify task memory scope behavior across core types, project memory logic, engine tool prompts, and related docs
- Add regression coverage for memory scope and runtime plugin alias handling in core/dashboard/engine tests
- Add agent avatar API routes and dashboard UI support for avatar display and storage documentation
- Add line-number gutter toggle support in FileEditor and Files modal with accompanying component tests
- Include changeset for @runfusion/fusion documenting memory scope guidance update
Fusion-Task-Id: FN-3485
This merge adds a line-number toggle to the Files modal with persisted preference, introduces an AgentAvatar component with server-side avatar storage routes, and adds documentation for both the toggle and avatar storage. It also includes a regression test for runtime plugin alias behavior and updat
Fusion-Task-Id: FN-3528
Adds a regression test for runtime plugin alias functionality (FN-3298 Step 3), covering 25 lines of test coverage for this feature.
Fusion-Task-Id: FN-3298
Six new tests covering the three bugs fixed in the previous commit:
- Retry limit: stops showing toasts after 3 consecutive failures,
resets counter on success
- Skip flag: startFreshSession sets/clears skipNextSessionInitRef,
creates new session even when existing one exists
- Ref stability: switchSession reads activeSession from ref so it
correctly detects "same session" and skips re-initialization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three interacting bugs caused "Failed to initialize chat" toast spam and
prevented fresh session creation:
1. Race condition in handleCreateFreshSession — setting chatMode/
selectedAgentId before startFreshSession triggered the session-init
useEffect, which called switchSession and resumed the old session
instead of creating a new one. Fixed with skipNextSessionInitRef.
2. Infinite retry loop — shouldRetrySessionInit retried indefinitely
when initializeSession failed, producing unbounded toast spam.
Fixed with a 3-retry cap (initRetryCountRef).
3. Cascading re-renders — switchSession depended on activeSession in
its closure, getting a new identity on every state change and
re-triggering the consumer's useEffect. Fixed by reading
activeSession from a ref instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the local fn/fusion CLI is on the wrong version, the banner now
says "Update the Fusion CLI", shows installed vs expected versions,
and labels the action "Update with npm" instead of the generic install
copy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The test clicked 'Medium' and 'Continue' synchronously without waiting
for the scope question options to fully render. Use findByText/findByRole
to wait for elements to appear before interacting, and add a timeout to
the final waitFor for the second question.
Previously the back button left the dashboard page entirely because
useNavigationHistory was only enabled for mobile viewports. Now it's
enabled for all viewports — desktop and mobile — so the browser back
button dismisses modals and reverts view changes within the SPA.
Changes:
- Enable useNavigationHistory for desktop (enabled: true instead of enabled: isMobile)
- Remove all isMobile ? historyAwareHandler : plainHandler ternaries
- Always use navigation-aware handlers (openDetailTask, openSettingsWithNav, etc.)
- Update JSDoc to reflect desktop support
Up/Down arrows now cycle the focused panel on the Main page (mirroring
Left/Right), except on the Logs panel where they keep their existing
role of navigating log entries. Expanding a log entry with Enter now
also disables xterm mouse reporting so the user can click-drag to
select the message text; closing the expanded view restores wheel
scrolling.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
node-pty was previously only present transitively via the workspace
@fusion/dashboard devDependency, which is stripped at publish time. Fresh
users running `npx runfusion.ai` hit a 503 "PTY module could not be loaded"
when opening the dashboard terminal. Tightened the package-config guard so
this regression is caught next time.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch process.emitWarning in the shared vitest setup to drop the
"SQLite is an experimental feature" notice; align the test mock for
getQrPayload with the canonical RemoteQrPayload signature.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Raise checkForChanges slow-poll warn threshold from 100ms to 750ms so
warnings only fire when cycles approach the 1s poll interval, and route
skill-resolver info diagnostics through log() instead of warn().
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the race called out in code review: when recovery samples a
stale run id and a fresh run is spawned for the same agent before
endHeartbeatRun() lands, only the sampled id is terminated — never the
freshly-spawned run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the dashboard crashes mid-heartbeat, the agentRuns row is left in
status='active' forever. HeartbeatTriggerScheduler.onTimerTick treats
any active run as "still running" and skips every subsequent tick, so
agents go silent indefinitely (observed: 6+ hours). The existing
in-memory missed-heartbeat watchdog can't help — its trackedAgents map
is wiped on process restart.
SelfHealingManager.recoverStaleHeartbeatRuns now reconciles these on
startup and during periodic maintenance: terminates active runs whose
processPid does not match the current process, has no recorded pid, or
has been active for more than 6 hours.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The MissionLoop calls this.missionStore.listMissions() during startup
recovery, but the mock TaskStore's getMissionStore() return value didn't
include this method. When the runtime startup sequence raced ahead, it
would hit "listMissions is not a function" — making the test flaky.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The merge completes FN-3498 across three steps: adds ownership-aware done-task reconciliation to the merger, prevents branch-missing head SHA pollution during merge operations, and restores workspace typecheck compatibility. Core changes touch the merger (103 lines) and self-healing module (67 lines
Fusion-Task-Id: FN-3498
Merged four commits implementing comment-driven retriage: triage rules now respond to specific comment patterns (Step 1) and surface needs-replan feedback inputs in the UI (Step 2), with documentation for the new behavior and a bug fix restoring workspace typecheck defaults. Changes span the core ta
Fusion-Task-Id: FN-3502
Merges FN-3470 in two steps: first, runtime plugins now prefer source path aliases over build artifacts, with hardening tests for vitest alias resolution and plugin view registry updates; second, a new `ensure-test-artifacts.mjs` bootstrap script guarantees required test files exist before test runs
Fusion-Task-Id: FN-3470
This merge introduces an eval automation domain store with persistence schema and a plugin dashboard view registry (FN-3512/FN-3513), adds scheduled eval batch architecture documentation (FN-3388), and includes substantial test coverage for Research routes and hooks (FN-3368 steps 1-3). The branch a
Fusion-Task-Id: FN-3368
The options parameter in __setCreateFnAgent's inline arrow already
uses any to match the module-level let (which has its own suppress
comment). Add the missing eslint-disable-next-line so CI passes.
Unrelated to the spinner fix — pre-existing on main.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-existing lint error on main — the `any` cast in __setCreateFnAgent
mirrors the eslint-disable already on the adjacent variable declarations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simulates a database where project_insight_runs exists without lifecycle
and cancelledAt columns (the state that caused the original bug), then
verifies that re-opening the database adds the columns and creating a run
succeeds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This merge adds three major features: a new **eval domain store** (`eval-store.ts`, `eval-types.ts`) for AI evaluation data with persistence schema and a `PluginDashboardViewHost` for extensibility; a **plugin dashboard view registry** with navigation integration that lets plugins register custom vi
Fusion-Task-Id: FN-3512
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
Merged FN-3157 to add a plugin dashboard views system, including a plugin view registry with lazy loading, navigation integration for Header and MobileNavBar, a usePluginDashboardViews hook with cache and refetch support, and tests covering the no-loader path. Also added documentation in `docs/PLUGI
Fusion-Task-Id: FN-3157