Duplicate tasks created by the same agent are no longer auto-archived by default; they are flagged for review instead, controlled by a new opt-in project setting.
- Add project setting `autoArchiveDuplicateTasksEnabled` (default false) gating the FN-4892 same-agent duplicate intake path
- Add `flagSameAgentDuplicate` path and `nearDuplicateOf` metadata used when auto-archive is disabled; tombstone-resurrection blocking is unchanged
- Wire the setting through core settings schema/types/store, dashboard SchedulingSection UI, and i18n strings
- Update docs (settings-reference.md, task-management.md) to describe the new default-off behavior
- Add a changeset for the @runfusion/fusion minor release
- Extend duplicate-intake, tombstone-window, store-parent-task-dedup, and reliability-interaction tests to cover both flag states
Files changed:
$(cat /tmp/fn7658_stat.txt)
Fusion-Task-Id: FN-7658
Fusion-Task-Lineage: 7d0d1074-1020-48a8-b96f-186154c2c408
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Retains the GitHub Import Tasks modal's provider/tab/filter/selection state so returning to Import Tasks doesn't reset the user's in-progress import setup.
- GitHubImportModal now persists provider, active tab, label filter, remote, and issue selection per project via a new modalPersistence hook, restoring them on remount instead of always defaulting.
- Added packages/dashboard/app/hooks/modalPersistence.ts to encapsulate the persisted-state read/write logic backed by projectStorage.
- projectStorage.ts gains the `kb-dashboard-github-import-state` storage key.
- Falls back to the existing default-remote auto-detect behavior when no persisted state exists.
- Added extensive test coverage in GitHubImportModal.test.tsx for the new persistence behavior.
- Updated docs/dashboard-guide.md to describe the retained state.
- Added a patch changeset for @runfusion/fusion.
Files changed:
.changeset/fn-7657-github-import-state-retained.md | 7 +
docs/dashboard-guide.md | 2 +
.../dashboard/app/components/GitHubImportModal.tsx | 204 +++++++++++++--
.../__tests__/GitHubImportModal.test.tsx | 282 +++++++++++++++++++++
packages/dashboard/app/hooks/modalPersistence.ts | 72 ++++++
packages/dashboard/app/utils/projectStorage.ts | 1 +
6 files changed, 547 insertions(+), 21 deletions(-)
Fusion-Task-Id: FN-7657
Fusion-Task-Lineage: c8086340-368c-4efd-a12a-4cddeeb0aa26
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes chat sessions not showing the working/"Thinking…" indicator when returning to a session whose generation was already in flight but hadn't emitted its first delta yet.
- useChat.ts: selectSession's authoritative fetchChatSession refresh now reattaches whenever refreshedSession.isGenerating===true, instead of also requiring a populated inFlightGeneration snapshot (which is null pre-first-delta)
- Added a guard so the reattach only proceeds if the user hasn't navigated away from the session while the refresh was in flight (activeSessionRef.current?.id === id)
- Calls attachIfGenerating(id, refreshedSession.inFlightGeneration, { silent: true }) when no stream is already attached, reusing existing double-attach guarding
- Added regression tests in useChat.test.ts covering the reattach-on-isGenerating-alone behavior and the stale-session navigation guard
- Added a patch changeset documenting the fix
Files changed:
.changeset/fn-7656-chat-reattach-working-state.md | 7 ++
.../dashboard/app/hooks/__tests__/useChat.test.ts | 113 +++++++++++++++++++++
packages/dashboard/app/hooks/useChat.ts | 22 +++-
3 files changed, 141 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7656
Fusion-Task-Lineage: c923c16a-391f-4475-aab8-6194bbc675f7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix the Board Auto-approve plan shortcut leaking onto hold (Todo-like) columns; it must render only on the intake/planning column.
- Board.tsx: gate the planAutoApproveEnabled/onTogglePlanAutoApprove prop pair on columnDef.flags.intake only (dropped the || columnDef.flags.hold clause) for both the aggregate and single-workflow column renders
- Column.tsx: update the FNXC comment to document that Board.tsx is the single source of truth for this intake-only gating; Column.tsx just renders whatever prop it receives
- docs/dashboard-guide.md: correct the Board guide to describe the toggle as intake/planning-column-only, not hold columns
- Board.test.tsx: fix the existing intake/hold test expectation to assert the hold column does NOT get the toggle, and add a regression test reproducing the built-in Coding workflow's Todo (hold) column symptom
- add a patch changeset documenting the fix
Files changed:
.changeset/FN-7653-plan-auto-approve-intake-only.md | 7 +++++++
docs/dashboard-guide.md | 5 +++--
packages/dashboard/app/components/Board.tsx | 6 ++++--
packages/dashboard/app/components/Column.tsx | 5 ++++-
.../app/components/__tests__/Board.test.tsx | 20 +++++++++++++++++---
5 files changed, 35 insertions(+), 8 deletions(-)
Fusion-Task-Id: FN-7653
Fusion-Task-Lineage: 10c5f01a-b00c-4039-9b83-a8a8965fc56c
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Reconcile the automation live-run panel's terminal status with the authoritative run result so successful runs no longer flash "Run failed".
- ScheduledTasksModal/RoutineCard now reconcile SSE terminal status against the POST/registry result instead of trusting raw stream teardown.
- Gate benign SSE teardown (post-terminal close, reconnect exhaustion) from being surfaced as a failure state.
- Apply the same reconciliation to both /routines/:id/run/stream and /automations/:id/run/stream routes in routes.ts.
- Add regression coverage in RoutineCard, ScheduledTasksModal, and routes-automation tests.
- Add a patch changeset documenting the fix.
Files changed:
.changeset/fn-7652-automation-live-run-false-failure.md | 7 ++
packages/dashboard/app/components/ScheduledTasksModal.tsx | 66 ++++++++++++++--
packages/dashboard/app/components/__tests__/RoutineCard.test.tsx | 37 +++++++++
packages/dashboard/app/components/__tests__/ScheduledTasksModal.test.tsx | 78 +++++++++++++++++++
packages/dashboard/src/__tests__/routes-automation.test.ts | 87 ++++++++++++++++++++++
packages/dashboard/src/routes.ts | 52 ++++++++++++-
6 files changed, 319 insertions(+), 8 deletions(-)
Fusion-Task-Id: FN-7652
Fusion-Task-Lineage: 61fc89f5-d25d-44de-9699-bc8ad2a0dea6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Removes the visible "Stop generation" text label from the planner chat's stop button while keeping it accessible via aria-label.
- Add showStopText prop to StandardChatActionButton (defaults to showSendText) to independently control Send vs Stop visible text
- Set showStopText={false} in TaskPlannerChatTab so the streaming stop button renders icon-only
- Update TaskPlannerChatTab test to assert no visible text span on the stop button while aria-label is retained
- Add changeset for @runfusion/fusion (patch)
Files changed:
.changeset/fn-7655-planner-stop-icon-only.md | 7 +++++++
.../dashboard/app/components/StandardChatSurface.tsx | 16 ++++++++++++++--
packages/dashboard/app/components/TaskPlannerChatTab.tsx | 3 +++
.../app/components/__tests__/TaskPlannerChatTab.test.tsx | 4 +++-
4 files changed, 27 insertions(+), 3 deletions(-)
Fusion-Task-Id: FN-7655
Fusion-Task-Lineage: f68a8bfa-30ba-439e-97d0-28654a614c54
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes project-switch hydration so a persisted "settings" view resolves to the Board instead of re-opening Settings.
- Extend resolveLandingTaskView() in useViewState.ts to treat "settings" the same as "command-center", resolving both to "board" for the auto-restored/hydrated landing view only
- Add regression tests covering the settings->board landing resolution in useViewState.test.ts
- Add changeset documenting the patch-level fix
Files changed:
.changeset/fn-7649-project-switch-board-landing.md | 7 ++
.../app/hooks/__tests__/useViewState.test.ts | 74 ++++++++++++++++++++++
packages/dashboard/app/hooks/useViewState.ts | 5 +-
3 files changed, 85 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7649
Fusion-Task-Lineage: 7179efd6-bb1b-4ea4-a062-479b9b1fffa3
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Follow-through on FN-5048: the four residual fixed 100ms sleeps in the
websocket badge integration tests (3 subscription-establishment waits + 1
cross-instance pub/sub propagation wait) are replaced with deterministic
awaits on the server-side WebSocketManager subscription:changed event and the
shared pub/sub message event. Removes ~400ms of unconditional real-time waiting
and closes the ordering races the sleeps papered over.
Fusion-Task-Id: FN-5048
Fix the Planner Chat composer's streaming Stop button rendering narrower than the idle Send button by giving both variants a shared width floor.
- Declare a locally-scoped --chat-input-control-size on .task-planner-chat-composer (same formula as ChatView.css's .chat-input-row so the shared .chat-input-send/.chat-input-stop classes no longer read an undefined custom property and fall back to width: auto.
- Add a min-inline-size floor bound to that property on .task-planner-chat-send (present on both send and stop variants) so neither button renders narrower than the other on desktop.
- Add a regression test asserting the desktop control-size floor, the pre-existing mobile square sizing, and the FN-7594 stop-icon visibility contract.
- Add a changeset documenting the fix as a patch release.
Files changed:
.changeset/fn-7634-planner-stop-button-width.md | 7 +++++
.../app/components/TaskPlannerChatTab.css | 8 ++++++
.../__tests__/TaskPlannerChatTab.test.tsx | 33 ++++++++++++++++++++++
3 files changed, 48 insertions(+)
EOF
)
Fusion-Task-Id: FN-7634
Fusion-Task-Lineage: e73c836f-3c2d-4871-ac93-fdf5e52de5f6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Align the Priority chip, Execution-mode toggle, and Oversight dropdown trigger to the exact same box height in the task detail metadata cluster, closing a gap where a shared min-height floor still let controls diverge.
- Add explicit `height: var(--detail-priority-control-min-height)` to `.detail-priority-chip`, `.detail-execution-mode-toggle`, and `.detail-oversight-menu-trigger` alongside the existing `min-height`, so none can outgrow or undershoot the others regardless of flex stretch/content differences
- Keep `min-height` as a safety-net floor for edge cases like font scaling
- Add regression test asserting all three controls share the same fixed height token on desktop and mobile, and that the Oversight popover itself remains unaffected
- Add changeset documenting the fix as a patch-level bug fix
Files changed:
.../fn-7633-priority-execution-oversight-height.md | 7 ++++
.../dashboard/app/components/TaskDetailModal.css | 44 ++++++++++++++++---
...etailModal.responsive-and-dependencies.test.tsx | 49 ++++++++++++++++++++++
3 files changed, 95 insertions(+), 5 deletions(-)
Fusion-Task-Id: FN-7633
Fusion-Task-Lineage: 7a89743e-117f-4032-9614-a9a15f2a9b08
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Authentication settings previously enumerated providers straight from pi AuthStorage's live runtime registry, so connecting a runtime plugin (e.g. Hermes Runtime) could narrow/collapse the visible provider list. This adds a static, hand-maintained supported-provider catalog and unions it with storage-reported providers so presence in the list is deterministic while status stays live.
- Add packages/dashboard/src/routes/auth-provider-catalog.ts with STATIC_OAUTH_PROVIDER_CATALOG, STATIC_API_KEY_PROVIDER_CATALOG, and unionProviderCatalog() (catalog always wins on presence; runtime-only extras still surface; runtime name wins on name conflicts).
- Update register-auth-routes.ts's GET /api/auth/status to union the static catalogs with storage.getOAuthProviders()/getApiKeyProviders() instead of relying solely on runtime-reported providers.
- Extend routes-auth.test.ts coverage for the new catalog-union behavior (provider presence stable across narrowed runtime registries, extras preserved, name precedence).
- Add changeset fn-7625-static-auth-provider-catalog.md (patch, fix).
Files changed:
.changeset/fn-7625-static-auth-provider-catalog.md | 7 +
.../dashboard/src/__tests__/routes-auth.test.ts | 180 +++++++++++++++++++--
.../dashboard/src/routes/auth-provider-catalog.ts | 93 +++++++++++
.../dashboard/src/routes/register-auth-routes.ts | 25 ++-
4 files changed, 291 insertions(+), 14 deletions(-)
Fusion-Task-Id: FN-7625
Fusion-Task-Lineage: be984497-b881-4a8f-9860-544617e2b5f7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the onboarding/settings GitHub step so it never offers a dashboard OAuth login for github (no github OAuth provider is ever registered; pi only ships anthropic/github-copilot/openai-codex), replacing the broken Connect OAuth button with gh CLI guidance and a clearer server-side error.
- Remove the "Connect OAuth (optional)" button and its login-instructions panel from the onboarding branch that runs when hasGithubProvider is false (ModelOnboardingModal.tsx), since it always called handleLogin("github") against a non-existent provider
- Update ModelOnboardingModal tests to cover the new gh-CLI-only flow
- Make POST /api/auth/login return a clear, actionable 400 naming the requested provider, the registered dashboard OAuth providers, and that GitHub integration uses gh CLI/token auth instead of a generic "Unknown provider" / model-not-found error
- Add routes-auth.test.ts coverage for the improved unknown-provider error message
- Add a patch changeset documenting the fix
Files changed:
.changeset/fn-7624-github-onboarding-auth.md | 7 +++++
packages/dashboard/app/components/ModelOnboardingModal.tsx | 32 +++++++---------------
packages/dashboard/app/components/__tests__/ModelOnboardingModal.test.tsx | 32 +++++++++++++++++++++-
packages/dashboard/src/__tests__/routes-auth.test.ts | 22 +++++++++++++++
packages/dashboard/src/routes/register-auth-routes.ts | 14 +++++++++-
5 files changed, 83 insertions(+), 24 deletions(-)
Fusion-Task-Id: FN-7624
Fusion-Task-Lineage: e7be1b0a-6e50-479d-b56e-1284e8a94b7f
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Adds a close affordance to the embedded Settings header on mobile, since only a bottom nav bar (no sidebar) is available to exit there.
- Render a mobile-only `modal-close` button in the embedded Settings header when `isEmbedded && viewportMode === "mobile"`, wired to the existing `onClose` prop.
- Leave desktop/tablet embedded and the standalone modal presentation unchanged.
- Add regression tests covering the new mobile close button.
- Add a patch changeset documenting the fix.
Files changed:
.changeset/fn-7627-mobile-settings-close.md | 7 ++
.../dashboard/app/components/SettingsModal.css | 16 +++
.../dashboard/app/components/SettingsModal.tsx | 17 +++
.../__tests__/SettingsModal.mobileClose.test.tsx | 125 +++++++++++++++++++++
4 files changed, 165 insertions(+)
Fusion-Task-Id: FN-7627
Fusion-Task-Lineage: b39c7172-bce3-4fb2-9095-58ae376c43ef
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Root-caused and fixed the third recurrence of the mobile terminal shortcut bar not scrolling horizontally: styles.css's mobile lockdown resets touch-action to pan-y across ancestors, and touch-action's used value is the intersection of the touched element's and every ancestor's value, so the leaf .terminal-shortcut-panel's pan-x was silently defeated even though it was already correct.
- Opt the terminal overlay and modal ancestors (.modal-overlay.terminal-modal-overlay, .modal.terminal-modal--mobile, plain-media-query mobile modal, and the shortcut/status footer) into touch-action: pan-x pan-y so descendant leaf touch-action values can take effect
- Add FNXC:Terminal comments documenting the ancestor-intersection root cause and recurrence history (FN-7550/FN-7560)
- Add a documented solution note under docs/solutions/ui-bugs/ for the ancestor-intersection touch-action pattern
- Add regression tests asserting the modal/overlay/footer ancestors carry the pan-x pan-y opt-in
- Add a changeset for the fix
Files changed:
.../fn-7621-mobile-terminal-shortcut-scroll.md | 7 ++
...on-ancestor-intersection-defeats-leaf-scroll.md | 57 +++++++++++
.../dashboard/app/components/TerminalModal.css | 38 ++++++++
.../components/__tests__/TerminalModal.test.tsx | 106 +++++++++++++++++++++
4 files changed, 208 insertions(+)
Fusion-Task-Id: FN-7621
Fusion-Task-Lineage: 771fd79e-e193-43b0-908b-0e8fe2fc2c70
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the mobile dashboard terminal sometimes rendering completely blank on open by having TerminalModal recover from a zero/collapsed container box.
- TerminalModal now attaches a persistent ResizeObserver directly on the xterm container, mirroring SessionTerminal's existing pattern
- When the container reports a zero/collapsed box on the first post-open fit, it now re-fits once the real box settles instead of staying stuck at FitAddon's degenerate 2x1-cell floor
- Added regression tests covering TerminalModal and SessionTerminal zero-geometry recovery
- Documented the root cause and fix in docs/solutions/ui-bugs/mobile-terminal-blank-render-zero-geometry-container.md
- Added a patch changeset for @runfusion/fusion
Files changed:
.changeset/fn-7620-mobile-terminal-blank-render.md | 7 +
docs/solutions/ui-bugs/mobile-terminal-blank-render-zero-geometry-container.md | 112 +++++++
packages/dashboard/app/components/TerminalModal.tsx | 49 +++
packages/dashboard/app/components/__tests__/SessionTerminal.test.tsx | 66 ++++
packages/dashboard/app/components/__tests__/TerminalModal.test.tsx | 358 +++++++++++++++++++++
5 files changed, 592 insertions(+)
Fusion-Task-Id: FN-7620
Fusion-Task-Lineage: 103f5b17-9a6e-4e9a-ab61-65ccb2203a8d
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Update five dashboard app test files whose assertions drifted from
intentional product changes that landed on main without updating them:
- graph-workflow-header: FN-7057 treats stale/missing workflow ids as the
default workflow, so FN-unknown now shows under the default selection.
- EngineControlMenu.css: FN-7340 added a 768px range-thumb touch-target
block; narrow the popover-breakpoint assertion to that selector.
- MissionManager.delete-confirm: FN-7156 removed first-mission auto-select;
explicitly select the mission before the detail-delete flow.
- board-mobile-initial-render: FN-7342 preserves board column scroll during
stabilization; FN-6825 renders the workflow toolbar on options, not callbacks.
- workflow-auto-layout: FN-7265 removed the stepwise review node (per-step
review lives in the foreach); the connected run ends at completion-summary.
No assertion was loosened or deleted to force a pass; each change cites the
breaking commit via an FNXC comment. packages/dashboard is private (no changeset).
recoverActiveMissions (mission-execution-loop.ts:263) calls
missionStore.reconcileSupersededGeneratedFixFeatures per slice; the 5
MissionExecutionLoop-backed mocks here omitted it, so recovery threw
(TypeError) at the slice loop and aborted before processTaskOutcome /
ensureFeatureAssertionLinked / startValidatorRun ran — 4 tests failed.
Add a no-op stub (matches mission-execution-loop.test.ts reference) with
an FNXC:MissionReconcile note. No-op is correct: supersession is not
exercised by these tests.
### Problem
In **Project Settings → Plugins**, the **Browse registry** panel fails
to load with:
```
Failed to load registry: Plugin "registry" not found
```
The registry listing never appears, so one-click plugin
discovery/install is unusable.
### Root cause
In `createApiRoutes` (`packages/dashboard/src/routes.ts`), the generic
project-scoped route **`GET /plugins/:id`** is registered **before** the
plugin sub-router (`createPluginRouter`) — which owns **`GET
/plugins/registry`** — is mounted (`router.use("/plugins",
createPluginRouter(...))`).
Express matches routes in registration order, so a request to
`/api/plugins/registry` matches `:id` with `id === "registry"`, calls
`pluginStore.getPlugin("registry")`, and throws `Plugin "registry" not
found`. The real registry handler (which builds the curated registry
manifest) is never reached.
### Why not just reorder the mount?
The two handlers are **not** equivalent:
- the inline `GET /plugins/:id` is **project-scoped** via
`getProjectContext(req)`,
- the sub-router uses the **global** plugin store.
Mounting the sub-router first would shadow the project-scoped routes and
change scoping semantics for other endpoints. So reordering is the wrong
fix.
### Fix
Let the reserved static path fall through. In the inline `GET
/plugins/:id` handler, when `id === "registry"`, call `next()` so the
later-mounted sub-router serves the registry listing (it already handles
the `projectId` query param). Minimal and targeted — `"registry"` is the
only static GET path under `/plugins` that collides with the
single-segment `:id` pattern.
```ts
router.get("/plugins/:id", async (req, res, next) => {
if (req.params.id === "registry") { next(); return; } // fall through to the registry sub-route
...
});
```
### Tests
Adds a regression test in `plugin-routes.routes.test.ts` (using the
existing `createApiRoutes` harness that reproduces the real mount order)
asserting `GET /api/plugins/registry`:
- returns **200** with a `plugins` array, and
- **never** calls `pluginStore.getPlugin("registry")` (i.e. is no longer
shadowed by `:id`).
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed the `/plugins/registry` endpoint so it responds correctly
instead of being treated like a plugin ID.
* Improved route handling to ensure the registry page/API is reached
even when generic plugin routes are registered first.
* **Tests**
* Added regression coverage for the `/plugins/registry` route to verify
the correct response and prevent the generic plugin lookup from
intercepting it.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Problem
Two settings that already exist in the `Settings` schema and are honored
by the engine have **no control anywhere in the dashboard UI**:
- `buildTimeoutMs` — max time for build/verification commands (default
`300000` = 5 min)
- `insightExtractionEnabled` (+ `insightExtractionSchedule`) — periodic
extraction of durable insights from completed tasks into memory
Because there's no UI, the only way to change them is to hand-edit
`config.json` — but that has to be done with the app fully closed, since
the running app rewrites `config.json` from its database on
reload/shutdown and silently clobbers live file edits. That's a
confusing footgun (edits appear to "not stick"), and 5 minutes is too
low a build timeout for large monorepo / Docker builds.
### Change
Expose both via controls that mirror the existing patterns in the same
sections — no schema, route, or persistence changes needed (the keys
already flow through `form`/`setForm` → `updateSettings`).
- **Scheduling section:** "Build/Verification Timeout (minutes)", placed
next to the existing "Stuck Task Timeout (minutes)", using the same
minutes↔ms conversion.
- **Memory section:** "Enable Insight Extraction" checkbox + conditional
cron "Schedule" field, placed next to the existing Auto-Summarize
controls (matching how `insightExtractionSchedule` is already documented
in `types.ts`).
Both use the existing `t(...)` i18n fallback style used throughout these
sections.
### Scope note (feedback welcome)
Both live in their existing **project-scoped** sections (Scheduling,
Memory), which is the natural home. If maintainers want these settable
as **global/user defaults** too, I'm happy to add a global-defaults
counterpart in a follow-up — just wanted to keep this PR focused and
non-duplicative.
### Testing
- Both keys are pre-existing fields on the `Settings` type
(`buildTimeoutMs?: number` at `packages/core/src/types.ts`;
`insightExtractionEnabled?`/`insightExtractionSchedule?` likewise), so
the additions are type-safe.
- Controls follow the exact JSX/handler pattern of adjacent fields
already in each section.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added an **Insight Extraction** option in memory settings, including
an enable/disable toggle and a schedule field that appears when enabled.
* Added a **Build/Verification Timeout** setting in scheduling, with
minute-based input and helpful guidance text.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The Plugins settings 'Browse registry' feature failed with
'Failed to load registry: Plugin "registry" not found'.
Root cause: in createApiRoutes (routes.ts), the generic project-scoped
'GET /plugins/:id' route is registered BEFORE the plugin sub-router
(createPluginRouter) that owns 'GET /plugins/registry' is mounted. Express
matches in registration order, so a request to /api/plugins/registry matched
':id' with id='registry', called pluginStore.getPlugin('registry') and threw
'Plugin "registry" not found' — the real registry handler was never reached.
Reordering the mount is unsafe: the inline ':id' route is project-scoped via
getProjectContext, while the sub-router uses the global plugin store, so
moving it would change scoping semantics. Instead, let the reserved static
path fall through: when id === 'registry', call next() so the mounted
sub-router serves the registry listing (which already handles projectId).
Adds a regression test asserting GET /api/plugins/registry returns 200 with a
plugins array and never calls getPlugin('registry').
Both settings already exist in the Settings schema and are honored by the
engine, but neither had a control in the dashboard, so users could only
change them by hand-editing config.json while the app was closed (the
running app rewrites config.json from its DB, clobbering live file edits).
- Add 'Build/Verification Timeout (minutes)' to the Scheduling section,
next to the existing stuck-task timeout (same minutes<->ms conversion).
- Add 'Enable Insight Extraction' + cron schedule to the Memory section,
next to the existing auto-summarize controls.
Both are placed in their existing project-scoped sections. Follow-up: a
global-defaults counterpart could be added if maintainers want these
settable at the user/global level too.
Task creation surfaces stopped hardcoding column:"triage", so new tasks now land in the selected-or-default workflow's resolved intake column instead of always jumping to Planning/triage.
- Removed hardcoded column:"triage" override in engine's createTaskCreateTool (fn_task_create), letting TaskStore.createTask resolve the landing column from the workflow's intake-trait column.
- Removed the equivalent hardcoded override in the pi extension's fn_task_create, and updated its response text to echo the actual landing column instead of a fixed "Column: triage" string.
- Fixed signal-route, GitHub-import, and planning-subtask-route task creation to stop forcing column when no workflowId is given (or, for planning subtask routes, even when one is provided).
- Custom workflows with a non-triage intake column (e.g. Inbox) now correctly capture new cards inert until released, while the default builtin:coding workflow still resolves to "triage" byte-identically.
- Added regression coverage (agent-tools-intake-column.test.ts, extension-workflow-tools.test.ts) and a patch changeset documenting the fix.
Files changed:
.changeset/fn-7611-intake-column.md | 7 ++
.../src/__tests__/extension-workflow-tools.test.ts | 70 +++++++++++
packages/cli/src/extension.ts | 10 +-
.../src/__tests__/register-signal-routes.test.ts | 8 +-
.../dashboard/src/__tests__/routes-github.test.ts | 2 -
.../dashboard/src/routes/register-git-github.ts | 16 ++-
.../src/routes/register-planning-subtask-routes.ts | 24 +++-
.../dashboard/src/routes/register-signal-routes.ts | 8 +-
.../__tests__/agent-tools-intake-column.test.ts | 138 +++++++++++++++++++++
packages/engine/src/__tests__/agent-tools.test.ts | 1 -
packages/engine/src/agent-tools.ts | 21 +++-
11 files changed, 288 insertions(+), 17 deletions(-)
Fusion-Task-Id: FN-7611
Fusion-Task-Lineage: daf7f755-b1c7-4859-b74f-f15593d5e79e
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Replace the fixed generic "Would you like to go deeper?" theme buckets with AI-proposed, plan-specific topics, falling back to the existing regex-derived themes when the AI supplies none.
- Add optional PlanningSummary.deepeningThemes (id/label/description) to the completion payload contract in @fusion/core.
- Instruct the planning AI prompt to propose 2-5 concrete, plan-aligned deepening themes tied to the plan's actual title/description/deliverables.
- Add normalizeDeepeningThemes to validate/sanitize untrusted AI-supplied theme data (dedupe, cap at 6, trim, drop malformed entries) and omit the field entirely when nothing valid remains.
- Update buildDeepeningCheckpointOptions to prefer AI-supplied deepeningThemes over the generic CHECKPOINT_THEME_CANDIDATES regex fallback, keeping the reserved 'Proceed to final plan' option first and deterministic in both branches.
- Update docs/dashboard-guide.md to describe the new plan-specific deepening behavior and its generic fallback.
- Add unit test coverage for the new normalization and checkpoint-option-building logic.
- Add a minor changeset for @runfusion/fusion.
Files changed:
.changeset/fn-7616-planning-deepening-themes.md | 7 +
docs/dashboard-guide.md | 3 +-
packages/core/src/types.ts | 11 ++
.../planning-interview-formatters.test.ts | 176 +++++++++++++++++++++
.../src/__tests__/routes-planning.test.ts | 61 +++++++
packages/dashboard/src/planning.ts | 86 +++++++++-
6 files changed, 341 insertions(+), 3 deletions(-)
Fusion-Task-Id: FN-7616
Fusion-Task-Lineage: f6c1d0d7-f0ca-45c9-85cd-d57958ad94c7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes the Task Detail Oversight dropdown trigger rendering shorter than the Priority and Execution-mode controls on non-mobile viewports.
- Made `.detail-oversight-menu-dropdown` an `inline-flex` with `align-items: stretch` so the popover-positioning wrapper participates in `.detail-meta-inline-controls`'s stretch behavior instead of only sizing to its own content.
- Added `align-self: stretch` to `.detail-oversight-menu-trigger` so it fills the now-stretched wrapper, matching Priority/Execution-mode's direct-child stretch.
- Added a regression test asserting the wrapper/trigger stretch declarations exist, apply at every viewport, and don't leak into the absolutely-positioned popover.
- Added a patch changeset documenting the fix.
Files changed:
.changeset/fn-7618-oversight-trigger-height.md | 7 ++++
.../dashboard/app/components/TaskDetailModal.css | 26 ++++++++++++
...etailModal.responsive-and-dependencies.test.tsx | 48 ++++++++++++++++++++++
3 files changed, 81 insertions(+)
Fusion-Task-Id: FN-7618
Fusion-Task-Lineage: f918c2aa-5677-446c-a7dc-17c72adb9c27
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fix Planning Mode's Back button incorrectly rendering the AI generation/loading view instead of returning directly to the previous question.
- handleBack no longer sets view to "loading" during the deterministic rewindPlanningSession call; that view is reserved for real model-generation turns.
- Added isBackPending state to drive a lightweight inline pending indicator on the Back button (spinner icon, disabled Back/Continue) while the rewind request is in flight, keeping the QuestionForm mounted throughout.
- On success, the rewound history/question is applied the same as before; on failure, the error message is surfaced while remaining on the question view (never loading).
- Added a changeset for the fix.
- Expanded PlanningModeModal.planning-flow.test.tsx coverage for the Back button's success/error/pending behavior.
Files changed:
.changeset/FN-7615-planning-back-no-generation.md | 7 +
.../dashboard/app/components/PlanningModeModal.tsx | 34 +++-
.../PlanningModeModal.planning-flow.test.tsx | 182 ++++++++++++++++++++-
3 files changed, 217 insertions(+), 6 deletions(-)
Fusion-Task-Id: FN-7615
Fusion-Task-Lineage: 27e9c541-ce2f-42de-b83a-777af1e56858
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Introduces a single canonical step-number helper so the task-dialog step indicators agree with the Activity tab for the same underlying step.
- Add `getCanonicalStepNumber()` in `packages/dashboard/app/lib/step-display.ts`, returning the raw 0-based, PROMPT.md-numbered step index (Step 0 = Preflight), clamped to a valid range.
- Update `ActiveAgentsPanel` to derive its step/total-steps display from the new helper instead of adding its own +1 to `task.currentStep`.
- Update `TaskTokenStatsPanel`'s step-progress row to use the same canonical helper instead of its own +1 math.
- Add regression tests (`step-number-alignment.test.tsx`) asserting the task-dialog and Activity-tab step numbers stay in sync across surfaces.
Files changed:
.../dashboard/app/components/ActiveAgentsPanel.tsx | 8 +-
.../app/components/TaskTokenStatsPanel.tsx | 7 +-
.../__tests__/step-number-alignment.test.tsx | 162 +++++++++++++++++++++
packages/dashboard/app/lib/step-display.ts | 57 ++++++++
4 files changed, 229 insertions(+), 5 deletions(-)
Fusion-Task-Id: FN-7612
Fusion-Task-Lineage: a33703f5-32cb-4d10-9153-399821517ea3
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fixes TaskDetailModal so manual PR affordances stay visible based on the live global auto-merge setting rather than the per-task effective override, and repairs a pre-existing test regression from the FN-7510 oversight default change.
- isManualPrFlow now checks mergeStrategy === "pull-request" && !autoMergeEnabled (live global setting) instead of the per-task effective auto-merge override, fixing a regression from FN-7255 that stranded users without manual PR controls when a task's auto-merge override was true but global auto-merge was off.
- Pinned plannerOversightLevel: "off" on the Chat-first default-routing test fixture so the FN-7510 autonomous-oversight default doesn't add an extra Activity-view option and break the test's actual intent (asserting Chat-first tab routing).
- Added changeset documenting the fix.
Files changed:
.changeset/fn-7607-manual-pr-flow.md | 7 +++++++
packages/dashboard/app/components/TaskDetailModal.tsx | 14 +++++++++++++-
.../TaskDetailModal.attachments-and-tabs.test.tsx | 12 +++++++++++-
3 files changed, 31 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7607
Fusion-Task-Lineage: f0b077d4-792f-4e43-8e40-43d325920be5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Unifies the previously mobile-only Oversight overflow menu into a single, always-present dropdown that replaces the scattered desktop oversight buttons and the separate mobile affordance.
- Replace discrete desktop oversight action buttons in TaskDetailModal's footer with one universal "Oversight actions" dropdown trigger, reusing the menu across desktop and mobile breakpoints.
- Simplify TaskDetailModal.tsx footer rendering logic, removing now-redundant responsive branching for oversight controls.
- Update TaskDetailModal.css to drop the old mobile-only oversight-overflow styles and support the unified dropdown across breakpoints.
- Update definition-actions, oversight-controls, oversight-mobile, rendering, and responsive-and-dependencies tests to assert the single dropdown behavior and disambiguate the exact "Actions" button query from the new "Oversight actions" aria-label.
- Refresh docs/dashboard-guide.md to describe the unified oversight dropdown UX.
Files changed:
docs/dashboard-guide.md | 14 +-
packages/dashboard/app/components/TaskDetailModal.css | 89 +++++------
packages/dashboard/app/components/TaskDetailModal.tsx | 177 +++------------------
packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx | 70 ++++----
packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-controls.test.tsx | 130 ++++++++++-----
packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-mobile.test.tsx | 42 +++--
packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx | 27 ++--
packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx | 57 ++++---
8 files changed, 278 insertions(+), 328 deletions(-)
Fusion-Task-Id: FN-7604
Fusion-Task-Lineage: afbb7573-d654-48db-a9ac-aecbd8e22e46
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Give the TaskDetailModal priority chip distinct tinted borders/backgrounds per level so low/high/urgent/normal are visually distinguishable at a glance.
- Add per-level border-color and stronger background overrides for .detail-priority-chip.card-priority-badge--{low,high,urgent}, using the matching semantic color token (info/warning/error) with higher specificity than the shared base rule.
- Leave the FN-7585 shared base chip rule and FN-7597 neutral 'normal' treatment untouched; scope changes strictly to .detail-priority-chip so read-only TaskCard badge tints are unaffected.
- Add a regression test asserting each level has distinct, non-var(--border) border-colors and backgrounds, mutually distinct across levels, while the read-only TaskCard badge selectors remain unchanged.
Files changed:
.../dashboard/app/components/TaskDetailModal.css | 33 ++++++++++
...etailModal.responsive-and-dependencies.test.tsx | 71 ++++++++++++++++++++++
2 files changed, 104 insertions(+)
Fusion-Task-Id: FN-7601
Fusion-Task-Lineage: 1e2fc574-835c-43b0-8689-02884ad5c2d6
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
A present, unexpired Anthropic subscription OAuth token that lacks an
inference scope (e.g. a profile-only grant) authenticates identity but
403s on every model call. /auth/status previously validated only token
presence + expiry, so it reported such a token as connected while all
inference failed. It now treats an inference-incapable Anthropic OAuth
token as not-connected (authenticated:false, expired:true so the
re-login banner fires) with a scope-specific loginError. Gated to
Anthropic providers only; tokens with no recorded scopes are treated as
usable to avoid false negatives on fresh logins.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes overlapping Record and Clear buttons on the Keyboard Shortcuts settings rows by replacing the icon-only button class with a text button class and locking layout with flex-shrink.
- Swap ShortcutCaptureInput Record/Clear buttons off the icon-only `btn-icon` class (which forced line-height:0 and a 36px mobile square, clipping labels) onto a text-button class
- Add `.shortcut-capture` row CSS with `flex-shrink:0` on controls so the input and buttons never overlap and stack cleanly on mobile
- Add regression tests covering the Keyboard Shortcuts section layout
- Add changeset documenting the fix
Files changed:
.changeset/fn-7602-shortcut-row-layout.md | 7 ++
.../dashboard/app/components/SettingsModal.css | 17 ++++
.../settings/sections/ShortcutCaptureInput.tsx | 14 +++-
.../__tests__/KeyboardShortcutsSection.test.tsx | 95 ++++++++++++++++++++++
4 files changed, 131 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7602
Fusion-Task-Lineage: 50cf6975-f0fb-42dd-87b0-50578977a0f4
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>