Commit Graph

10590 Commits

Author SHA1 Message Date
gsxdsm
75cbc059c2 FN-7464: speed up insights route retry tests
Collapse deliberate retry waits in the insights route test suite while preserving retry coverage.

- Mock node:timers/promises in insights route tests so retry backoff resolves immediately.
- Document the FN-7464 performance rationale with an FNXC dashboard test comment.

Files changed:
 packages/dashboard/src/__tests__/insights-routes.test.ts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Fusion-Task-Id: FN-7464

Fusion-Task-Lineage: a4a77c7e-61ba-4abd-be80-059a2df55add

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:04 -07:00
gsxdsm
4be9275747 FN-7463: refresh test feedback baseline docs
Refresh the weekly test feedback-loop baseline and carry operator notes through the reporting helper.

- Add the 2026-W27 baseline snapshot with updated gate, pnpm test, quarantine, and slowest-test data.
- Refresh the published Markdown summary and trend table for #leads.
- Preserve operator notes in Markdown and printed leads summaries, with regression coverage for notes and empty live quarantine ledgers.

Files changed:
 docs/test-feedback-loop-baseline.md               |  52 +++++-----
 docs/test-feedback-loop-baselines.json            | 113 ++++++++++++++++++++++
 scripts/__tests__/test-feedback-baseline.test.mjs |  72 +++++++++++++-
 scripts/test-feedback-baseline.mjs                |  10 +-
 4 files changed, 219 insertions(+), 28 deletions(-)

Fusion-Task-Id: FN-7463

Fusion-Task-Lineage: 2279c412-5371-41dd-81d1-7fc397bb349a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
d9ef51492d FN-7462: show mobile chat conversation titles
Mobile direct-chat dropdowns now identify sessions by conversation title instead of model-name text.

- Render the mobile session trigger with the conversation title or Untitled while preserving the provider logo.
- Remove mobile trigger model-tag styling and assert the model badge stays out of the compact header.
- Document the mobile Chat dropdown behavior and add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7462-mobile-chat-dropdown-title.md   |  7 ++++
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/ChatView.css     |  8 -----
 packages/dashboard/app/components/ChatView.tsx     |  8 +++--
 .../__tests__/ChatView.core-contracts.test.tsx     | 25 +++++++++++---
 .../components/__tests__/ChatView.mobile.test.tsx  | 39 +++++++++++++++++++++-
 6 files changed, 72 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-7462
Fusion-Task-Lineage: 6a6e2ac3-ecca-4076-81c5-b4e4a65eb286
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
30a11ac919 FN-7461: count footer queues across task states
Correct the dashboard footer counter contract so active task pressure matches board state coverage.

- Count triage and planning lanes as queued while excluding done, archived, and inactive custom lanes.
- Treat only actionable blockedBy values as blocked tasks and keep running/stuck scoped to in-progress work.
- Cover every visible footer counter, background/overlap segments, and the intentional absence of a Done footer count in regression tests.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7461-footer-counters.md              |  7 ++
 packages/dashboard/app/api/legacy.ts               |  6 +-
 .../__tests__/ExecutorStatusBar.test.tsx           | 86 +++++++++++++++++++++-
 .../app/hooks/__tests__/useExecutorStats.test.ts   | 59 ++++++++-------
 packages/dashboard/app/hooks/useExecutorStats.ts   | 24 +++++-
 5 files changed, 150 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-7461

Fusion-Task-Lineage: a1eceb98-76b2-4820-95c4-888ad61b4162

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
00afb22bcb FN-7458: default startup theme mode to system
Default fresh dashboard startup and appearance reset to System mode while keeping Shadcn Ember as the color theme.

- Set global themeMode defaults and Settings fallback props to system.
- Resolve pre-hydration web and desktop startup from prefers-color-scheme, including invalid cache and fallback paths.
- Update Appearance reset behavior, focused theme tests, docs, and the release changeset.

Files changed:
 .changeset/fn-7458-system-theme-default.md         |   7 ++
 docs/dashboard-guide.md                            |   3 +-
 docs/settings-reference.md                         |   4 +-
 .../core/src/__tests__/global-settings.test.ts     |  17 +++-
 packages/core/src/__tests__/store-settings.test.ts |   6 +-
 packages/core/src/settings-schema.ts               |   6 +-
 .../app/__tests__/index-html-theme-link.test.ts    |  18 ++++
 .../dashboard/app/components/SettingsModal.tsx     |   8 +-
 .../dashboard/app/components/ThemeSelector.tsx     |   6 +-
 .../components/__tests__/ThemeDropdown.test.tsx    |   9 +-
 .../components/__tests__/ThemeSelector.test.tsx    |   2 +-
 .../dashboard/app/hooks/__tests__/useTheme.test.ts | 111 ++++++++++++++++++++-
 packages/dashboard/app/hooks/useTheme.ts           |  21 +++-
 packages/dashboard/app/index.html                  |  13 ++-
 packages/desktop/src/renderer/index.html           |  13 ++-
 15 files changed, 211 insertions(+), 33 deletions(-)

Fusion-Task-Id: FN-7458
Fusion-Task-Lineage: fb6184b4-9a6a-4131-9f97-f8cd12ef904c
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
7300bf54ce FN-7460: disable WebKit text scaling in terminals
Disable WebKit terminal text scaling so iPhone Safari preserves exact xterm cell metrics.

- Set terminal xterm host subtrees to disable text-size adjustment instead of pinning it at 100%.
- Update terminal CSS contract coverage for modal and session terminal surfaces.
- Document the real-iPhone recurrence and add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7460-ios-terminal-spacing.md                 |  7 +++++++
 .../ui-bugs/xterm-async-font-remeasure-paste-dedupe.md     |  7 ++++---
 packages/dashboard/app/__tests__/terminal-input.test.ts    | 14 +++++++-------
 packages/dashboard/app/components/SessionTerminal.css      |  7 +++++--
 packages/dashboard/app/components/TerminalModal.css        |  9 ++++++---
 .../app/components/__tests__/TerminalModal.test.tsx        |  7 +++++++
 6 files changed, 36 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-7460

Fusion-Task-Lineage: 00542017-457b-40b8-9139-084218bc3533

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
95325201a6 FN-7459: remember task popup geometry
Remember task-detail popup geometry so operators can reuse one positioned window across tasks.

- Share a stable persisted geometry key for task-detail FloatingWindow instances while keeping per-task window identity.
- Add regression coverage for shared task popup geometry, malformed persisted data fallback, and isolated non-task windows.
- Document desktop/tablet popup geometry persistence and add a release changeset.

Files changed:
 .changeset/fn-7459-task-popup-geometry.md          |   7 ++
 docs/dashboard-guide.md                            |   5 +-
 docs/settings-reference.md                         |   2 +-
 packages/dashboard/app/App.tsx                     |   5 +
 .../App.taskDetailFloatingGeometry.test.tsx        | 111 +++++++++++++++++++++
 .../dashboard/app/components/FloatingWindow.tsx    |   2 +-
 .../components/__tests__/FloatingWindow.test.tsx   |  83 ++++++++++++++-
 7 files changed, 210 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7459

Fusion-Task-Lineage: 84674283-024f-4ed5-b7a0-6dade1b77f8b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00
gsxdsm
96b2df115e fix(desktop): heal launch-mode/shell split-brain hanging Windows local runtime + fix Windows root build (#1878)
## Windows: local runtime hung at "Starting local Fusion runtime…"

### Root cause
Desktop startup had two independent persisted sources of truth that
could disagree:
- `desktop-launch-mode.json` — decides whether **main** *starts* the
embedded local runtime
- `shell-connections.json` (`desktopMode`) — decides whether the
renderer **launch gate** *waits* for it

`shell:setDesktopMode` persists shell settings **before** the fallible
`startLocalRuntimeOnce()` / `saveDesktopLaunchMode()`. So a first
"local" selection whose runtime start threw or was interrupted left
`shell=local` / `launch-mode=choose` **permanently**. Every later launch
then sat at "Starting local Fusion runtime…" polling a runtime nobody
started → 30s timeout.

### Fix (defense in depth) — `78f0bc31`
- `initializeApp` reconciles: a completed shell `local` selection is
authoritative → heals the launch-mode file and starts the runtime.
- `onDesktopModeChange` / `onDesktopLaunchModeChange` persist
launch-mode **before** the fallible start so it can't re-desync.
- `DesktopLaunchGate` no longer assumes main started the runtime — if
it's not running/starting it actively `setDesktopMode("local")` before
polling.
- Env-gated startup trace (`FUSION_STARTUP_TRACE`) so packaged builds
(which log nothing) are diagnosable.
- Regression tests: split-brain → runtime starts + file heals;
agreement-on-choose → no start.

**Verified end-to-end under real Electron 35 / Node 22.16**: from the
exact split-brain state the runtime now reaches `RUNNING` and the
launch-mode file heals.

### Also: Windows root-build breakages — `bd24bd4c8`
- `scripts/build-workspace.mjs` "run as main" guard compared
`import.meta.url` to `` `file://${process.argv[1]}` ``, which never
matches on Windows → root `pnpm build` silently no-opped (exit 0, no
dist). Now uses `pathToFileURL(process.argv[1]).href`.
- `spawn('pnpm', …)` without `shell:true` (ENOENT on Windows) in
`build-workspace.mjs` and `packages/cli/tsup.config.ts` → pass `shell`
on win32.

### Notes
- `@fusion/desktop` and `@fusion/dashboard` are private → no changeset.
- Build the Windows installer via the `desktop-windows` workflow
(`electron-builder --projectDir deploy`); local `pnpm deploy` staging
hits an unrelated directory-rename race on managed-workspace
filesystems.

🤖 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**
* Added optional desktop runtime startup tracing (enabled via
environment variable).
* **Bug Fixes**
* Improved local desktop handoff to prevent reload loops and navigate
directly to the embedded local runtime.
* Added “split-brain” healing between persisted launch mode and shell
settings.
* Prevented auto-registration of runtime root/CWD during
desktop/dashboard startup.
* Improved Windows compatibility for CLI/workspace command spawning and
npm install process handling.
* **Tests**
* Expanded local/Electron integration, navigation, and onboarding
regression coverage; improved async flushing for more reliable
initialization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-03 00:17:58 -07:00
gsxdsm
d7c25e3ccb fix(dashboard): garbage-collect stale SWR caches and add Clear local data button (#1877)
## Problem

Users reported the dashboard running out of browser `localStorage`
space. Root cause: stale SWR hydration entries were **never
garbage-collected**.

- `readCache` returned `null` for stale entries but left the bytes on
disk.
- No sweep existed for abandoned caches — per-chat-session and
per-chat-room message caches (up to 500 KB each, capped by
`DEFAULT_MAX_BYTES`) from old conversations accumulated indefinitely.
- No user-facing escape hatch to clear browser data.

With a typical ~5 MB origin quota, ~10 full chat-session caches could
exhaust storage.

## Fix — three layers

**1. Lazy GC in `readCache`** (`swrCache.ts`)
When a reader passes `maxAgeMs` and the entry is stale, `readCache` now
deletes the key instead of just returning `null`. Behavior-preserving —
every reader already treats a stale entry as a miss and re-fetches — so
the only observable change is freed quota on active paths.

**2. Boot sweep `pruneStaleCacheEntries()`** (`swrCache.ts` →
`DashboardLoader.tsx`)
Called once from `DashboardLoader` on mount, before hydration hooks read
their caches. Iterates all `kb-dashboard-*` keys and removes any
envelope older than 24 h (`SWR_LONG_MAX_AGE_MS`). Since 24 h is the
longest TTL any consumer uses, a pruned entry was already a miss for
every reader. This catches the real space hogs: abandoned
per-session/per-room message caches that are never read again.

**3. Settings → General "Clear local data"** (`GeneralSection.tsx`)
A new **Browser Data** panel with a button that confirms, then calls
`clearAllLocalCache()` — wipes all Fusion-owned browser data (`kb-*`,
`kb:*`, `fn-agent-log-*`, `fusion*`) while **preserving `fn.authToken`**
so the session survives the reload. Tasks and project settings live
server-side and are unaffected.

## Supporting fix

The test environment's `localStorage` mock (`vitest.setup.ts`) was
incomplete — it lacked `length` and `key()`, so any iteration-based
storage code silently no-op'd in tests. Added both to make it a faithful
`Storage` implementation.

## Verification

| Check | Result |
|---|---|
| swrCache tests | 14/14 ✅ |
| DashboardLoader tests | 6/6 ✅ |
| settings-sections tests | 15/15 ✅ |
| auth + useCurrentProject + useChat (regression) | 148/148 ✅ |
| Typecheck (`tsc --noEmit`) | clean ✅ |
| Lint (ESLint, 5 changed files) | clean ✅ |
| Changeset format (`pnpm check:changesets`) | valid ✅ |

## Files

- `packages/dashboard/app/utils/swrCache.ts` — lazy GC +
`pruneStaleCacheEntries` + `clearAllLocalCache`
- `packages/dashboard/app/components/DashboardLoader.tsx` — boot sweep
call
-
`packages/dashboard/app/components/settings/sections/GeneralSection.tsx`
— Clear local data button
- `packages/dashboard/app/utils/__tests__/swrCache.test.ts` — updated +
new tests
- `packages/dashboard/vitest.setup.ts` — complete the localStorage mock
- `.changeset/fix-dashboard-localstorage-quota-exhaustion.md`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a GitLab integration enable/disable toggle in Settings, with
collapsible GitLab sections and preserved saved credentials for
re-enable.
* Added a “Clear local data” option in Settings to remove cached browser
data while keeping sign-in state.
  * Added bundled support for Linear Import in the plugin manager.

* **Bug Fixes**
* Prevented dashboard storage quota issues by trimming stale cached data
automatically.
* Improved mobile chat header and iOS terminal behavior for better
spacing and keyboard handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-03 00:16:24 -07:00
gsxdsm
a436998a65 fix(dashboard): hide right dock by default + defer spurious onboarding project-not-found toast
- Right dock now defaults to HIDDEN when the operator has no stored preference (readStoredRightDockOpen),
  so first-run/onboarding lands on an uncluttered board; users opt in via the Header toggle (persists
  "true"). Combined with the existing taskView="board" default and viewMode->"project" transition, first
  run lands on the board. Updated the design comments and controller Harness tests (seed the open flag)
  and added a focused default-closed assertion.

- useDeepLink deferred the "Project 'X' not found" toast behind a 3s grace window. A project selected
  during onboarding is deep-linked via ?project=<id> before the projects list revalidates to include it,
  so the eager toast fired even though the project loads a beat later. The deferred toast is cancelled as
  soon as the project appears in the list; only a genuinely-absent project past the window still errors.
  Added symptom-verification coverage (project appears within window -> no toast) and updated the
  StrictMode/unknown-project/App-level tests to advance fake timers.

- Removed the stale ModelOnboardingModal test asserting the research-runs note that was intentionally
  removed from onboarding earlier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 00:12:10 -07:00
gsxdsm
9df13c7ffa fix(dashboard): garbage-collect stale SWR caches and add Clear local data button
Stale SWR hydration entries (per-chat-session/per-room message caches up to
500KB each) were never garbage-collected — readCache returned null for stale
entries but left the bytes on disk, and nothing swept abandoned caches. This
caused localStorage quota exhaustion for users with many projects and chat
sessions.

Three fixes:
- readCache now lazily deletes stale entries (behavior-preserving; every
  reader already treats stale as a miss and re-fetches)
- Boot sweep pruneStaleCacheEntries() in DashboardLoader removes any
  kb-dashboard-* entry older than 24h before hydration hooks read caches
- Settings > General "Browser Data" panel with a Clear local data button
  that wipes all Fusion-owned browser data while preserving the auth token

Also completes the vitest localStorage mock (was missing length/key).
2026-07-02 23:53:26 -07:00
gsxdsm
55f260ad73 fix(dashboard): persist onboarding model default + defer CLI-install banner
Two false-positive first-run banners:

1. "Select Default Model" recommendation appeared even after choosing a model in onboarding.
   The picked model lived only in local state until completeOnboarding ran on the final step, so
   selecting a model then exiting/skipping before the last step lost the choice — and
   defaultProvider/defaultModelId stayed unset, tripping the recommendation. Now the pick is persisted
   immediately in handleModelSelect, and completeOnboarding falls back to the first available model
   when the operator connected a provider but never opened the dropdown. Either path leaves a durable
   global default so the recommendation no longer misfires.

2. "Install the Fusion CLI" banner showed immediately on first run. Added a 3-day grace period keyed
   off the first time the banner becomes eligible; Settings -> General -> CLI Binary still installs on
   demand meanwhile, so this only defers the passive nudge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:49:43 -07:00
gsxdsm
914c38ff5d fix(dashboard): poll health so a stale "engine not running" banner clears
useDashboardHealth fetched /api/health once on mount and never again. Right after a project is
created the engine is still starting, so that single fetch reports engine.available=false and the
"AI engine is not running" banner shows — and because health was never refreshed, the banner stayed
up even after the engine came online (the user reported the banner while the engine was in fact
running). Poll every 15s and preserve the last value on transient errors so the banner clears on its
own once the engine reports available.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:42:14 -07:00
gsxdsm
424e66ee2e fix(dashboard): project setup asks for folder before name
The project name auto-derives from the chosen directory, so present the folder/directory picker
before the Project Name field — picking the folder first pre-fills a sensible name instead of
asking for a name before there is a folder to base it on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:33:50 -07:00
gsxdsm
0771c34b0b fix(dashboard): mark GitHub onboarding step done when authenticated via gh CLI
On the GitHub onboarding step, when GitHub is authenticated via the gh CLI (no OAuth provider),
the "Continue with gh CLI auth" button called setStep("project-setup") directly, skipping the
completion bookkeeping — so "github" was never added to completedSteps and step 2 never checked
off in the progress indicator. Advance via handleNext when ready via gh CLI (marks the step
completed) and via handleSkip when GitHub isn't connected (marks it skipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:31:15 -07:00
gsxdsm
4708d0b644 fix(dashboard): tidy first-run onboarding (drop research note; scope remote-connect card)
- Remove the "Research runs require provider credentials and an enabled Research View…" helper note
  from the AI-setup step.
- Show the "Connect remote Fusion server" card only when not already connected to a remote server
  (no active remote profile) — on any host including web — and never in LOCAL desktop mode, where the
  local runtime is already the backend and prompting for a remote URL just confused first-run setup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:09:37 -07:00
gsxdsm
776df1ac25 fix(desktop): wire a ModelRegistry so onboarding shows models (not just "connected")
createServer's modelRegistry is optional and, when absent, the /api/models endpoint returns an
empty list — so after connecting a provider (e.g. Anthropic) the onboarding model picker showed
"no models". The desktop wired authStorage but no ModelRegistry.

Add a shared createFusionModelRegistry(authStorage) factory to @fusion/engine (which already depends
on @earendil-works/pi-coding-agent) so non-CLI hosts don't need that dep directly, and pass its
result as modelRegistry from both desktop server paths. Verified against a clean embedded server:
/api/models now returns 24 Claude models instead of an empty list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 23:09:36 -07:00
gsxdsm
f92c255e45 FN-7457: stabilize plugin runner lifecycle hook tests
Replace real timer waits with a bounded microtask flush for plugin runner lifecycle hook tests.

- Add a shared flushMicrotasks helper for fire-and-forget hook assertions.
- Update task lifecycle hook tests to avoid setTimeout-based settling delays.
- Document the test-settling requirement with an FNXC comment.

Files changed:
 .../engine/src/__tests__/plugin-runner.test.ts     | 23 ++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-7457

Fusion-Task-Lineage: 8a4eb36c-4e36-4c97-a88d-d76b8f410dc8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 22:53:51 -07:00
gsxdsm
666adff1f7 test(desktop): mock createFusionAuthStorage in local-server engine mock
local-server now imports createFusionAuthStorage from @fusion/engine; add it to the test's engine
mock so the startup path resolves.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:41:24 -07:00
gsxdsm
98f46cb33a fix(desktop): wire auth storage so first-run onboarding (AI/GitHub) actually opens
The desktop embedded server called createServer WITHOUT an authStorage, so GET /api/auth/status
returned 500 "Authentication is not configured". The dashboard's first-run onboarding hook
(useAuthOnboarding -> fetchAuthStatus) catches that failure silently and never opens the model
onboarding wizard — so the desktop skipped straight to project creation with no AI/GitHub setup,
regardless of onboarding-completion flags (which is why clearing them did nothing). Providers also
couldn't be authenticated at all.

Wire createFusionAuthStorage() (the same storage the CLI dashboard/serve commands use) into both the
primary (local-runtime) and legacy (local-server) desktop server paths. Verified against a clean
embedded server: /api/auth/status now returns 200 with the provider list instead of 500. (Full
API-key provider wrapping stays CLI-only for now; OAuth + CLI providers are available on desktop.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:40:46 -07:00
gsxdsm
c976d75d8d fix(dashboard): start the engine on project creation so it isn't reported unavailable
POST /api/projects registered a project but only started its engine lazily on the first scoped
store access, so a freshly-created project — especially the operator's FIRST project on the
desktop, where no other engine is running — left engineManager with no running engine. The
dashboard's project view then showed "AI engine is not running" (EngineUnavailableBanner keys off
/api/health engine.available). Proactively warm the engine via getOrCreateProjectStore (fires the
onProjectFirstAccessed hook -> engineManager.onProjectAccessed -> ensureEngine) right after the
project is activated, fire-and-forget so it never blocks/fails the registration response.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 21:53:05 -07:00
gsxdsm
0c43ed42cf fix: address PR review feedback + typecheck failure
- DesktopLaunchGate: the chooser onPick("local") path still called the removed
  applyServerBaseUrl helper (broke Typecheck and the desktop local chooser flow) —
  call navigateToLocalRuntimeOrigin. Also re-read shell.getState() immediately before the
  self-healing start check so a stale mount snapshot doesn't fire a redundant
  setDesktopMode("local") on normal boots (Greptile).
- register-fn-binary-routes: on Windows the npm install runs under a shell, so a timeout's
  child.kill only stopped cmd.exe and left npm.cmd/node running — kill the whole process tree
  via taskkill /T on win32 (CodeRabbit).
- local-server.test: align with the new resolver contract — assert the runtime never
  auto-registers the root project and starts engine-less when no projects exist (CodeRabbit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:57:25 -07:00
gsxdsm
b843305144 fix(dashboard): auto-open first-run onboarding even when the provider list is empty
useAuthOnboarding gated its first-run check on `providers.length > 0`, so a brand-new install
(notably the desktop app on first launch, which can report zero configured providers) skipped
onboarding entirely and landed the operator on an empty dashboard with no AI/GitHub setup.

Evaluate first-run onboarding from completion state regardless of the provider list, so brand-new
users are guided through the model-onboarding wizard (AI -> GitHub -> Project) before project
creation. Existing branches (authenticated provider, completed onboarding, local completion,
setup-wizard deferral, one-shot guard) are unchanged. Adds an empty-provider-list regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:16:43 -07:00
gsxdsm
b331f26f3d fix(desktop,cli): never auto-create a project in home/cwd; onboard instead
The desktop embedded runtime auto-registered its runtime root (the user's HOME directory) as a
project on first launch, and bare `fusion` / `fn` / `fn dashboard` / `fusion dashboard`
auto-registered the CWD as a project. Both silently created a "cwd-mode" project the operator
never chose and dropped them onto a board for it.

- Desktop: replace ensureDesktopRuntimeProject (which registered home) with
  resolveDesktopRuntimePrimaryProject, which only PICKS an already-registered project as the
  primary engine target and registers nothing. With no projects the server starts engine-less
  (createServer's engine is optional) and the dashboard shows its onboarding empty state.
  Applied to both the primary (local-runtime) and legacy (local-server) desktop server paths.
- CLI dashboard command: ensureCwdProjectRegistered now runs with autoRegister:false, so it uses
  the CWD project only if already registered, else starts with none and the dashboard onboards.
  (serve/daemon keep their existing --no-auto-register flag; the CLI `desktop` launcher unchanged.)

Verified: with zero projects the embedded server starts, /api/health -> 200, /api/projects -> [],
/ serves the client. Unit test asserts resolveDesktopRuntimePrimaryProject registers nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:16:42 -07:00
gsxdsm
b276a98ae0 fix(dashboard): spawn npm with a shell on Windows for CLI install button
The CLI-binary panel's "Install with npm" button (POST /system/fn-binary/install) ran
`spawn("npm", ["install","-g","runfusion.ai"], { shell: false })`. On Windows npm resolves to
npm.cmd, which Node refuses to spawn without a shell (spawn npm ENOENT / EINVAL, CVE-2024-27980),
so the button failed with "spawn npm ENOENT". Use shell on win32; the command/args are fixed
constants with no caller input, so shell quoting is safe. (The npx spawns in cli skills/extension
already set shell:true.)

Verified on Windows: spawn("npm",["--version"],{shell:false}) -> ENOENT; {shell:true} -> ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:00:43 -07:00
gsxdsm
ca244c07a2 fix(desktop): load local UI from the runtime origin so /api is reachable
After the runtime starts, the packaged renderer was left on its file:// page and only had
?serverBaseUrl=… appended. But the dashboard client issues RELATIVE /api requests, so on a
file:// origin they resolve to file:///api/… and fail ("Can't reach the Fusion backend /
Failed to fetch"); the embedded server also sends no CORS header, so a cross-origin fetch
would be blocked as well. (The server itself is fine — verified it serves both /api/health
and the client HTML at /.)

Fix: once the runtime is running, navigate the window to the runtime's OWN origin
(http://127.0.0.1:<port>/), which the embedded server serves — making /api same-origin.
This mirrors how remote mode already navigates to its server URL. The gate now treats "page
served over http(s)" as the ready signal (protocol check) instead of a serverBaseUrl URL
param; that also supersedes the previous cached-context handoff check (04fd91f6) and keeps
the reload loop closed, since bootstrapShellHostContext() strips shell query params at load.

Regression tests: navigates to the runtime origin exactly once from file://; renders the app
without navigating when already served over http; starts the runtime first when it isn't
running, then navigates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 19:26:50 -07:00
gsxdsm
f9733341b5 FN-7453: add GitLab enablement controls
Add a settings-controlled GitLab enablement path while preserving saved GitLab configuration.

- Add project and global GitLab enable settings with collapsible Settings UI for URL and token controls.
- Gate GitLab auth, import loading, and import actions when GitLab integration is disabled.
- Preserve global GitLab values separately during global settings saves and document the new behavior.
- Cover enablement resolution, settings save behavior, disabled import UI, and GitLab route/auth gating with tests.

Files changed:
 .changeset/fn-7453-gitlab-enable-disclosure.md     |  7 ++
 docs/dashboard-guide.md                            |  7 ++
 docs/gitlab-parity-inventory.md                    |  1 +
 docs/settings-reference.md                         |  4 ++
 docs/task-management.md                            |  6 +-
 packages/core/src/__tests__/gitlab-config.test.ts  | 17 ++++-
 .../core/src/__tests__/settings-parity.test.ts     | 18 +++--
 packages/core/src/gitlab-config.ts                 | 15 ++++-
 packages/core/src/index.ts                         |  2 +-
 packages/core/src/settings-schema.ts               |  2 +
 packages/core/src/types.ts                         |  5 ++
 .../app/__tests__/settings-save-split.test.ts      | 20 +++---
 .../dashboard/app/components/GitHubImportModal.tsx | 43 +++++++++---
 .../dashboard/app/components/SettingsModal.css     | 77 +++++++++++++++++++++
 .../dashboard/app/components/SettingsModal.tsx     | 34 ++++++++-
 .../__tests__/GitHubImportModal.test.tsx           | 19 ++++++
 .../__tests__/SettingsModal.general.test.tsx       | 78 ++++++++++++++++++++++
 .../SettingsModal.scheduling-merge.test.tsx        |  7 +-
 .../app/components/settings/save-split.ts          |  5 +-
 .../settings/sections/GeneralSection.tsx           | 36 ++++++----
 .../settings/sections/GlobalGeneralSection.tsx     | 71 ++++++++++++--------
 .../components/settings/sections/MergeSection.tsx  | 44 +++++++-----
 .../dashboard/src/__tests__/gitlab-auth.test.ts    | 20 ++++++
 .../dashboard/src/__tests__/routes-gitlab.test.ts  | 11 +++
 packages/dashboard/src/gitlab-auth.ts              | 11 ++-
 25 files changed, 458 insertions(+), 102 deletions(-)

Fusion-Task-Id: FN-7453

Fusion-Task-Lineage: 81fbd39d-675f-49d6-8d13-b7fcb4d25658

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 19:01:09 -07:00
gsxdsm
04fd91f66b fix(desktop): stop local-runtime handoff reload loop (rapid "Starting Fusion" flashing)
After the runtime starts, DesktopLaunchGate calls applyServerBaseUrl() which reloads the
page with ?serverBaseUrl=… so the shell-host bootstrap can route API calls to the embedded
server. But main.tsx runs bootstrapShellHostContext() at module load — BEFORE the gate's
effect — and it strips every shell query param from the URL via history.replaceState. The
gate then checked window.location.search for serverBaseUrl (after an await), always missed
it, and re-ran the handoff → window.location.replace → reload → strip → an infinite reload
loop that renders as rapid "Starting local Fusion runtime…" flashing that never connects.

This was latent until the split-brain fix (78f0bc31) let the runtime actually start and
reach the handoff.

Fix: detect the completed handoff from the CACHED shell-host context
(getShellHostContext().serverUrl), which the bootstrap preserves, instead of the stripped
URL (URL param kept only as a fallback).

Adds a DesktopLaunchGate regression test: with serverUrl present in the cached context but
stripped from the URL, the gate renders children and does NOT reload; on first load it
performs the handoff exactly once. Verified the test fails against the pre-fix gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 18:45:20 -07:00
gsxdsm
7a4b0bf412 FN-7456: fix initial iOS terminal keyboard spacing
Fix iOS mobile terminal measurement so keyboard-open sessions size correctly on first render.

- Seed focused iOS terminal viewport baselines from guarded screen dimensions when the layout height is already keyboard-shrunk.
- Apply the same initial keyboard-open overlap handling to TerminalModal and the shared mobile keyboard hook.
- Add regression coverage for 10px and 12px mobile terminal sizing before repair events, plus a patch changeset.

Files changed:
 .changeset/fn-7456-ios-mobile-terminal-spacing.md  |   7 ++
 .../dashboard/app/components/TerminalModal.tsx     |  31 +++++-
 .../__tests__/SessionTerminal.mobile.test.tsx      |  42 ++++++++
 .../components/__tests__/TerminalModal.test.tsx    | 116 +++++++++++++++++++++
 packages/dashboard/app/hooks/useMobileKeyboard.ts  |  31 +++++-
 5 files changed, 225 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7456

Fusion-Task-Lineage: 8f11fc95-51ca-49b0-b9cd-b3e14501ab92

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 18:28:06 -07:00
gsxdsm
1430a42dd8 FN-7455: fix mobile direct chat header alignment
Keep the mobile direct-chat header on a single left-aligned row without losing accessible context.

- Hide the direct-chat ViewHeader title shell from layout while preserving the accessible Chat heading.
- Keep the back button first and the active session switcher beside it on a non-wrapping mobile row.
- Extend mobile chat coverage for long duplicate session titles, Bot fallback labels, and the CSS layout contract.
- Document the updated mobile Chat header behavior and add a patch changeset.

Files changed:
 .changeset/fn-7455-mobile-chat-header-layout.md    |  7 ++
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/ChatView.css     | 17 +++--
 packages/dashboard/app/components/ChatView.tsx     |  4 +-
 .../components/__tests__/ChatView.mobile.test.tsx  | 80 ++++++++++++++++++++--
 5 files changed, 98 insertions(+), 12 deletions(-)

Fusion-Task-Id: FN-7455

Fusion-Task-Lineage: fe14b542-ff6a-437b-ad89-8011c2b3c299

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 18:11:49 -07:00
gsxdsm
78ebeafcec FN-7454: show Linear Import in Plugin Manager
Register Linear Import as a built-in plugin so users can install and manage it from Plugin Manager.

- Add fusion-plugin-linear-import to the built-in plugin catalog.
- Extend Plugin Manager registry and rendering coverage for the Linear Import entry.
- Add a patch changeset documenting the operator-visible plugin visibility fix.

Files changed:
 .changeset/fn-7454-linear-plugin-visibility.md     |  7 ++
 .../dashboard/app/components/PluginManager.tsx     | 11 +++
 .../__tests__/PluginManager.registry.test.tsx      | 72 ++++++++++++++++++-
 .../components/__tests__/PluginManager.test.tsx    | 80 ++++++++++++++++++++++
 4 files changed, 168 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7454

Fusion-Task-Lineage: 1b54adb4-78cc-47cc-ad7a-d675de64fd49

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 18:06:00 -07:00
gsxdsm
bd24bd4c82 fix(build): make root workspace build run on Windows
Two Windows-only breakages in the build path:

- scripts/build-workspace.mjs: the "run as main" guard compared import.meta.url
  to `file://${process.argv[1]}`, which never matches on Windows (import.meta.url
  is file:///C:/… with forward slashes and a triple slash; argv[1] is C:\… with
  backslashes and no scheme). So `pnpm build` at the repo root silently no-opped
  (exit 0, no output, no dist) and packaging shipped empty/stale dist. Compare
  against pathToFileURL(process.argv[1]).href instead.

- scripts/build-workspace.mjs runPlannedBuilds and packages/cli/tsup.config.ts
  runWorkspaceCommand spawned `pnpm` without shell:true; on Windows pnpm is a
  .cmd shim Node refuses to spawn without a shell (ENOENT/EINVAL, CVE-2024-27980),
  failing with `spawn pnpm ENOENT`. Pass shell on win32 (args are fixed repo build
  invocations with no shell metacharacters).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:20:17 -07:00
gsxdsm
78f0bc3190 fix(desktop): heal launch-mode/shell split-brain that hung local runtime on Windows
Desktop startup used two independent persisted sources of truth that could
disagree: desktop-launch-mode.json decided whether main STARTS the embedded
local runtime, while shell-connections.json (desktopMode) decided whether the
renderer launch gate WAITS for it. shell:setDesktopMode persists shell settings
before the fallible startLocalRuntimeOnce()/saveDesktopLaunchMode(), so a first
"local" selection whose runtime start failed or was interrupted left
shell=local / launch-mode=choose permanently. Every subsequent launch then sat
at "Starting local Fusion runtime…" polling a runtime nobody started, timing out
after 30s.

Fix (defense in depth):
- initializeApp reconciles: a completed shell "local" selection is authoritative;
  it heals the launch-mode file and starts the runtime.
- onDesktopModeChange/onDesktopLaunchModeChange persist launch-mode BEFORE the
  fallible start so an interrupted start cannot re-create the desync.
- DesktopLaunchGate no longer assumes main started the runtime; if it is not
  running/starting it actively (re)starts via setDesktopMode("local") before polling.
- Add env-gated startup trace (FUSION_STARTUP_TRACE) so packaged builds, which
  otherwise log nothing, can diagnose this class of stall.

Regression tests assert the invariant (split-brain -> runtime starts + file heals;
agreement-on-choose -> no start). flushPromises now drains via a macrotask so
run()-based tests observe a fully-initialized app regardless of async chain length.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 15:20:15 -07:00
gsxdsm
765218f80f FN-7449: include chat token usage in dashboard totals
Chat token usage now contributes to Command Center token analytics totals alongside task execution usage.

- Add durable chat token usage rows and persistence hooks for assistant and room messages.
- Aggregate chat usage into token totals, time series, provider/model groups, CSV export, and dashboard counts.
- Cover chat token persistence and analytics with core and dashboard tests.
- Document the expanded dashboard token usage behavior and add a changeset for the published package.

Files changed:
 .changeset/fn-7449-chat-token-totals.md            |   7 +
 docs/dashboard-guide.md                            |   4 +-
 .../core/src/__tests__/token-analytics.test.ts     | 146 ++++++++++++++++++
 packages/core/src/chat-store.ts                    | 105 +++++++++++++
 packages/core/src/chat-types.ts                    |  37 +++++
 packages/core/src/db.ts                            |  52 ++++++-
 packages/core/src/index.ts                         |   3 +
 packages/core/src/token-analytics.ts               | 167 +++++++++++++++++----
 .../__tests__/CommandCenter.test.tsx               |   4 +-
 .../components/command-center/areas/TokensArea.tsx |   4 +
 .../src/__tests__/chat-manager-cli-send.test.ts    |  40 +++++
 .../dashboard/src/__tests__/chat-manager.test.ts   | 100 ++++++++++++
 .../src/__tests__/command-center-csv.test.ts       |   2 +
 packages/dashboard/src/chat.ts                     | 110 +++++++++++++-
 packages/dashboard/src/command-center-csv.ts       |   3 +
 15 files changed, 745 insertions(+), 39 deletions(-)

Fusion-Task-Id: FN-7449
Fusion-Task-Lineage: f2bacbb6-93b9-4874-b431-2049981b66c1
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 15:00:40 -07:00
gsxdsm
1d6bb08e79 FN-7437: bound planner fallback retries
Bound planner fallback retries so model exhaustion reports a clear terminal error instead of looping.

- Add planner fallback exhaustion state and loop-limit handling for triage and pi planning paths.
- Report exhausted provider/model fallback attempts with actionable error details.
- Cover planner fallback exhaustion with engine regression tests and add a patch changeset.

Files changed:
 .changeset/fn-7437-planner-fallback.md             |   7 +
 .../src/__tests__/fallback-model-observer.test.ts  |  31 ++++
 packages/engine/src/__tests__/pi.test.ts           | 106 ++++++++++++++
 packages/engine/src/__tests__/triage.test.ts       | 161 ++++++++++++++++++++-
 packages/engine/src/pi.ts                          |  73 +++++++++-
 packages/engine/src/triage.ts                      |  25 +++-
 6 files changed, 396 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7437

Fusion-Task-Lineage: e2b8361a-c590-4f10-8f95-06dfd77e944c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:43:32 -07:00
gsxdsm
dfb6e5270d FN-7443: add bundled Linear import plugin
Add a plugin-owned Linear importer that creates Fusion tasks from Linear issues.

- Add the fusion-plugin-linear-import package with settings, Linear GraphQL client, import routes, tools, and dashboard UI.
- Bundle and register the Linear import plugin in the CLI and dashboard plugin view registry.
- Document bundled plugin authoring details and cover duplicate detection, routes, tools, UI, and packaging with tests.

Files changed:
 .changeset/fn-7443-linear-import-plugin.md         |   7 +
 docs/PLUGIN_AUTHORING.md                           |   7 +
 docs/task-management.md                            |   2 +
 packages/cli/src/__tests__/bundle-output.test.ts   |  22 ++
 .../__tests__/bundled-plugin-install.test.ts       |  29 +++
 packages/cli/src/plugins/bundled-plugin-install.ts |   1 +
 .../cli/src/plugins/staged-bundled-plugin-ids.ts   |   1 +
 packages/cli/tsup.config.ts                        |   8 +
 .../__tests__/registerBundledPluginViews.test.tsx  |   9 +-
 .../app/plugins/registerBundledPluginViews.ts      |  18 ++
 .../app/types/plugin-dashboard-views.d.ts          |   9 +
 .../src/__tests__/routes-plugin-registry.test.ts   |   5 +
 .../runtime-plugin-alias-regression.test.ts        |  12 +
 packages/dashboard/src/registry-manifest.json      |  10 +
 packages/dashboard/vite.config.ts                  |   8 +
 packages/dashboard/vitest.config.ts                |   8 +
 plugins/fusion-plugin-linear-import/README.md      |  75 ++++++
 plugins/fusion-plugin-linear-import/manifest.json  |  48 ++++
 plugins/fusion-plugin-linear-import/package.json   |  38 +++
 .../scripts/copy-css.mjs                           |  11 +
 .../src/LinearImportView.css                       | 167 +++++++++++++
 .../src/LinearImportView.tsx                       | 263 +++++++++++++++++++++
 .../src/__tests__/LinearImportView.test.tsx        | 124 ++++++++++
 .../src/__tests__/import-linear.test.ts            |  78 ++++++
 .../src/__tests__/linear-client.test.ts            |  81 +++++++
 .../src/__tests__/routes.test.ts                   |  90 +++++++
 .../src/__tests__/tools.test.ts                    |  79 +++++++
 .../src/dashboard-interop.d.ts                     |  13 +
 .../src/dashboard-view.tsx                         |  10 +
 .../src/import-linear.ts                           | 154 ++++++++++++
 plugins/fusion-plugin-linear-import/src/index.ts   |  45 ++++
 .../src/linear-client.ts                           | 247 +++++++++++++++++++
 plugins/fusion-plugin-linear-import/src/routes.ts  | 149 ++++++++++++
 .../fusion-plugin-linear-import/src/settings.ts    |  68 ++++++
 plugins/fusion-plugin-linear-import/src/tools.ts   | 138 +++++++++++
 plugins/fusion-plugin-linear-import/tsconfig.json  |  14 ++
 .../fusion-plugin-linear-import/vitest.config.ts   |  40 ++++
 pnpm-lock.yaml                                     |  40 ++++
 pnpm-workspace.yaml                                |   1 +
 39 files changed, 2128 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7443
Fusion-Task-Lineage: a016a9d4-84a4-4a0b-b9b6-b9a2886da49a
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:31:16 -07:00
gsxdsm
3fac409cf9 FN-7452: preserve workflow settings after identity assignment
Preserve rootDir-migrated workflow settings once a durable project identity is assigned.

- Store the Fusion directory on Database instances so identity writes can detect rootDir-keyed workflow settings.
- Reconcile fallback workflow_settings rows into the identity-keyed row without overwriting existing identity values.
- Cover rootDir backfill, conflict merging, and corrupt or empty row handling in settings migration tests.
- Add a patch changeset for the published Fusion CLI package.

Files changed:
 .changeset/fn-7452-workflow-settings-identity.md   |  7 ++
 .../core/src/__tests__/settings-migration.test.ts  | 89 ++++++++++++++++++++++
 packages/core/src/db.ts                            | 84 ++++++++++++++++----
 3 files changed, 166 insertions(+), 14 deletions(-)

Fusion-Task-Id: FN-7452

Fusion-Task-Lineage: 0a49a969-fbce-45bb-adda-95b67e5c680d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:24:09 -07:00
gsxdsm
2050323d16 FN-7451: preserve workflow setting edits during saves
Workflow settings now keep newer pending edits when earlier save requests finish.\n\n- Snapshot pending workflow values before saving so the request cannot mutate under the save.\n- Clear only keys whose pending value still matches the completed request in Workflow Settings and Project Models.\n- Cover same-key, clear-to-default, and model-lane edits made while saves are in flight.\n- Add a patch changeset for the published Fusion package.\n\nFiles changed:\n .changeset/fn-7451-workflow-settings-save-race.md  |   7 ++\n .../app/__tests__/settings-sections.test.tsx       | 109 ++++++++++++++++++-\n .../app/components/WorkflowSettingsPanel.tsx       |  21 +++-\n .../__tests__/WorkflowSettingsPanel.test.tsx       | 121 ++++++++++++++++++++-\n .../settings/sections/ProjectModelsSection.tsx     |  25 ++++-\n 5 files changed, 272 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7451

Fusion-Task-Lineage: 82f5e1cf-fabb-4fc6-936c-f42dcd9337ac

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:18:08 -07:00
gsxdsm
1d6011c3a6 FN-7450: collapse mobile chat header rows
Collapse the mobile direct chat header into the shared top row.

- Move the mobile direct-thread back button and session switcher into ViewHeader actions.
- Hide the redundant mobile thread header while preserving desktop thread identity and context details.
- Update mobile chat styling, docs, changeset, and header contract tests for the single-row layout.

Files changed:
 .changeset/fn-7450-mobile-chat-header.md           |   7 +
 docs/dashboard-guide.md                            |   3 +-
 packages/dashboard/app/components/ChatView.css     |  53 +++++-
 packages/dashboard/app/components/ChatView.tsx     | 197 +++++++++++----------
 .../__tests__/ChatView.core-contracts.test.tsx     |  48 ++---
 .../components/__tests__/ChatView.mobile.test.tsx  |  76 ++++++--
 6 files changed, 256 insertions(+), 128 deletions(-)

Fusion-Task-Id: FN-7450

Fusion-Task-Lineage: c266a9b8-7fb1-410e-9c35-adad4c6a2d47

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:09:35 -07:00
gsxdsm
22fd0da2ad FN-7448: Fix 30-day token model ranges
Command Center token analytics now attributes Last 30 days model usage from durable per-model timestamps.

- Filter per-model token buckets by their own last-used timestamps while preserving legacy task-level fallback rows.
- Count unique tasks across totals, groups, and time series to avoid double-counting multi-model usage.
- Cover model/provider groups, API routing, and TokensArea rendering for Last 30 days multi-model data.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7448-token-usage-last-30-days.md     |   7 ++
 .../core/src/__tests__/token-analytics.test.ts     | 128 +++++++++++++++++++--
 packages/core/src/token-analytics.ts               |  92 ++++++++++-----
 .../areas/__tests__/TokensArea.test.tsx            |  50 ++++++++
 .../register-command-center-routes.test.ts         |  86 ++++++++++++++
 5 files changed, 327 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-7448

Fusion-Task-Lineage: 5d5c976b-5623-4d7a-a728-5a3959deac1d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 14:04:11 -07:00
gsxdsm
ffcb54b8bf FN-7446: handle missing planning MCP resolver results
Keep planning session creation resilient when the MCP resolver test seam returns no shaped result.

- Add a planning MCP resolution helper that defaults malformed resolver output to an empty server list.
- Cover both non-streaming and streaming planning sessions when MCP resolution returns undefined.
- Update the shared engine mock to return the full empty MCP resolver shape.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7446-planning-mcp-resolver.md        |  7 +++++
 .../src/__tests__/mcp-lane-forwarding.test.ts      | 35 +++++++++++++++++++++-
 packages/dashboard/src/planning.ts                 | 18 +++++++++--
 packages/dashboard/src/test/mockCoreEngine.ts      |  4 +--
 4 files changed, 59 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7446

Fusion-Task-Lineage: 998c30d2-2bed-4d25-b49f-3475048d6c07

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:58:13 -07:00
gsxdsm
8d7abb8c33 FN-7447: fix Android terminal mobile viewport sizing
Fix Android keyboard-open terminal layout by sizing mobile shells from the visual viewport.

- Track visualViewport width in the terminal modal and mobile keyboard detection.
- Apply keyboard-constrained mobile terminal sizing even when CSS media queries see a wider layout viewport.
- Cover Android visualViewport width behavior with modal, session terminal, and hook regressions.
- Document the fix pattern and add a patch changeset for the published Fusion package.

Files changed:
 .../fn-7447-android-mobile-terminal-spacing.md     |  7 ++
 ...ndroid-mobile-terminal-visual-viewport-width.md | 26 ++++++++
 .../dashboard/app/components/TerminalModal.css     | 21 +++++-
 .../dashboard/app/components/TerminalModal.tsx     |  8 +++
 .../__tests__/SessionTerminal.mobile.test.tsx      | 40 +++++++++++-
 .../components/__tests__/TerminalModal.test.tsx    | 76 ++++++++++++++++++++++
 .../app/hooks/__tests__/useMobileKeyboard.test.ts  | 38 +++++++++++
 packages/dashboard/app/hooks/useMobileKeyboard.ts  | 10 ++-
 8 files changed, 222 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-7447

Fusion-Task-Lineage: c01faf0f-842e-4632-bf8f-ae54070c3bf8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:51:25 -07:00
gsxdsm
5984f327d3 FN-7445: add Project Files creation and search controls
Improve the Project Files browser with first-class creation actions and recursive file search.

- Add visible create-file and create-folder buttons for Files — Project while keeping compact controls for embedded pickers.
- Add debounced recursive project file search with loading, retry, empty, and path-context result states.
- Cover project files creation and search behavior in dock, modal, and file browser tests.
- Document the new Project Files controls and add a release changeset.

Files changed:
 .changeset/fn-7445-project-files-create-search.md  |   7 +
 docs/dashboard-guide.md                            |   3 +-
 .../dashboard/app/components/DockFilesView.tsx     |   1 +
 packages/dashboard/app/components/FileBrowser.css  |  88 +++++++++++++
 packages/dashboard/app/components/FileBrowser.tsx  | 145 ++++++++++++++++++++-
 .../dashboard/app/components/FileBrowserModal.tsx  |   1 +
 .../components/__tests__/DockFilesView.test.tsx    |  34 +++--
 .../app/components/__tests__/FileBrowser.test.tsx  | 109 ++++++++++++++++
 .../components/__tests__/FileBrowserModal.test.tsx |  52 ++++++++
 9 files changed, 426 insertions(+), 14 deletions(-)

Fusion-Task-Id: FN-7445

Fusion-Task-Lineage: 41510def-4900-42ee-beab-b67f28dfeaee

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:44:41 -07:00
gsxdsm
ec0256f7e5 FN-7444: add planning summary deepening checkpoint
Planning Mode now holds completed summaries behind a mandatory deepening prompt before finalization.

- Add shared constants and persistence for pending planning summaries.
- Insert the “Would you like to go deeper?” checkpoint with proceed, themed, and custom-topic responses.
- Update modal handling, API formatting, docs, changeset, and regression coverage for persisted and streamed planning flows.

Files changed:
 .changeset/fn-7444-planning-deepening-checkpoint.md       |   7 +
 docs/dashboard-guide.md                            |   4 +
 packages/core/src/index.ts                         |   2 +-
 packages/core/src/types.ts                         |  12 +
 packages/dashboard/app/components/PlanningModeModal.tsx |  25 ++-
 packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx       | 193 +++++++++++++++-
 packages/dashboard/src/__tests__/planning-interview-formatters.test.ts          |  79 ++++++-
 packages/dashboard/src/__tests__/routes-planning.test.ts          | 207 ++++++++++++++++-
 packages/dashboard/src/__tests__/session-persistence-roundtrip.test.ts          |  74 +++++-
 packages/dashboard/src/ai-session-store.ts         |   2 +
 packages/dashboard/src/planning.ts                 | 249 ++++++++++++++++++---
 packages/dashboard/src/test/mockCoreEngine.ts      |   2 +
 12 files changed, 815 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-7444
Fusion-Task-Lineage: 43ee1853-558b-4168-b52c-ebcc4ece4521
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:38:02 -07:00
gsxdsm
25fecd7843 FN-7442: return GitHub issue actions to list
Return successful GitHub issue import and close flows to the issue list.

- Clear the selected GitHub issue and switch mobile preview back to the list after successful import or close actions.
- Preserve the selected preview on failures so users can retry with the existing error affordance.
- Add regression coverage for desktop and mobile import/close success and failure navigation states.
- Document the post-import list reset behavior and add a patch changeset.

Files changed:
 .changeset/fn-7442-github-import-return-list.md    |   7 +
 docs/dashboard-guide.md                            |   2 +-
 .../dashboard/app/components/GitHubImportModal.tsx |  20 +-
 .../__tests__/GitHubImportModal.test.tsx           | 210 +++++++++++++++++++--
 4 files changed, 218 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-7442

Fusion-Task-Lineage: e334a7c1-68de-48f7-be31-b036ba741685

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:30:08 -07:00
gsxdsm
72adb5231a FN-7441: add sidebar rename controls for chat conversations
Add an explicit sidebar rename affordance for direct Chat conversations while preserving existing rename paths.

- Add edit buttons beside delete controls on direct chat session rows and wire them to the existing rename dialog.
- Keep sidebar action spacing and accessibility labels stable across desktop and mobile layouts.
- Cover sidebar, context-menu, and mobile switcher rename behavior with ChatView tests.
- Document the sidebar rename entry point and add the published package changeset.

Files changed:
 .changeset/fn-7441-chat-conversation-rename.md     |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/ChatView.css     |  51 ++++-----
 packages/dashboard/app/components/ChatView.tsx     |  54 ++++++---
 .../__tests__/ChatView.core-interactions.test.tsx  | 122 +++++++++++++++++++++
 .../components/__tests__/ChatView.mobile.test.tsx  |  72 ++++++++++++
 6 files changed, 264 insertions(+), 44 deletions(-)

Fusion-Task-Id: FN-7441

Fusion-Task-Lineage: 39a2c393-dd85-4362-9472-58bb137b906c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:23:13 -07:00
gsxdsm
91fb53f3c7 FN-7440: add agent update tool
Add a Fusion extension tool for updating existing agent configuration in place.

- Register fn_agent_update with editable agent fields, validation, and non-ephemeral guards.
- Enforce org-scoped authorization for agent callers and privileged manager-clearing semantics for operators.
- Cover update success, hierarchy denial, cycle prevention, and runtime/instruction edits in extension tests.
- Document the new tool in agent and Fusion skill references and add a published package changeset.

Files changed:
 .changeset/fn-7440-agent-update-tool.md            |   7 +
 docs/agents.md                                     |  21 +-
 package.json                                       |   1 +
 packages/cli/skill/fusion/SKILL.md                 |   2 +-
 .../cli/skill/fusion/references/extension-tools.md |  21 ++
 .../skill/fusion/references/fusion-capabilities.md |   1 +
 .../src/__tests__/extension-agent-update.test.ts   | 351 +++++++++++++++++++++
 packages/cli/src/extension.ts                      | 230 ++++++++++++++
 pnpm-lock.yaml                                     |   1 +
 9 files changed, 628 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7440

Fusion-Task-Lineage: a6f4c928-5a63-4cf1-aa0b-4e38b536e965

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:16:07 -07:00
gsxdsm
aa8f1f32ee FN-7438: recover stale branch-group references
Recover branch-group detail views after restarts and let operators clear stale per-task group context safely.

- Add Task Detail stale branch-group recovery UI that clears only the current task via the assign API.
- Verify durable branch groups and members survive TaskStore/API restarts, while stale references can be reset without losing unrelated metadata.
- Improve integration-branch fallback diagnostics for repositories that use non-origin remotes.
- Document the recovery path, durable branch-group storage expectations, and release the fix as a patch.

Files changed:
 .../fn-7438-branch-group-restart-recovery.md       |  7 ++
 docs/dashboard-guide.md                            |  5 +-
 docs/settings-reference.md                         |  2 +-
 docs/storage.md                                    |  2 +-
 .../core/src/__tests__/branch-group-store.test.ts  | 43 +++++++++++-
 .../dashboard/app/components/BranchGroupCard.css   |  9 +++
 .../dashboard/app/components/BranchGroupCard.tsx   | 49 +++++++++++++-
 .../dashboard/app/components/TaskDetailModal.tsx   | 14 +++-
 .../components/__tests__/BranchGroupCard.test.tsx  | 40 +++++++++++
 .../components/__tests__/TaskDetailModal.test.tsx  | 11 ++-
 .../src/__tests__/routes-branch-groups.test.ts     | 79 +++++++++++++++++++++-
 .../src/__tests__/integration-branch.test.ts       | 41 +++++++++++
 packages/engine/src/integration-branch.ts          | 54 ++++++++++++++-
 13 files changed, 343 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-7438
Fusion-Task-Lineage: 09ef3dc3-8319-49a7-9f4d-c95a3e069d39
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 13:07:16 -07:00
gsxdsm
c49a933fb0 FN-7428: add GitLab tracking coverage and reconciliation support
Add GitLab tracking persistence, analytics, and reconciliation coverage across core, dashboard, and CLI paths.

- Store GitLab tracking and closed-at metadata when importing issues and merge requests from CLI, extension tools, and dashboard routes.
- Add GitLab source-issue analytics, Command Center GitLab signal surfaces, CSV export fields, and a closed-at backfill route.
- Cover GitLab tracking storage, reconciliation, CLI imports, dashboard import UI, route behavior, and Command Center signals with focused tests.

Files changed:
 .changeset/fn-7428-gitlab-import-tracking.md       |   7 +
 .../__tests__/extension-gitlab-tracking.test.ts    | 140 ++++++++++++
 .../__tests__/task-command-gitlab-import.test.ts   |  18 +-
 packages/cli/src/commands/task.ts                  |   1 +
 packages/cli/src/extension.ts                      |   2 +-
 .../src/__tests__/gitlab-issue-analytics.test.ts   | 243 +++++++++++++++++++++
 .../__tests__/gitlab-source-issue-storage.test.ts  | 128 +++++++++++
 .../store-gitlab-tracking-reconcile.test.ts        | 125 +++++++++++
 packages/core/src/gitlab-issue-analytics.ts        | 227 +++++++++++++++++++
 packages/core/src/index.ts                         |   8 +
 packages/core/src/store.ts                         |  21 +-
 .../__tests__/GitHubImportModal.test.tsx           |  46 ++++
 .../components/__tests__/gitlabTracking.test.tsx   |  43 ++++
 .../components/command-center/CommandCenter.tsx    |   5 +
 .../components/command-center/areas/GitlabArea.tsx | 126 +++++++++++
 .../areas/__tests__/areas.gitlab-signals.test.tsx  |  83 +++++++
 .../gitlab-source-issue-reconciler.test.ts         | 187 ++++++++++++++++
 .../register-command-center-routes.test.ts         |  52 +++++
 .../__tests__/register-git-gitlab.backfill.test.ts | 116 ++++++++++
 .../dashboard/src/__tests__/routes-gitlab.test.ts  |  59 +++--
 packages/dashboard/src/command-center-csv.ts       |  21 ++
 .../src/gitlab-source-issue-reconciler.ts          | 104 +++++++++
 packages/dashboard/src/gitlab.ts                   |  16 +-
 .../src/routes/register-command-center-routes.ts   |  25 +++
 packages/dashboard/src/routes/register-gitlab.ts   |  29 +++
 25 files changed, 1800 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-7428

Fusion-Task-Lineage: 7b0ebb5c-c6e7-42a9-a339-b2dd1d4e263a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 12:34:35 -07:00
gsxdsm
326c72b1e4 FN-7436: group Anthropic auth options first
Keep Anthropic authentication options grouped at the top of Settings while preserving auth-state sections.

- Prioritize Claude CLI, Anthropic Subscription, and Anthropic API Key before other providers in the shared card order.
- Render supported CLI and non-CLI auth cards from one sorted list so other CLI providers cannot split Anthropic entries.
- Cover the mixed CLI plus Anthropic subscription/API-key ordering case and add a patch changeset.

Files changed:
 .changeset/fn-7436-auth-anthropic-order.md         |   7 ++
 .../__tests__/AuthenticationSection.test.tsx       | 103 ++++++++++++++++++++-
 .../settings/sections/AuthenticationSection.tsx    |  91 ++++++++++--------
 3 files changed, 160 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-7436

Fusion-Task-Lineage: 653a0126-ea2b-43a6-a829-dc72dc47bfde

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-02 12:27:04 -07:00