Commit Graph

12192 Commits

Author SHA1 Message Date
gsxdsm
58d55d6439 chore(release): v0.74.0-beta.0
Version bump via changesets.
2026-07-24 23:12:53 -07:00
gsxdsm
a03eb0b39c fix(dashboard-tests): green Full Suite after chat tags, TaskForm meta, remote lifecycle
- Replace undefined --space-2xs in ChatView tag menu with calc(--space-xs / 2)
- Stub fetchChatTags/create/rename/delete on streaming-thread api mock for useChat mount
- Expect TaskForm model/tracking callbacks with TaskFormValueChangeMeta source
- Drive remote tunnel lifecycle via one stop then error status (no double Stop race)
2026-07-24 23:02:16 -07:00
gsxdsm
330e4970f0 refactor(release): move the version-anchor package.json rewrite into the shared lib
Makes the re-anchor file mutation unit-testable alongside the anchor decision.
2026-07-24 23:01:11 -07:00
gsxdsm
dba9746287 fix(release): base the next beta on the shipped stable version
After a stable release, main stayed inside the old pre-mode cycle, so the next
beta numbered below the published stable (v0.73.0-beta.7 after v0.73.0) and the
dev checkout kept reporting the last beta.

- beta releases re-anchor a stale pre-mode cycle on the newest stable tag
- both channels refuse a version at or below the newest published stable
- stable promotion now back-merges release into main automatically (fail-soft
  on conflict) so the local dev version is the stable version
2026-07-24 22:59:19 -07:00
gsxdsm
1847d2bc2a chore(release): back-merge v0.73.0 from release
Keeps .changeset/project-switch-modal-reset.md: it was re-edited on main after
the v0.73.0 cut (f9f283293) and covers an unreleased fix.
2026-07-24 22:55:17 -07:00
gsxdsm
3c3acbf769 docs(settings): record why global settings are not all in postgres
Global settings are already split three ways -- values in settings.json, the
revision journal in postgres, and globalMaxConcurrent/defaultProjectId in
central tables -- so the recurring "finish the cutover" proposal keeps getting
re-litigated from scratch.

Write down the two hard constraints (startup-factory reads
embeddedPostgresMaxConnections to start postgres; createFusionAuthStorage is
synchronous and host-agnostic), the recovery argument, and the one real
motivation for a partial move (multi-node policy consistency), plus the
machine-tier vs operator-policy-tier rule for placing new keys.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:46:27 -07:00
gsxdsm
a727e20843 fix(auth): read the Anthropic credential preference from the resolved global dir
Global settings live in settings.json under the resolved global dir, which
falls back to the pre-rename ~/.pi/fusion and ~/.pi/kb dirs for installs that
never migrated. The reader hardcoded ~/.fusion, so on those installs the
operator's preference was silently ignored and resolution fell back to raw-key
precedence -- the same silent fallback the preference exists to remove.

Mirror the legacy-aware lookup getModelRegistryModelsPath already does for
models.json rather than importing core's resolver, which throws under VITEST
when called without an explicit dir.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:38:15 -07:00
gsxdsm
190cc041bc fix(lanes): resolve a model pair everywhere a session is constructed
Audit of the class behind the planning bug: createFnAgent forwards no model
unless both defaultProvider and defaultModelId are set, after which
pi-coding-agent picks its own built-in default (anthropic/claude-opus-4-8).
Seven lanes resolved no pair at all, so they hit that path on every call --
a permanent 401 invalid x-api-key for custom-provider and subscription
operators, and a hole in test-mode forcing:

- milestone/slice interviews (no model plumbing at all)
- subtask breakdown, triage and streaming paths
- agent generation
- text refine and goal drafting
- agent reflection (optional ctor pair no production caller supplies)

Two more resolved the halves independently, which the runtime treats as
unset: research synthesis defaults and pr-conflict-resolver's hand-rolled
copy of resolveProjectDefaultModel (which also skipped test-mode overrides).

Add lane-session-model.ts as the shared resolver and a source ratchet that
fails when a dashboard session is constructed from an inline literal with no
model decision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:32:49 -07:00
gsxdsm
8dc6598aa0 feat(auth): let operators choose which Anthropic credential wins
An operator can hold a raw Anthropic API key and a Claude subscription OAuth
login at once, and the raw key always won silently. A stale or revoked saved
key therefore shadowed a working subscription and failed every direct Anthropic
call with 401 invalid x-api-key, while both Settings cards still read Active.

Add the global anthropicAuthPreference setting ("api-key" default, preserving
the historical precedence, or "subscription"), read in resolveAnthropicRuntimeApiKey
straight from ~/.fusion/settings.json so it applies without a restart and needs
no settings plumbing through createFusionAuthStorage. Neither value removes a
source: with one credential configured, resolution reaches it either way.

Settings -> Authentication now names the credential in use on the two Anthropic
cards and renders the control, but only when both are actually connected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:32:39 -07:00
gsxdsm
8156308695 feat(quick-add): show a visible Start button for waiting-column workflows
Replace the hidden long-press/right-click Start menu on Quick Add's Save with a
visible Start button in the action row, rendered only for workflows whose first
visible lane is a hold column (or Coding (Ideas)). Eligibility, the workflow
snapshot, the create-time column override, and the hold-first follow-up move are
unchanged; ineligible workflows render no Start chip or shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:32:30 -07:00
gsxdsm
1959e7c02c fix(planning): keep the selected model pair on rebuilt planning agents
ensureSessionAgent rebuilt the agent with an empty provider/model pair while
preserving draftThinkingLevel, so resumed turns (respond, retry, rewind, drafts
resumed after the in-memory agent was dropped) fell through to the runtime's
built-in default model (anthropic/claude-opus-4-8) and hit api.anthropic.com
with a key the operator never configured. The non-streaming start had the same
hole. Resolve the pair from the persisted draft, then the lane's settings, on
every rebuild and start.

Also route planning through createResolvedAgentSession like chat/executor/merger
so CLI and plugin runtimes can own their own auth and planning emits
session:runtime-resolved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:17:39 -07:00
gsxdsm
e01dc7d3d3 feat(board): speed up kanban scrolling and drop desktop snapping
Desktop board scrollers no longer snap: the browser's proximity-snap settle
animation was capturing wheel/trackpad pans and reading as a slow, sticky drag
toward a column center. Base `.board`, `.board-workflow-columns`, and
`.lane-columns` declare `scroll-snap-type: none`; proximity snap is re-declared
in phone-tier media blocks only, where the JS column pager owns paging.

On phones, the hook now owns post-lift motion instead of waiting it out. A
directional lift kills native inertia and animates to its target column via rAF
ease-out (~190-300ms), so the page starts moving on lift rather than after a
native fling that can coast for most of a second. Fling reach is preserved by
deriving a page count (1-3) from release velocity sampled off the board's own
scroll ticks, not from however far inertia happens to travel.

Guards: re-touch cancels the animation and hands the axis back to the finger;
reduced motion, missing rAF, and sub-2px distances fall back to the instant hard
jump; unmount mid-animation restores the frozen inline styles; a fast drag that
rests before lifting is not treated as a flick.

Tap-to-stop-during-momentum is gone as an interaction (no long coast remains to
interrupt). Its regression test is reframed around the equivalent seam: a drag
that interrupts the page animation wins over the pending page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 22:16:11 -07:00
gsxdsm
4b4df1ff30 FN-8565: restore tablet task modal resizing
Restore resizable Task Detail and New Task windows on 768px touch tablets.

- Classify known touch tablets separately from phone sheets
- Restore bounded modal geometry and resize grips with keyboard support
- Add regression coverage, documentation, and a patch changeset

Files changed:
 .changeset/fn-8565-tablet-task-modal-resize.md     |  7 +++
 docs/dashboard-guide.md                            |  5 ++
 .../task-detail-modal-tablet-width.test.ts         | 15 +++++
 packages/dashboard/app/components/NewTaskModal.css | 18 +++++-
 packages/dashboard/app/components/NewTaskModal.tsx | 44 +++++++++++++-
 .../dashboard/app/components/TaskDetailModal.css   | 30 ++++++++++
 .../dashboard/app/components/TaskDetailModal.tsx   | 40 +++++--------
 .../app/components/__tests__/NewTaskModal.test.tsx | 68 +++++++++++++++++++++-
 ...etailModal.responsive-and-dependencies.test.tsx | 51 ++++++++++++++++
 .../hooks/__tests__/useModalResizePersist.test.tsx | 53 ++++++++++++++++-
 .../dashboard/app/hooks/useModalResizePersist.ts   | 58 +++++++++++++++---
 11 files changed, 352 insertions(+), 37 deletions(-)

Fusion-Task-Id: FN-8565

Fusion-Task-Lineage: 7d9bbeb9-0e6a-4ad9-8b4d-e9f3d8aef650

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 19:20:16 -07:00
gsxdsm
e3dba364d1 FN-8564: update bundled Pi runtime to 0.82.0
Update Fusion's matched Pi dependencies and compatibility coverage for version 0.82.0.

- Pin Pi AI and coding-agent packages to the exact 0.82.0 release pair.
- Refresh provider catalog, supplemental model, auth storage, and Droid thinking coverage.
- Add the published CLI patch changeset.

Files changed:
 .changeset/fn-8564-pi-082.md                       |   7 +
 packages/cli/package.json                          |   4 +-
 packages/cli/src/__tests__/package-config.test.ts  |   2 +-
 packages/core/package.json                         |   2 +-
 packages/dashboard/package.json                    |   2 +-
 ...ister-model-routes-kimi-k3-supplemental.test.ts |   6 +-
 packages/engine/package.json                       |   4 +-
 .../src/__tests__/provider-registration.test.ts    |   4 +-
 packages/engine/src/auth-storage.ts                |  11 +-
 packages/engine/src/pi.ts                          |   6 +
 packages/pi-claude-cli/package.json                |   8 +-
 .../src/thinking-config.ts                         |  10 +-
 pnpm-lock.yaml                                     | 176 +++++++++++----------
 pnpm-workspace.yaml                                |   6 +-
 .../__tests__/check-pi-versions-pinned.test.mjs    |   8 +-
 15 files changed, 142 insertions(+), 114 deletions(-)

Fusion-Task-Id: FN-8564

Fusion-Task-Lineage: 543c5e17-4cb2-446f-9a1c-ec7ec8b8117a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 19:06:14 -07:00
gsxdsm
c50e303a94 fix(viewport): keep large phones in mobile mode so the bottom nav renders
FN-8557 excluded any touch device from mobile mode when its reported physical
screen exceeded the 480px phone threshold, at any CSS width. Large Android
phones report exactly that, so they resolved to tablet: MobileNavBar returns
null off mode "mobile", while MobileNavBar.css still displayed at
(max-width: 768px) — JS and CSS disagreeing about the same device. The board
also fell back to the horizontally-scrollable desktop layout.

No tablet uses a <=600px viewport as its primary layout, so width now
overrides the physical-screen heuristic below that floor; the carve-out
FN-8557 wanted (portrait tablets at the 768 boundary) keeps the 601-768 band.

The floor checks all three width signals the classifier already trusts —
media query, innerWidth, visualViewport — since each can lead on a different
device or update late on rotation. Regression tests cover all three; each
fails against the pre-fix classifier.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 18:54:27 -07:00
gsxdsm
749167cbed fix(engine-controls): surface a paused engine instead of showing it as idle
A paused engine with nothing running derived executorState "idle", so the
footer badge was indistinguishable from a healthy engine waiting for work.
That is exactly the state a pause settles into once in-flight tasks drain:
triage and planning stall while the board keeps moving, with the pause only
visible by opening the Engine Control menu. Pause state now dominates run
state; the adjacent counters still report throughput.

In the CLI TUI, the global `t` (Git view) branch returned before the Utilities
dispatch in the same key handler, so the advertised "[t] Toggle Engine Pause"
was unreachable dead UI. It now yields when Utilities owns input, and because
the shortcut can stop the board, pausing takes a second `t` within 5s while
resuming stays single-press.

Tests assert the invariant across the whole state matrix (both pause flags x
0/1/5 running), not just the zero-running repro, plus the TUI routing, the
two-press pause, single-press resume, and re-arm behavior.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 18:49:19 -07:00
gsxdsm
f3a69497dc FN-8563: preserve new task edits before defaults load
Treat asynchronous New Task defaults as pristine while retaining operator changes for discard confirmation.

- Track initialization versus user writes for workflow steps, models, and GitHub defaults
- Prevent delayed model auto-preset selection from overwriting an operator-selected custom model
- Cover blank-modal close paths and the delayed-settings custom-model regression

Files changed:
 .changeset/fn-8563-pristine-new-task-close.md      |   7 ++
 packages/dashboard/app/components/NewTaskModal.tsx |  68 +++++++++--
 packages/dashboard/app/components/TaskForm.tsx     |  58 ++++++---
 .../app/components/__tests__/NewTaskModal.test.tsx | 134 +++++++++++++++++++++
 4 files changed, 235 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-8563

Fusion-Task-Lineage: d70c1e41-37b4-4cb6-bcf7-9bd7dd64ac39

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 18:43:29 -07:00
gsxdsm
cc053915f3 test(dashboard-tests): drive SettingsModal auto-save retry/trailing tests with fake timers
Two auto-save tests waited out the real 500ms debounce via waitFor (up to two
cycles each), unlike the sibling coalesces test which already uses fake timers.
Switch both to vi.advanceTimersByTimeAsync(500) to remove ~1.7s of wall-clock
dead time from the dashboard's slowest feedback-loop suite with identical
coverage (Standing Rule: prefer fake timers over real time waits).
2026-07-24 18:11:24 -07:00
gsxdsm
a9d5b06013 FN-8562: add tags to chat conversations
Enable project-scoped reusable tags for Direct chat sessions.

- Add tag storage, migrations, and scoped assignment APIs.
- Add chat sidebar tag creation, assignment, and filtering controls.
- Document tag behavior and cover schema and chat interactions.
- Establish the session project/id candidate key before creating scoped tag foreign keys.

Files changed:
 .changeset/fn-8562-chat-conversation-tags.md       |   7 ++
 docs/dashboard-guide.md                            |   4 +
 docs/storage.md                                    |   2 +
 .../src/__tests__/postgres/schema-applier.test.ts  |   8 +-
 packages/core/src/async-chat-store.ts              | 117 ++++++++++++++++++++-
 packages/core/src/chat-store.ts                    |  32 ++++++
 packages/core/src/chat-types.ts                    |  14 +++
 packages/core/src/index.gate.ts                    |   3 +
 packages/core/src/index.ts                         |   3 +
 .../postgres/migrations/0036_chat_session_tags.sql |  64 +++++++++++
 packages/core/src/postgres/schema-applier.ts       |  16 ++-
 packages/core/src/postgres/schema/project.ts       |  34 ++++++
 packages/dashboard/app/api.ts                      |   1 +
 packages/dashboard/app/api/chat.ts                 |  18 ++++
 packages/dashboard/app/components/ChatView.css     |  17 +++
 packages/dashboard/app/components/ChatView.tsx     |  70 +++++++++++-
 .../__tests__/ChatView.core-interactions.test.tsx  |  27 +++++
 .../dashboard/app/hooks/__tests__/useChat.test.ts  |   1 +
 packages/dashboard/app/hooks/useChat.ts            |  52 ++++++++-
 .../dashboard/src/routes/register-chat-routes.ts   |  70 ++++++++++++
 20 files changed, 550 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-8562

Fusion-Task-Lineage: 4efe798c-0865-451a-adbd-6b85f9f8b149

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 18:09:32 -07:00
gsxdsm
03cfc2dfc8 FN-8561: add lifecycle dates to task cards
Show localized creation and completion dates directly on task cards.

- Render compact, locale-aware lifecycle timestamps with accessible full-date titles.
- Persist archive timestamps for completed archived-task fallbacks and add coverage.
- Add translated labels, documentation, and a minor release changeset.

Files changed:
 .changeset/fn-8561-task-card-dates.md              |  7 +++
 docs/dashboard-guide.md                            |  1 +
 .../__tests__/archive-entry-serialization.test.ts  | 35 ++++++++++++++
 packages/core/src/task-store/serialization.ts      |  8 ++++
 packages/core/src/types/task-core.ts               |  5 ++
 packages/dashboard/app/components/TaskCard.css     | 27 +++++++++++
 packages/dashboard/app/components/TaskCard.tsx     | 55 ++++++++++++++++++++++
 .../__tests__/TaskCard.host-inventory.test.tsx     | 21 +++++++++
 .../app/components/__tests__/TaskCard.test.tsx     | 17 +++++++
 .../dashboard/app/i18n/__tests__/format.test.ts    | 19 +++++++-
 packages/dashboard/app/i18n/format.ts              | 38 +++++++++++++++
 packages/i18n/locales/en/app.json                  |  4 ++
 packages/i18n/locales/es/app.json                  |  4 ++
 packages/i18n/locales/fr/app.json                  |  4 ++
 packages/i18n/locales/ko/app.json                  |  4 ++
 packages/i18n/locales/zh-CN/app.json               |  4 ++
 packages/i18n/locales/zh-TW/app.json               |  4 ++
 17 files changed, 256 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8561

Fusion-Task-Lineage: 474b949b-d8e7-469a-b564-00acae66e58a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 11:15:43 -07:00
gsxdsm
ab41554980 fix(cli-tests): load task.js once for lock-retry suite under real timers
Full Suite shard 4 timed out runTaskShow lock-exhaustion at the default 5s
budget (run 30096660913): each case re-imported the heavy task.js graph under
fake timers, so cold CI workers spent the whole budget on transform and left
unhandled store.getTask / process.exit races after the timeout.

Import task.js once per cached-store describe under real timers via a mutable
store holder, and enable fake timers only around the backoff body. Exhaustion
cases now finish in ~1ms locally while keeping the shipped entry path.
2026-07-24 08:27:57 -07:00
gsxdsm
6166b496e4 FN-8559: refresh test timing snapshots
Refresh timing data and keep velocity reports aligned with the current snapshot.

- Attribute CI timing reports from absolute checkout paths
- Render report-only slowest tests from the latest timing snapshot
- Update timing snapshot data and regression coverage

Files changed:
 scripts/__tests__/ci-test-shard-timings.test.mjs  |    9 +
 scripts/__tests__/test-velocity-baseline.test.mjs |   38 +
 scripts/ci-test-shard.mjs                         |   13 +
 scripts/test-timings.json                         | 2522 +++++++++++++--------
 scripts/test-velocity-baseline.mjs                |   33 +-
 5 files changed, 1616 insertions(+), 999 deletions(-)

Fusion-Task-Id: FN-8559

Fusion-Task-Lineage: 09ed6b78-f82f-4732-a5e3-1066efe385b3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 06:21:53 -07:00
gsxdsm
c5a8421533 FN-8560: forward desktop test telemetry flags
Desktop test execution now preserves CI reporter and JSON output flags.

- Forward caller-selected Vitest reporters and output files through the desktop test wrapper.
- Add coverage for reporter syntax and shard timing command forwarding.
- Document desktop timing artifact requirements.

Files changed:
 docs/testing.md                                    |  7 ++++-
 packages/desktop/scripts/__tests__/test-args.test.ts | 36 ++++++++++++++++++++++
 packages/desktop/scripts/test-args.ts              | 13 ++++++++
 packages/desktop/scripts/test.ts                   |  3 +-
 scripts/__tests__/ci-test-shard.test.mjs           |  9 ++++++
 5 files changed, 66 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8560

Fusion-Task-Lineage: 2a89b28d-39f6-4949-aec2-1123c36126cf

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 05:30:45 -07:00
gsxdsm
19f25f9a35 fix(dashboard-tests): align SettingsModal suites with FN-8453 and #2400; de-race worktree copy-files save
- general: FN-8453 removed the duplicate "Max Triage Concurrent" control
  (assert it stays gone); #2400 replaced the per-phase moved-to-workflow note
  with the editable "Project workflow model lanes" section.
- scheduling-merge: await the updateSettings call that carries
  worktreeCopyFiles instead of assuming calls[0] (CI lane-load ordering).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 03:11:22 -07:00
gsxdsm
c60b6bf2f7 fix(dashboard-tests): harden planning-browser-e2e Chromium launch for CI runners
On GitHub runners headless system Chrome dies at launch without --no-sandbox
and --disable-dev-shm-usage, cascading all five tests as "browser has been
closed" (run 30081843074). The lane had been masked by the shard-4 watchdog
kill since the file landed, so it had never actually executed on CI. Flags
apply only under CI; local launches keep the default sandbox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 02:39:18 -07:00
gsxdsm
12fa85eefb fix(dashboard-tests): finish the FN-8491 mock backlog; contain FN-8557 innerWidth leakage
Nine more api-lane files get the established getProjectScopedPluginMcpServers
stub (includes shared-branch-group-entry-points, whose two current failures
were FN-8491 500s — the historical per-task-derived pair is gone). App lane:
FN-8557 made window.innerWidth<=768 a mobile signal, so leaked innerWidth=375
defineProperty stamps flipped later ListView/settings tests into mobile
layout (reset in beforeEach), and useModalResizePersist's 700px "mobile"
fixture became tablet-class (now a phone-class 375px viewport).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 02:14:26 -07:00
gsxdsm
16d30ee7b0 fix(dashboard-tests): clear the FN-8491 plugin-MCP mock backlog unmasked by the watchdog fix
The core watchdog kill had been hiding everything scheduled after it in
shard 4; with the budget fixed, 15 api-lane files surfaced. Thirteen needed
the established FN-8491 recipe (mock stores expose
getProjectScopedPluginMcpServers so the binder short-circuits). Also:
mcp-lane-forwarding tracks resolveManualAiPromptMcpServers' move to
automation-step-execution and FN-8538's getSettings on planning stores;
planning-answered-question-reemit handles PR #2417's synchronous single-turn
admission with a bounded onceAdmitted retry (admission rejections are
side-effect free); routes-system tracks getProjectPluginLoader resolution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 01:33:29 -07:00
gsxdsm
cdc5b7f901 fix(dashboard-tests): settle canvas hydration before the edge-targeted optional-group pick
Full-suite run 30077108784 hit an additive insert under CI lane load (group
spliced while merge→end survived) because the toolbar pick ran before the
canvas settled its edge-target state; 5/5 green locally. Same
settle-before-interact class as 5a5796bca; recurrence goes to quarantine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 01:20:43 -07:00
gsxdsm
973c978f91 FN-8557: preserve terminal geometry on tablets
Keep floating terminal controls available on touch tablets across responsive and keyboard viewport changes.

- Classify known tablet screens separately from phone fallbacks.
- Restore tablet floating and docked geometry at the 768px breakpoint with larger touch resize targets.
- Cover keyboard-shrunken and breakpoint tablet interactions, and document the responsive behavior.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 .../dashboard/app/components/TerminalModal.css     |  76 +++++++++--
 .../dashboard/app/components/TerminalModal.tsx     |  33 ++---
 .../components/__tests__/TerminalModal.test.tsx    | 150 +++++++++++++++++++++
 .../app/hooks/__tests__/useViewportMode.test.ts    |  14 ++
 packages/dashboard/app/hooks/useViewportMode.ts    |  33 ++++-
 6 files changed, 277 insertions(+), 31 deletions(-)

Fusion-Task-Id: FN-8557

Fusion-Task-Lineage: cd334682-e70a-4531-ab53-c5c0898f0bf1

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 00:59:42 -07:00
gsxdsm
c5e9a7956a fix(ci): stop watchdog false-kills of the grown core slice; actually upload timing artifacts
- Shard watchdog floor 25min (was 15): the July PG-cutover test growth pushed
  @fusion/core past 900s on contended CI runners; run 30075604930 killed a
  healthy core run at exactly the floor because the 27-day-old (still "fresh")
  undercounting timings snapshot tightened the budget to it — the same
  false-kill class as the 5->15min raise. Floor pin + in-band example updated.
- full-suite.yml timing upload: include-hidden-files — the .timings/ dot-dirs
  were silently excluded by upload-artifact@v4, so the step has uploaded
  nothing since it was added and the snapshot could never be refreshed from CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 00:55:38 -07:00
gsxdsm
e4fc3d2acb FN-8558: enlarge Quick Chat tablet drag target
Make the floating Quick Chat header easier to drag on tablet viewports.

- Increase only the floating Chat header touch target in the tablet viewport band.
- Cover floating header controls for empty and populated chats and scope the CSS contract.
- Add a patch changeset for the Quick Chat usability fix.

Files changed:
 .changeset/quick-chat-tablet-drag-header.md        |  7 ++++
 packages/dashboard/app/components/ChatView.css     | 13 +++++++
 packages/dashboard/app/components/__tests__/ChatView.mobile.test.tsx  | 41 ++++++++++++++++++++++
 packages/dashboard/app/components/__tests__/FloatingWindow.test.tsx   | 20 +++++++++++
 4 files changed, 81 insertions(+)

Fusion-Task-Id: FN-8558

Fusion-Task-Lineage: 2d2f788b-b417-4fa3-b066-8790858b393a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 00:46:44 -07:00
gsxdsm
c3cebcd56b FN-8556: fix Windows agent target selection
Make direct-chat Agent selection reliable when Windows Electron suppresses the click after pointer activation.

- Switch target mode on primary pointerdown while retaining keyboard activation.
- Expose selected Model and Agent modes with aria-pressed semantics.
- Cover pointer activation and persistence across direct-chat layouts.
- Add a patch changeset for the Windows selection fix.

Files changed:
 .changeset/fn-8556-windows-agent-selection.md      |  7 ++++
 .../app/components/ChatThinkingLevelControl.tsx    | 28 ++++++++++++-
 .../__tests__/ChatThinkingLevelControl.test.tsx    | 27 +++++++++++--
 .../__tests__/ChatView.thinking-level.test.tsx     | 46 +++++++++++++++++-----
 4 files changed, 93 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-8556

Fusion-Task-Lineage: 25b06177-3b59-4d2d-8440-e92fe7172259

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-24 00:35:34 -07:00
gsxdsm
f6795317a8 fix(dashboard-tests): useTasks column normalization asserts the post-cutover contract
b2a7425c7 replaced the six-legacy-id whitelist with normalizeColumnId: custom
workflow column ids pass through untouched, only structurally unusable values
(non-string/empty) fall back to triage. The two normalization tests now assert
both halves of that invariant instead of the deleted whitelist behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 00:28:55 -07:00
gsxdsm
94f1bd9527 fix(dashboard-tests): align remaining ChatView send assertions with FN-8502 delivery callbacks
Same drift as chat-commands/mobile: sendMessage gained the {onDelivered,onFailed}
third argument; autosize and draft suites now expect it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 00:09:44 -07:00
gsxdsm
fa6e4fef22 fix(dashboard-tests): satisfy FN-8491 plugin-MCP store contract across route suites; align planning create-task envelope
- routes-auth/automation/git/github/tasks: FN-8491 binds the plugin-MCP
  provider on every project-context resolution; mock stores now expose
  getProjectScopedPluginMcpServers so routes stop 500ing.
- routes-github: stub FN-8442 durable planning-claim plumbing whose internal
  getSession bypassed the namespace spy; the scoped-store routing contract
  is asserted unchanged.
- api-git: POST /planning/create-task now returns the FN-8442
  {task, alreadyCreated} envelope; mock matches.
- TaskDetailModal.tab-persistence: settle-then-requery before clicking the
  Session tab (detached-node race under CI load).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 23:51:29 -07:00
gsxdsm
74236211ea fix(dashboard): repaint stalled terminal renderer so first shell prompt shows without a keypress
On some systems the terminal opened blank — buffered prompt present but
never painted (renderer stalled at init: WebGL activation on a zero-sized
canvas or context-loss fallback). Every automatic recovery path fit() but
never refreshed, and fit() with unchanged cols/rows triggers no internal
xterm repaint, so only user input, a font-size change, or a new tab
repaired it. Observer/geometry-driven fits in TerminalModal and
SessionTerminal now always follow fit() with an explicit full-viewport
terminal.refresh(0, rows-1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 23:51:12 -07:00
gsxdsm
d7752931b0 fix(dashboard-tests): align remote-access mock store with FN-8491, ChatView mobile with FN-8502, and de-race planning claim tests
- remote-access-routes: FN-8491 made every project-context resolution call the
  plugin-MCP binder; the mock store now satisfies the runtime-owned-store guard.
- ChatView.mobile: sendMessage gained the FN-8502 {onDelivered,onFailed} arg.
- PlanningModeModal.planning-flow: settle-then-requery before clicking Proceed
  (detached-node race under CI load, same class 5a5796bca fixed for Stop/Refine)
  and await the create-dispatch mock signal instead of the DOM alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 23:09:59 -07:00
gsxdsm
da0d73c853 fix(release): give desktop closure staging 30min in bun binary builds
The CLI full-package build's nested @fusion/desktop build stages the
production closure via pnpm deploy (~1300+ packages); on cold-store macOS
release runners that exceeded runWorkspaceCommand's default 10-minute
timeout and killed every v0.73.0-beta.* bun-darwin-arm64 release leg with
exit 143. Raise the desktop sub-build budget to 30 minutes and widen the
build-binaries job timeout to 45 minutes to match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:56:52 -07:00
gsxdsm
f9f2832936 fix(dashboard): dismiss popped-out/main-panel/dock task detail and Quick Chat on project switch
Task detail does not always render through modalManager.detailTask: with
Open tasks as popups it opens as FloatingWindows, with the right-sidebar
setting it opens in the right dock, and changes-tab opens use the
main-panel task-detail view. None of those were closed by
closeProjectScopedModals, so switching projects left the previous
project's task windows over the new project — and the Quick Chat
floating window (App state) stayed open the same way.

useProjectActions now receives a composite App-level reset (via a stable
ref, since the dock and main-panel pieces are constructed later in App)
that closes project-scoped modals, all popped-out task windows (new
usePoppedOutTasks.closeAll), main-panel task detail when present, the
right-dock task, and Quick Chat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:53:04 -07:00
gsxdsm
127b640b3f chore(release): v0.73.0
Version bump via changesets.
2026-07-23 22:43:43 -07:00
gsxdsm
ec535b5f3c fix(dashboard-tests): stub Element.prototype.scrollIntoView in SystemControlsArea suite
The rebuild-job effect schedules jobSectionRef scrollIntoView in a rAF; jsdom
elements lack the method, so a frame firing before unmount threw an unhandled
error that failed the run even with all assertions passing. Module-level stub
follows the ChatView.message-edit convention; the per-test spy still overrides it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:37:38 -07:00
gsxdsm
e17151cba5 fix(cli-tests): align CLI suite with inbox-mail help, beta versions, and planning-session store
Stale-test drift, no product changes: FN-8424 inbox reply help text and
fn message inbox --user routing, beta-track prerelease suffixes in version
regexes (0.73.0-beta.N), FN-8399 onMigrationProgress in createTaskStoreForBackend,
#2400 workflow-docs heading, and the durable planning-session store mocks for
fn task plan (0412113de/fdd120232).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:35:12 -07:00
gsxdsm
593f38249c chore(release): v0.73.0-beta.6
Version bump via changesets.
2026-07-23 22:16:37 -07:00
gsxdsm
0a6f84bbdf fix(dashboard): index the FN-8348 Report row in settings search; re-green backfill test lane
Product fixes surfaced by the drift guards:
- GeneralSection.search.ts: FN-8348 added the Report row (bug/feedback/idea/help)
  without a search-index entry, so settings search could not find it.
- WorkflowNodeEditor.css: FN-8526 introduced the undefined deprecated alias
  --text-secondary; substitute the FN-8043 migration token --text-muted.

Stale-test alignment (no assertions weakened):
- settings-sections: builtin:coding-ideas is no longer deprecated post-#2378.
- TaskDetailModal workflow/oversight suites: mocked workflows gain the columns
  array FN-8476 metadata resolution requires; rerender-refetch tests use
  persistent mocks since the board-workflows effect now keys on task identity.
- ChatView.chat-commands: sendMessage gained the FN-8502 delivery-callback arg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:13:25 -07:00
gsxdsm
1d4cd27c73 fix(tests): give PG-harness plugin suites the 15s timeout the golden-template harness budgets for
The shared pg-test-harness pays the golden schema-template cold start inside
the first PG test of each vitest invocation and is budgeted against core's 15s
testTimeout, but the six PG-consuming plugin packages ran at vitest's 5s
default — on saturated CI runners the first PG test (e.g. whatsapp-chat
persistence.pg) timed out before its assertions ran. Propagate the 15s budget
to all six plugin configs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:09:51 -07:00
gsxdsm
d8b5ef62db fix(dashboard): key Chat, Missions, and GitHub Import by project against cross-project leaks
Audit follow-up to the Planning/subtask project-switch fixes — three more
surfaces had the same bug class:

- Embedded ChatView survived a project swap when both projects last used
  the chat view: useChat refetched the session list on projectId change
  but never reset activeSession/messages or closed the live stream, so
  project A's conversation kept rendering (and streaming) under project B.
  Now keyed by project like Quick Chat's FN-8257 FloatingWindow key.
- MissionManager's nested always-mounted MissionInterviewModal (and the
  interviewTarget-driven MilestoneSliceInterviewModal) reconnected the
  previous project's interview session under the new projectId and saved
  the goal draft under the new project's kb-mission-last-goal key.
  MissionManager is now keyed by project; the interview modal saves an
  un-started goal draft on unmount under its own project id.
- Always-mounted GitHubImportModal's persist effect depends on projectId,
  so a swap re-fired it with the old project's provider/labels/repo
  selections and wrote them under the new project's storage key. Now
  keyed by project (the embedded Import Tasks view already unmounted).

Verified SAFE without changes: TaskDetail/Group/Files/WorkflowNodeEditor
(conditionally rendered + closed on swap), Settings/Usage/Schedules/
Agents (cross-project by design or self-correcting projectId-keyed
hydration), and the remaining embedded views (projectId-keyed fetch
hooks, no streams or scoped drafts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:59:55 -07:00
gsxdsm
0dd34cd306 fix(chat): don't wipe task-bound planner chat history on /new or /clear
With showTaskChatsInCommonFeed enabled, task-planner sessions appear in the
common Direct feed, so /new//clear there hit ChatView's generic intercept and
createSession orphaned the task's planner history behind a fresh session.
Consume the command with a warning toast for task-bound sessions instead.

Also updates 6 stale ChatView.core.test.tsx sendMessage assertions broken by
FN-8502's onDelivered/onFailed options argument.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:58:21 -07:00
gsxdsm
049c36c9ae fix(chat): narrate task-chat step numbers 1-based to match the card's step count
The proactive status narration printed the internal 0-based step index, so the
final step of a 13-step task announced "Starting Step 12" next to a card
showing "12/13". Display now uses index + 1 in both the engine builders and
the store-side updateStep narration; the 0-based tool/PROMPT.md contract is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:58 -07:00
gsxdsm
345dccbe7d fix(dashboard): consume seeded Planning initial plan on auto-start to stop duplicate sessions
The seeded initialPlan lived in modalManager state while embedded Planning
fully unmounts on main-content navigation, wiping its in-component auto-start
guard — so every navigate-back remount (and the project-switch remount key)
auto-started a duplicate planning session and abandoned the one in flight.
The payload is now a one-shot handoff: PlanningModeModal calls the new
onInitialPlanConsumed the moment auto-start fires, useModalManager clears
planningInitialPlan, and remounts take the stored-active-session restore path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:47 -07:00
gsxdsm
b007de5f94 fix(ci,tests): repair binary release pipeline and re-green the full suite
Binary Release (v0.73.0-beta.5 was fully red):
- bun compile: mark chromium-bidi external — playwright-core@1.60 (feature-video)
  optionally requires it and bun fails closed on unresolvable requires.
- Windows desktop EXE: quote -c.publish.channel=beta in release.yml; PowerShell
  tokenizes the bare flag into `-c` + a path and electron-builder ENOENTs on it.

Full suite (all 4 shards red from stale-test drift, no product bugs found):
- engine: align mock stores/assertions with atomic store.moveTaskIf dispatch
  (#2371), the fail-closed non-empty PROMPT.md artifact gate (#2390), oldest-
  first admission (FN-8453), alreadyClaimed graph routing (#2393), startStep
  step projection (#2403/FN-8464), structured retry presentation (FN-8503),
  provider-lane pause reasons (#2339), typed column-boundary entry (#2378),
  Type.Integer in CAS document schemas (#2375), bounded model-registry refresh.
- engine-no-blocking-shellout: re-pin 17 drifted allowlist line numbers and drop
  the stale REBASE_HEAD entry whose execSync was removed.
- core: schema-applier expectations track migrations 0033-0035 (96 tables) and
  the synthetic 0000 fixture gains workflow_work_items/mission_contract_assertions;
  work-item terminal state is "succeeded" post-#2378.

Known follow-up (not addressed here): self-healing starved-refinement escalation
bumps task.priority, which FN-8453 oldest-first admission no longer consults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:00 -07:00