Flattens the Todo sidebar list rows so active/hover states read through background and text color only, without per-row borders or the active-row left accent stripe.
- Removed `border: 1px solid transparent` and hover `border-color` from `.todo-list-item`
- Added hover text color instead of hover border to keep hover state visible
- Removed the `border-color` and inset box-shadow accent stripe from `.todo-list-item--active`
- Added a CSS contract test asserting sidebar list rows stay flat (no left accent stripe, no per-row borders)
Files changed:
packages/dashboard/app/components/TodoView.css | 9 +++++----
.../components/__tests__/TodoView.mobile-css.test.ts | 19 +++++++++++++++++++
2 files changed, 24 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-7870
Fusion-Task-Lineage: 78db20c0-7e53-427c-95da-7c9d5fa828d7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds a one-click commit-and-push affordance to the Git Manager modal's Changes panel, letting users commit staged changes and immediately push the active branch without a separate step.
- Add handleCommitAndPush callback in GitManagerModal that reuses createCommit and pushBranch, refreshes file changes/status on success, and surfaces a distinct toast (with the local commit hash preserved) if the push step fails after a successful commit
- Wire commitAndPush through to ChangesPanel and render a new "Commit and Push" button beside the existing Commit button, disabled while committing, when the message is empty, or when there are no staged files
- Add test coverage for the commit-and-push flow, including the partial-failure case where commit succeeds but push fails
- Add a minor changeset documenting the new Git Manager feature
Files changed:
.changeset/fn-7868-git-manager-commit-push.md | 7 +++
.../dashboard/app/components/GitManagerModal.tsx | 64 +++++++++++++++++++-
.../components/__tests__/GitManagerModal.test.tsx | 68 ++++++++++++++++++++++
3 files changed, 138 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7868
Fusion-Task-Lineage: 8b6913db-6f2a-45ab-b99d-a5c11ce53439
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Board TaskCard priority badges no longer render visible priority text, so the .card-meta-badges row cannot wrap onto a new line when a priority label widens it.
- TaskCard.tsx: drop the visible priority-label <span>, add title/aria-label with the full priority label, and keep the label reachable via a visually-hidden span for assistive tech
- TaskCard.css: update the FNXC comment on .card-priority-badge to reflect the icon-only rationale (spacing/geometry rules unchanged, still shared with the Task Detail chip/select)
- TaskCard.test.tsx: assert icon-only rendering (no visible text node/span), title/aria-label correctness, visually-hidden label content, and that the badge is absent for tasks without a priority; loosen the mocked lucide icons to forward arbitrary props
- Add a patch changeset documenting the icon-only priority badge fix
Files changed:
.changeset/icon-only-priority-badges.md | 7 +++++
packages/dashboard/app/components/TaskCard.css | 2 +-
packages/dashboard/app/components/TaskCard.tsx | 12 ++++++---
.../app/components/__tests__/TaskCard.test.tsx | 30 +++++++++++++++++-----
4 files changed, 39 insertions(+), 12 deletions(-)
Fusion-Task-Id: FN-7867
Fusion-Task-Lineage: 5c845c23-0a9f-47b4-9a75-6c410b507ef4
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Project-scoped chat managers can be cached before the project engine boots, so fn_send_message/fn_read_messages were silently dropped for lazily-booted (desktop) sessions while browser sessions kept them; the fix refreshes the cached manager's MessageStore post-construction and surfaces a diagnostic + chat-stream warning when the reduced tool schema condition occurs instead of failing silently.
Key changes:
- ChatManager gains setMessageStore() to refresh a cached manager's MessageStore post-construction, mirroring the existing setPluginRunner() refresh seam
- getOrCreateScopedChatManager()/resolveScopedChatManager() now accept and wire an optional MessageStore, upgrading already-cached managers instead of leaving them stale
- register-chat-routes.ts now passes engine.getMessageStore() through to the scoped chat manager resolver
- ChatManager emits a new 'warning' chat-stream event (code: tool-schema-reduced) plus a diagnostics.warn() call when a bound agent has no MessageStore, so reduced tool schema is agent-visible instead of a silent per-call failure
- Added regression tests covering MessageStore wiring/refresh in chat-project-services and chat-manager, plus a patch changeset documenting the fix
Files changed:
.changeset/fn-7854-chat-tool-schema-parity.md | 7 ++
.../dashboard/src/__tests__/chat-manager.test.ts | 124 ++++++++++++++++++++-
.../src/__tests__/chat-project-services.test.ts | 67 +++++++++++
packages/dashboard/src/chat-project-services.ts | 10 +-
packages/dashboard/src/chat.ts | 39 +++++++
.../dashboard/src/routes/register-chat-routes.ts | 2 +-
6 files changed, 245 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-7854
Fusion-Task-Lineage: 1d1ee3e7-608b-4b7d-be45-138b38b27f17
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the artifact viewer FloatingWindow (image/video/PDF/document) so it opens as a full-screen sheet on mobile instead of a small draggable/resizable desktop-style window.
- Add a mobile-breakpoint override for .artifacts-gallery-window that clamps the FloatingWindow to inset:0/100vw/100dvh with no border/radius/shadow
- Hide the FloatingWindow resize handle and disable header drag cursor/touch-action on mobile so the sheet can't be dragged or resized like the desktop window
- Add a CSS-contract regression test (ArtifactsGallery.css.test.ts) asserting the mobile sheet rules exist while desktop keeps the header drag affordance
- Update dashboard-guide.md docs to describe desktop draggable/resizable behavior vs. mobile full-screen sheet behavior
- Add a patch changeset for @runfusion/fusion documenting the fix
Files changed:
.changeset/fn-7865-artifact-viewer-mobile-sheet.md | 7 +++
docs/dashboard-guide.md | 5 +-
.../dashboard/app/components/ArtifactsGallery.css | 28 +++++++++-
.../__tests__/ArtifactsGallery.css.test.ts | 63 ++++++++++++++++++++++
4 files changed, 100 insertions(+), 3 deletions(-)
Fusion-Task-Id: FN-7865
Fusion-Task-Lineage: 0b5dfaee-3f7b-4a2e-968c-324182ae7953
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Artifact-registration mailbox notifications now render a shared inline preview and open-artifact link instead of plain text metadata.
- Add MailboxArtifactAttachment component rendering an inline image/document preview plus an "open artifact" link from message.metadata (artifactId/artifactType/mimeType) via artifactMediaUrl
- Wire MailboxModal and MailboxView to render the new attachment for artifact-registered messages, with supporting CSS
- Emit metadata.mimeType from notifyArtifactRegistered in agent-tools.ts so mailbox surfaces can pick the right preview affordance without an extra artifact fetch
- Add/extend tests for the new component and for MailboxView/agent-artifact-tools coverage
- Update dashboard guide docs and add a changeset for the feature
Files changed:
.changeset/fn-7864-artifact-mail-link.md | 7 ++
docs/dashboard-guide.md | 2 +-
.../app/components/MailboxArtifactAttachment.tsx | 103 +++++++++++++++++++++
packages/dashboard/app/components/MailboxModal.css | 74 +++++++++++++++
packages/dashboard/app/components/MailboxModal.tsx | 15 +++
packages/dashboard/app/components/MailboxView.tsx | 15 +++
.../__tests__/MailboxArtifactAttachment.test.tsx | 65 +++++++++++++
.../app/components/__tests__/MailboxView.test.tsx | 93 +++++++++++++++++++
.../src/__tests__/agent-artifact-tools.test.ts | 32 ++++++-
packages/engine/src/agent-tools.ts | 5 +
10 files changed, 409 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7864
Fusion-Task-Lineage: a6502e18-5f7f-4c67-80fb-a709e4a52c50
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Bounds the execute->pause-abort->todo dispatch loop so a task can no longer requeue forever with no visible signal or terminal state.
- Track a progress-anchored `executeRequeueLoopCount`/`executeRequeueLoopSignature` pair on the task row (current step + step statuses) so slow no-progress requeue cycles are counted independently of the scheduler's wall-clock `dispatchStormCount` guard.
- Warn visibly in the task log at `EXECUTE_REQUEUE_LOOP_VISIBLE_THRESHOLD` (3) and terminalize non-paused, non-terminal tasks at `MAX_EXECUTE_REQUEUE_LOOP_CYCLES` (6) with `status:"failed"` and an `EXECUTION_DISPATCH_LOOP_EXHAUSTED:` error, preserving worktree/branch/step progress.
- Emit a new `task:execution-dispatch-loop-terminalized` run-audit mutation type with ids/counts/outcomes-only metadata.
- Reset the loop counters on real progress, manual retry, forward moves (in-review/done/archived), and unpause, in both the executor and scheduler.
- Add DB migration 142 (`executeRequeueLoopCount`, `executeRequeueLoopSignature` columns) plus store read/write/reset plumbing.
- Add reliability-interactions coverage for the new loop guard and extend store-persistence tests for the new columns.
- Document the new behavior in AGENTS.md and docs/architecture.md.
Files changed:
AGENTS.md | 1 +
docs/architecture.md | 2 +
packages/core/src/__tests__/store-persistence.test.ts | 45 +++++
packages/core/src/db.ts | 17 +-
packages/core/src/manual-retry-reset.ts | 1 +
packages/core/src/store.ts | 22 ++-
packages/core/src/types.ts | 11 ++
.../execute-requeue-loop-guard.test.ts | 188 +++++++++++++++
packages/engine/src/executor.ts | 67 +++++++-
packages/engine/src/run-audit.ts | 2 +
packages/engine/src/scheduler.ts | 8 +-
11 files changed, 355 insertions(+), 9 deletions(-)
Fusion-Task-Id: FN-7863
Fusion-Task-Lineage: db40507f-5851-435e-8854-c1ed695b4154
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Aligns the task card header so the id chip, first badge row, and right-side size/action controls share a consistent centered vertical baseline, using the existing card chip height tokens for row rhythm on both desktop and mobile while preserving FN-7837 wrapping behavior.
- Give .card-header-badges and .card-id a shared min-height (--card-chip-height) and switch .card-id to inline-flex with centered items and line-height:1 so it lines up with sibling chips instead of sitting on its own baseline
- Add min-height (--card-chip-height) to .card-header-actions so the right-aligned size/action cluster matches the id/badge row height
- Add a mobile-breakpoint override giving .card-id, .card-header-badges, and .card-header-actions a shared --card-chip-height-mobile min-height, extending the existing FN-4365/FN-4351/FN-7837 compact mobile header comment
- Add/extend TaskCard.badge-wrap tests: a shared expectSharedHeaderBaseline() assertion helper, new in-progress and no-badges alignment test cases, and a test asserting the mobile header rhythm CSS rule is present in loaded app CSS
Files changed:
packages/dashboard/app/components/TaskCard.css | 23 +++--
.../__tests__/TaskCard.badge-wrap.test.tsx | 100 ++++++++++++++++++++-
2 files changed, 116 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-7862
Fusion-Task-Lineage: 1d66fbd6-30bc-4a76-9eb4-3b8734ddadc3
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Debug org agents error state recovery regression: durable heartbeat-managed
agents with a non-recoverable error (permanent/credential/model-access/
config, not stale-worktree/module-resolution) were previously left
indefinitely in bare `state:"error"` with no operator-visible reason,
and CLI agent inspection tools did not surface error/pause diagnostics.
- Timer path (`HeartbeatMonitor`) and run-entry recovery now classify
non-recoverable durable heartbeat errors and park the agent `paused`
with `pauseReason:"error-unrecoverable"` instead of restart-looping or
sitting in `error` forever.
- `SelfHealingManager` mirrors the same non-recoverable classification in
its recovery sweep, parking with the same reason/metadata and skipping
the exhausted/next-retry gates for that terminal bucket.
- New `agent:error-parked-unrecoverable` run-audit event type emitted by
both the heartbeat and self-healing paths (ids/counts/outcomes-only
metadata).
- `fn_agent_show` now prints `Last Error`, `Pause Reason`, and a compact
`Error Recovery` counter line; `fn_list_agents` prints the same
diagnostics only for agents currently in `error`/`paused`.
- Updated `AGENTS.md`, `docs/agents.md`, and `docs/architecture.md` to
document the new terminal-park behavior and CLI diagnostics surface.
- Added a changeset (`@runfusion/fusion` patch) describing the
operator-facing fix.
Files changed:
.changeset/fn-7859-org-agent-error-diagnostics.md | 7 ++
AGENTS.md | 2 +-
docs/agents.md | 3 +-
docs/architecture.md | 4 +-
packages/cli/src/__tests__/extension.test.ts | 68 ++++++++++++++++
packages/cli/src/extension.ts | 64 +++++++++++++++
.../src/__tests__/heartbeat-error-recovery.test.ts | 47 ++++++++++-
packages/engine/src/__tests__/self-healing.test.ts | 94 ++++++++++++++++++----
packages/engine/src/agent-heartbeat.ts | 71 +++++++++++++++-
packages/engine/src/run-audit.ts | 1 +
packages/engine/src/self-healing.ts | 46 +++++++++--
11 files changed, 375 insertions(+), 32 deletions(-)
Fusion-Task-Id: FN-7859
Fusion-Task-Lineage: 09b2035d-e8a0-438f-b1ab-1b0048b35c76
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix useChat so already-rendered user/assistant messages no longer flicker away while an agent turn is actively streaming.
- useChat.ts: during an active streaming turn for the current session, treat stale/empty/cross-session loadMessages responses as append-only against the visible thread instead of replacing it, merging any genuinely new same-session messages in and skipping the session-cache write when the active thread is being preserved.
- ChatView.streaming-thread.test.tsx: add coverage asserting the rendered thread stays visible across mid-turn session-update/tool-call/stale-reload churn.
- useChat.test.ts: add hook-level regression tests for the append-only/merge/cache-skip behavior during active streaming.
- docs/architecture.md, docs/dashboard-guide.md: document the append-only mid-turn thread-stability behavior.
- Add changeset (patch) for @runfusion/fusion describing the user-facing fix.
Files changed:
.../fn-7853-chat-mid-turn-message-stability.md | 7 +
docs/architecture.md | 1 +
docs/dashboard-guide.md | 1 +
.../__tests__/ChatView.streaming-thread.test.tsx | 130 +++++++++++++
.../dashboard/app/hooks/__tests__/useChat.test.ts | 208 +++++++++++++++++++++
packages/dashboard/app/hooks/useChat.ts | 35 +++-
6 files changed, 380 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7853
Fusion-Task-Lineage: d9909469-082c-4eeb-81fb-b36d1a9e4705
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Patch useTasks pauseTask/unpauseTask to update local hook state and the project SWR task cache immediately on API success, instead of waiting for SSE/poll to reconcile paused state.
- pauseTask/unpauseTask now bump fetchVersionRef, patch the in-memory tasks list, and patch/clear the project SWR cache the same way retryTask/bypassReview already do
- guards against stale in-flight fetches clobbering the just-applied paused/unpaused state and against missing-id cache entries
- adds regression tests covering immediate local+cache reflection for pause and unpause, stale in-flight fetch ordering, and missing-id stability
- adds a patch changeset documenting the user-facing fix
Files changed:
.changeset/fn-7861-immediate-pause-state.md | 7 +
.../dashboard/app/hooks/__tests__/useTasks.test.ts | 151 +++++++++++++++++++++
packages/dashboard/app/hooks/useTasks.ts | 66 ++++++++-
3 files changed, 222 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7861
Fusion-Task-Lineage: fefbaf4f-8eb7-44a7-a1e2-ac8471a726bd
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Session skill merging (collectPluginSkillNames) previously ignored per-project
Skills view enable/disable toggles and only consulted each plugin's static
default, so a user disabling a plugin skill in the Skills view would still see
it merged into live agent sessions. Extracted the effective-enablement
resolver shared by dashboard discovery and engine session assembly into
@fusion/core so both surfaces stay in sync.
- Added packages/core/src/skill-settings.ts with computeSkillId/parseSkillId/
normalizeStoredSkillPath/getSkillSettingState/resolvePluginSkillEnabled,
exported from @fusion/core's index.
- packages/dashboard/src/skills-adapter.ts now re-exports and delegates to the
shared @fusion/core resolver instead of duplicating its own
getSkillSettingState/computeSkillId/parseSkillId implementations.
- packages/engine/src/session-skill-context.ts: collectPluginSkillNames now
accepts a projectRootDir, reads project settings via skill-resolver's newly
exported readProjectSettings/resolveProjectRoot, and calls
resolvePluginSkillEnabled instead of only checking the plugin's static
skill.enabled flag; mergePluginSkills passes projectRootDir through.
- packages/engine/src/skill-resolver.ts: exported readProjectSettings and
ProjectSkillSettings for reuse by session-skill-context.
- Updated docs/plugin-management.md to document that per-project Skills view
toggles now apply to runtime agent sessions, not just discovery.
- Added unit tests for the new core resolver and updated dashboard/engine
tests to cover per-project toggle overrides in session merging.
- Added a patch changeset for @runfusion/fusion.
Files changed:
.changeset/fn-7858-plugin-skill-session-toggle.md | 7 ++
docs/plugin-management.md | 4 +-
packages/core/src/__tests__/skill-settings.test.ts | 62 +++++++++
packages/core/src/index.ts | 8 ++
packages/core/src/skill-settings.ts | 102 +++++++++++++++
.../dashboard/src/__tests__/skills-adapter.test.ts | 60 ++++++++-
packages/dashboard/src/skills-adapter.ts | 107 +++-------------
.../src/__tests__/session-skill-context.test.ts | 140 ++++++++++++++++++++-
packages/engine/src/session-skill-context.ts | 23 +++-
packages/engine/src/skill-resolver.ts | 4 +-
10 files changed, 409 insertions(+), 108 deletions(-)
Fusion-Task-Id: FN-7858
Fusion-Task-Lineage: 90e44d24-e385-4a74-b8e4-3c864ec39a95
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Path-registered plugin reload/restart now refreshes persisted manifest metadata instead of leaving stale version/settingsSchema in the store.
- PluginLoader.loadPlugin/reloadPlugin call a new refreshPersistedManifestMetadata helper after each fresh module import, generalizing the previously bundled-only refresh to path-registered plugins
- Refresh is metadata-only (version, settingsSchema) via a stable-JSON comparison, preserving per-project enablement and saved setting values, and is a no-op when nothing changed
- PluginStore.PluginUpdateInput/updatePlugin gain a settingsSchema field (undefined = unchanged, null = explicitly clear) so updatePlugin can persist manifest schema changes independently of setting values
- Docs: add a "Updating path-registered plugins" section to docs/PLUGIN_AUTHORING.md describing the new reload/refresh loop
- Tests: add coverage in plugin-loader.test.ts and plugin-store.test.ts for manifest metadata refresh on load/reload and settingsSchema persistence
- Add a patch changeset for @runfusion/fusion
Files changed:
.changeset/fn-7855-plugin-manifest-refresh.md | 7 +
docs/PLUGIN_AUTHORING.md | 10 ++
packages/core/src/__tests__/plugin-loader.test.ts | 177 ++++++++++++++++++++++
packages/core/src/__tests__/plugin-store.test.ts | 42 +++++
packages/core/src/plugin-loader.ts | 53 +++++++
packages/core/src/plugin-store.ts | 10 ++
6 files changed, 299 insertions(+)
Fusion-Task-Id: FN-7855
Fusion-Task-Lineage: f4d94023-5a27-4059-a7a5-61f524c171b8
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Issue #2015: product-code executor tasks were repeatedly routed to a
liaison-only agent because every routing path gated only on the coarse
role field, and several binding primitives had no guard at all.
- Add runtimeConfig.assignmentPolicy ("auto" | "explicit-only" | "none");
"none" can never be bound to implementation tasks by ANY path — no
override bypasses it (the liaison guarantee)
- Route every binding surface through one shared evaluator
(evaluateImplementationTaskBind): claimTaskForAgent, the previously
unguarded checkoutTask/assignTask primitives, selectNextTaskForAgent
(including the in-progress re-selection loop), scheduler auto-assign
pool, heartbeat inbox/auto-claim, fn_delegate_task, CLI agent-id
validation, and dashboard assign/checkout/inbox routes
- Lock project isolation with a regression test: a foreign-project
agent id is rejected by every binding primitive
- Expose Assignment Policy in Agent Detail settings; document in
docs/agents.md; add changeset
Fusion-Task-Id: FN-7851
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pausing an in-progress task never stuck: the pause teardown re-queued the
row to todo with a plain engine move, and the reopen block wiped
paused/pausedByAgentId/pausedReason. The graph-failure classifier then saw
an unpaused row, misread the hard-cancel as an engine-internal abort, and
auto-continued the session (graphResumeRetryCount 1/2, 2/2); once the
budget was exhausted the benign re-queue left the row dispatchable and the
scheduler re-dispatched it seconds later — an indefinite pause/resume
bounce, burning a fresh worktree + pnpm install per cycle.
- store: new moveTask option `preservePause` keeps the pause park across a
reopen-to-todo/triage move (flag-ON trait hook + flag-OFF legacy inline,
kept in sync). It never SETS a pause, only prevents clearing one.
- executor teardown: when the pause that caused the abort is still in
force, move with preservePause so the row lands in todo still parked
(scheduler skips paused/userPaused rows until explicit unpause).
- classifier: a live task pause is labeled operator intent, never
"engine abort during pause/resume"; the benign log now says
"parked … awaiting explicit unpause" instead of the contradictory
"cleared for normal scheduling" for parked rows.
Surfaces covered by tests: flag-ON hook (preserve + never-set + default
clear), classifier no-auto-continue for task-pause/user-pause/global-pause
rows in todo, provenance labels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Grok advertises promptCapabilities.image=false and ignores ACP image
ContentBlocks (live probe: NO_IMAGE). Path-based vision works when the
agent is given an absolute file path. Include path hints in chat prompts
from .fusion/chat-attachments and carry path on ChatImageContent for
file:// uris.
Fix chat image/file attachments not rendering until re-entering the thread by reconciling the optimistic temp user bubble with the persisted user-message SSE echo during active streaming.
- In useChat, when a persisted user-role message arrives via chat:message:added while the active session is streaming, replace the optimistic temp-* bubble with the reconciled persisted message (real id + attachment filenames) instead of leaving the temp bubble in place with no refetch.
- Add regression coverage: persisted user attachment echo reconciles without duplicate/refetch, attachment-only echo reconciles content+attachments, and text-only echo still reconciles without duplicating messages.
- Extend test helper makeMessage to pass through attachments overrides.
Files changed:
.../dashboard/app/hooks/__tests__/useChat.test.ts | 160 +++++++++++++++++++++
packages/dashboard/app/hooks/useChat.ts | 13 ++
2 files changed, 173 insertions(+)
Fusion-Task-Id: FN-7849
Fusion-Task-Lineage: dbabda9c-5842-4d16-bafb-776a6536e51f
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Update the TUI splash tagline to match the README's current product positioning, with matching test and changeset.
- Changed FUSION_TAGLINE in packages/cli/src/commands/dashboard-tui/logo.ts from "multi node agent orchestrator" to "software factory", with an FNXC comment explaining the rationale
- Updated the dashboard TUI smoke test assertion to expect "software factory" instead of the old tagline
- Added a patch changeset documenting the tagline change
Files changed:
.changeset/fn-7850-tui-tagline.md | 7 +++++++
packages/cli/src/commands/dashboard-tui/__tests__/app.test.tsx | 2 +-
packages/cli/src/commands/dashboard-tui/logo.ts | 6 +++++-
3 files changed, 13 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7850
Fusion-Task-Lineage: d8517d7c-f7dd-43af-bb57-0092c7339aad
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
AcpRuntimeAdapter.promptWithFallback ignored options, so dashboard chat
images never became ACP ContentBlock image entries. Extract images from
prompt options and pass them through buildPromptBlocks for both acp-runtime
and the Grok vendored client.
Grok emits `_x.ai/session_notification` / `_x.ai/session/update` for
hook_execution status. The ACP SDK routes those to Client.extNotification;
without it, every successful post_tool_use hook logged -32601 Method not
found. Implement no-op extMethod/extNotification on default and bridging
handlers in acp-runtime and the Grok vendored copy.
Matches pi wrapToolsWithActionGate semantics: callers that omit
actionGateContext (chat/triage) intentionally leave tools ungated.
Add a content-free warn when a non-pi runtime receives customTools without
gate context so the path is visible without inventing deny-all defaults.
Greptile P1 on PR #2011: Grok ACP (and other plugin runtimes) previously
executed engine-injected fn_* tools without the pi action-gate / permanent-
agent / RTK rewrite chain. Wrap customTools once in createResolvedAgentSession
for non-pi runtimes so loopback MCP bridges dispatch already-gated closures.
Pi still owns its own wrap chain inside createFnAgent to avoid double-wrapping.
Replace one-shot grok -p JSON with native grok agent stdio (ACP) for realtime
streaming, tool visibility, and multi-turn sessions. Vendor the ACP client
into fusion-plugin-grok-runtime, forward Fusion fn_* tools and operator MCP,
stage Fusion skills via --plugin-dir, authenticate per xAI headless docs, and
align project chat manager store resolution so Grok chat sessions can send.
Restores the GitHub star count pill on mobile Settings, which had been hidden by a prior mobile CSS override, and updates related tests to match.
- Remove the <=768px `display:none` on `.settings-github-star-btn__count` in SettingsModal.css so the count stays visible; only the redundant "Star" label text stays collapsed on mobile to save space (relies on `.settings-modal-heading` min-width: 0 to truncate the title before the pill wraps)
- Add a changeset (`@runfusion/fusion` patch) documenting the fix
- Update settings-mobile.test.tsx with a new regression test asserting the star count stays visible and formatted (e.g. "1.2k") in both the modal and embedded SettingsView on mobile, plus a helper to scan mobile-only CSS media blocks for the absence of the display:none rule, and align existing mobile CSS assertions (section-heading padding, settings-navigation base rule) with current styles
- Update SettingsModal.models-auth.test.tsx version-label assertions ("Version 1.2.3" -> "v1.2.3") and seed `fusion:settings:show-advanced` in localStorage to match current UI
Files changed:
.changeset/mobile-settings-star-count.md | 7 +++
.../dashboard/app/components/SettingsModal.css | 9 ++-
.../__tests__/SettingsModal.models-auth.test.tsx | 12 ++--
.../components/__tests__/settings-mobile.test.tsx | 66 +++++++++++++++++++++-
4 files changed, 82 insertions(+), 12 deletions(-)
Fusion-Task-Id: FN-7848
Fusion-Task-Lineage: 0bbd0e81-6edb-4e9a-884d-b48fcf41f202
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds static MODEL_PRICING rows for three previously-unpriced models so their token usage renders a dollar cost instead of "—" in the dashboard.
- Add zai:glm-5.2, minimax:minimax-m3, and kimi-coding:kimi-k2.6-preview pricing rows to MODEL_PRICING, sourced from each provider's public pricing docs
- Bump pricingAsOf to 2026-07-11
- Add regression tests asserting costFor() prices these three models (not unavailable) and that lookupPricing() resolves them by provider-normalized and bare model-id keys
- Add a minor changeset documenting the pricing addition for @runfusion/fusion release notes
Files changed:
.changeset/fn-7847-model-pricing.md | 7 +++++
packages/core/src/__tests__/model-pricing.test.ts | 24 +++++++++++++++
packages/core/src/model-pricing.ts | 36 ++++++++++++++++++++++-
3 files changed, 66 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7847
Fusion-Task-Lineage: 6c138aa3-53e9-4165-909d-c8fc02acb48b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Extend the dashboard's Task Documents tab to union each task's registered documents with its task-scoped artifacts, with an inline right-pane viewer for the added artifact types.
- DocumentsView Task Documents tab now merges task documents and task-scoped artifacts per task group, sorted/grouped consistently
- Adds an inline right-pane artifact viewer (image/video/audio/pdf/inline-doc/other) reusing getArtifactCategory + artifactMediaUrl/fetchArtifact
- Selection state is a discriminated document|artifact union kept separate from Project Files selection; the standalone Artifacts gallery tab is unchanged
- Updates dashboard-guide.md to describe the merged Task Documents behavior (grouping, search, and preview now cover both documents and artifacts)
- Adds a minor changeset for @runfusion/fusion documenting the artifact-in-Task-Documents feature
- Expands DocumentsView test coverage for the new union/selection/preview behavior
Files changed:
.changeset/fn-7845-task-documents-artifacts.md | 7 +
docs/dashboard-guide.md | 6 +-
.../dashboard/app/components/DocumentsView.css | 142 +++++++-
.../dashboard/app/components/DocumentsView.tsx | 389 ++++++++++++++++++---
.../components/__tests__/DocumentsView.test.tsx | 290 ++++++++++++++-
5 files changed, 780 insertions(+), 54 deletions(-)
Fusion-Task-Id: FN-7845
Fusion-Task-Lineage: 32bbe6dc-4c02-449c-a13f-38abb8fd727d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Repositions the S/M/L size badge on task cards so it is the trailing element in the header-actions cluster, aligning its right margin with the card's top padding instead of leaving it stranded before the menu button.
- Move the `card-size-badge` span to render after the more-actions menu button within `.card-header-actions` in TaskCard.tsx
- Add FNXC layout comment documenting why the badge must be last (right-edge alignment while preserving FN-7837 no-orphaned-second-row grouping)
- Add a regression test asserting the size badge is the last child of `.card-header-actions` with no trailing sibling
- Add a patch changeset documenting the fix for release notes
Files changed:
.changeset/FN-7846-card-size-badge-right-edge.md | 7 +++++++
packages/dashboard/app/components/TaskCard.tsx | 14 +++++++++-----
.../app/components/__tests__/TaskCard.test.tsx | 21 +++++++++++++++++++++
3 files changed, 37 insertions(+), 5 deletions(-)
Fusion-Task-Id: FN-7846
Fusion-Task-Lineage: ee2c1864-e0fe-4d82-a280-59edbb923dca
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Unifies the two independent durable-agent error-recovery paths (heartbeat timer and self-healing sweep) so they share one retry budget, eligibility check, and audit surface instead of racing separate counters.
- Share the heartbeatErrorRecovery attempt budget between HeartbeatMonitor's timer-entry recovery and SelfHealingManager.recoverOrphanedAgents(), with self-healing's legacy durableErrorRecovery metadata folded into the same counter via readHeartbeatErrorRetryCount().
- Add isHeartbeatErrorRecoverable() as the single transient/non-operator-actionable eligibility check, used by both the heartbeat timer and self-healing paths (self-healing additionally allows stale-worktree module-resolution errors).
- resetHeartbeatErrorRecoveryMetadata() now strips the legacy durableErrorRecovery field so recovered agents don't retain stale sweep bookkeeping.
- Self-healing emits the shared agent:auto-recover-error-state / agent:error-retry-exhausted run-audit events with source:"self-healing", and parks the agent paused with pauseReason:"error-retry-exhausted" on budget exhaustion, matching the heartbeat-timer behavior.
- Update AGENTS.md, docs/architecture.md, and docs/agents.md to describe the consolidated recovery budget and audit surface.
- Add a patch changeset documenting the fix for @runfusion/fusion.
Files changed:
.changeset/fn-7844-error-recovery-coordination.md | 7 ++
AGENTS.md | 2 +-
docs/agents.md | 14 ++--
docs/architecture.md | 2 +-
packages/engine/src/__tests__/heartbeat-error-recovery.test.ts | 13 +++-
packages/engine/src/__tests__/self-healing.test.ts | 58 ++++++++++++++-
packages/engine/src/agent-heartbeat.ts | 35 ++++++---
packages/engine/src/self-healing.ts | 85 ++++++++++++++++++----
8 files changed, 180 insertions(+), 36 deletions(-)
Fusion-Task-Id: FN-7844
Fusion-Task-Lineage: b70dcba5-56b6-412c-8be2-ef827bee9964
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
pushAfterMerge was only implemented in the soft-deprecated legacy aiMergeTask
pipeline, so after master-plan U0 made runAiMerge the sole merge path the
setting silently did nothing and origin fell permanently behind local main.
- runAiMerge now runs a post-finalize push step: working-tree-independent
ref-to-ref push fast path; on remote divergence a detached clean-room
pull --rebase (with AI conflict resolution) pushes HEAD and CAS-advances
the local integration ref (explicit non-FF opt-in, push path only), then
runs merge-advance auto-sync and refreshes mergeDetails.commitSha.
- Push failures stay non-fatal (task finalizes done) with push:origin
run-audit events and PushToRemoteFailed task-log entries.
- Merge settings: Push Remote free-text replaced by remote + target-branch
dropdowns (Custom… escape, free-text fallback when no remotes), persisting
to the same pushRemote setting string. New GET /api/git/remotes/:name/branches
endpoint lists remote-tracking branches.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Heartbeat-managed durable agents that land in state:"error" now self-recover on the next heartbeat instead of staying stuck until an operator intervenes.
- HeartbeatTriggerScheduler keeps timers armed for durable heartbeat-managed agents in error state when the last error is transient and not operator-actionable (credential/quota/model-access/permanent-config failures stay parked).
- executeHeartbeat clears recoverable errors at run entry (error → active, clears lastError), bounded by MAX_HEARTBEAT_ERROR_RECOVERY_ATTEMPTS (settings-overridable); a successful run resets the counter.
- On budget exhaustion, the agent is parked paused with pauseReason:"error-retry-exhausted".
- Emits new run-audit events agent:auto-recover-error-state and agent:error-retry-exhausted (added to DatabaseMutationType).
- Adds heartbeat-error-recovery.test.ts and extends heartbeat-scheduler.test.ts to cover the recovery/exhaustion paths.
- Adds changeset and documents the new behavior in AGENTS.md and docs/architecture.md.
Files changed:
.changeset/fn-7835-agent-error-auto-recovery.md | 7 +
AGENTS.md | 1 +
docs/architecture.md | 2 +
.../src/__tests__/heartbeat-error-recovery.test.ts | 323 +++++++++++++++++++++
.../src/__tests__/heartbeat-scheduler.test.ts | 89 +++++-
packages/engine/src/agent-heartbeat.ts | 209 ++++++++++++-
packages/engine/src/run-audit.ts | 2 +
7 files changed, 618 insertions(+), 15 deletions(-)
Fusion-Task-Id: FN-7835
Fusion-Task-Lineage: 1bbb28a3-8eb9-40e3-8177-6658ec5dae40
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Removes the mobile stacked-card override for the Summary tab's per-model token/cost table so it stays a real, horizontally-scrollable table matching the Command Center pattern, and updates the covering tests/changeset accordingly.
- Drop the @media (max-width: 768px) block in TaskDetailModal.css that converted .task-summary-token-table rows into stacked cards (display:block, thead hidden, td::before labels), so the wrapper's overflow-x: auto and table min-width now govern mobile layout.
- Update FNXC:TaskDetailSummaryTokenCost comments to document the new horizontal-scroll contract instead of the removed stacked-card behavior, and refresh the TaskCostTab.css FNXC comment to match.
- Add a new regression test (token-table-mobile-scroll.test.ts) asserting the task-detail token table wrapper keeps overflow-x: auto, the mobile media block no longer stacks rows into cards, and the Command Center .cc-table-wrap stays scrollable.
- Update the existing TaskDetailModal summary-tab test to assert the stacked-card CSS is absent from the mobile block instead of asserting its presence.
- Add a patch changeset describing the fix for end users.
Files changed:
.changeset/mobile-token-table-scroll.md | 7 +++
.../__tests__/token-table-mobile-scroll.test.ts | 70 +++++++++++++++++++++
packages/dashboard/app/components/TaskCostTab.css | 2 +-
.../dashboard/app/components/TaskDetailModal.css | 73 ++--------------------
.../__tests__/TaskDetailModal.summary-tab.test.tsx | 13 ++--
5 files changed, 90 insertions(+), 75 deletions(-)
Fusion-Task-Id: FN-7843
Fusion-Task-Lineage: bb6dde7c-f205-45f3-984a-0fc52be5d547
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds a shared urgency color source to priorityIndicator and wires it into every priority-glyph surface so low/normal/high/urgent read consistently by color, not just icon shape.
- priorityIndicator.tsx: add colorVar (low=info/blue, normal=muted, high=warning/amber, urgent=error/red) and new getPriorityColorVar() export as the single source of truth
- QuickEntryBox: tint the icon-only priority trigger and each option row in the priority picker with the matching urgency color
- TaskForm: tint the New Task inline priority glyph using the same color source
- TaskCard: render a colored priority glyph alongside the existing text label in the card-priority-badge (kept the non-normal visibility gate and badge geometry via a small CSS gap addition)
- Updated/added tests for QuickEntryBox, TaskCard (badge, badge-height, badge-wrap), and priorityIndicator to assert the new colors; added a patch changeset and a dashboard-guide.md doc update
Files changed:
.changeset/fn-7842-priority-color-coding.md | 7 +++++
docs/dashboard-guide.md | 7 +++--
.../dashboard/app/components/QuickEntryBox.tsx | 7 +++--
packages/dashboard/app/components/TaskCard.css | 2 ++
packages/dashboard/app/components/TaskCard.tsx | 6 +++-
packages/dashboard/app/components/TaskForm.tsx | 7 +++--
.../components/__tests__/QuickEntryBox.test.tsx | 17 +++++++++--
.../__tests__/TaskCard.badge-height.test.tsx | 5 ++++
.../__tests__/TaskCard.badge-wrap.test.tsx | 5 ++++
.../app/components/__tests__/TaskCard.test.tsx | 33 +++++++++++++++++++++-
.../app/utils/__tests__/priorityIndicator.test.tsx | 13 +++++----
packages/dashboard/app/utils/priorityIndicator.tsx | 16 ++++++++---
12 files changed, 103 insertions(+), 22 deletions(-)
Fusion-Task-Id: FN-7842
Fusion-Task-Lineage: 0b2d0d15-6e61-45fc-9378-bc09002bef55
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Replaces the standalone Archive button on done task cards with an Actions dropdown that groups Archive and Revert, mirroring the existing in-progress "Send back" menu pattern.
- Add a card-done-actions dropdown (Actions trigger + menu) rendered for done cards, reusing card-send-back* styling
- Move Archive into the dropdown menu; add Revert as a menu item when the task is revertable (isRevertable)
- Only render the dropdown trigger when at least one action (archive/revert) is available, avoiding an empty button shell
- Restrict the old inline card-revert-btn to archived cards only (done cards now use the dropdown)
- Add outside-click handling and aria-haspopup/aria-expanded wiring for the new menu
- Add i18n key tasks.doneActions
- Update TaskCard tests to cover the dropdown (archive/revert menu items, empty-state omission) and mock useToast in board-mobile tests for isolated TaskCard renders
- Add changeset for @runfusion/fusion (patch)
Files changed:
.changeset/fn-7839-done-card-actions-dropdown.md | 7 ++
packages/dashboard/app/components/TaskCard.tsx | 88 ++++++++++++++++++----
.../app/components/__tests__/TaskCard.test.tsx | 82 +++++++++++++++-----
.../app/components/__tests__/board-mobile.test.tsx | 15 +++-
4 files changed, 157 insertions(+), 35 deletions(-)
Fusion-Task-Id: FN-7839
Fusion-Task-Lineage: 1f8137cb-22b1-43dd-beaa-1bee0387d44b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the narrow-container (phone-width) Todo view so the visible list or
detail panel stretches to fill available height instead of inheriting the
tablet two-panel sidebar's max-height cap.
- Scope the single-panel stack rule to .todo-view-layout .todo-view-sidebar /
.todo-view-main so it wins over the later @media (max-width:768px)
sidebar max-height cap, and add height:100%/max-height:none.
- Add regression tests asserting the narrow single-panel stack is uncapped
while the tablet two-panel sidebar keeps its existing height cap.
- Add a patch changeset documenting the fix.
Files changed:
.changeset/fn-7841-todo-mobile-height.md | 7 ++++++
packages/dashboard/app/components/TodoView.css | 11 ++++++---
.../__tests__/TodoView.mobile-css.test.ts | 28 ++++++++++++++++++++++
3 files changed, 43 insertions(+), 3 deletions(-)
Fusion-Task-Id: FN-7841
Fusion-Task-Lineage: e6b497ae-2568-4cae-8b48-7f57f45c8a23
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Stops decidePlannerRecovery from recording noisy advisory confirmation interventions for merger/pull-request stages that never actually block progress when auto-merge will proceed unattended.
- decidePlannerRecovery now returns action "none" (no pending confirmation, no steering comment, no overseer:intervention entry) for merger/pull-request stages when autoMergeWillProceed === true, since this checkpoint is purely advisory in that case
- Genuine human-approval blocks (autoMergeWillProceed === false) and the neutral pure-function default (undefined) keep the await_confirmation decision intact
- Updated planner-recovery.test.ts to assert the new "none" outcome for the advisory case
- Simplified planner-overseer-intervention-wiring.test.ts to match the reduced intervention surface
- Added changeset documenting the fix as a patch-level bug fix
Files changed:
.changeset/fn-7840-advisory-merger-confirmations.md | 7 ++
packages/core/src/__tests__/planner-recovery.test.ts | 32 ++---
packages/core/src/planner-recovery.ts | 47 ++++---
packages/engine/src/__tests__/planner-overseer-intervention-wiring.test.ts | 135 +++++----------------
4 files changed, 79 insertions(+), 142 deletions(-)
Fusion-Task-Id: FN-7840
Fusion-Task-Lineage: 610a9003-f229-4e78-9948-ee0bb85193bc
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Groups TaskCard header badges so the id and right-aligned size/actions cluster never wrap, fixing the S/M/L size chip dropping to its own row when extra badges (fast-mode, priority, oversight, PR/GitHub, etc.) are present.
- Introduce hasHeaderBadges/hasHeaderActions guards and wrap the middle badge cluster in a new .card-header-badges container so only .card-header-badges wraps, while .card-id and .card-header-actions stay pinned to the top row
- Update TaskCard.css: .card-header becomes a non-wrapping flex row; .card-header-badges takes over the wrapping/flex-grow behavior previously on .card-header; .card-id gets flex-shrink: 0; .card-header-actions gets flex: 0 0 auto and align-self: flex-start; mobile media query gains .card-header-badges alongside .card-meta-badges
- Add FNXC:TaskCardLayout comments documenting the FN-7837 layout requirement (non-wrapping header row, wrapping badge cluster)
- Extend TaskCard.badge-wrap.test.tsx and TaskCard.test.tsx coverage for the new header grouping/wrap behavior
- Add changeset FN-7837-card-size-badge-alignment.md (patch, fix) for @runfusion/fusion
Files changed:
.changeset/FN-7837-card-size-badge-alignment.md | 7 +++
packages/dashboard/app/components/TaskCard.css | 29 +++++++--
packages/dashboard/app/components/TaskCard.tsx | 38 ++++++++++++
.../__tests__/TaskCard.badge-wrap.test.tsx | 70 ++++++++++++++++++++--
.../app/components/__tests__/TaskCard.test.tsx | 27 ++++++---
5 files changed, 156 insertions(+), 15 deletions(-)
Fusion-Task-Id: FN-7837
Fusion-Task-Lineage: 9f70abcf-3b23-41b3-8642-aa34a561996d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Raises Grok and Droid CLI cold-start timeout defaults from 60s to 120s and lets operators override them via environment variables.
- Grok runtime adapter: new GROK_CLI_FIRST_OUTPUT_TIMEOUT_MS env override for the first-output cold-start guard; default raised 60000ms → 120000ms; invalid/non-positive values fall back to the default
- Droid provider: new PI_DROID_CLI_FIRST_LINE_TIMEOUT_MS env override for the first-line cold-start guard; default raised 60000ms → 120000ms; invalid/non-positive values fall back to the default
- 30-minute inactivity safety net left unchanged on both adapters
- Added/updated unit tests covering the new env-driven timeout resolution and fallback behavior for both plugins
- Documented the new settings in docs/settings-reference.md and both plugin READMEs
- Added a minor changeset for @runfusion/fusion
Files changed:
.changeset/fn-7838-cli-timeout-configurable.md | 7 ++
docs/settings-reference.md | 13 ++-
plugins/fusion-plugin-droid-runtime/README.md | 8 ++
.../src/__tests__/provider.test.ts | 97 +++++++++++++++++++++-
.../fusion-plugin-droid-runtime/src/provider.ts | 26 ++++--
plugins/fusion-plugin-grok-runtime/README.md | 8 ++
.../src/__tests__/runtime-adapter.test.ts | 52 +++++++++++-
.../src/runtime-adapter.ts | 23 ++++-
8 files changed, 222 insertions(+), 12 deletions(-)
Fusion-Task-Id: FN-7838
Fusion-Task-Lineage: 7aad4470-b28f-42bd-be01-8363a1dd05e5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the Task Documents view rendering blank/border-only rows once many task-card groups load in the scrolling sidebar; each card now opts out of flex shrink so overflow clipping no longer compresses group content out of view.
- DocumentsView.css: add `flex: 0 0 auto` to `.documents-task-sidebar-group` so cards keep their natural height instead of being shrunk by the flex column when many groups are loaded
- DocumentsView.test.tsx: add regression test rendering 54 loaded task-document groups, asserting `flex-shrink: 0` and that group heading/content text remains visible and interactive
- Add changeset documenting the patch-level fix
Files changed:
.changeset/fn-7836-task-documents-rendering.md | 7 +++
.../dashboard/app/components/DocumentsView.css | 4 ++
.../components/__tests__/DocumentsView.test.tsx | 71 ++++++++++++++++++++++
3 files changed, 82 insertions(+)
Fusion-Task-Id: FN-7836
Fusion-Task-Lineage: f07bad59-c6b9-41e3-9475-5a4339044bb4
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>