ab228551e9e0fa2e576e65fdca509062c9610629
773 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cdf67c1d98 |
fix(dashboard): stop Planning Mode retry loop, make AI sessions multi-tab (#2101)
## Problem Reported: planning gets stuck in a cycle of retrying and regenerating after a response was already supplied. After the user answers a planning question, `submitResponse` pushed the answer to history but left `session.currentQuestion` pointing at the just-answered question for the whole next generation. The planning SSE route's catch-up path re-emits `currentQuestion` to every fresh connection — and each FN-7946 auto-retry (#2073) opens a fresh connection. So after any generation error: 1. Auto-retry connects a fresh stream → the server re-emits the **already-answered** question. 2. The client treats any question event as progress: it **resets the 3-attempt auto-retry budget** and re-shows the answered question. 3. The retry regenerates; if it errors again the cycle repeats with a fresh budget — an unbounded retry/regenerate loop. Re-answering the stale question also 409-collided with the in-flight generation, feeding the same loop. ## Fix Invariant: `currentQuestion` is only set while the session is genuinely awaiting user input. - `submitResponse` clears it the moment an answer is accepted (normal turns and the deepening checkpoint), while preserving the legacy 200 respond contract on generation failure (the modal ignores the body and lets the SSE error drive recovery). - `retrySession` scrubs stale questions persisted by pre-fix builds before regenerating. - `buildSessionFromRow` only restores a question when the persisted row is `awaiting_input`. - `didSubmitSameAnswer` now compares against the last history entry so the duplicate-submit 409 message survives. - Agent onboarding gets the same fix (its SSE route also re-emits `currentQuestion` on connect); retry now asks the next question instead of re-asking the answered one. Surface enumeration: mission and milestone interviews keep questions the same way but their SSE routes never re-emit on connect, and the auto-retry budget machinery is Planning-Mode-only — planning + onboarding were the two affected surfaces. ## Symptom Verification - **Original symptom:** after answering a question, Planning Mode loops between "Retrying…" and regenerating, re-showing the already-answered question, with the auto-retry budget never exhausting. - **Exact reproduction:** answer a question, have the next generation fail (stuck watchdog/provider error), let the client auto-retry open a fresh SSE connection. - **Assertion it is gone:** new regression suite `planning-answered-question-reemit.test.ts` asserts `currentQuestion` is cleared mid-generation, on generation failure, on retry, and on restore from non-`awaiting_input` rows — so the SSE catch-up path has nothing stale to re-emit. All 5 tests fail against pre-fix code and pass with the fix; an onboarding regression test covers the sibling surface. ## Verification - New regression tests: 5/5 fail on pre-fix code, pass with the fix (plus 1 onboarding test). - Existing suites: 137 planning server tests pass (3 failures in `routes-planning.test.ts` fail identically without this change — pre-existing on the branch); all 69 `PlanningModeModal.planning-flow` client tests pass; `tsc --noEmit` clean; `pnpm check:changesets` passes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Made Planning Mode (and related planning controls) lock-free and multi-tab—no more take-over/active-in-another-tab lock overlays. * **Bug Fixes** * Fixed Planning Mode retry/generation flows where already-answered questions could reappear. * Ensured answered questions clear immediately and aren’t re-emitted during session recovery/SSE catch-up. * Improved session restoration and preserved legacy recovery behavior when generation fails after an answer. * **Tests** * Added regression coverage for the answered-question invariant and updated existing tests to reflect lock-free behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- ## Follow-up: Planning Mode is now multi-tab via DB state (lock-free) Second commit removes all cross-tab coordination from planning — the persisted session row is the single source of truth and multiple tabs can read and interact with the same session: - **Server:** `/planning/*` routes no longer run `checkSessionLock` or parse `tabId`; a stale `tabId` from an older client is ignored instead of 409'd. Subtask/mission interview routes keep their existing lock behavior. - **Client:** `PlanningModeModal` drops `useSessionLock`, the `useAiSessionSync` BroadcastChannel broadcasts, `sessionTabId`/`lockSessionId` state, and the "Take Control" overlay. Tabs stay current via the per-session SSE stream plus the global `ai_session:updated` events `useBackgroundSessions` already consumes; concurrent writes resolve via the server's generation-in-progress guard (409). - **API client:** planning functions lose their `tabId` params. - **Fix uncovered by the refactor:** the 8s stuck-poll now resolves the session id inside each tick — the removed lock state was what previously re-armed the poll after Start Planning resolved the session id. - Also fixes a pre-existing PG-cutover break in `planning-generation-cancellation.test.ts` (`getSession` is async). Verification: 144 client planning tests and 137 server planning tests pass (the 3 remaining `routes-planning.test.ts` failures are pre-existing on the branch and fail identically without these changes); `tsc --noEmit` and eslint clean on changed files; `pnpm check:changesets` passes. Lock-conflict route tests were rewritten to assert lock-free semantics, plus a new modal test proving a session stays fully interactive with no lock acquisition even when another tab is active. --- ## Follow-up 2: the per-tab session lock is gone entirely Third commit extends the multi-tab model from planning to **every** AI interview surface (planning, subtask breakdown, mission interview, milestone/slice interview) and deletes the lock machinery root and branch. **Server** - Deleted the `/ai-sessions/:id/lock`, `/lock/force`, and `/lock/beacon` routes. - Dropped `checkSessionLock` from every planning/subtask/mission/milestone route (both copies — `routes.ts` and `mission-routes.ts`). A `tabId` from an older client is ignored, never 409'd; all `tabId` body parsing is gone. - Dropped `acquireLock` / `releaseLock` / `forceAcquireLock` / `getLockHolder` / `releaseStaleLocks` from `AiSessionStore`, plus the `@fusion/core` async helpers (`acquireAiSessionLock` et al) and core's re-exports. - Removed `lockedByTab`/`lockedAt` from `AiSessionRow`/`AiSessionSummary`, the upsert SQL, and all four session producers. **Client** - Deleted `useSessionLock` and the now-orphaned `getSessionTabId` util. - Removed the Take Control overlay, the "active in another tab" banners, and `BackgroundTasksIndicator`'s active-elsewhere gate (the confirm prompt and lock badge — sessions now just open). - Reduced `useAiSessionSync` to what its own comments already called it — a low-latency *status* supplement to SSE: no `activeTabMap`, `broadcastLock/Unlock/Heartbeat`, `owningTabId`, `tab:*` messages, or stale-heartbeat sweep. - Dropped `tabId` from every session API client function; removed the lock CSS. **Deliberately kept: the two DB columns.** `ai_sessions.locked_by_tab` / `locked_at` remain as dead, always-NULL columns with a deprecation note. Dropping them is an irreversible migration, and released binaries still name those columns explicitly in their upsert — an older install pointed at the same database would fail every session write. They can be dropped once no such binary can reach it. No code reads or writes them. **Verification**: 397 client tests and 137 server planning tests pass (the same 3 `routes-planning.test.ts` failures are pre-existing — verified identical on a clean stash); `tsc --noEmit` clean for `@fusion/core` and `@fusion/dashboard`; eslint clean on all changed files; the 30 PG `schema-applier` tests pass (they exercise the retained columns); `pnpm check:changesets` passes. The lock-conflict route tests and both modal lock tests were rewritten to assert the inverse: routes and modals stay fully interactive while another tab "holds" a lock, and the lock API is never called. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d0ce7829c0 |
FN-7953: fix mobile OAuth code submit taps
Submit Anthropic OAuth manual codes on the first mobile tap instead of requiring keyboard dismissal first. - Add a reusable touch action gesture hook that handles touch/pointer activation before synthetic clicks. - Wire the OAuth manual code Submit button to invoke submission on the first touch while preventing duplicate click handling. - Cover the mobile double-tap regression and document the UI bug pattern for future fixes. Files changed: .../oauth-manual-code-mobile-double-tap-submit.md | 60 +++++++++++ .../app/components/OAuthManualCodeForm.tsx | 31 +++++- .../__tests__/OAuthManualCodeForm.test.tsx | 110 +++++++++++++++++++++ .../hooks/__tests__/useTouchActionGesture.test.ts | 110 +++++++++++++++++++++ .../dashboard/app/hooks/useTouchActionGesture.ts | 89 +++++++++++++++++ 5 files changed, 399 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7953 Fusion-Task-Lineage: d387cdbd-25a7-4b7d-add6-27a1ded5cbea Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
79d4299be2 |
fix: preserve provider and workflow behavior after migration
Use canonical Anthropic OAuth refresh, keep CLI-backed providers out of API-key auth rows, parse Grok's omitted zero usage, and carry board workflow context into task creation. |
||
|
|
c15c78feeb |
feat: migrate storage from SQLite to PostgreSQL (#1793)
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover Migrates Fusion's storage layer to the embedded PostgreSQL `AsyncDataLayer` (the default backend) and **completes the satellite-store + feature cutover** so every dashboard and Command Center surface works in PG mode. ## Status — every surface works in embedded-PG mode Verified live against a running embedded-Postgres dashboard (all **200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate; core/engine/cli/dashboard typecheck clean). | Area | Surfaces | State | |---|---|---| | Satellite stores | workflows, todos, insights, research, missions, goals, mailbox | ✅ | | Views | artifacts, documents, evals | ✅ | | Command Center | activity, productivity, team, tokens, tools, **workflows**, **github**, **signals**, **plugin-activations**, **live** (all 10) | ✅ | | Run execution | insight generation, research run execution | ✅ (store-path; AI step needs a provider) | | Live updates | SSE push for mission/research/insight events | ✅ | | Workflow editing | create / update / delete / select (+ id counter) | ✅ | | Engine | mission autopilot, incident-signal ingestion, regression storm-guard, agent wake-on-message | ✅ | | Core | tasks, agents, secrets, automations, memory, chat, usage, PRs, git | ✅ | ## Approach Each satellite store gets an `Async<Store>` wrapper exposing the sync store's method names over the existing `async-*-store.ts` helpers; `get<Store>Store()` returns a `Sync | Async` union; consumers `await` (harmless on sync), and engine/CLI paths that can't convert use `instanceof Sync` graceful fallback. Analytics aggregators branch on `"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*` (snake_case) in PG. Executors/orchestrators/autopilot are await-converted to drive the union store; the async store wrappers extend `EventEmitter` so SSE live-push fires in both backends. Not-yet-ported capabilities degrade gracefully (never 500) and are individually called out in commits. ## Sync with main The branch is kept continuously merged with `main` (currently through FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer applies. Use **Create a merge commit** (or squash) to land it — GitHub's rebase-merge cannot replay a merge-maintained branch. ## Residual Review Findings Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5) applied 3 safe fixes (see `fix(review): apply autofix feedback`). The following are **real but gated** — recorded here as follow-up work rather than auto-applied. All are SQLite→PostgreSQL **concurrency/atomicity regressions**: the sync stores were immune only by SQLite's single-writer, single-threaded-handler execution; the async ports open multi-await read-modify-write windows. **Reachability is low today** because the execution engines that generate concurrent same-run mutations (insight run executor, research orchestrator/dispatcher) are `instanceof`-gated to sync mode in PG. No process-crash class survived (all engine fallbacks correctly guard the sync store). - **[P1] Research `appendResearchEvent` dual-write is non-atomic** (`packages/core/src/async-research-store.ts`, corroborated: adversarial + reliability). The `research_run_events` insert (own transaction) and the `run.events` jsonb update are separate writes — a crash between them, or two concurrent appends, splits the table count from the jsonb array. **Fix:** perform the seq-insert and the jsonb update in one `layer.transactionImmediate`. - **[P1] Research run terminal-reversion via stale full-row persist** (`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`). Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert a terminal run to `running` by overwriting the whole row, bypassing the transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status …` guard, or optimistic version column. - **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU** — concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:** `SELECT … FOR UPDATE` / enclosing transaction. - **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race** (`async-insight-store.ts`) — two callers can each create an "active" run. **Fix:** partial unique index on `(projectId, trigger) WHERE status IN ('pending','running')`. - **[P3] `createResearchRetryRun` return-value divergence** — sync returns the pre-update `queued` snapshot; async returns the reloaded `retry_waiting` run (persisted state is identical). Pick one side for cross-backend parity. - **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1 fan-out** — O(milestones×slices) sequential round-trips hold one pool slot per request; can starve the pool for large hierarchies. **Fix:** batched/joined reads. - **Testing gaps:** no PG-mode concurrency tests (interleaved status/event mutations), no sync↔async parity assertion for the lifecycle-error codes, and no mission status/health rollup parity test vs the sync `MissionStore`. ~~Out of scope (deferred): AI run *execution* (insight/research) + mission autopilot + live SSE mission events remain sync-gated/degraded in PG mode.~~ **Since ported** — insight/research run execution, mission autopilot, and SSE live push all run on the async layer now, which also makes the concurrency findings above genuinely reachable; they remain open follow-ups. --- ## Update — 2026-07-12: production-readiness hardening & live acceptance Everything below landed on this branch since the description above was written: **Production blockers from review — fixed** - `recoverStaleTransitionPending` ported to the async layer (backend moves write + clear the crash-safe marker; startup/maintenance sweeps no longer throw). - Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write changed columns only (full-row upserts silently resurrected stale fields across concurrent store instances — the "task stuck unplanned forever" bug). - First-boot **auto-migration**: booting the PG backend over a project with a legacy `fusion.db` migrates it automatically (loud failure, SQLite kept as backup), and the dashboard shows a one-time **"your data was migrated" banner** with the backup paths and a Need-help Discord link. - `pg_dump`/`pg_restore` discovered from common install locations for embedded-mode backups. - The PG suite is part of the blocking merge gate (`test:pg-gate`). **Multi-project isolation (PR #2007, merged into this branch)** - `project_id` partition key on tasks / archived tasks / config, `taskProjectScope` threaded through every scan/claim/count, per-project config rows, layer bound to the project at startup. - Review P1 follow-up: the shared cold-storage `archive.archived_tasks` table is also partitioned and all archived-board reads/counts/searches are scoped. - Schema drift self-heal generalized to schema-qualified columns so existing databases upgrade in place. **Other changes** - Node settings sync **removed** in PG mode (409 `settings-sync-disabled-postgres`) — nodes share state by connecting to the same database; auth sync kept (per-machine file). - Perf (review findings): `listTasks` pushes column filter + ORDER BY + LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200 messages. - Fixed a false "operator action required" pause-abort log fired on every successfully auto-merged task. **Live acceptance — PASSED (2026-07-12)** A sandboxed instance (isolated HOME, embedded PG, real Opus executor) ran a task through the complete cycle: create → triage (AI spec) → execute → in-review → AI squash-merge landed on the project's `main` → done. A write+read sweep of every data surface (settings, comments, documents, attachments + artifact bridge + artifact edit, chat with real generation, goals, missions, agent mail, secrets, workflows, memory, CC analytics) was green on embedded PG. **Known remaining work** - The per-project `config` PK re-key has no upgrade path for pre-isolation embedded-PG databases (needs a real `DROP CONSTRAINT`/re-key migration; fresh databases are fine). - `pg_dump`/`pg_restore` binaries are not yet bundled in release artifacts (PATH/common-location discovery only). - The satellite-store concurrency findings listed above. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Phil Larson <hello@phillarson.xyz> Co-authored-by: fusion-merge <fusion-merge@local> |
||
|
|
7246df22f6 |
FN-7944: add setting to keep task popups attached to their Board/List view
Adds an opt-in project setting so open task-detail popups stay attached to the Board or List view where they were opened, instead of floating over every main-content view. - New project setting taskPopupsBoardListOnly (default: off) in settings-schema.ts and ProjectSettings type, with default preserved via settings-defaults tests. - usePoppedOutTasks now stores each popup's originating TaskView alongside its task snapshot (PoppedOutTaskEntry), keeping legacy tasks output for existing callers. - App.tsx adds isTaskPopupVisibleForView() gating helper and filters popped-out entries to the current view for rendering/keyboard-close handling, while hidden popups remain mounted in hook state (not cleared) so switching back to the originating view restores them with shared persisted geometry. - Settings -> Appearance gets a new "Keep task popups on their Board/List view" checkbox (AppearanceSection.tsx) with i18n strings and updated settings search text in SettingsModal. - Documentation updated in docs/dashboard-guide.md and docs/settings-reference.md to describe the render-only hide/restore behavior. - New/updated tests: App.taskPopupViewGating.test.tsx, usePoppedOutTasks.test.ts, AppearanceSection.test.tsx, settings-default-descriptions.test.tsx, settings-defaults.test.ts. Files changed: docs/dashboard-guide.md | 5 +- docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 13 +++ packages/core/src/settings-schema.ts | 5 + packages/core/src/types.ts | 7 ++ packages/dashboard/app/App.tsx | 49 +++++++-- .../app/__tests__/App.taskPopupViewGating.test.tsx | 113 +++++++++++++++++++++ .../dashboard/app/components/SettingsModal.tsx | 3 +- .../settings/sections/AppearanceSection.tsx | 8 ++ .../sections/__tests__/AppearanceSection.test.tsx | 21 ++++ .../settings-default-descriptions.test.tsx | 1 + .../app/hooks/__tests__/usePoppedOutTasks.test.ts | 14 +++ packages/dashboard/app/hooks/useAppSettings.ts | 4 + packages/dashboard/app/hooks/usePoppedOutTasks.ts | 27 +++-- packages/i18n/locales/en/app.json | 2 + 15 files changed, 255 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-7944 Fusion-Task-Lineage: 4b8ced0e-1853-429f-8482-163821a35ae6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
daf3f15fd1 |
FN-7909: add room-level thinking effort override for Chat Rooms
Adds a per-room thinking-effort (reasoning level) override for Chat Rooms so all room responders can share a consistent override instead of relying only on per-agent/global defaults. - Persist `chat_rooms.thinkingLevel` with a new core DB migration and store read/write support - Extend chat-store and chat-types with thinkingLevel plumbing for room create/update - Wire the dashboard chat room API/routes and legacy handlers to accept and return thinkingLevel - Add a ChatView room settings control (with CSS) and useChatRooms hook support for setting/clearing the override - Resolve room responder defaultThinkingLevel from the room override when present - Update docs (dashboard-guide, settings-reference) and add a minor changeset for the feature Files changed: .changeset/fn-7909-room-thinking-level.md | 7 +++ docs/dashboard-guide.md | 1 + docs/settings-reference.md | 2 +- packages/core/src/__tests__/chat-store.test.ts | 21 ++++++++ packages/core/src/__tests__/db-migrate.test.ts | 57 ++++++++++++++++++++++ packages/core/src/chat-store.ts | 12 ++++- packages/core/src/chat-types.ts | 10 ++++ packages/core/src/db.ts | 28 ++++++++++- packages/dashboard/app/api/__tests__/chat-rooms-api.test.ts | 8 +-- packages/dashboard/app/api/legacy.ts | 4 +- packages/dashboard/app/components/ChatView.css | 16 ++++++ packages/dashboard/app/components/ChatView.tsx | 29 ++++++++++- packages/dashboard/app/components/__tests__/ChatView.rooms.test.tsx | 24 +++++++++ packages/dashboard/app/hooks/__tests__/useChatRooms.test.ts | 22 +++++++++ packages/dashboard/app/hooks/useChatRooms.ts | 16 ++++++ packages/dashboard/src/__tests__/chat-room-routes.test.ts | 26 ++++++++++ packages/dashboard/src/__tests__/chat.rooms.test.ts | 42 ++++++++++++++++ packages/dashboard/src/chat.ts | 8 +++ packages/dashboard/src/routes/register-chat-room-routes.ts | 21 ++++++-- 19 files changed, 338 insertions(+), 16 deletions(-) Fusion-Task-Id: FN-7909 Fusion-Task-Lineage: 2741eca9-5305-4f6c-81bf-ae644a9fe307 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8835c6cb48 |
FN-7908: add in-chat model/agent switcher to brain-icon popup
Extend the chat brain-icon popup and its backing session PATCH route so an active Direct chat's model or agent can be switched mid-conversation instead of only being set at creation time. - Add a Model/Agent section to ChatThinkingLevelControl (the brain-icon popup) for picking a model provider/model or retargeting to a real agent without leaving the chat. - Extend PATCH /api/chat/sessions/:id to accept modelProvider/modelId (as a validated pair via the existing validateModelPair helper) and agentId, forwarding only the keys present in the body so omitted fields leave the session's stored target untouched. - Add chat-store updateSession support for the agentId clause alongside the existing model/thinkingLevel fields, and a useChat.setSessionModel hook for the dashboard to call the new PATCH capability. - Update i18n locale strings (en/es/fr/ko/zh-CN/zh-TW) and dashboard-guide.md docs for the new switcher UI. - Add unit/integration test coverage across chat-store, chat-manager, chat-routes, useChat, ChatThinkingLevelControl, and ChatView for the new model/agent switch behavior. - Add changeset fn-7908-chat-model-agent-switcher.md (minor, @runfusion/fusion). Files changed: .changeset/fn-7908-chat-model-agent-switcher.md | 7 + docs/dashboard-guide.md | 3 +- packages/core/src/__tests__/chat-store.test.ts | 21 ++ packages/core/src/chat-store.ts | 8 + packages/core/src/chat-types.ts | 2 + packages/dashboard/app/api/legacy.ts | 11 +- .../app/components/ChatThinkingLevelControl.tsx | 219 ++++++++++++++++++--- packages/dashboard/app/components/ChatView.css | 135 ++++++++++++- packages/dashboard/app/components/ChatView.tsx | 23 ++- .../__tests__/ChatThinkingLevelControl.test.tsx | 109 +++++++++- .../__tests__/ChatView.thinking-level.test.tsx | 67 ++++++- .../dashboard/app/hooks/__tests__/useChat.test.ts | 166 +++++++++++++++- packages/dashboard/app/hooks/useChat.ts | 56 ++++++ .../dashboard/src/__tests__/chat-manager.test.ts | 38 ++++ .../dashboard/src/__tests__/chat-routes.test.ts | 117 ++++++++++- .../dashboard/src/routes/register-chat-routes.ts | 48 ++++- packages/i18n/locales/en/app.json | 8 +- packages/i18n/locales/es/app.json | 8 +- packages/i18n/locales/fr/app.json | 8 +- packages/i18n/locales/ko/app.json | 8 +- packages/i18n/locales/zh-CN/app.json | 8 +- packages/i18n/locales/zh-TW/app.json | 8 +- 22 files changed, 1007 insertions(+), 71 deletions(-) Fusion-Task-Id: FN-7908 Fusion-Task-Lineage: b1104865-9b0c-4d77-973e-89152fe245e0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
23cb061af2 |
FN-7898: add in-chat thinking-level control next to the attach button
Adds a Brain-icon popover control in the chat composer that lets users change an existing session's reasoning-effort level mid-conversation, extending the existing create-time-only thinking-level picker. - Add ChatThinkingLevelControl component (Brain-icon trigger + popover) wired into ChatView's direct-session composer, gated to non-CLI model-loop sessions only - Extend PATCH /api/chat/sessions/:id to accept an optional thinkingLevel field, validated via existing validateThinkingLevel helper; null/empty string explicitly clears back to the inherited default, omitting the key leaves it untouched - Add useChat().setSessionThinkingLevel hook method to call the new PATCH capability - Add i18n strings (thinkingLevelButton) across all locales and regenerate packages/i18n/src/resources.d.ts - Add changeset for @runfusion/fusion (minor) and update docs/dashboard-guide.md Files changed: .changeset/fn-7898-chat-thinking-level-control.md | 7 + docs/dashboard-guide.md | 2 + packages/dashboard/app/api/legacy.ts | 4 +- .../app/components/ChatThinkingLevelControl.tsx | 133 +++++++++++ packages/dashboard/app/components/ChatView.css | 73 ++++++ packages/dashboard/app/components/ChatView.tsx | 20 ++ .../__tests__/ChatThinkingLevelControl.test.tsx | 103 ++++++++ .../__tests__/ChatView.message-edit.test.tsx | 1 + .../components/__tests__/ChatView.test-harness.tsx | 1 + .../__tests__/ChatView.thinking-level.test.tsx | 262 +++++++++++++++++++++ .../dashboard/app/hooks/__tests__/useChat.test.ts | 108 +++++++++ packages/dashboard/app/hooks/useChat.ts | 59 +++++ .../dashboard/src/__tests__/chat-routes.test.ts | 83 +++++++ .../dashboard/src/routes/register-chat-routes.ts | 35 ++- packages/i18n/locales/en/app.json | 1 + packages/i18n/locales/es/app.json | 1 + packages/i18n/locales/fr/app.json | 1 + packages/i18n/locales/ko/app.json | 1 + packages/i18n/locales/zh-CN/app.json | 1 + packages/i18n/locales/zh-TW/app.json | 1 + packages/i18n/src/resources.d.ts | 96 ++++++-- 21 files changed, 970 insertions(+), 23 deletions(-) Fusion-Task-Id: FN-7898 Fusion-Task-Lineage: a052a6ef-d2d3-45af-9b92-221996780b1b Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
7a51f95b38 |
FN-7901: persist thinkingLevel for insight model selection
Adds a persisted Thinking Level (reasoning-effort) selector to manual insight generation, threading the selection through the dashboard API, insight run metadata, and retries. - Add inline Thinking Level selector to the InsightsView model-config popover, persisted to localStorage (fusion-insight-thinking) - Thread thinkingLevel through triggerInsightRun (legacy API client) and useInsights.runInsights - Validate and store thinkingLevel in insight run inputMetadata.metadata on the POST /insights/run route; resolve it via resolvePlanningThinkingLevel for the actual generation call - Recover and reapply the original run's thinkingLevel on retry (retryInsightRunLifecycle) so retries reuse the same reasoning-effort setting - Export resolvePlanningThinkingLevel from @fusion/engine - Document the new Thinking Level selector in docs/dashboard-guide.md - Add a minor changeset for @runfusion/fusion Files changed: .changeset/fn-7901-insight-thinking-level.md | 7 ++ docs/dashboard-guide.md | 1 + .../app/__tests__/insight-model-selector.test.tsx | 41 ++++++++++- packages/dashboard/app/api/legacy.ts | 2 + packages/dashboard/app/components/InsightsView.tsx | 24 +++++- .../app/hooks/__tests__/useInsights.test.ts | 36 ++++++++- packages/dashboard/app/hooks/useInsights.ts | 6 +- .../src/__tests__/insights-routes.test.ts | 86 ++++++++++++++++++++++ packages/dashboard/src/insights-routes.ts | 36 ++++++++- packages/engine/src/index.ts | 1 + 10 files changed, 227 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-7901 Fusion-Task-Lineage: a6249526-e97d-403e-b853-e497d16f425b Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
06ec0e606e |
FN-7866: add auto-save toggle for the workspace file editor (default on)
Adds a shared, persisted auto-save preference for workspace text-file editing, defaulted to on, surfaced as a toolbar toggle in both the Files modal and right-dock Files view. - Add useAutoSavePreference hook: persists the fn-file-editor-auto-save localStorage preference, broadcasts same-window changes via a custom event (storage events only reach other documents), and defaults to true. - Extend useWorkspaceFileEditor with an autoSave flag that debounces (800ms) and triggers save() for a loaded, editable file with real pending changes, keyed by workspace+file+content to avoid re-firing on failed writes. - Add an Auto-save toggle button to FileEditor's toolbar (autoSaveEnabled/onToggleAutoSave/canToggleAutoSave props), hidden for read-only/preview/binary files. - Wire the shared preference into FileBrowserModal and DockFilesView, disabling auto-save for binary files in the modal. - Add fileEditor.autoSave / fileEditor.toggleAutoSave i18n strings and document the new default behavior in docs/dashboard-guide.md. - Add/extend tests covering the new hook, debounced auto-save behavior, and toolbar toggle wiring across FileEditor, FileBrowserModal, and DockFilesView. Files changed: docs/dashboard-guide.md | 3 + .../dashboard/app/components/DockFilesView.tsx | 6 +- .../dashboard/app/components/FileBrowserModal.tsx | 20 ++-- packages/dashboard/app/components/FileEditor.tsx | 17 +++- .../components/__tests__/DockFilesView.test.tsx | 37 ++++++- .../components/__tests__/FileBrowserModal.test.tsx | 86 +++++++++++++--- .../app/components/__tests__/FileEditor.test.tsx | 56 +++++++++++ .../hooks/__tests__/useAutoSavePreference.test.ts | 66 +++++++++++++ .../hooks/__tests__/useWorkspaceFileEditor.test.ts | 108 +++++++++++++++++++++ .../dashboard/app/hooks/useAutoSavePreference.ts | 79 +++++++++++++++ .../dashboard/app/hooks/useWorkspaceFileEditor.ts | 47 ++++++++- packages/i18n/locales/en/app.json | 2 + 12 files changed, 500 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-7866 Fusion-Task-Lineage: 0604de18-666d-4872-abce-2a3886c9ea55 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e559b2b538 |
FN-7853: preserve chat thread during active streaming turns
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> |
||
|
|
20c6db9534 |
FN-7861: make pause/unpause task state update the board immediately
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> |
||
|
|
3d7eaeabee |
FN-7849: reconcile streaming user-message echo to render chat attachments immediately
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> |
||
|
|
53427cde2c | fix: prevent stale planning notifications | ||
|
|
79264d4990 |
FN-7824: auto-reconnect terminal on first launch instead of parking disconnected
Terminal WebSocket sessions now retry with capped backoff through cold-start failures instead of giving up and requiring a manual Reconnect click. - useTerminal tracks whether a socket has ever successfully opened via hasEverConnectedRef - a never-connected initial connect ignores MAX_RECONNECT_ATTEMPTS and keeps retrying at capped backoff, staying in the reconnecting affordance until it opens - mid-session drops (sockets that opened at least once) keep the existing bounded give-up behavior, and permanent 4000/4004 closes remain terminal - context-change invalidation now uses a ref flag (contextChangedSinceLastEffectRef) consumed inside the effect instead of a transient boolean dependency, avoiding cleanup re-runs that tore down the replacement socket during context-switch/reconnect races - manual reconnect() and context/session changes reset hasEverConnectedRef so cold-start behavior reapplies per session - added a patch changeset and expanded useTerminal test coverage for first-launch reconnect vs. mid-session disconnect behavior - documented the first-launch reconnect behavior in docs/dashboard-guide.md Files changed: .changeset/FN-7824-terminal-first-launch-autoreconnect.md | 7 + docs/dashboard-guide.md | 3 + packages/dashboard/app/hooks/__tests__/useTerminal.test.ts | 208 ++++++++++++++++++++- packages/dashboard/app/hooks/useTerminal.ts | 34 +++- 4 files changed, 234 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-7824 Fusion-Task-Lineage: 7ed696d0-449e-4dc0-9be0-48b429b8c844 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
937650472a |
FN-7820: add Cost tab to task detail and optional card cost badge
Adds a shared cost-derivation utility and surfaces token/cost info in a new Cost tab on the task detail modal, plus an opt-in per-card cost badge on the board. - Extract token-cost calculation into a shared taskTokenCost helper (read-time costFor derivation) reused by the Summary tab, new Cost tab, and card badge - Add TaskDetailModal Cost tab (TaskCostTab.tsx/.css) showing cost breakdown for a task - Simplify TaskSummaryTab by delegating cost math to the shared helper - Add default-off project setting showCostBadgeOnCards (settings-schema.ts, types.ts) with a SettingsModal/AppearanceSection toggle - Add CostBadgeContext to thread the setting into TaskCard without prop drilling - Show an optional cost badge on TaskCard when the setting is enabled - Update i18n strings across en/es/fr/ko/zh-CN/zh-TW locales - Update docs (dashboard-guide.md, settings-reference.md) and add changeset fn-7820-cost-tab-and-card-badge.md Files changed: .changeset/fn-7820-cost-tab-and-card-badge.md | 7 ++ docs/dashboard-guide.md | 4 + docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 13 ++ packages/core/src/settings-schema.ts | 5 + packages/core/src/types.ts | 5 + packages/dashboard/app/App.tsx | 5 + .../dashboard/app/components/SettingsModal.tsx | 6 + packages/dashboard/app/components/TaskCard.css | 7 +- packages/dashboard/app/components/TaskCard.tsx | 27 +++- packages/dashboard/app/components/TaskCostTab.css | 51 ++++++++ packages/dashboard/app/components/TaskCostTab.tsx | 91 ++++++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 14 ++- .../dashboard/app/components/TaskSummaryTab.tsx | 123 +----------------- .../app/components/__tests__/TaskCard.test.tsx | 81 +++++++++++- .../app/components/__tests__/TaskCostTab.test.tsx | 55 ++++++++ .../TaskDetailModal.attachments-and-tabs.test.tsx | 11 +- .../settings/sections/AppearanceSection.tsx | 8 ++ .../sections/__tests__/AppearanceSection.test.tsx | 20 +++ .../settings-default-descriptions.test.tsx | 1 + .../dashboard/app/context/CostBadgeContext.tsx | 19 +++ packages/dashboard/app/hooks/useAppSettings.ts | 15 +++ .../app/utils/__tests__/taskTokenCost.test.ts | 62 +++++++++ packages/dashboard/app/utils/taskTokenCost.ts | 139 +++++++++++++++++++++ packages/i18n/locales/en/app.json | 29 ++++- packages/i18n/locales/es/app.json | 30 ++++- packages/i18n/locales/fr/app.json | 27 +++- packages/i18n/locales/ko/app.json | 30 ++++- packages/i18n/locales/zh-CN/app.json | 30 ++++- packages/i18n/locales/zh-TW/app.json | 30 ++++- 30 files changed, 789 insertions(+), 157 deletions(-) Fusion-Task-Id: FN-7820 Fusion-Task-Lineage: d33c5678-a68c-4b29-9db1-8ff0369dfd72 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
1d2d73ba5c |
fix(memory): fix insights parsing + modernize Memory, Insights, Todos, and agent Memory UI
- parseInsightsContent stripped bullet prefixes before filtering for them, so every
insights category rendered as one blob and counts were wrong (5 shown vs 84 real)
- drop dead GET /memory and GET /memory/stats mount fetches from useMemoryData and
stop refetching the file list on every file selection
- Memory view: full-width layout, accent tabs, 2-column Engines card grid, remove
duplicated capability badges, correct spacing-token-as-font-size rules
- Todos: single-row items with quiet inline action cluster (stacked on narrow/mobile)
- Insights: flat card list (no card-in-card), 28px/16px actions muted until hover
- Agent Memory tab: shared FileEditor (CodeMirror) for memory files, per-section save
actions, distinct inline-toggle aria-labels, fix {{date}} i18n interpolation
- PR screenshots under docs/assets/memory-ui-review-2026-07/
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
6317fcddb5 |
FN-7813: add embedded worktree-rooted multi-tab Terminal to Task Detail
Add an interactive, worktree-rooted, multi-tab Terminal tab to the Task Detail view, distinct from the pre-existing CLI-agent Session tab. - TaskDetailModal gains a new embedded Terminal tab (single non-workspace task with one recorded worktree) that mounts TerminalModal in a new `embedded` render mode, rooted at the task's worktree - Rename the existing agent-session tab label to "Session" to disambiguate it from the new Terminal tab - useTerminalSessions gains task-scoped session storage and a `defaultCwd` option so embedded terminal tabs persist separately from footer/global project terminal tabs and start in the task worktree - TerminalModal/CSS updated to support the embedded layout mode - Update lazy-loaded-views docs test and AGENTS.md exclusion list to cover the new `LazyTerminalModal` task-detail-internal surface - Document the new Session/Terminal tab split in docs/dashboard-guide.md - Add i18n strings for the new Terminal tab across all locales - Add a changeset (minor) for @runfusion/fusion Files changed: .changeset/FN-7813-worktree-terminal-tab.md | 7 + AGENTS.md | 2 +- docs/dashboard-guide.md | 3 + .../app/__tests__/lazy-loaded-views-docs.test.ts | 4 +- .../dashboard/app/components/TaskDetailModal.css | 17 +++ .../dashboard/app/components/TaskDetailModal.tsx | 41 +++++- .../dashboard/app/components/TerminalModal.css | 51 +++++++ .../dashboard/app/components/TerminalModal.tsx | 71 +++++++--- .../__tests__/TaskDetailModal.test-helpers.ts | 3 + .../TaskDetailModal.worktree-terminal.test.tsx | 139 ++++++++++++++++++ .../components/__tests__/TerminalModal.test.tsx | 29 ++++ .../hooks/__tests__/useTerminalSessions.test.ts | 157 +++++++++++++++++++++ .../dashboard/app/hooks/useTerminalSessions.ts | 63 ++++++--- packages/i18n/locales/en/app.json | 3 +- packages/i18n/locales/es/app.json | 3 +- packages/i18n/locales/fr/app.json | 3 +- packages/i18n/locales/ko/app.json | 3 +- packages/i18n/locales/zh-CN/app.json | 3 +- packages/i18n/locales/zh-TW/app.json | 3 +- 19 files changed, 550 insertions(+), 55 deletions(-) Fusion-Task-Id: FN-7813 Fusion-Task-Lineage: 4ef86a15-347a-4862-b01c-5063d8004cb8 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
9024f3a639 |
feat: agent-created visual artifacts end-to-end + redesigned category gallery with doc editing
Agents could never get screenshots/wireframes/mocks into the Artifacts view:
fn_artifact_register was gated on assignedAgentId (never set in default
ephemeral mode), the only image payload source was inline base64, and no
prompt ever told agents to register visual deliverables.
- always expose fn_artifact_register to executor sessions ("executor" author
fallback), resolve relative paths against the task worktree, and default
taskId to the executing task (heartbeat task lane too)
- add a `path` payload source: file read with 50MB cap, extension MIME
inference, PNG/JPEG/GIF/WebP signature + SVG sniff validation, persisted
through managed artifact storage
- executor/heartbeat/planning prompts + engine-tools reference now instruct
agents to register screenshots, wireframes, mockups, and recordings
- new ArtifactsGallery: Images/Docs/PDFs/Videos/Audio/Other category sections
and filter chips, visual tile grid + lightbox, embedded PDF viewer, audio
player rows, download rows; mobile-responsive down to the 768px breakpoint
- doc artifacts open a full viewer rendered as markdown by default with an
in-place edit mode using the shared CodeMirror FileEditor; persisted via new
GET/PATCH /api/artifacts/:id + TaskStore.updateArtifact and live-refreshed
through the new artifact:updated SSE event
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
035caca6c8 |
FN-7775: Add thinking level selection to new chat model picker
Adds a per-session thinking-level selector to the new chat model dropdown, persisting the choice through the chat store and engine session options. - Adds thinkingLevel column to chat_sessions with a db migration - Extends chat-store, chat-types, and chat.ts to read/write thinkingLevel - ChatView model selector now exposes a thinking-level control alongside model choice - useChat and register-chat-routes plumb thinkingLevel through session creation/API - engine/src/index.ts passes thinkingLevel as defaultThinkingLevel session option - Adds a minor changeset and updates settings-reference/dashboard-guide docs - Adds/updates unit tests across core and dashboard packages Files changed: .changeset/fn-7775-chat-thinking-level.md | 7 ++ docs/dashboard-guide.md | 1 + docs/settings-reference.md | 2 +- packages/core/src/__tests__/chat-store.test.ts | 15 +++- packages/core/src/__tests__/db-migrate.test.ts | 33 ++++++++ packages/core/src/chat-store.ts | 12 ++- packages/core/src/chat-types.ts | 6 ++ packages/core/src/db.ts | 14 +++- packages/dashboard/app/api/legacy.ts | 2 +- packages/dashboard/app/components/ChatView.tsx | 16 +++- .../__tests__/ChatView.core-interactions.test.tsx | 75 +++++++++++++++--- .../dashboard/app/hooks/__tests__/useChat.test.ts | 17 +++- packages/dashboard/app/hooks/useChat.ts | 6 +- .../dashboard/src/__tests__/chat-manager.test.ts | 90 ++++++++++++++++++++++ packages/dashboard/src/chat.ts | 23 ++++++ .../dashboard/src/routes/register-chat-routes.ts | 25 +++++- packages/engine/src/index.ts | 1 + 17 files changed, 318 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-7775 Fusion-Task-Lineage: e16c7d3b-361e-4908-87ad-10be17a47c47 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
167067c5b0 |
FN-7767: fix Artifacts tab showing 0 count on default-scope dashboards
Fix useArtifacts fetching/subscribing only when a projectId is present, which left the Artifacts tab stuck at 0 on single-project dashboards where currentProject is unset at mount. - useArtifacts now builds a cache key and fetches/subscribes even without a projectId, scoping the cache under a __default__ key - SSE subscription omits the projectId query param when unset (default/unscoped /api/events) and only filters incoming events by projectId when one is set - Added/updated tests covering the default-scope fetch, cache, and SSE subscription paths - Added a changeset documenting the fix Files changed: .changeset/fn-7767-artifacts-default-scope.md | 7 ++++ .../app/hooks/__tests__/useArtifacts.test.ts | 42 +++++++++++++++++--- packages/dashboard/app/hooks/useArtifacts.ts | 37 ++++++------------ .../__tests__/artifacts-route-integration.test.ts | 45 ++++++++++++++++++++++ 4 files changed, 100 insertions(+), 31 deletions(-) Fusion-Task-Id: FN-7767 Fusion-Task-Lineage: b4ea9b1f-2908-4f5b-bf75-d6fdc45f9340 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
cc901c2b9d |
FN-7762: expand update-notification test coverage across CLI, dashboard, and desktop surfaces
Broadens regression coverage for the npm-release update-check invariant so it holds across every consuming surface, not just the reported repro. - Replace the update-check route/service semver spot-checks with a parametrized case matrix (equal, newer, older, prerelease/build metadata, short/long version segments) to close false-positive/false-negative gaps. - Add dedicated route-level tests asserting the update-check API route surfaces the same invariant. - Add CLI update command tests covering notification rendering across version-comparison cases. - Add desktop native update-check tests covering the same invariant on the desktop shell. - Add dashboard useUpdateCheck hook tests verifying consistent notification behavior for the hook consumers. Files changed: packages/cli/src/commands/__tests__/update.test.ts | 59 ++++++++++++++++++ .../app/hooks/__tests__/useUpdateCheck.test.ts | 25 ++++++++ .../src/__tests__/update-check-route.test.ts | 71 ++++++++++++++++++++++ .../dashboard/src/__tests__/update-check.test.ts | 42 +++++++------ packages/desktop/src/__tests__/native.test.ts | 27 ++++++++ 5 files changed, 206 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-7762 Fusion-Task-Lineage: 6ab34312-fb4e-487a-aefc-2ab133bf79af Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
626e00288c |
FN-7720: add operator review-lane bypass for stranded pre-merge review failures
Add a policy-gated review-lane bypass primitive so operators can unstick cards stranded by a failed pre-merge review step (e.g. the no-feedback review-engine defect), without exposing it to agent-driven lanes.
- Add `store.bypassFailedPreMergeReviewStep(id, { reason, actor })` in @fusion/core plus `getLatestFailedPreMergeReviewStep` in task-merge.ts, and new `bypassedBy`/`bypassedAt`/`bypassReason`/`bypassedFromStatus`/`bypassedFromVerdict` fields on `WorkflowStepResult`
- Add operator-only `fn_task_bypass_review` CLI/pi-extension tool; explicitly withheld from executor/reviewer/triage agent tool lists
- Add `POST /tasks/:id/bypass-review` dashboard API route and wire it through `register-task-workflow-routes.ts` and legacy API compatibility layer
- Add dashboard UI affordance (context menu action + task detail modal + right-dock controller wiring) to trigger the bypass with a reason
- Add i18n strings for the bypass action/labels across en/es/fr/ko/zh-CN/zh-TW locales
- Update `gating-classifications.ts` to recognize the bypassed state
- Add unit tests: `store-bypass-review.test.ts`, `task-merge-bypass.test.ts`, extension test coverage, and `useTasks` hook test coverage
- Update docs (`docs/workflow-steps.md`, `docs/dashboard-guide.md`, AGENTS.md, fusion skill references) to describe the new bypass tool/route
- Add changeset `.changeset/fn-7720-review-lane-bypass-primitive.md` (minor)
Files changed:
$(git diff --cached --stat)
Fusion-Task-Id: FN-7720
Fusion-Task-Lineage: 590b020a-ae02-4b51-8189-df8f54bf3044
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
|
||
|
|
6cff782308 |
FN-7710: refresh model caches so Grok/Cursor CLI models appear without reopening Settings
Adds a shared single-flight cache refresh so newly enabled Grok/Cursor CLI providers show their models in pickers immediately, instead of requiring a Settings reopen. - useModelsCache now exposes a shared refreshModelsCache() that clears the SWR MODELS cache key and notifies subscribers - AuthenticationSection calls refreshModelsCache() after toggling cursor-cli/grok-cli/claude-cli/llama-cpp providers - Server-side cursor/grok model-cache lookups use a short negative-TTL so transient cold-start empty results self-heal instead of sticking - Adds regression tests covering the cache refresh flow, hook behavior, and cursor/grok cache TTL self-healing - Adds changeset (patch) documenting the fix Files changed: .../fn-7710-cli-provider-model-cache-refresh.md | 7 + ...thenticationSection.modelsCacheRefresh.test.tsx | 137 ++++++++++++++++++ .../settings/sections/AuthenticationSection.tsx | 32 +++-- .../app/hooks/__tests__/useModelsCache.test.ts | 159 ++++++++++++++++++++- packages/dashboard/app/hooks/useModelsCache.ts | 72 +++++++++- .../src/__tests__/cursor-model-cache.test.ts | 34 +++++ .../src/__tests__/grok-model-cache.test.ts | 33 +++++ packages/dashboard/src/cursor-model-cache.ts | 23 ++- packages/dashboard/src/grok-model-cache.ts | 23 ++- 9 files changed, 500 insertions(+), 20 deletions(-) Fusion-Task-Id: FN-7710 Fusion-Task-Lineage: ebac46ba-5b3e-41f2-acc4-26f9139c0f71 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
0039480334 |
fix(FUX-039): harden runtime-fallback agent-card viewport gating
Follow-up hardening on the RuntimeFallbackBadge viewport-gating work: - AgentsView.tsx: registerAgentCardRef now returns a cached, stable callback per key (agentCardRefCallbacksRef) instead of a fresh closure each render. A fresh closure reads as unmount+remount to React; in environments without IntersectionObserver the mount path calls setVisibleAgentCardKeys -> re-render -> another fresh closure -> an infinite re-render loop (including jsdom). The cached entry is evicted on true unmount (el === null) so the Map cannot grow unbounded across created/deleted agents. - ActiveAgentsPanel.tsx: document the viewport-gated badge polling with an FNXC comment (behavior unchanged). - useRuntimeFallbackStatus.ts: guard __resetRuntimeFallbackToastDedupeStoreForTests to a no-op outside the test build (import.meta.env.MODE !== "test") so the test-only dedupe reset can never affect production code paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
7cb76669db |
fix: resolve 3 staff-engineer review findings from #1957 (init_error mislabel, unbounded off-screen polling, duplicate toasts) (#1960)
## Summary A Staff Engineer pre-landing review (Greptile/CodeRabbit) on #1957 (merged) flagged four structural issues. This PR fixes the three that were confirmed still present on `main`; the fourth (an unregistered-rule `eslint-disable-next-line react-hooks/exhaustive-deps` comment) was already fixed in #1957's second commit before merge and needed no further change. 1. **`resolvePluginRuntime()` mislabeled "found but failed to init" as `not_found`.** When a `runtimeHint` plugin registration is found but `pluginContext`/`createRuntimeContext(...)` comes back falsy, the resolver returned `reason: "not_found"` — indistinguishable from "never registered" — defeating the point of a distinct `FallbackReason`. Now returns `reason: "init_error"`. Updated the existing test that wrongly asserted `"not_found"` for this path, and added a new test asserting all three reachable `FallbackReason` values (`not_found`, `init_error`, `factory_error`) are pairwise distinct. 2. **`ActiveAgentsPanel.tsx`/`AgentsView.tsx` hardcoded `isInViewport={true}`.** Every agent card (live-agent header, board card, list card) polled the runtime-fallback endpoint every 30s forever, even scrolled off-screen — unlike `TaskCard.tsx`'s correct `IntersectionObserver`-gated pattern. Both files now thread a real `IntersectionObserver`-backed viewport signal into `RuntimeFallbackBadge`. Added regression tests proving polling stops once a badge instance's `isInViewport` transitions to `false` and resumes once it goes back to `true` (desktop + a mobile-breakpoint variant), plus verified via `tsc --noEmit` for `@fusion/dashboard`. 3. **Toast dedupe was per-hook-instance, not shared.** `useRuntimeFallbackStatus`'s `lastToastedEventIdRef` was a local `useRef`, so the same task rendered simultaneously in two card surfaces (e.g. `ActiveAgentsPanel` + `AgentsView`) fired two separate toasts for one fallback event. Dedupe now lives in module-level shared state (a bounded `Map` keyed by `taskId:eventId`, FIFO-evicted past 500 entries) so a fallback event toasts exactly once across every simultaneously-mounted badge instance for the same task. Added a cross-instance regression test mounting two badges for the same `taskId`/`eventId` and asserting exactly one toast fires. ## Test evidence - `pnpm --filter @fusion/engine exec vitest run src/__tests__/runtime-resolution.test.ts --reporter=dot` — 25/25 pass - `pnpm --filter @fusion/dashboard exec vitest run app/components/__tests__/RuntimeFallbackBadge.test.tsx --reporter=dot` — 11/11 pass - `pnpm --filter @fusion/dashboard run typecheck` — clean - `pnpm --filter @fusion/engine run typecheck` — clean ## Scope Isolated 6-file diff on top of current `main` (`packages/engine/src/runtime-resolution.ts`, `packages/engine/src/__tests__/runtime-resolution.test.ts`, `packages/dashboard/app/hooks/useRuntimeFallbackStatus.ts`, `packages/dashboard/app/components/ActiveAgentsPanel.tsx`, `packages/dashboard/app/components/AgentsView.tsx`, `packages/dashboard/app/components/__tests__/RuntimeFallbackBadge.test.tsx`). No behavior outside the three findings above was touched. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - The desktop dashboard now supports plugin-backed runtime features, improving how plugin-enabled workflows are loaded and run. - Agent cards now pause background fallback polling when they’re off-screen, helping the dashboard feel smoother and more responsive. - **Bug Fixes** - Improved runtime fallback handling so missing runtimes and initialization failures are reported more accurately. - Toast notifications are now better deduplicated, reducing repeated alerts when multiple views show the same fallback state. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a832b7979f |
FN-7686: skip redundant session-list round trip on fresh terminal load
Speed up initial terminal load by short-circuiting the no-op server session list call when there are no persisted local tabs to validate. - useTerminalSessions: when readTabsFromStorage returns zero tabs, skip the listTerminalSessions HTTP call entirely and mark bootstrap ready immediately, unblocking auto-create/WebSocket connect instead of serializing behind a provably-discarded round trip - Reload-with-persisted-tabs path is unchanged and still awaits the list call since its result is decision-relevant there - Add regression tests covering the fresh-load fast path and the persisted-tabs path - Add changeset (patch) and a docs/solutions write-up of the bootstrap-list-serialized-before-auto-create issue Files changed: .changeset/fn-7686-slow-terminal-initial-load.md | 7 ++ ...bootstrap-list-serialized-before-auto-create.md | 87 ++++++++++++++++++++++ .../hooks/__tests__/useTerminalSessions.test.ts | 73 ++++++++++++++++++ .../dashboard/app/hooks/useTerminalSessions.ts | 23 +++++- 4 files changed, 189 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7686 Fusion-Task-Lineage: 9c708329-6362-4c2e-967f-aea12849c47c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
fd541bbc04 |
FN-7687: pin mobile header to nowrap so fold/unfold refold cannot wrap it
Fixes the mobile top header wrapping onto a second line after a foldable phone is unfolded then refolded (a live resize, not a reload). - .header now explicitly sets flex-wrap: nowrap instead of relying on the flex default - .header-left gets flex: 1 1 auto; min-width: 0 promoted from the mobile-only media query to the base rule, so it shrinks/truncates during the resize before the width media query re-settles - .header-actions gets flex: 0 0 auto; min-width: 0 so the action icon cluster stays at intrinsic size and is never squeezed off-row - Added Header.test.tsx coverage asserting the nowrap/shrink contract across populated and empty header states, on mobile/tablet/desktop - Added useViewportMode.test.ts regression reproducing a fold->unfold->refold visualViewport resize cycle, confirming mode resolves back to mobile - Added changeset for @runfusion/fusion (patch/fix) Files changed: .changeset/fn-7687-mobile-header-single-line-refold.md | 7 ++ packages/dashboard/app/components/Header.css | 14 ++++ packages/dashboard/app/components/__tests__/Header.test.tsx | 78 ++++++++++++++++++++++ packages/dashboard/app/hooks/__tests__/useViewportMode.test.ts | 59 ++++++++++++++++ 4 files changed, 158 insertions(+) Fusion-Task-Id: FN-7687 Fusion-Task-Lineage: 2b88a26e-d380-458c-b602-b6496e39311d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
2479081415 |
test(FUX-039): add cross-instance toast dedupe regression test
Co-authored-by: Fusion <noreply@runfusion.ai> |
||
|
|
be94f630ea |
Surface runtime-resolution fallback in dashboard; thread real FallbackReason (#1957)
Closes/relates to Runfusion/Fusion#1956. ## Summary Surfaces silent runtime-resolution fallback in the dashboard, and threads the real `FallbackReason` ("not_found" vs "factory_error") through instead of hardcoding `"not_found"` for every fallback. ## Changes - `packages/engine/src/runtime-resolution.ts`: `resolvePluginRuntime()` now returns a tagged miss result (`{ ok: false, reason }`) distinguishing "not found" from "factory/instantiation error" instead of collapsing both to `null`. `resolveRuntime()` threads the real reason through to `logRuntimeFallback(...)` and returns it via `ResolvedRuntime.fallbackReason`. - `packages/engine/src/agent-session-helpers.ts`: `createResolvedAgentSession()` includes `fallbackReason` in the `session:runtime-resolved` audit event metadata when present. - `packages/dashboard/src/routes/register-task-workflow-routes.ts`: new `GET /api/tasks/:id/runtime-fallback` endpoint, returning the most recent `session:runtime-resolved` event normalized for UI consumption (`wasConfigured`, `runtimeHint`, `reason`, `showFallbackBadge`). - `packages/dashboard/app/hooks/useRuntimeFallbackStatus.ts` (new): polls the endpoint, dedupes toast firing per audit-event-id. - `packages/dashboard/app/components/RuntimeFallbackBadge.tsx` (new): renders the badge + fires the toast; wired into `TaskCard.tsx`, `ActiveAgentsPanel.tsx`, and `AgentsView.tsx` (board and list variants). ## Test plan - `pnpm --filter @fusion/engine exec vitest run src/__tests__/runtime-resolution.test.ts` — 24/24 pass (21 pre-existing + 3 new, none weakened) - `pnpm --filter @fusion/dashboard exec vitest run src/routes/__tests__/register-task-workflow-routes.runtime-fallback.test.ts` — 5/5 pass (empty/configured-ok/fallback-with-hint/fallback-blank-hint/stale-superseded states) - `pnpm --filter @fusion/dashboard exec vitest run app/components/__tests__/RuntimeFallbackBadge.test.tsx` — 8/8 pass (all data states + mobile breakpoint + toast-fires-once) - `pnpm --filter @fusion/dashboard run typecheck` and `pnpm --filter @fusion/engine run typecheck` — both clean <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added runtime-fallback warning badges across task and agent views (including board and “working on” sections) with automatic toast notifications. * Introduced a new backend API to surface the latest runtime-fallback state for a task. * Added runtime-fallback status polling and UI messaging to reflect the most recent state. * **Bug Fixes** * Prevented repeated toasts by deduplicating notifications across polling updates. * Improved fallback reporting so the UI reflects the latest runtime-resolved audit event. * Enhanced diagnostics by distinguishing fallback reasons (e.g., missing runtime vs factory failure) for clearer user guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
03161adfb9 |
FN-7659: paginate and sort the Archived column newest-first
Adds server-side pagination for the Archived task column, sorted by most-recently-archived first, with a Show more control on the dashboard.
- Add ArchiveDatabase.listPage and TaskStore.listArchivedTasks for a bounded SQL LIMIT/OFFSET read ordered by archivedAt DESC
- Add GET /tasks/archived route for paged archive fetches, leaving the legacy merged listTasks({includeArchived}) path unchanged
- Wire useTasks.loadArchivedTasks to fetch page 1 on first Archived-column expand and loadMoreArchivedTasks for subsequent pages
- Add a "Show more" affordance in Column.tsx/Board.tsx/MainContent.tsx to trigger loading additional archived pages
- Extend taskSorting.ts to keep archived task ordering stable with the new paged data
- Add core and dashboard tests covering archive pagination and store/route behavior
- Add changeset for @runfusion/fusion (minor) and update docs/storage.md and docs/dashboard-guide.md
Files changed:
.changeset/FN-7659-archived-pagination.md | 7 +
docs/dashboard-guide.md | 4 +-
docs/storage.md | 7 +
packages/core/src/__tests__/archive-db-pagination.test.ts | 94 ++++++++
packages/core/src/__tests__/store-archive-search.test.ts | 63 ++++++
packages/core/src/archive-db.ts | 18 ++
packages/core/src/store.ts | 32 +++
packages/dashboard/app/App.tsx | 5 +-
packages/dashboard/app/api/legacy.ts | 19 ++
packages/dashboard/app/components/Board.tsx | 19 +-
packages/dashboard/app/components/Column.tsx | 48 ++++-
packages/dashboard/app/components/__tests__/Column.test.tsx | 41 ++++
packages/dashboard/app/components/__tests__/taskSorting.test.ts | 27 +++
packages/dashboard/app/components/dashboard/MainContent.tsx | 9 +
packages/dashboard/app/components/dashboard/types.ts | 6 +
packages/dashboard/app/components/taskSorting.ts | 16 ++
packages/dashboard/app/hooks/__tests__/useTasks.test.ts | 236 ++++++++++++++++++++-
packages/dashboard/app/hooks/useTasks.ts | 173 ++++++++++++++-
packages/dashboard/app/test/mockApi.ts | 3 +
packages/dashboard/src/routes/__tests__/tasks-archived-pagination.test.ts | 94 ++++++++
packages/dashboard/src/routes/register-task-workflow-routes.ts | 32 +++
21 files changed, 930 insertions(+), 23 deletions(-)
Fusion-Task-Id: FN-7659
Fusion-Task-Lineage: 7a5a1f62-277c-4f29-883c-62e75b269bc5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
|
||
|
|
511bcaf56d |
FN-7657: persist GitHub issue import modal state across close/reopen
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> |
||
|
|
0bed997af8 |
feat: surface runtime-resolution fallback in dashboard, thread real FallbackReason
Fixes silent runtime fallback visibility (dashboard never read wasConfigured or session:runtime-resolved) and threads the real FallbackReason (not_found vs factory_error) through resolveRuntime()/logRuntimeFallback instead of hardcoding "not_found" for every fallback. - packages/engine/src/runtime-resolution.ts: resolvePluginRuntime() now returns a tagged miss result distinguishing not_found from factory_error; resolveRuntime() threads the real reason through and returns it as ResolvedRuntime.fallbackReason - packages/engine/src/agent-session-helpers.ts: includes fallbackReason in the session:runtime-resolved audit event metadata - packages/dashboard/src/routes/register-task-workflow-routes.ts: new GET /api/tasks/:id/runtime-fallback endpoint - packages/dashboard/app/hooks/useRuntimeFallbackStatus.ts + packages/dashboard/app/components/RuntimeFallbackBadge.tsx: new polling hook + badge/toast component wired into TaskCard, ActiveAgentsPanel, and AgentsView Ref: Fusion task FUX-022, investigations/FUX-017-hermes-runtime-fallback.md recommendation #1 |
||
|
|
e29fea38e0 |
FN-7656: restore chat working indicator when reattaching to an active generation
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>
|
||
|
|
efabdd6f04 |
FN-7651: remove chat "Search in title only" toggle
Simplifies chat search UX by always matching both title and message content, removing the now-unneeded title-only toggle button and state. - Removed the "Search in title only" toggle button and its CSS from ChatView - Dropped searchInTitleOnly/setSearchInTitleOnly state and logic from useChat; content-search query params are now always-on - Updated ChatView tests to drop title-only toggle interactions and assertions - Removed the title-only-search i18n string across all locales - Updated dashboard-guide.md docs to reflect the simplified search behavior - Added a patch changeset documenting the removal Files changed: .../fn-7651-remove-chat-title-only-toggle.md | 7 +++ docs/dashboard-guide.md | 4 +- packages/dashboard/app/components/ChatView.css | 18 -------- packages/dashboard/app/components/ChatView.tsx | 26 +++-------- .../__tests__/ChatView.autosize.test.tsx | 2 - .../__tests__/ChatView.content-search.test.tsx | 51 ++++++---------------- .../components/__tests__/ChatView.draft.test.tsx | 2 - .../__tests__/ChatView.hash-mention.test.tsx | 2 - .../__tests__/ChatView.mobile-render.test.tsx | 2 - .../components/__tests__/ChatView.rooms.test.tsx | 2 - .../__tests__/ChatView.scroll-to-top.test.tsx | 2 - .../components/__tests__/ChatView.test-harness.tsx | 2 - packages/dashboard/app/hooks/useChat.ts | 39 ++++++++--------- packages/i18n/locales/en/app.json | 1 - packages/i18n/locales/es/app.json | 1 - packages/i18n/locales/zh-CN/app.json | 1 - packages/i18n/locales/zh-TW/app.json | 1 - packages/i18n/locales/ko/app.json | 1 - packages/i18n/locales/fr/app.json | 1 - 19 files changed, 47 insertions(+), 118 deletions(-) Fusion-Task-Id: FN-7651 Fusion-Task-Lineage: 5a31825c-8e6e-441f-800d-6053f5f844ba Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ce4f173d8f |
FN-7649: resolve settings landing view to board on project switch
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> |
||
|
|
6777eea5d2 |
FN-7631: add content search to Chat sidebar with title-only toggle
Chat sidebar search now matches message content by default, not just the conversation title/agent, with an opt-out toggle to restore title-only filtering. - Add ChatStore.searchSessionsByMessageContent (parameterized LIKE ... ESCAPE) for server-side content search across sessions - GET /chat/sessions route (register-chat-routes.ts, legacy.ts) gains q/titleOnly query params, debounced server-side content lookup merged with local title/agent matches - useChat hook exposes searchInTitleOnly state and wires debounced content search into session list results - ChatView renders a "Search in title only" toggle beside the search box (desktop + mobile) and shows a "Matched: ..." preview snippet on content-matched rows - Task-planner sessions remain excluded from content matches via the same common-feed visibility guard used for the normal session list - Add unit/integration tests: chat-store content-search, chat-routes API test, ChatView content-search test - Update docs/dashboard-guide.md to document the new content search behavior and toggle - Add changeset fn-7631-chat-content-search.md (@runfusion/fusion minor) Files changed: .changeset/fn-7631-chat-content-search.md | 7 + docs/dashboard-guide.md | 2 + .../__tests__/chat-store.content-search.test.ts | 157 +++++++++++++++++++++ packages/core/src/chat-store.ts | 64 +++++++++ packages/core/src/chat-types.ts | 8 ++ packages/dashboard/app/api/legacy.ts | 23 ++- packages/dashboard/app/components/ChatView.css | 30 ++++ packages/dashboard/app/components/ChatView.tsx | 26 ++++ .../__tests__/ChatView.autosize.test.tsx | 2 + .../__tests__/ChatView.content-search.test.tsx | 114 +++++++++++++++ .../components/__tests__/ChatView.draft.test.tsx | 2 + .../__tests__/ChatView.hash-mention.test.tsx | 2 + .../__tests__/ChatView.mobile-render.test.tsx | 2 + .../components/__tests__/ChatView.rooms.test.tsx | 2 + .../__tests__/ChatView.scroll-to-top.test.tsx | 2 + .../components/__tests__/ChatView.test-harness.tsx | 2 + packages/dashboard/app/hooks/useChat.ts | 105 ++++++++++++-- .../dashboard/src/__tests__/chat-routes.test.ts | 78 ++++++++++ .../dashboard/src/routes/register-chat-routes.ts | 39 ++++- packages/i18n/locales/en/app.json | 2 + packages/i18n/locales/es/app.json | 2 + packages/i18n/locales/fr/app.json | 2 + packages/i18n/locales/ko/app.json | 2 + packages/i18n/locales/zh-CN/app.json | 2 + packages/i18n/locales/zh-TW/app.json | 2 + 25 files changed, 667 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7631 Fusion-Task-Lineage: bc68b489-26a7-453e-901b-bda816af364e Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
42009cfdb9 |
FN-7628: allow editing sent chat messages and rewinding agent responses
Adds the ability to edit a previously sent message in an agent chat, which rewinds the session/task room and regenerates the response from the edited message. - Add chat-store support for locating/replacing a message and truncating subsequent history for a rewind - Add a chat-manager rewind-session flow and a new register-chat-routes endpoint to rewind a room to an edited message - Add legacy API route wiring and useChat hook support for issuing an edit request - Add ChatView/StandardChatSurface/TaskPlannerChatTab UI affordances (edit control, styling) to trigger message edits - Add a changeset documenting the new chat message-edit capability - Add unit/integration tests covering chat-store rewind logic, chat-manager rewind-session behavior, chat routes, useChat, and ChatView edit UI Files changed: .changeset/fn-7628-chat-message-edit.md | 7 + docs/dashboard-guide.md | 4 + packages/core/src/__tests__/chat-store.test.ts | 171 ++++++++++++++ packages/core/src/chat-store.ts | 95 ++++++++ packages/dashboard/app/api/legacy.ts | 22 ++ packages/dashboard/app/components/ChatView.css | 78 ++++++ packages/dashboard/app/components/ChatView.tsx | 14 ++ .../app/components/StandardChatSurface.tsx | 87 ++++++- .../app/components/TaskPlannerChatTab.tsx | 8 + .../__tests__/ChatView.autosize.test.tsx | 1 + .../__tests__/ChatView.default-model-icon.test.tsx | 1 + .../components/__tests__/ChatView.draft.test.tsx | 1 + .../__tests__/ChatView.hash-mention.test.tsx | 1 + .../__tests__/ChatView.message-edit.test.tsx | 262 +++++++++++++++++++++ .../__tests__/ChatView.mobile-render.test.tsx | 1 + .../components/__tests__/ChatView.rooms.test.tsx | 1 + .../__tests__/ChatView.scroll-to-top.test.tsx | 1 + .../components/__tests__/ChatView.test-harness.tsx | 1 + .../dashboard/app/hooks/__tests__/useChat.test.ts | 98 ++++++++ packages/dashboard/app/hooks/useChat.ts | 60 +++++ .../__tests__/chat-manager-rewind-session.test.ts | 185 +++++++++++++++ .../dashboard/src/__tests__/chat-manager.test.ts | 12 + .../dashboard/src/__tests__/chat-routes.test.ts | 124 ++++++++++ packages/dashboard/src/chat.ts | 147 +++++++++++- .../dashboard/src/routes/register-chat-routes.ts | 52 ++++ 25 files changed, 1429 insertions(+), 5 deletions(-) Fusion-Task-Id: FN-7628 Fusion-Task-Lineage: 36d98989-1b75-428c-baf1-b2c7e8e78013 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8b4e5224ea |
fix(FN-7591): stop intake-column cards vanishing from the workflow board
Tasks added to a workflow whose intake column differs from the default (e.g. Coding (Ideas) -> "ideas") disappeared from the board until a manual reload. The board resolves a card's lane from the board-workflows taskWorkflowIds map, which only refetches on mount/focus/workflow-CRUD SSE -- never on task creation. A freshly created card was absent from that map, fell back to the default workflow (no "ideas" column), and was dropped from every lane. - Board.tsx: force one board-workflows refetch (deferred a tick, signature-guarded) whenever a rendered task is missing from taskWorkflowIds, so its real workflow + intake column resolve for any create surface. - Board.tsx: re-home a selected-workflow task whose column the workflow no longer declares into the intake lane instead of a phantom bucket. - useBoardWorkflows.ts: widen refreshBoardWorkflows type to accept forceFresh. - Add regression tests for tasks arriving via the tasks prop (SSE / non-board create surfaces) and the orphan-column safety net. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cf3fe8b485 |
FN-7591: make dashboard create surfaces resolve intake column from workflow instead of hard-coding triage
Fixes dashboard task creation so new cards land in the selected/default workflow's intake column instead of always forcing legacy triage, letting workflows like Coding (Ideas) park new cards in 'ideas' until an operator promotes them. - InlineCreateCard, QuickEntryBox, and NewTaskModal no longer hard-code column:"triage"; InlineCreateCard now forwards workflowId at create time instead of applying it post-create. - Fixed a glue-layer regression in useTaskHandlers.ts (handleBoardQuickCreate/handleModalCreate) that re-forced column:"triage" even after UI surfaces stopped sending it. - Added/updated tests covering the store's intake-column resolution and the dashboard create surfaces/hooks. - Documented the new manual-intake-column parking behavior in dashboard-guide.md and workflow-steps.md. - Added a patch changeset for @runfusion/fusion. Files changed: .changeset/fn-7591-coding-ideas-intake.md | 7 +++ docs/dashboard-guide.md | 4 ++ docs/workflow-steps.md | 1 + packages/core/src/__tests__/store-create-intake-column.test.ts | 20 ++++++++ packages/dashboard/app/App.tsx | 5 +- packages/dashboard/app/components/InlineCreateCard.tsx | 28 ++++------ packages/dashboard/app/components/NewTaskModal.tsx | 5 +- packages/dashboard/app/components/QuickEntryBox.tsx | 5 +- packages/dashboard/app/components/TodoView.tsx | 7 ++- packages/dashboard/app/components/__tests__/InlineCreateCard.test.tsx | 59 +++++++++++++++++++++- packages/dashboard/app/components/__tests__/QuickEntryBox.test.tsx | 14 +++-- packages/dashboard/app/components/__tests__/TodoView.test.tsx | 10 ++-- packages/dashboard/app/components/__tests__/board-quickcreate-workflow-lane-visibility.test.tsx | 45 ++++++++++++++++- packages/dashboard/app/hooks/__tests__/useTaskHandlers.test.ts | 27 ++++++++-- packages/dashboard/app/hooks/useTaskHandlers.ts | 8 ++- 15 files changed, 207 insertions(+), 38 deletions(-) Fusion-Task-Id: FN-7591 Fusion-Task-Lineage: 510f0e6a-89e7-468f-a6df-ad6aebd5c33a Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e7cb2f1fed |
FN-7525: add Revert/Undo affordance to Done and Archived task cards
Adds a Revert action so operators can undo landed changes for Done/Archived tasks directly from the board. - Adds onRevertTask wiring through Board, Column, Lane, ListView, TaskDetailModal, and WorktreeGroup surfaces - Adds a Revert affordance to TaskCard (Done/Archived states) with confirm UX and CSS - Adds POST /tasks/:id/revert legacy API route supporting "auto" mode with an AI-undo fallback (mode: "ai") on conflict - Wires useTasks hook and dashboard MainContent/types to support the new revert action - Adds new i18n strings for the revert affordance - Adds a minor changeset for @runfusion/fusion documenting the feature - Adds/updates tests: TaskCard.test.tsx, board-mobile.test.tsx, api-git.test.ts - Updates docs/dashboard-guide.md and docs/task-management.md Files changed: .changeset/fn-7525-revert-card-affordance.md | 7 + docs/dashboard-guide.md | 2 +- docs/task-management.md | 10 ++ packages/dashboard/app/App.tsx | 7 +- packages/dashboard/app/__tests__/api-git.test.ts | 51 +++++++ packages/dashboard/app/api/legacy.ts | 51 +++++++ packages/dashboard/app/components/AppModals.tsx | 5 +- packages/dashboard/app/components/Board.tsx | 10 +- packages/dashboard/app/components/Column.tsx | 8 +- packages/dashboard/app/components/Lane.tsx | 5 +- packages/dashboard/app/components/ListView.tsx | 80 ++++++++++- packages/dashboard/app/components/TaskCard.css | 24 +++- packages/dashboard/app/components/TaskCard.tsx | 127 ++++++++++++++++- packages/dashboard/app/components/TaskDetailModal.tsx | 85 ++++++++++++ packages/dashboard/app/components/WorktreeGroup.tsx | 6 + packages/dashboard/app/components/__tests__/TaskCard.test.tsx | 151 +++++++++++++++++++++ packages/dashboard/app/components/__tests__/board-mobile.test.tsx | 63 +++++++++ packages/dashboard/app/components/dashboard/MainContent.tsx | 4 + packages/dashboard/app/components/dashboard/types.ts | 8 ++ packages/dashboard/app/components/useRightDockController.tsx | 4 + packages/dashboard/app/hooks/useTasks.ts | 21 ++- packages/i18n/locales/en/app.json | 11 ++ 22 files changed, 718 insertions(+), 22 deletions(-) Fusion-Task-Id: FN-7525 Fusion-Task-Lineage: b9e2ca94-4ec6-4443-8e41-cf4828018856 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
3dd227b945 |
FN-7557: default plan approval mode to auto-approve-all
Changes the project-wide plan approval default from deferring to per-workflow settings to auto-approving all task plans, so new/unset projects skip the manual awaiting-approval gate by default. - Change DEFAULT_PROJECT_SETTINGS.planApprovalMode default from "workflow" to "auto-approve-all" in settings-schema.ts, with FNXC comments documenting the requirement change - Update ProjectSettings.planApprovalMode JSDoc in types.ts to reflect the new default - Update useAppSettings hook's initial state and hydration fallback to default to "auto-approve-all" while still honoring an explicit stored "workflow" value - Update MergeSection UI: move the "(default)" label from the "Use workflow setting" option to "Auto-approve all tasks", keeping the select's fallback value in sync - Update settings-reference.md docs and i18n locale/resource strings to match the new default label - Update existing tests (MergeSection legacy auto-merge cleanup, settings default descriptions, useAppSettings) to assert the new default, and add coverage for the updated hydration/fallback behavior - Add changeset fn-7557-plan-auto-approve-default.md documenting the behavior change Files changed: .changeset/fn-7557-plan-auto-approve-default.md | 7 +++++ docs/settings-reference.md | 2 +- packages/core/src/settings-schema.ts | 6 +++- packages/core/src/types.ts | 3 ++ .../dashboard/app/components/SettingsModal.tsx | 3 +- .../components/settings/sections/MergeSection.tsx | 9 ++++-- .../MergeSection.legacy-automerge-cleanup.test.tsx | 4 +-- .../settings-default-descriptions.test.tsx | 3 +- .../app/hooks/__tests__/useAppSettings.test.ts | 35 +++++++++++++++++++--- packages/dashboard/app/hooks/useAppSettings.ts | 12 ++++++-- packages/i18n/locales/en/app.json | 4 +-- packages/i18n/src/resources.d.ts | 2 +- 12 files changed, 71 insertions(+), 19 deletions(-) Fusion-Task-Id: FN-7557 Fusion-Task-Lineage: 7dcfe339-6088-4ebc-8387-eb81258a693d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f992e6aefa |
FN-7553: add dedicated keyboard shortcuts settings section
Adds a standalone Keyboard Shortcuts settings section with an easier-to-use capture input and support for more shortcut actions. - Introduce a new KeyboardShortcutsSection with a dedicated ShortcutCaptureInput component for recording key combos - Split keyboard-shortcut settings out of the general settings section into their own settings tab - Extend the shortcut schema/types and useDashboardKeyboardShortcuts hook to support additional actions - Update settings save-split, section-keys, and defaults/parity tests to cover the new section - Update dashboard docs and add a changeset for the new settings section Files changed: .changeset/fn-7553-keyboard-shortcuts-section.md | 7 + docs/dashboard-guide.md | 22 ++- packages/core/src/__tests__/global-settings.test.ts | 9 +- packages/core/src/__tests__/settings-defaults.test.ts | 4 + packages/core/src/__tests__/settings-parity.test.ts | 2 +- packages/core/src/settings-schema.ts | 6 +- packages/core/src/types.ts | 12 ++ packages/dashboard/app/App.tsx | 26 +++- packages/dashboard/app/__tests__/App.keyboard-shortcuts.test.tsx | 47 ++++++- packages/dashboard/app/components/SettingsModal.css | 56 ++++++-- packages/dashboard/app/components/SettingsModal.tsx | 30 +++- packages/dashboard/app/components/__tests__/SettingsModal.general.test.tsx | 63 --------- packages/dashboard/app/components/__tests__/SettingsModal.keyboardShortcuts.test.tsx | 156 +++++++++++++++++++++ packages/dashboard/app/components/settings/__tests__/section-keys.test.ts | 1 + packages/dashboard/app/components/settings/save-split.ts | 6 +- packages/dashboard/app/components/settings/sections/GlobalGeneralSection.tsx | 38 ----- packages/dashboard/app/components/settings/sections/KeyboardShortcutsSection.tsx | 78 +++++++++++ packages/dashboard/app/components/settings/sections/ShortcutCaptureInput.tsx | 118 ++++++++++++++++ packages/dashboard/app/components/settings/sections/__tests__/KeyboardShortcutsSection.test.tsx | 113 +++++++++++++++ packages/dashboard/app/hooks/__tests__/useDashboardKeyboardShortcuts.test.tsx | 73 +++++++++- packages/dashboard/app/hooks/useDashboardKeyboardShortcuts.ts | 38 ++++- packages/dashboard/app/utils/__tests__/keyboardShortcuts.test.ts | 37 ++++- packages/dashboard/app/utils/keyboardShortcuts.ts | 54 ++++++- 23 files changed, 854 insertions(+), 142 deletions(-) Fusion-Task-Id: FN-7553 Fusion-Task-Lineage: 51c1ad69-fbd3-45ce-8d2d-45d9962d7b76 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
2f23d2260d |
FN-7494: add configurable dashboard shortcuts
Add configurable dashboard keyboard shortcuts for opening Quick Chat and Terminal. - Add global settings defaults, schemas, persistence, and Settings UI controls for dashboard shortcuts. - Register safe document-level shortcut handling with editable-target guards and Escape popup dismissal. - Normalize shortcut strings, detect disabled/conflicting bindings, and document operator behavior. - Cover shortcut parsing, dashboard listener behavior, and settings persistence with tests. Files changed: .changeset/fn-7494-keyboard-shortcuts.md | 7 + docs/dashboard-guide.md | 14 ++ .../core/src/__tests__/global-settings.test.ts | 20 +++ .../core/src/__tests__/settings-defaults.test.ts | 10 ++ .../core/src/__tests__/settings-parity.test.ts | 10 ++ packages/core/src/__tests__/store-settings.test.ts | 10 ++ packages/core/src/settings-schema.ts | 8 + packages/core/src/types.ts | 12 ++ packages/dashboard/app/App.tsx | 52 ++++++ .../dashboard/app/components/SettingsModal.css | 21 +++ .../dashboard/app/components/SettingsModal.tsx | 11 ++ .../__tests__/SettingsModal.general.test.tsx | 63 ++++++++ .../app/components/settings/save-split.ts | 1 + .../settings/sections/GlobalGeneralSection.tsx | 38 +++++ .../useDashboardKeyboardShortcuts.test.tsx | 101 ++++++++++++ packages/dashboard/app/hooks/useAppSettings.ts | 8 +- .../app/hooks/useDashboardKeyboardShortcuts.ts | 66 ++++++++ .../app/utils/__tests__/keyboardShortcuts.test.ts | 76 +++++++++ packages/dashboard/app/utils/keyboardShortcuts.ts | 175 +++++++++++++++++++++ 19 files changed, 702 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7494 Fusion-Task-Lineage: 30445f4d-c0c5-4657-bd79-fc2acaf3c37d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
61c8bdc117 |
FN-7497: keep accepted chat streams waiting
Keep accepted-but-silent chat streams waiting so late responses can reconcile without false timeout failures. - Stop aborting accepted chat streams when the first SSE event timer fires without content. - Cover desktop, mobile, planner chat, reattach, hook, and SSE parser paths for late accepted responses. - Add a patch changeset for the chat first-event timeout fix. Files changed: .changeset/fn-7497-chat-first-event-timeout.md | 7 +++ .../app/api/__tests__/legacy-chat-stream.test.ts | 27 ++++++-- packages/dashboard/app/api/legacy.ts | 8 ++- .../__tests__/ChatView.core-interactions.test.tsx | 41 +++++++++++++ .../__tests__/TaskPlannerChatTab.test.tsx | 71 ++++++++++++++++++++++ .../dashboard/app/hooks/__tests__/useChat.test.ts | 41 +++++++++++++ 6 files changed, 188 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-7497 Fusion-Task-Lineage: bb53793d-dc78-4a25-af22-ed1c62b73094 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6b19e36ca1 |
Address PR review feedback (#1889)
- probeWorktrunk: also refuse a bare wt/wt.exe override on Windows (resolves to Windows Terminal via PATH), and tighten the package-dir match from a broad 'windowsterminal' substring to 'microsoft.windowsterminal' so a genuine worktrunk under an unrelated *windowsterminal* folder is still probed. - Fix worktrunk enable deadlock/save-race: probe status when the user views the Worktrees section (not gated on 'enabled', which deadlocked since the toggle is disabled until status==installed), and re-verify on Save so a fast enable+save can't silently persist enabled:false. Hook 'refresh' now returns the fetched status and is exposed. - Tests: bare-wt refusal, forward-slash Windows Terminal path, unrelated windowsterminal-folder is probed, and a rerender enabled false->true probe-once transition; update SettingsModal mocks for the new refresh(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
89123997b9 |
fix(desktop): stop Windows Terminal popup — real cause is worktrunk 'wt' name collision
The 1882/1883 terminal-auto-create guard fixed the wrong subsystem; the embedded terminal was already guarded. The actual trigger: worktrunk's CLI is named 'wt', colliding with Windows Terminal (wt.exe) on PATH, so probing it with 'wt --version' launched Windows Terminal and popped its native version dialog — fired automatically by the Settings worktrunk-status fetch on mount. - useWorktrunkInstallStatus: only auto-fetch /api/worktrunk/status when the integration is enabled (user opt-in), never on a plain Settings/dashboard mount. - probeWorktrunk: refuse to exec a resolved 'wt' that is the Windows Terminal alias (WindowsApps / WindowsTerminal package dir), covering every resolution surface (cached/override/PATH/install/settings-route). Basename computed host-independently so the guard holds when the build host is POSIX. - Tests for both guards; report updated with corrected root cause + Symptom Verification + Surface Enumeration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b4b1f6d7ae |
FN-7476: fix desktop engine availability banner
Treat desktop embedded engine managers as automation-capable during startup so the dashboard avoids false remediation. - Report process-level engine availability when a modern manager can lazily start or is starting project engines.\n- Keep project-scoped status details on /api/engine/status while hiding the dashboard-only unavailable banner in desktop mode.\n- Add dashboard health polling, banner, server health, and changeset coverage for the desktop false-banner regression.\n\nFiles changed:\n .changeset/fn-7476-desktop-engine-banner.md | 7 +++++++\n .../dashboard/__tests__/DashboardBanners.test.tsx | 18 ++++++++++++++++\n .../app/hooks/__tests__/useDashboardHealth.test.ts | 24 +++++++++++++++++++++-\n packages/dashboard/src/__tests__/server.test.ts | 24 ++++++++++++++++++----\n packages/dashboard/src/server.ts | 9 +++++---\n 5 files changed, 74 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-7476 Fusion-Task-Lineage: d54a9872-252b-44c5-9c6d-6168b65118c7 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
50786f29d4 |
FN-7475: delay GitHub setup warnings
Delay dashboard GitHub setup warnings until the project grace period expires while keeping AI setup warnings immediate. - Add per-project GitHub warning delay state and persistence. - Route dashboard GitHub warnings to Settings → Authentication with a Connect GitHub action. - Hide non-actionable GitHub-only warnings in the New Task modal and update localized copy, docs, and tests. Files changed: .changeset/fn-7475-github-setup-warning.md | 7 ++ docs/dashboard-guide.md | 6 + packages/dashboard/app/App.tsx | 11 +- packages/dashboard/app/components/NewTaskModal.tsx | 8 +- .../app/components/SetupWarningBanner.css | 10 ++ .../app/components/SetupWarningBanner.tsx | 18 ++- .../app/components/__tests__/NewTaskModal.test.tsx | 46 ++++++- .../__tests__/SetupWarningBanner.test.tsx | 40 ++++++ .../app/components/dashboard/DashboardBanners.tsx | 3 + .../dashboard/__tests__/DashboardBanners.test.tsx | 125 ++++++++++++++++++- .../dashboard/app/components/dashboard/types.ts | 1 + .../__tests__/useGithubSetupWarningDelay.test.ts | 134 +++++++++++++++++++++ .../app/hooks/useGithubSetupWarningDelay.ts | 96 +++++++++++++++ packages/dashboard/app/utils/projectStorage.ts | 1 + packages/i18n/locales/en/app.json | 5 +- packages/i18n/locales/es/app.json | 5 +- packages/i18n/locales/fr/app.json | 5 +- packages/i18n/locales/ko/app.json | 5 +- packages/i18n/locales/zh-CN/app.json | 5 +- packages/i18n/locales/zh-TW/app.json | 5 +- packages/i18n/src/resources.d.ts | 127 +++++++++++++------ 21 files changed, 606 insertions(+), 57 deletions(-) Fusion-Task-Id: FN-7475 Fusion-Task-Lineage: 5bf1fffa-b58c-42a1-b170-367a4c20eaaf Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6d7715fe9e | Merge branch 'main' into desktop-release-issues-report |