Commit Graph

120 Commits

Author SHA1 Message Date
gsxdsm
478f226a54 test: green full-suite CI after main drift (#2229)
## Summary
Restores green **Full Suite (non-blocking)** runs on `main`. Recent main
merges left i18n key parity, schema baseline bookkeeping (0011→0012),
heartbeat tool inventory (FN-8058 `fn_task_logs_read`), and merger
whitespace-classification mocks (execFile `git diff -p -w :2: :3:`) out
of date, so all four test shards failed.

## Root causes observed on main
- **Shard 4 / `@fusion/i18n`**: missing `skipConfirmationDialogs*` +
`reviewBudgetExhausted` in non-en locales; orphan
`awaitingApprovalPlanReviewReplanCap`
- **Shard 3 / `@fusion/core`**: `SCHEMA_BASELINE_VERSION` advanced to
`0012` while tests still equated it with
`OWNER_PROJECT_ID_SPLIT_VERSION` (`0011`) and omitted `0012` from
applied-migration lists
- **Shards 1–2 / `@fusion/engine`**: tool count/snapshot drift for
`fn_task_logs_read`; merger tests still mocked `git diff-tree` for
trivial classification after the execFile `:2:`/`:3:` cutover; mock
provider `updateTask` arity drift

## Changes
- Locale catalogs: add missing keys, drop orphan key
- Schema applier tests: immutable 0011 identity + baseline 0012 lists
- Heartbeat + gating snapshots: include `fn_task_logs_read`
- Merger unit mocks: recognize `git diff -p -w :2:path :3:path`
- Mock provider: accept optional third `updateTask` arg

## Test plan
- [x] `pnpm --filter @fusion/i18n exec vitest run` — 23/23
- [x] `pnpm --filter @fusion/core exec vitest run
src/__tests__/postgres/schema-applier.test.ts` (immutable + automation
upgrade) — pass
- [x] `pnpm --filter @fusion/core exec vitest run` project-identity +
satellite-fusiondir — pass
- [x] Engine suites from failed CI shards (file-scoped,
hermes/openclaw/paperclip/grok, reliability post-finalize/mission,
heartbeat, gating, merger recovery/prompt, mock-provider, etc.) — pass
- [ ] Full Suite workflow green on merge to main

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

- **New Features**
  - Improved project data isolation across backend operations.
- Added safer optional toast handling when UI components render outside
the full application shell.
  - Added support for reading task logs during agent heartbeat sessions.

- **Bug Fixes**
- Prevented runtime probes from hanging and avoided scanning large
binary files.
  - Improved path handling for workspaces with missing descendants.
- Corrected task retry state resets and GitHub import/issue-close
behavior.

- **Style**
  - Improved chat, terminal, and settings spacing.
  - Added clearer accessibility labeling for the auto-merge control.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-16 16:01:29 -07:00
gsxdsm
e7c5de0a6e FN-8138: add restart controls after Settings updates
Expose a supervised restart affordance after an in-app update succeeds.

- Detect restart capability while update results are visible and handle scheduled or failed restart requests
- Add accessible restart status, capability guidance, responsive styling, and English translations
- Cover restart states across desktop and mobile Settings modal tests

Files changed:
 .../fn-8138-settings-restart-after-update.md       |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 .../dashboard/app/components/SettingsModal.css     |  21 +++-
 .../dashboard/app/components/SettingsModal.tsx     | 110 ++++++++++++++--
 .../__tests__/SettingsModal.general.test.tsx       | 139 ++++++++++++++++++++-
 .../__tests__/SettingsModal.test-harness.tsx       |   4 +
 .../components/__tests__/settings-mobile.test.tsx  |   4 +-
 packages/i18n/locales/en/app.json                  |   4 +
 8 files changed, 274 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-8138

Fusion-Task-Lineage: 24e8cb9a-ad64-4419-b3ce-461850624365

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 14:40:26 -07:00
gsxdsm
f58b56488c FN-8125: align mobile Settings auth cards
Align Authentication provider card content with the Settings section header on mobile.

- Remove the nested mobile gutter within Authentication panels.
- Preserve Custom Provider card spacing outside authentication panels.
- Cover scoped mobile alignment rules and add a patch changeset.

Files changed:
 .changeset/fn-8125-mobile-auth-card-alignment.md   |  7 +++++++
 .../dashboard/app/components/SettingsModal.css     | 22 ++++++++++++++++++++++
 .../components/__tests__/settings-mobile.test.tsx  |  7 +++++--
 3 files changed, 34 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8125

Fusion-Task-Lineage: a299fe3e-8a32-401a-85f2-85fe58e61da3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 12:54:00 -07:00
gsxdsm
b891e3a37b fix(dashboard): drop Settings footer Help icon and fix its underline/sizing
The Help link is an <a class="btn"> and .btn never resets link
text-decoration, so the browser's default underline painted under the
icon+label box, reading as an overlap. Drop the icon (redundant next to
the "Help" label) and reset text-decoration on the shared
discord/help anchor-button selector. Also fold the Help button into the
same mobile 36px touch-target rule as Export/Import/Reset/Save so all
five footer buttons render at a consistent height.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 10:53:54 -07:00
gsxdsm
daf5b1297d fix(dashboard): restore 36px touch target for mobile Settings footer buttons
Export/Import/Reset/Cancel/Save use .btn-sm, which the global mobile
touch-target rule deliberately excludes to keep dense table/card button
rows compact. That exclusion also caught the Settings footer, leaving
those buttons at ~24px tall on mobile — visibly smaller than the Help
and auth Test/Disable buttons on the same rail. Scope the 36px minimum
back to just this footer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 10:40:33 -07:00
gsxdsm
4b7f0d2d0e fix(dashboard): theme every Settings checkbox and move all inline help behind ? icons
- One settings-scoped checkbox rule (accent, size, focus ring) so the Advanced-settings
  toggle, SettingsToggleRow, ntfy/webhook card headers, and MCP toggle stop falling
  back to the browser-default accent.
- Fix the empty/off-screen help bubble on mobile: .notification-provider-header and
  .settings-field-label-row are now positioned ancestors for SettingsHelpTip.
- Migrate every remaining inline <small> description across settings sections to the
  shared SettingsHelpTip "?" affordance (validation errors and live status stay inline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 01:06:43 -07:00
gsxdsm
55745af80f Settings: one type scale, every setting searchable, nav grouped by topic (#2158)
Settings had three compounding problems: you couldn't find a setting,
and once you found it, it didn't look like its neighbour.

## Organization — the nav was grouped by the wrong thing

It was grouped by **scope** (Global / Runtimes / Project). Scope is an
*attribute* of a setting, not a category — nobody opens Settings
thinking "I need a project-authority setting." That single choice split
five concepts across two groups, including **two nav entries both
labelled "MCP Servers"**, distinguishable only by a small icon.

Now grouped by topic, with paired sections adjacent and stating their
own scope:

![Topic-first settings
navigation](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/nav-topic-groups.png)

```
PREFERENCES     Appearance · Keyboard Shortcuts · Notifications · General · Global
PROJECT         General · Project · Commands & Scripts · Worktrees · Merge
AI & MODELS     Models · Global · Models · Project · CLI Agents · Agents & Permissions · Prompts · Memory
AUTOMATION      Scheduling & Capacity · Scheduled Evals
INTEGRATIONS    Authentication · MCP Servers · Global · MCP Servers · Project · Plugins · Runtimes · Secrets
INFRASTRUCTURE  Node Sync · Node Routing · Remote Access · Backups
ADVANCED        Experimental Features
```

## Search — it now finds settings, not just sections

Search matched only hand-written `searchableText` keyword arrays per nav
entry, and those demonstrably rotted: Project Models accumulated 20
keywords across **two separate fixes** (FN-7907, then
title-summarization on 2026-07-14) because operators searched
"summarize" and got nothing.

Every setting is now indexed from **its real label and help text** — 123
settings across 18 sections, zero curated keywords. The same query that
was patched twice by hand:


![Search returns individual
settings](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/search-summarize.png)

Two of those four hits match on *help text*, which a keyword index
structurally cannot do. Picking a result jumps to the exact control,
**opens its collapsed disclosure**, and highlights it:

![Jump to
field](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/jump-highlight.png)


**This can't rot again.** `settings-search-index.test.ts` extracts every
`descriptor={{ key }}` from section sources and fails the build if one
isn't indexed. "All settings are searchable" is an enforced invariant,
not a promise.

## Consistency — one type scale

A text field's label and a toggle's label in the same section were
styled **three different ways**: `.form-group label`
(12px/600/uppercase/muted), a `.settings-content` override narrowing it
to 0.72rem, and `.checkbox-label` (13px/500/sentence-case) whose every
declaration carried `!important` purely to out-specify the other two.

| | Before | After |
|---|---|---|
| Sections on shared primitives | 1 | **18** |
| Indexed searchable settings | 0 | **123** |
| `form-group` in settings | 226 | **98** |
| `checkbox-label` in settings | 79 | **40** |


![Appearance](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/appearance.png)

![Scheduling](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/scheduling.png)

![Backups](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/backups.png)

![Worktrees](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/worktrees.png)

![Memory](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/memory.png)

![Merge](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/merge.png)

![Notifications](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/notifications.png)
![General ·
Project](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/general.png)

**Global `.form-group` is untouched** — 35 non-settings files style
forms with it, so settings migrate *off* it rather than restyle it
underneath the rest of the dashboard.

### A real latent bug this surfaced
`--font-size-sm` and `--font-size-md` were named by **12 declarations**
across AgentDetailView, DockTaskList, SetupWizardModal, and
ModelOnboardingModal — but **defined nowhere**. Those rules silently
no-op'd and inherited. The command-center token guard is the only thing
that catches this class of omission and it doesn't cover those files.
The scale is now complete (`2xs · xs · sm · base · md · lg`); `md` is
1.125rem to hold current rendering, since unstyled `h3` already inherits
the 1.17em UA default.

## What deliberately did *not* migrate

Some rows stay bespoke **on purpose**, not from incompleteness:

- **Password fields** (`ntfyAccessToken`, `githubAuthToken`,
`gitlabAuthToken`) — `SettingsTextRow` hardcodes `type="text"`, so
migrating would have **rendered stored tokens unmasked**.
- **Help text with embedded `<code>`/links** — `descriptor.help` is a
single string; flattening would drop markup or reword copy.
- **`<details>` progressive disclosure** in Merge — a descriptor's help
renders unconditionally, so migrating ~10 rows would delete the
disclosure and produce a wall of prose.
- **Dynamic flag lists** (Experimental) and bespoke editors/CRUD
(Prompts, Agents & Permissions, Plugins, KeyboardShortcuts' capture
widget) — no settings field name and no i18n key to anchor honestly.

## Data-model ambiguities surfaced (not papered over)

These need a human call and are **not** fixed here:

- **Five keys are declared in BOTH `DEFAULT_GLOBAL_SETTINGS` and
`DEFAULT_PROJECT_SETTINGS`**: `worktrunk`, `testMode`, `gitlabEnabled`,
`gitlabAuthToken`, `gitlabAuthTokenType`. No scope badge can be stamped
honestly, so those rows are left bespoke.
- **`globalMaxConcurrent` lives in the *project* blob** despite its
name, its dedicated global endpoint, and the "Global" header it renders
under. Its badge is omitted rather than assert a contradiction.
- **Two settings were editable from two screens**: `gitlabEnabled`
(General + Merge) and `githubTrackingDefaultRepo` (General + Global
General). Both are ambiguous-scope and custom widgets, so deduplication
is left as follow-up.


## Follow-ups from review

**`SettingsTextRow` gained `type`, so the token rows could migrate.** It
hardcoded `type="text"`, which is why every secret-bearing row (ntfy
access token, GitHub/GitLab tokens, the Cloudflare tunnel token) stayed
hand-rolled — migrating would have rendered stored secrets in plain
text. `password` rows now default to `autocomplete="off"` so a browser
never offers to save an API token, and masking is pinned by tests: a
regression there would not throw and would not look wrong in review, the
field would simply render the token.

That also made them findable. Searching "token" previously matched
nothing useful; it now returns 9 settings including *Access token* and
*Tunnel token*:


**Jump-to-field now reveals collapsed disclosures.** Rows inside a
closed `<details>` are in the DOM but invisible, so the jump scrolled to
and highlighted a control the operator could not see. The settings most
worth searching for are exactly the ones behind "Advanced".

**The scope banner is gone.** It claimed one scope for a whole section,
which was false wherever a section mixed them — Appearance is a "global"
nav entry whose task-presentation toggles are all project-scoped.
Per-row badges already say this accurately, so the banner and its dead
CSS are removed.

**Scheduling is split by scope.** `globalMaxConcurrent` moved to its own
`Scheduling · Global` section instead of sitting above the project
settings behind an in-section subheading. One section held two authority
levels, so "does this affect my other projects?" depended on which
subheading you had scrolled past — and a search result landing
mid-section shows no subheading at all.

![Scheduling ·
Project](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/scheduling.png)

**Text-entry padding is now genuinely uniform.** Settings shipped two
input treatments: `.input`/`.select` (6px 10px at 13px) and the global
`.form-group input` rule (8px 12px at 14px). Padding depended on whether
an ancestor happened to be a `.form-group`, and because `.form-group
input` (0,1,1) out-specifies `.input` (0,1,0), naming the standard class
on a nested control did nothing. Measured in-browser after the fix: **51
controls across four sections, one appearance, zero outliers.** The same
specificity trap was silently re-imposing the uppercase/muted label
treatment on migrated rows nested in a `.form-group`; fixed as an
invariant rather than per-row, since sections legitimately keep
`.form-group` around bespoke content.

## Reconciling with #2147 (please review this call)

PR #2147 landed while this branch was open and deliberately moved the
two import auto-translate controls **off** `SettingsToggleRow` onto
`checkbox-label`, pinning that markup with a test written to survive *"a
refactor back onto the primitive"*. Its objection was that the primitive
rendered a right-aligned toggle switch clashing with the section's
native checkboxes — two idioms in one section.

Both halves of that objection are now gone: the primitive renders a
native checkbox **before** its label, and every checkbox in that section
— including the neighbour the test asserts parity against — renders
through it. The idiom split is resolved by migrating all of them rather
than de-migrating these two, so the markup assertions now track the
primitive. **Every behavioural contract from #2147 is kept and still
pinned**, and one was a real bug on this branch: switching
auto-translate off wrote `false` where it must write `undefined`,
leaving an explicit opt-out in the settings blob instead of staying
unset.

#2147's curated translate keywords are preserved for the genuine
vocabulary gaps ("localize", "localization", "foreign language issues")
that appear in no copy. FN-8016's rewritten `taskPopupsBoardListOnly`
copy (default now enabled) is adopted into the migrated row and its
search entry.

Worth noting: #2147's own FNXC says the translate controls were
*"effectively unfindable"* because *"settings search only matches
curated terms plus advertised i18n keys"* — 25 keywords hand-added days
ago. That is precisely the rot this PR's derived index removes.


## Source Control — the duplicate had a cause

GitLab settings were split across **three** sections (General: enable +
URLs; Merge: auth token + type; Global General: all five at global
scope) and GitHub across two. That split is *why* `gitlabEnabled` ended
up writable from both General and Merge — two enable toggles for one
key, last-save-wins.

A `Source Control · Global` / `· Project` pair now owns all 17 keys,
adjacent under Integrations, with **one** GitLab disclosure and **one**
enable toggle:

![Source Control ·
Project](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/source-control.png)

Key ownership moved with them in `section-keys.ts` / `save-split.ts`, so
every key has exactly one owner (`section-keys.test.ts` enforces
disjointness).

**A latent bug surfaced by the move:** nine sites outside the registries
hardcode `"global-general"`/`"general"` and silently gate **scope
routing** — four in `save-split.ts`, five in `SettingsModal.tsx`. Left
stale, global GitLab edits would have been written as project overrides.
Also verified against the schema: **all five `gitlab*` keys AND
`githubTrackingDefaultRepo`** are declared in both defaults (more than
the four originally identified), so those rows carry no scope badge
rather than assert a scope the data model can't support.

## Help moved behind a "?" beside every label

Rendering every description inline turned dense sections into walls of
prose — median help is ~100 chars, some past 400. That pressure is what
made Merge invent its own "More details" disclosure, so one section
showed two idioms. Measured across sections, Merge's help was **not**
unusually long (median 103 vs Appearance's 168, which rendered inline),
so the disclosure wasn't earning its keep.

The copy is deferred **visually, not removed**: the bubble is always
rendered and only fades in, so it stays in the accessibility tree for
`aria-describedby`, stays findable with in-page find, and **the search
index keeps matching on help text**. Errors are never deferred — a
validation message you must hunt for is one you won't see.

Only ~24 of 136 `<small>` blocks were actually row help. The rest stay
inline on purpose and aren't help: validation errors, live status,
empty-state explanations, per-option descriptions inside a multi-select,
and copy explaining *why* a control is disabled.

`children: ReactNode` (not a string) is what let the `<code>`-bearing
and link-bearing rows migrate without rewording your copy — a string API
is precisely why they were hand-rolled before.

### Mobile, verified on a 390px viewport

![Help tip on
mobile](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/mobile-help-tip.png)

Driving a real phone-sized viewport caught two bugs that neither jsdom
nor code review did:

- **Bubble rendered off-screen.** The label line reads "Name [scope] ?",
so the "?" sits well right of centre; anchored to the trigger, the
bubble spanned x=338→658 against a 390px screen — 268px unreachable.
`max-width` clamps width but can't help when the *anchor* is near the
edge. It now anchors to the row (`inset-inline: 0`): re-measured at
x=20→370 inside 390. An earlier comment claimed this behaviour; only the
comment existed.
- **Two bubbles open at once.** Outside-`pointerdown` dismissal misses a
path: `click` fires with **no pointer event** when Enter/Space activates
a focused trigger, so a keyboard user opening a second tip left the
first open underneath. Tips now broadcast on open and close each other;
the regression test asserts the bare-click path specifically.

Also verified on touch: tapping outside dismisses, and opening a second
tip closes the first — no stranded bubbles.

**Checkbox wrapping.** On a 390px viewport a long label ("Keep task
popups on the view where they were opened") stranded its checkbox alone
on line 1, with the text on lines 2-3 and the badge on line 4. The head
was a flex row and the label was a flex ITEM, so once it no longer fit
beside the checkbox the whole label wrapped rather than its text. Label
+ badge + tip now form one group that absorbs the wrapping, leaving the
checkbox as the only sibling item; continuation lines align under the
first word.

Audited every checkbox and radio on all 31 screens at 390px afterwards:
**101 controls, all on the first line of their label text.** (The
audit's first pass flagged 41 — all false positives from measuring
`<label>` elements whose text is a bare text node, i.e. the label box
included the checkbox. Re-measuring the text nodes themselves via Range
cleared them.)



### Every row, including the ones that stayed bespoke

Merge was the last holdout — 18 `<details>` "More details" disclosures
plus 4 inline blocks, an idiom it invented and no other section used.
All 22 now use the same "?":


![Merge](https://raw.githubusercontent.com/Runfusion/Fusion/468f71dfa065be6f46e4fccfe09f18518fbf4e81/shots/merge.png)

Project Models likewise rendered lane help as prose while the global
lanes next door already used the tip; its help now hangs on the existing
lane label row beside the Override/Inherited badge (the badge is live
state and stays visible; the fallback chain behind it is what you open
deliberately).

**Audited all 31 screens programmatically** (label treatments, control
padding, row overflow, leftover banners, horizontal scroll):
- **one label treatment on every screen**, one control treatment, zero
overflowing rows, zero banners, no horizontal scroll
- the copy still rendered inline is deliberately not row help:
validation errors, live status, block descriptions, per-option text
inside multi-selects, and copy explaining *why* a control is disabled

**Known gap:** the three plugin runtime screens (Hermes / OpenClaw /
Paperclip) still render inline help. They delegate to
`HermesRuntimeCard` / `OpenClawRuntimeCard` / `PaperclipRuntimeCard` —
separate card components outside the settings tree — and their copy *is*
genuine row help ("Leave blank to resolve hermes from your PATH"). They
are advanced-only and were left out of this pass rather than swept in at
the end without review.

## Padding and label consistency (measured, not eyeballed)

Two idioms were still visible on one screen — Merge rendered "PLAN
APPROVAL MODE" in caps directly above "Auto-merge conflict retries" in
sentence case. Rows that deliberately stay bespoke inherited the global
`.form-group label` treatment.

| | Before | After |
|---|---|---|
| Label treatments | uppercase/muted/11.5px **and** sentence/14px | **70
labels, one treatment** |
| Control padding | `6px 10px` **and** `8px 12px` | **81 controls, one
treatment** |
| Row gaps | 12 / 16 / 20 by adjacency | **0** — every row owns its
space |

The cause was a specificity trap: `.form-group input` (0,1,1)
out-specifies `.input` (0,1,0), so naming the standard class on a nested
control did nothing. Fixed settings-scoped; the global `.form-group` is
untouched (35 non-settings files depend on it, where uppercase is that
context's convention).

## Advanced settings toggle — verified

Confirmed in-browser after the regroup: **OFF → 15 sections / 5 groups;
ON → 31 sections / 7 groups**, `data-show-advanced` flips, preference
persists. The now-empty **Infrastructure and Advanced group headers are
correctly hidden** when off — the case the regroup could have broken,
since those groups contain only advanced sections.

## Pre-existing failures found (verified NOT caused by this PR)

Each verified by running the identical file on the parent commit and
diffing the **failure sets**, not just the counts:

| Failure | Verified |
|---|---|
| `SettingsModal.scheduling-merge.test.tsx` — 55 failures | identical
set before/after |
| `SettingsModal.remote-notifications.test.tsx` — 16 failures |
identical set before/after |
| `settings-default-descriptions.test.tsx` — `sqliteMigrationNotice`,
`postgresMigrationInboxMessageSentAt` | fails on clean tree |
| i18n `parity.test.ts` — 12 violations
(`settings.general.autoTranslate*`, `taskDetail.plan.*`) | 12 before, 12
after |

**This PR adds zero new failures.**

Fixed along the way: a stale `AppearanceSection` assertion testing copy
FN-7945 deliberately rewrote (failing silently), the ungrammatical "1
matching sections", and `&ldquo;` rendering literally on screen.

## Verification

- `tsc --noEmit -p tsconfig.app.json` → **0 errors** (note: the default
`tsconfig.json` only covers `src/` and does **not** typecheck `app/`)
- `pnpm test:gate` → **63 passed**
- Settings surface → 68 failures, every one a verified subset of the
pre-existing baseline, diffed by failure SET not count (this branch
incidentally fixes 4)
- `pnpm test:gate` 63/63 · lint clean across 83 changed files · `tsc -p
tsconfig.app.json` 0 errors
- Rebased onto `main`: conflicts with #2147 and FN-8016 resolved
- Driven in a real browser at 1440px and 390px: search, jump-to-field,
help tips, advanced toggle, and every migrated section
- Driven in a real browser: search, jump-to-field, highlight, and every
migrated section

🤖 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**
* Settings search now indexes individual settings controls, ranks
matches, and navigates directly to the exact row with a temporary
highlight.
* **UI Improvements**
* Migrated settings sections to shared row primitives
(toggle/select/number/text/textarea) for consistent spacing and
touch-friendly controls.
* Updated typography to a complete tokenized type scale; added the “?”
help tip and tokenized row highlight/error styling.
  * Navigation and search labels now show clear Global vs Project scope.
* **Bug Fixes**
* Improved search accuracy using label/help/keywords and fixed settings
search counts/pluralization and MCP scope labels.
* **Tests**
* Added/updated checks to ensure the settings search index stays
consistent with rendered rows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 22:00:27 -07:00
gsxdsm
b613a87e75 FN-7848: keep GitHub star count visible in mobile Settings header
Restores the GitHub star count pill on mobile Settings, which had been hidden by a prior mobile CSS override, and updates related tests to match.

- Remove the <=768px `display:none` on `.settings-github-star-btn__count` in SettingsModal.css so the count stays visible; only the redundant "Star" label text stays collapsed on mobile to save space (relies on `.settings-modal-heading` min-width: 0 to truncate the title before the pill wraps)
- Add a changeset (`@runfusion/fusion` patch) documenting the fix
- Update settings-mobile.test.tsx with a new regression test asserting the star count stays visible and formatted (e.g. "1.2k") in both the modal and embedded SettingsView on mobile, plus a helper to scan mobile-only CSS media blocks for the absence of the display:none rule, and align existing mobile CSS assertions (section-heading padding, settings-navigation base rule) with current styles
- Update SettingsModal.models-auth.test.tsx version-label assertions ("Version 1.2.3" -> "v1.2.3") and seed `fusion:settings:show-advanced` in localStorage to match current UI

Files changed:
 .changeset/mobile-settings-star-count.md           |  7 +++
 .../dashboard/app/components/SettingsModal.css     |  9 ++-
 .../__tests__/SettingsModal.models-auth.test.tsx   | 12 ++--
 .../components/__tests__/settings-mobile.test.tsx  | 66 +++++++++++++++++++++-
 4 files changed, 82 insertions(+), 12 deletions(-)

Fusion-Task-Id: FN-7848

Fusion-Task-Lineage: 0bbd0e81-6edb-4e9a-884d-b48fcf41f202

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-11 23:18:49 -07:00
gsxdsm
26f0c5ae8a FN-7825: add resizable Settings navigation rail with persisted width
Removes the hard divider between the Settings navigation rail and content, keeps section rows single-line with ellipsis overflow, and adds a draggable/keyboard-resizable handle that persists the rail's width in localStorage across the standalone modal and embedded Settings page.

- Add a resize handle (.settings-nav-resize-handle) between .settings-navigation and .settings-content, draggable via pointer events and resizable with ArrowLeft/ArrowRight when focused
- Persist chosen width to localStorage (fusion:settings-nav-width), clamped between 200px and 420px, defaulting to 248px; restore on mount
- Make .settings-navigation the sole owner of rail width via a --settings-nav-width CSS custom property instead of a fixed width, and drop the border-right divider
- Keep nav section labels on one line with white-space: nowrap + text-overflow: ellipsis in both the modal (SettingsModal.css) and embedded (styles.css) nav item styles
- Hide the resize handle on mobile; mobile keeps the stacked section picker unaffected
- Update docs/dashboard-guide.md to describe the new divider-less rail and resize behavior
- Add SettingsModal.navResize.test.tsx covering drag-resize, keyboard-resize, and width persistence
- Add changeset .changeset/fn-7825-settings-nav-resizable.md (minor)

Files changed:
 .changeset/fn-7825-settings-nav-resizable.md                                    |   7 +
 docs/dashboard-guide.md                                                         |   3 +
 packages/dashboard/app/components/SettingsModal.css                             |  56 ++++-
 packages/dashboard/app/components/SettingsModal.tsx                             | 124 +++++++++-
 packages/dashboard/app/components/__tests__/SettingsModal.navResize.test.tsx     | 268 +++++++++++++++++++++
 packages/dashboard/app/styles.css                                               |  27 ++-
 6 files changed, 467 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-7825
Fusion-Task-Lineage: 34b940b4-2698-46a4-b47c-cda0b0cac564
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-11 18:48:59 -07:00
gsxdsm
11fce4e4bb docs(settings): refresh complete screenshot coverage 2026-07-11 17:03:36 -07:00
gsxdsm
9b22927f3c feat(settings): simplify section details and layout 2026-07-11 17:03:36 -07:00
gsxdsm
19055c6c0e feat(settings): simplify advanced controls 2026-07-11 17:03:36 -07:00
gsxdsm
e4d404ea74 fix(dashboard): keep GitLab disclosure inside settings gutter and stop footer Save clipping
The GitLab Configuration disclosure was the only .settings-content
child without the form-group horizontal gutter, so its bordered box and
right-flushed checkbox leaked to the pane edge. The footer action rail
was a no-wrap flex with zero slack, clipping Save whenever extra footer
content appeared; it now wraps on desktop (mobile scroll rail intact).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:17:29 -07:00
gsxdsm
4d4e9ad5cb FN-7785: reduce margin and padding across mobile Settings pages
Tightens spacing on the Settings modal's mobile (≤768px) layout so pages feel less loose on narrow viewports, and updates mobile settings tests to match.

- Reduce .settings-content scroll container padding and cut section-heading/margin/padding tokens from --space-lg/--space-md down to --space-sm across settings-note, remote-status-bar, remote-share-block, remote-cli-detection, remote-external-tunnel-panel, notification-provider-card, settings-scope-banner, memory-file-summary, settings-description, auth-* rows/cards/hints, and settings-preset-* controls
- Add tighter padding for settings-empty-state and theme-selector, and restructure settings-model-lane-actions spacing (margin-block + padding)
- Update settings-mobile.test.tsx assertions to reflect the new compact spacing values
- Add changeset (patch) documenting the mobile Settings spacing fix

Files changed:
 .changeset/fn-7785-mobile-settings-spacing.md      |  7 +++
 .../dashboard/app/components/SettingsModal.css     | 73 +++++++++++++---------
 .../components/__tests__/settings-mobile.test.tsx  | 43 +++++++++----
 3 files changed, 82 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-7785

Fusion-Task-Lineage: ca9332ea-782d-41de-ba51-010caea9489e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-10 08:26:41 -07:00
gsxdsm
1ba588d707 FN-7773: fix mobile Settings footer spacing to prevent version overlap
Tightens the mobile Settings modal footer rail so Version/Help, Import/Export/Reset, and Save no longer overlap or crowd on small viewports.

- Split modal-header and modal-actions padding rules so the mobile footer uses tighter --space-xs block padding independently of the header
- Center-align modal-actions-left/right, footer version, update-check, and version-check-button on the mobile footer rail
- Make the version text and version-check button non-wrapping inline elements with normalized line-height so they stop overlapping neighboring controls
- Add a settings-modal-version rule as a non-wrapping inline-flex box
- Extend settings-mobile.test.tsx with regression coverage for the tightened mobile footer layout
- Add a patch changeset documenting the fix

Files changed:
 .changeset/fn-7773-mobile-settings-footer.md       |  7 +++
 packages/dashboard/app/components/SettingsModal.css | 55 +++++++++++++++----
 packages/dashboard/app/components/__tests__/settings-mobile.test.tsx | 62 +++++++++++++++++-----
 3 files changed, 103 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-7773

Fusion-Task-Lineage: ea45e7bb-2560-4d17-89dd-9dbc7a307351

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-10 07:30:08 -07:00
gsxdsm
9ce0b49054 FN-7752: tighten mobile Settings modal layout
Squashes FN-7752, improving the mobile Settings modal layout to reduce chrome and simplify section navigation on small screens.

- Replace the mobile section-picker button row with a compact dropdown-only selector, keeping an accessible aria-label
- Slim down the header and footer, collapsing footer actions to a single row on mobile
- Tighten SettingsModal.css breakpoint rules (≤768px) for header/footer sizing and spacing
- Update settings-mobile tests to cover the new dropdown-only picker and single-row footer behavior
- Add changeset documenting the mobile layout fix

Files changed:
 .changeset/fn-7752-mobile-settings-layout.md       |  7 +++
 .../dashboard/app/components/SettingsModal.css     | 62 ++++++++++++++++------
 .../dashboard/app/components/SettingsModal.tsx     | 19 +++++--
 .../components/__tests__/settings-mobile.test.tsx  | 26 +++++++--
 4 files changed, 90 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7752

Fusion-Task-Lineage: 5dea597c-19f7-49c4-979a-7528d84fa6c5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 21:19:40 -07:00
gsxdsm
547740bb66 FN-7751: move mobile settings search toggle inline with section picker
Relocates the mobile-only settings search icon toggle so it sits inline next to the section dropdown instead of its own row above it, tightening the mobile Settings header.

- Move the settings-search-toggle button out of the standalone .settings-search row into a new .settings-mobile-section-picker-control-row alongside the mobile section <select>.
- Preserve FN-7713 expand/hide toggle behavior and active-query preservation; desktop/tablet layout unaffected.
- Add CSS for .settings-mobile-section-picker-control-row to lay out the select and toggle button inline.
- Update settings-mobile tests to assert the toggle renders next to the section picker.
- Add changeset (patch) documenting the fix.

Files changed:
 .../fn-7751-mobile-settings-search-inline.md       |  7 ++
 docs/dashboard-guide.md                            |  4 +-
 .../dashboard/app/components/SettingsModal.css     | 23 ++++--
 .../dashboard/app/components/SettingsModal.tsx     | 89 +++++++++++-----------
 .../components/__tests__/settings-mobile.test.tsx  | 38 ++++++++-
 5 files changed, 105 insertions(+), 56 deletions(-)

Fusion-Task-Id: FN-7751

Fusion-Task-Lineage: 8bb9a32b-80f4-4b73-a366-d23e97106b73

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 20:13:20 -07:00
gsxdsm
21d1201de1 FN-7713: collapse mobile Settings search row behind an expand/hide toggle
Mobile Settings modal now hides the search row by default and exposes a toggle icon to expand/hide it, keeping desktop layout unchanged.

- Add mobile-only searchRowExpanded state and toggle affordance in SettingsModal.tsx
- Add toggle icon styling in SettingsModal.css
- Update dashboard-guide.md docs to describe the new mobile behavior
- Add/extend tests covering the collapsed-by-default state and toggle interaction
- Add changeset (feature, no release wording) for @runfusion/fusion

Files changed:
 .../fn-7713-mobile-settings-search-toggle.md       |   7 ++
 docs/dashboard-guide.md                            |   3 +
 .../dashboard/app/components/SettingsModal.css     |  31 ++++++
 .../dashboard/app/components/SettingsModal.tsx     | 112 ++++++++++++++-------
 .../__tests__/SettingsModal.general.test.tsx       |   7 ++
 .../components/__tests__/settings-mobile.test.tsx  |  69 +++++++++++++
 6 files changed, 192 insertions(+), 37 deletions(-)

Fusion-Task-Id: FN-7713

Fusion-Task-Lineage: 4ce90317-28ce-45b4-a1d7-8fd662a922ae

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 19:58:06 -07:00
gsxdsm
ebf8f87fdb FN-7627: add mobile close button to embedded Settings screen
Adds a close affordance to the embedded Settings header on mobile, since only a bottom nav bar (no sidebar) is available to exit there.

- Render a mobile-only `modal-close` button in the embedded Settings header when `isEmbedded && viewportMode === "mobile"`, wired to the existing `onClose` prop.
- Leave desktop/tablet embedded and the standalone modal presentation unchanged.
- Add regression tests covering the new mobile close button.
- Add a patch changeset documenting the fix.

Files changed:
 .changeset/fn-7627-mobile-settings-close.md        |   7 ++
 .../dashboard/app/components/SettingsModal.css     |  16 +++
 .../dashboard/app/components/SettingsModal.tsx     |  17 +++
 .../__tests__/SettingsModal.mobileClose.test.tsx   | 125 +++++++++++++++++++++
 4 files changed, 165 insertions(+)

Fusion-Task-Id: FN-7627

Fusion-Task-Lineage: b39c7172-bce3-4fb2-9095-58ae376c43ef

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:04:49 -07:00
gsxdsm
b9d60b3c39 FN-7602: fix Record/Clear button overlap in Keyboard Shortcuts rows
Fixes overlapping Record and Clear buttons on the Keyboard Shortcuts settings rows by replacing the icon-only button class with a text button class and locking layout with flex-shrink.

- Swap ShortcutCaptureInput Record/Clear buttons off the icon-only `btn-icon` class (which forced line-height:0 and a 36px mobile square, clipping labels) onto a text-button class
- Add `.shortcut-capture` row CSS with `flex-shrink:0` on controls so the input and buttons never overlap and stack cleanly on mobile
- Add regression tests covering the Keyboard Shortcuts section layout
- Add changeset documenting the fix

Files changed:
 .changeset/fn-7602-shortcut-row-layout.md          |  7 ++
 .../dashboard/app/components/SettingsModal.css     | 17 ++++
 .../settings/sections/ShortcutCaptureInput.tsx     | 14 +++-
 .../__tests__/KeyboardShortcutsSection.test.tsx    | 95 ++++++++++++++++++++++
 4 files changed, 131 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7602

Fusion-Task-Lineage: 50cf6975-f0fb-42dd-87b0-50578977a0f4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-05 18:56:24 -07:00
gsxdsm
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>
2026-07-04 21:28:19 -07:00
gsxdsm
87a700cd4d FN-7506: add scoped settings reset actions
Add a Settings footer reset flow for scoped menu and project-wide defaults.

- Add Reset Settings dialog actions for the active settings menu and all project settings.
- Track section-owned settings keys in a shared scope-aware registry and reuse it for save/reset validation.
- Cover modal/mobile reset behavior, registry invariants, docs, i18n strings, and a release changeset.

Files changed:
 .changeset/fn-7506-settings-reset.md               |   7 +
 docs/dashboard-guide.md                            |  12 +
 .../dashboard/app/components/SettingsModal.css     |  33 +++
 .../dashboard/app/components/SettingsModal.tsx     | 215 +++++++++++++++++-
 .../__tests__/SettingsModal.general.test.tsx       | 145 ++++++++++++
 .../components/__tests__/settings-mobile.test.tsx  |  37 +++-
 .../settings/__tests__/section-keys.test.ts        | 171 ++++++++++++++
 .../app/components/settings/save-split.ts          |   9 +-
 .../app/components/settings/section-keys.ts        | 246 +++++++++++++++++++++
 packages/i18n/locales/en/app.json                  |  11 +
 packages/i18n/locales/zh-CN/app.json               |  11 +
 11 files changed, 886 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7506
Fusion-Task-Lineage: a627e820-fe3b-42c5-adf2-97469bbe7a3b
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 13:36:01 -07:00
gsxdsm
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>
2026-07-04 11:38:42 -07:00
gsxdsm
efa8105036 FN-7495: add settings search
Add a searchable Settings navigation that filters visible sections by setting names and keywords.

- Add a Settings search field with clear and empty-state affordances for desktop and mobile layouts.
- Filter only the already-visible Settings sections while preserving matching group headers and mobile section labels.
- Add searchable section metadata, localized labels, tests, docs, and a release changeset.

Files changed:
 .changeset/fn-7495-settings-search.md              |   7 +
 docs/dashboard-guide.md                            |   5 +
 .../dashboard/app/components/SettingsModal.css     |  97 +++++-
 .../dashboard/app/components/SettingsModal.tsx     | 346 ++++++++++++++++-----
 .../__tests__/SettingsModal.general.test.tsx       |  71 +++++
 .../components/__tests__/settings-mobile.test.tsx  |  25 ++
 .../settings/sections/McpServersCard.tsx           |   2 +-
 packages/i18n/locales/en/app.json                  |  11 +
 8 files changed, 475 insertions(+), 89 deletions(-)

Fusion-Task-Id: FN-7495
Fusion-Task-Lineage: 1d703059-6156-4d20-afbd-3cdb64e3e9f3
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 10:42:20 -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
1d860ec310 feat: global concurrency slider (footer + dashboard) and scoped settings
Add a "Global Max Concurrent" slider to the footer engine menu and the
Command Center Concurrency card, and group the Scheduling settings by
Global vs Project scope so the global cap isn't mistaken for a per-project
setting (clearer on mobile).

Both sliders are backed by a single shared `useGlobalConcurrency` hook
(module-level store) so they read/write one source of truth and revalidate
after every PUT /api/global-concurrency — fixing the last-writer-wins and
stale-clobber races a per-component cache would cause. The hook treats a
fetch error as non-interactive (slider disabled, not stuck at 1), surfaces
a save-state indicator, and flushes a pending edit on menu close / unmount
so a quick drag-then-dismiss is never silently dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 22:19:24 -07:00
gsxdsm
7b60539006 FN-6953: honor unsaved ntfy config in tests
Let ntfy test notifications use the current Settings form values before they are saved.

- Send unsaved ntfy enabled/topic/server/token values from all Settings ntfy test buttons.
- Resolve request-scoped ntfy config on the backend for general, message, and room test notifications.
- Publish message and room ntfy tests directly with the resolved config instead of the active persisted notification service.
- Cover unsaved ntfy test behavior across Settings UI and API routes.

Files changed:
 .changeset/fn-6953-ntfy-test-unsaved-config.md     |   5 +
 .../dashboard/app/components/SettingsModal.css     |   5 +-
 .../dashboard/app/components/SettingsModal.tsx     |  21 +-
 .../components/__tests__/SettingsModal.test.tsx    |  60 +++-
 .../src/__tests__/routes-settings.test.ts          | 181 ++++++++---
 .../src/routes/register-settings-memory-routes.ts  | 355 +++++++++------------
 6 files changed, 380 insertions(+), 247 deletions(-)

Fusion-Task-Id: FN-6953

Fusion-Task-Lineage: 90557168-3b11-4ab4-b5c1-4261225600ba
2026-06-23 16:47:38 -07:00
gsxdsm
f9043d733e fix(dashboard): polish workflow and chrome defaults 2026-06-22 19:48:50 -07:00
gsxdsm
a1cac3a6a3 fix(dashboard): replace quick chat with modal chat 2026-06-22 15:23:43 -07:00
gsxdsm
2505d09771 fix(dashboard): Settings header matches canonical ViewHeader; trim footer bottom spacing
Embedded Settings header now uses the canonical treatment (min-height var(--view-header-min-height), space-lg/space-xl padding, surface bg, 1px divider, var(--todo) icon, 1.125rem/600 title, actions pinned right) — was a transparent no-divider bespoke header. Also trim the embedded footer's padding-bottom so the gap below the Save/Help/Version/Import-Export row matches the gap above it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:00:43 -07:00
gsxdsm
533d10095d feat(dashboard): finish ViewHeader rollout + normalize content padding
- Migrate Insights, Dev Server, Todos, Pull Requests to the shared ViewHeader.
- Fix doubled top padding (ViewHeader already pads top) across Documents/Agents/Mailbox/Missions content areas.
- Nudge embedded-view headers to the shared spec (CommandCenter icon 20; WorkflowNodeEditor icon+1.125rem title+space-lg; Settings embedded icon). ChatView intentionally headerless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 03:34:16 -07:00
gsxdsm
ef8ca55ebf fix(dashboard): embedded main-views keep the mobile header/footer
Scope each converted modal's mobile full-screen/viewport-takeover rules to :not(--embedded) (Settings, GitHub import, Git Manager, Workflows) so the embedded main-content variant fills only the content pane and the app Header + MobileNavBar stay visible on mobile. Modal presentation unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 03:34:16 -07:00
gsxdsm
6719e6195c feat(dashboard): Settings loads as a main-panel view
Add a 'settings' main-content task view: SettingsModal gains a presentation=embedded mode (no overlay/close, modal-only behaviors disabled, CC-style padded header) and a thin SettingsView wrapper. App renders it in renderMainContent (before the overview gate so the gear works with no project); settings entry points navigate to the view (carrying the deep-link section via setSettingsSection) while the modal mount stays for bootstrap callers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 03:34:15 -07:00
gsxdsm
87e87a8f1a FN-6693: enforce dashboard CSS token references
Extend the dashboard CSS token guard and replace stale custom-property references with defined design tokens.

- Add a dashboard-wide CSS token validity test that scans component/app CSS for undefined custom-property references.
- Include dashboard CSS tests in the dashboard Vitest config and document the guard in testing guidance.
- Remap undefined CSS variables across dashboard components and command-center styles to existing semantic or local tokens.

Files changed:
 docs/testing.md                                    |   3 +
 .../dashboard-css-token-validity.css.test.ts       | 165 +++++++++++++++++++++
 .../dashboard/app/components/ActiveAgentsPanel.css |  10 +-
 .../dashboard/app/components/AgentLogViewer.css    |   2 +-
 .../app/components/AgentReflectionsTab.css         |  10 +-
 packages/dashboard/app/components/AgentsView.css   |   6 +-
 .../dashboard/app/components/BranchGroupCard.css   |   6 +-
 packages/dashboard/app/components/ChatView.css     |  12 +-
 .../app/components/CliBinaryInstallBanner.css      |   2 +-
 .../dashboard/app/components/CliBinaryPanel.css    |   2 +-
 .../app/components/ConversationHistory.css         |  12 +-
 .../dashboard/app/components/DashboardLoader.css   |   2 +-
 .../dashboard/app/components/DesktopLaunchGate.css |   4 +-
 .../dashboard/app/components/DirectoryPicker.css   |   2 +-
 .../dashboard/app/components/FileMentionPopup.css  |   4 +-
 .../dashboard/app/components/GitHubImportModal.css |  10 +-
 packages/dashboard/app/components/GoalsView.css    |   2 +-
 .../dashboard/app/components/GroupTaskModal.css    |  18 +--
 packages/dashboard/app/components/InsightsView.css |  10 +-
 packages/dashboard/app/components/Lane.css         |   8 +-
 .../dashboard/app/components/LanguageSelector.css  |   8 +-
 packages/dashboard/app/components/MailboxModal.css |  62 ++++----
 .../app/components/MergeAdvanceNotice.css          |   2 +-
 .../dashboard/app/components/MissionManager.css    |  10 +-
 .../app/components/MobileWorkflowGraphView.css     |   2 +-
 .../app/components/ModelOnboardingModal.css        |  12 +-
 .../app/components/OnboardingDisclosure.css        |   4 +-
 .../dashboard/app/components/PlanningModeModal.css |   2 +-
 .../dashboard/app/components/PluginManager.css     |  58 ++++----
 .../components/PostOnboardingRecommendations.css   |   4 +-
 .../dashboard/app/components/PullRequestView.css   |  32 ++--
 packages/dashboard/app/components/QuickChatFAB.css |   4 +-
 .../dashboard/app/components/QuickEntryBox.css     |   6 +-
 .../dashboard/app/components/ReliabilityView.css   |   6 +-
 packages/dashboard/app/components/ScriptsModal.css |  34 ++---
 .../dashboard/app/components/SessionTerminal.css   |  28 ++--
 .../dashboard/app/components/SettingsModal.css     |   6 +-
 .../dashboard/app/components/SkillMultiselect.css  |   2 +-
 packages/dashboard/app/components/TaskCard.css     |  24 +--
 .../dashboard/app/components/TaskDocumentsTab.css  |   8 +-
 .../dashboard/app/components/TaskFieldsSection.css |  20 +--
 .../dashboard/app/components/TerminalModal.css     |  22 +--
 .../app/components/WorkflowFieldsPanel.css         |   6 +-
 .../app/components/WorkflowNodeEditor.css          |  30 ++--
 .../dashboard/app/components/WorkspaceSelector.css |   2 +-
 .../components/command-center/CommandCenter.css    | 106 ++++++-------
 .../components/command-center/DateRangePicker.css  |  18 +--
 .../command-center/MissionControlPanel.css         |  14 +-
 .../app/components/command-center/SdlcFunnel.css   |   2 +-
 .../command-center/areas/SystemStatsArea.css       |  24 +--
 .../app/components/command-center/areas/areas.css  |  62 ++++----
 .../components/command-center/charts/charts.css    | 104 ++++++-------
 packages/dashboard/vitest.config.ts                |   1 +
 53 files changed, 592 insertions(+), 423 deletions(-)

Fusion-Task-Id: FN-6693

Fusion-Task-Lineage: e9ccf3e6-fee9-47e0-9474-7b5580adbf31
2026-06-19 04:27:01 -07:00
gsxdsm
e8c2d516af FN-6386: add one-click update installation
Add a dashboard update action that installs available Fusion releases directly from the UI.

- Add an install-update API route backed by npm global install with bin-collision retry handling.
- Add Update now controls, loading/error/success states, and responsive styling to the update banner and settings modal.
- Extend localization, documentation, changeset coverage, and update-check tests for the new install flow.

Files changed:
 .changeset/fn-6386-update-now-button.md            |   5 +
 docs/dashboard-guide.md                            |   4 +
 docs/settings-reference.md                         |   2 +
 packages/dashboard/app/api/legacy.ts               |  13 ++
 .../dashboard/app/components/SettingsModal.css     |  38 +++++-
 .../dashboard/app/components/SettingsModal.tsx     |  96 ++++++++++++--
 .../app/components/UpdateAvailableBanner.css       |  46 +++++++
 .../app/components/UpdateAvailableBanner.tsx       | 103 ++++++++++++---
 .../components/__tests__/SettingsModal.test.tsx    |  79 +++++++++++
 .../__tests__/UpdateAvailableBanner.test.tsx       |  57 +++++++-
 .../components/__tests__/settings-mobile.test.tsx  |  19 +++
 .../src/__tests__/update-check-route.test.ts       |  78 ++++++++++-
 .../dashboard/src/__tests__/update-check.test.ts   |  45 +++++++
 .../src/routes/register-update-check-routes.ts     |  25 +++-
 packages/dashboard/src/update-check.ts             |  93 +++++++++++++
 packages/i18n/locales/en/app.json                  |  14 +-
 packages/i18n/src/resources.d.ts                   | 146 ++++++++++++++++++++-
 17 files changed, 819 insertions(+), 44 deletions(-)

Fusion-Task-Id: FN-6386

Fusion-Task-Lineage: bcccf253-c0f1-493e-b849-b189a65d1479
2026-06-13 16:30:28 -07:00
gsxdsm
474b492b26 FN-6027: show and space default workflow model overrides
Expose default workflow model lane overrides directly in project settings.

- load and persist default workflow model lane overrides from the active project workflow
- add inline workflow lane status, reset, save, and advanced policy actions in project model settings
- add CSS contract and modal coverage for the workflow model action row spacing and placement

Files changed:
 .../dashboard/app/components/SettingsModal.css     |  20 ++
 .../components/__tests__/SettingsModal.test.tsx    |  20 +-
 .../SettingsModal.workflow-model-lane-css.test.ts  |  24 ++
 .../settings/sections/ProjectModelsSection.tsx     | 245 ++++++++++++++++++++-
 4 files changed, 298 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-6027

Fusion-Task-Lineage: 981a5f01-f4b7-467e-9e2f-4ac8e4ed40fb
2026-06-08 13:32:58 -07:00
gsxdsm
6c9a81a05f fix(review): apply autofix feedback 2026-06-05 01:53:42 -07:00
gsxdsm
cb9a3f1cc5 feat(settings): surface sweep for the hard-move — export v2 with workflowSettings, sync moved-key filtering, CLI redirect hints, consistency guard 2026-06-04 23:41:30 -07:00
gsxdsm
38ff2ef86d FN-5932: fix research settings containment layout
Keep research settings controls inside their containment wrappers so inputs stay onscreen across breakpoints.

- wrap advanced provider controls in a dedicated research settings body container
- tighten research grid and field min-width behavior in desktop and mobile styles
- add regression coverage for global and project research sections on desktop and mobile

Files changed:
 packages/dashboard/app/components/SettingsModal.css                  |  37 +++++++-
 packages/dashboard/app/components/SettingsModal.tsx                  | 104 +++++++++++----------
 packages/dashboard/app/components/__tests__/SettingsModal.test.tsx   |  65 +++++++++++++
 packages/dashboard/app/components/__tests__/settings-mobile.test.tsx |  48 ++++++++++
 4 files changed, 201 insertions(+), 53 deletions(-)

Fusion-Task-Id: FN-5932

Fusion-Task-Lineage: 22dff41f-b563-40d0-97ea-1ca6d1e09466
2026-06-03 00:49:22 -07:00
gsxdsm
fca6e7f7db FN-5781: move settings Help link to footer version row
Relocate the Settings Help/discussions action from the header controls to the footer version area for clearer placement.

- Remove the Help button from the settings header action group and keep Star/Discord there.
- Add the Help link beside the footer version/update-check section with the same hardened external-link attributes.
- Update Settings modal styling for the new footer help placement and spacing behavior.
- Adjust Settings modal and mobile CSS tests to assert the new Help location and height contract selectors.

Files changed:
 .../dashboard/app/components/SettingsModal.css     | 12 ++++++++----
 .../dashboard/app/components/SettingsModal.tsx     | 22 +++++++++++-----------
 .../components/__tests__/SettingsModal.test.tsx    | 12 +++++++++++-
 .../components/__tests__/settings-mobile.test.tsx  |  4 ++--
 4 files changed, 32 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-5781

Fusion-Task-Lineage: 90fe2f30-c2fe-438b-b486-3b6ef14e21a6
2026-05-31 11:55:11 -07:00
gsxdsm
b6b902485e FN-5779: restore Star on GitHub header button
Restore the Settings header GitHub star CTA while removing its configurability.

- keep the Star on GitHub link in Settings header with refreshed split-pill styling and alignment
- reintroduce GitHub star count fetching/caching and click-tracking helpers used by the header control
- update Settings modal header-action test expectations to include the GitHub star link
- revise the changeset note to reflect removing only the showGitHubStarButton setting/toggle

Files changed:
 .changeset/FN-5777-removal.md                      |   4 +-
 packages/dashboard/app/components/SettingsModal.css     |  51 ++++++++-
 packages/dashboard/app/components/SettingsModal.tsx     | 118 ++++++++++++++++++++-
 packages/dashboard/app/components/__tests__/SettingsModal.test.tsx    |   4 +-
 4 files changed, 170 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-5779

Fusion-Task-Lineage: f485a062-6110-4a79-b42d-70710e3ce5da
2026-05-31 11:55:11 -07:00
gsxdsm
62bc1e4458 FN-5777: remove GitHub star setting and button
Remove the dashboard setting and UI entry points for the GitHub star prompt.

- Remove the Star on GitHub option from settings state types and schema definitions.
- Delete SettingsModal UI, handlers, and styles tied to the star button and related layout.
- Update SettingsModal tests and add a changeset documenting the patch release impact.

Files changed:
 .changeset/FN-5777-removal.md                      |   7 ++
 packages/core/src/settings-schema.ts               |   1 -
 packages/core/src/types.ts                         |   4 -
 .../dashboard/app/components/SettingsModal.css     |  51 +-------
 .../dashboard/app/components/SettingsModal.tsx     | 137 +--------------------
 .../components/__tests__/SettingsModal.test.tsx    |   5 +-
 6 files changed, 13 insertions(+), 192 deletions(-)

Fusion-Task-Id: FN-5777

Fusion-Task-Lineage: 16367ba6-ad22-4ba0-a033-005ccc420c19
2026-05-31 11:55:10 -07:00
gsxdsm
ec92434f4c FN-5765: move settings version check from header to footer
Relocate Settings version/update UI into the modal footer to reduce header crowding.

- Remove the version/update-check control block from the Settings modal header.
- Add a dedicated footer version container and keep the update-check action/result rendering there.
- Update Settings modal CSS for the new footer layout and mobile wrapping behavior.
- Extend mobile tests to verify footer placement and update-check button clickability.

Files changed:
 packages/dashboard/app/components/SettingsModal.css    | 25 +++++++--
 packages/dashboard/app/components/SettingsModal.tsx    | 64 +++++++++++-----------
 packages/dashboard/app/components/__tests__/settings-mobile.test.tsx | 27 ++++++++-
 3 files changed, 77 insertions(+), 39 deletions(-)

Fusion-Task-Id: FN-5765

Fusion-Task-Lineage: 97923f08-e787-4274-a4ce-8b615b909468
2026-05-31 08:32:01 -07:00
gsxdsm
93d3a58cb8 FN-5763: add Discord link next to GitHub star button
Add a Discord CTA in the Settings header alongside the existing GitHub star action.

- Add a Discord header action/link in SettingsModal next to the GitHub star button
- Update SettingsModal styles to support the additional header action
- Extend SettingsModal tests to cover rendering and behavior of the new Discord link

Files changed:
 packages/dashboard/app/components/SettingsModal.css        |  2 ++
 packages/dashboard/app/components/SettingsModal.tsx        | 13 ++++++++++++-
 .../app/components/__tests__/SettingsModal.test.tsx        | 14 +++++++++++++-
 3 files changed, 27 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-5763

Fusion-Task-Lineage: 758eddf8-246c-41be-9742-a9d5b4b0eb17
2026-05-31 08:32:01 -07:00
gsxdsm
23e0593cb1 FN-5668: preserve word-boundary wrapping in mobile settings text
Prevent mobile settings prose from splitting words mid-token while keeping long code snippets overflow-safe.

- add a CSS regression test that inspects the mobile media-query rules in SettingsModal.css
- switch mobile backup code wrapping to overflow-wrap:anywhere with normal word-break
- update mobile settings helper text to keep break-word wrapping with normal word-break

Files changed:
 .../app/__tests__/settings-mobile-wrap.test.ts     | 46 ++++++++++++++++++++++
 .../dashboard/app/components/SettingsModal.css     |  5 ++-
 2 files changed, 49 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-5668

Fusion-Task-Lineage: eb66376e-a535-4d07-adfe-4a2d048b93a7
2026-05-29 08:20:28 -07:00
gsxdsm
916047c2ae feat(dashboard): Integration branch is a dropdown of local branches + Custom…
Replaces the plain text input with a <select> that lists the project's
local branches (loaded via fetchGitBranches when the Merge section
becomes visible) plus an (auto-detect) default and a Custom… option for
branches that don't exist locally yet.

Branch list is deduped + sorted with common integration names (main,
master, trunk, develop) pinned to the top so the typical case is one
click. Choosing Custom… swaps in a text input with a "Use dropdown"
link to revert.

A previously-saved value not in the loaded list (branch deleted
locally, or initial render before fetch resolves) falls through to the
custom input automatically so the operator can still see + edit it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:44:47 -07:00
gsxdsm
d37bebf8bf feat(FN-5516): merge fusion/fn-5516 2026-05-22 17:24:38 -07:00
gsxdsm
ed4d021d3d fix(dashboard): keep mobile nav visible on Android landscape and during keyboard
- Broaden mobile media query to include (max-height: 480px) so landscape
  phones (which exceed 768 CSS px wide) still render the bottom nav and
  mobile board layout instead of desktop horizontally-scrollable columns.
- Guard useMobileKeyboard against pinch-zoom (vv.scale > 1) — Android
  Chrome ignores user-scalable=no, and a focused textarea + zoom was
  false-positiving keyboard-open and hiding MobileNavBar.
- Read documentElement.clientHeight instead of stale window.innerHeight
  when computing keyboard overlap (Android multi-window can leave
  innerHeight cached at a wildly different value than the actual layout
  viewport — observed 2848 while html was 797).
- Add interactive-widget=resizes-content to the viewport meta so Android
  Chrome shrinks the layout viewport with the soft keyboard, matching iOS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:12:36 -07:00
Fusion (runfusion.ai)
252ae24434 feat(FN-5442): add merge mode warning banner to SettingsModal
Added a merge mode warning banner to SettingsModal with styling and visibility tests.

Fusion-Task-Id: FN-5442
2026-05-21 13:06:49 -07:00
Fusion
da339cf3ce feat(FN-4673): complete Step 2 — widen copilot device-code panel
Fusion-Task-Id: FN-4673
Fusion-Task-Lineage: 165601b1-c20c-40d5-addb-3c42d710d66d
2026-05-15 15:14:14 -07:00