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>
Renders every task document in the Artifacts tab expanded and as rendered Markdown by default, with the Markdown/Plain preference persisted across sessions instead of resetting per document.
- Replace single expandedDocKey/expandedContent state with a multi-key expandedDocKeys Set plus a per-document revisionContentByKey map so multiple documents can be expanded simultaneously.
- Default renderMarkdown to true and persist the operator's Markdown/Plain toggle choice to localStorage (fusion.taskDocuments.renderMarkdown) via readBooleanPref/writeBooleanPref helpers.
- Auto-expand newly loaded documents while preserving collapse state for documents the user has explicitly collapsed, tracked per taskId.
- Update handleStartEdit and handleViewRevision to operate per-document-key instead of a single global expanded document.
- Add changeset (@runfusion/fusion patch) describing the Artifacts-tab default-expanded Markdown behavior.
- Rework TaskDocumentsTab tests for multi-document expand/collapse, per-card markdown rendering, and localStorage-backed preference persistence.
Files changed:
.changeset/fn-7833-artifacts-tab-markdown-expand-default.md | 7 +
packages/dashboard/app/components/TaskDocumentsTab.tsx | 149 +++++++++-----
packages/dashboard/app/components/__tests__/TaskDocumentsTab.test.tsx | 223 +++++----------------
3 files changed, 160 insertions(+), 219 deletions(-)
Fusion-Task-Id: FN-7833
Fusion-Task-Lineage: 1915c594-7191-47a2-962b-18136d572cf1
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Gives the Artifacts view's Task Documents sidebar a distinct card-per-task look with more breathing room between task groups, replacing the flat bordered-row list.
- Restyle .documents-task-sidebar-group into a bordered, rounded card with shadow and inter-group gap instead of a bottom-border-only divider
- Strengthen the group header (bolder task id/title, tinted background) so it reads as a container rather than a peer row
- Add hover/selected background treatment and left-indent to .documents-task-document-item entries, scoped under .documents-task-documents-sidebar so Project Files and Artifacts stay unaffected
- Add a regression test asserting group headers remain non-selectable containers distinct from selectable document rows
- Update dashboard-guide.md wording to describe the new distinct task-card grouping
- Add changeset (patch) documenting the sidebar restyle
Files changed:
.changeset/fn-7834-task-documents-grouping.md | 7 +++
docs/dashboard-guide.md | 2 +-
.../dashboard/app/components/DocumentsView.css | 38 +++++++++++++---
.../components/__tests__/DocumentsView.test.tsx | 50 ++++++++++++++++++++++
4 files changed, 90 insertions(+), 7 deletions(-)
Fusion-Task-Id: FN-7834
Fusion-Task-Lineage: 9bac7666-19ba-410b-81dc-d9201a61d0b5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Reworks the Task Detail terminal experience: the embedded Terminal tab now sits between Comments and Cost, its workspace picker defaults to the task's worktree, and the mobile terminal panel is shorter.
- Move the Terminal tab in Task Detail's tab strip to sit right after Comments and before Cost (previously Cost was earlier and Terminal was near the Session tab)
- TerminalModal now defaults its workspace picker to the useWorkspaces entry whose worktree matches the passed defaultCwd, but only until the operator manually changes the selection; the footer/global terminal still defaults to Project Root since it doesn't pass defaultCwd
- Reduce `.detail-section--worktree-terminal`'s mobile min-height from min(65dvh, 14 * --space-2xl) to min(50dvh, 11 * --space-2xl) so tab context and controls stay reachable above the fold
- Update docs/dashboard-guide.md to describe the new Comments → Terminal → Cost tab order and the worktree-matching picker default
- Add regression tests covering the new tab order and the default terminal workspace selection behavior
- Add a patch changeset describing the user-facing change
Files changed:
.changeset/FN-7832-task-terminal-picker-and-tab-order.md | 7 +++
docs/dashboard-guide.md | 9 +--
packages/dashboard/app/components/TaskDetailModal.css | 5 +-
packages/dashboard/app/components/TaskDetailModal.tsx | 30 +++++-----
packages/dashboard/app/components/TerminalModal.tsx | 19 +++++++
packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx | 15 ++---
packages/dashboard/app/components/__tests__/TaskDetailModal.worktree-terminal.test.tsx | 12 ++++
packages/dashboard/app/components/__tests__/TerminalModal.test.tsx | 64 ++++++++++++++++++++++
8 files changed, 134 insertions(+), 27 deletions(-)
Fusion-Task-Id: FN-7832
Fusion-Task-Lineage: 4ee67a65-8564-49c9-b93c-8c3eab05c073
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds a distinct "Reviewing" status badge that surfaces on TaskCard and ListView rows while a task's optional plan-review workflow step is actively running, reusing the unified progress predicate so board and list surfaces stay in sync.
- Add isPlanReviewRunning(task) helper in taskProgress.ts, derived from getUnifiedTaskProgress's workflow-plan-review item status
- Render a pulsing "Reviewing" badge on TaskCard header (additive to existing status badges, with title/data-testid) while plan-review is running
- Render the matching "Reviewing" badge on both grouped and ungrouped ListView row layouts for parity with TaskCard
- Add supporting CSS for .card-status-badge--reviewing and .list-status-badge--reviewing
- Add unit tests for isPlanReviewRunning and component tests for the new badge across TaskCard and ListView
- Add minor changeset documenting the new operator-facing badge
Files changed:
.changeset/tidy-reviewing-badges.md | 7 ++
packages/dashboard/app/components/ListView.css | 10 +++
packages/dashboard/app/components/ListView.tsx | 22 +++++-
packages/dashboard/app/components/TaskCard.css | 10 +++
packages/dashboard/app/components/TaskCard.tsx | 25 ++++++-
.../app/components/__tests__/ListView.test.tsx | 78 ++++++++++++++++++++++
.../app/components/__tests__/TaskCard.test.tsx | 31 +++++++++
.../app/utils/__tests__/taskProgress.test.ts | 16 ++++-
packages/dashboard/app/utils/taskProgress.ts | 10 +++
9 files changed, 205 insertions(+), 4 deletions(-)
Fusion-Task-Id: FN-7831
Fusion-Task-Lineage: d36f8c63-9b84-400a-8b10-3b9f3b04212b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Give the Insights view header its own dedicated mobile layout so the title no longer collapses to an ellipsis and action buttons no longer crowd together at narrow widths/short heights.
- Extend the mobile header media query to also trigger on short viewports (max-height: 480px), not just narrow widths
- Force the Insights title onto its own full-width row (flex: 1 0 100%) and let it wrap actions below instead of shrinking
- Stop truncating the title span (overflow: visible; text-overflow: clip) so "Insights" is never cut to "I…"
- Let the actions cluster wrap to full width, left-aligned, with no leading margin so touch targets stay usable
- Add regression tests covering the maximal header action cluster and asserting the new mobile/tablet/desktop CSS media-query contracts
Files changed:
packages/dashboard/app/components/InsightsView.css | 29 ++++++-
.../app/components/__tests__/InsightsView.test.tsx | 88 ++++++++++++++++++++++
2 files changed, 116 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7830
Fusion-Task-Lineage: 4c92cb43-5c08-4b76-9f51-805ffa5deec9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Relocates the shared terminal action-control cluster into the bottom status-bar footer at every breakpoint and replaces the fixed tablet-viewport tab collapse with a container-width overflow check.
- Move font-size, Clear, Shortcuts, Preferences, connection status, pin, and pop-out controls out of the desktop header into the `.terminal-status-bar` footer at all widths (desktop/tablet/mobile/floating/docked/pinned/embedded), replacing the prior viewport-tier-based split.
- Replace `isTerminalTabletViewport()` with `evaluateTabsOverflow()`, a container-size (ResizeObserver-driven) check with hysteresis that swaps the `.terminal-tabs` strip for the existing mobile-style `.terminal-mobile-tabs` dropdown whenever the tab strip doesn't fit, independent of viewport breakpoint.
- Update TerminalModal.css to match the new footer-first layout and drop now-unused tablet-tier header rules.
- Update dashboard-guide.md terminal usage steps to describe the new always-footer control location and the width-based (not tablet-only) tab dropdown fallback.
- Expand TerminalModal.test.tsx coverage for the overflow-driven tab collapse/expand behavior and footer control placement.
- Add changeset fn-7829-terminal-shortcuts-footer.md (patch, feature) documenting the footer/tab-dropdown change; resolve an add/add conflict on the pre-existing artifacts-doc-editing-and-comment-fix.md changeset by keeping fusion/fn-7829's summary wording.
Files changed:
.../artifacts-doc-editing-and-comment-fix.md | 2 +-
.changeset/fn-7829-terminal-shortcuts-footer.md | 7 +
docs/dashboard-guide.md | 9 +-
.../dashboard/app/components/TerminalModal.css | 121 +++-----
.../dashboard/app/components/TerminalModal.tsx | 336 +++++++++++----------
.../components/__tests__/TerminalModal.test.tsx | 185 ++++++++----
6 files changed, 351 insertions(+), 309 deletions(-)
Fusion-Task-Id: FN-7829
Fusion-Task-Lineage: 443c6e69-8946-4307-8a1a-f4f90681a054
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Claude per-model weekly usage is parsed generically from the OAuth payload's
limits[] scoped entries (live probe disproved the seven_day_fable key guess).
Grok now prefers ~/.grok/auth.json OIDC credentials against
cli-chat-proxy.grok.com/v1/billing?format=credits for a real percent-used
weekly credits window, falling back to the xAI API-key validity card.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- scope session collections to the active project\n- clean up runtime stage registration in discovery tests\n- model brainstorms and plans as repeatable artifact collections\n- compact the singleton Strategy presentation