Two heavy CLI tests were dominating wall time:
- chat.test.ts "--once exits with timeout note" waited the real 30s
reply-timeout floor. Added a replyTimeoutMs option to
runChatInteractive so the test can use 200ms.
- bundled-plugin-install.test.ts "loads the real bundled dependency
graph plugin" runs esbuild and a live PluginLoader (~18s). Gated
behind FUSION_RUN_SLOW_TESTS=1; the install/upgrade logic is covered
by mocked unit tests in the same file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MasterKeyManager.loadKeytar() now bails out early when
FUSION_MASTER_KEY_DISABLE_KEYCHAIN=1, and the core vitest setup sets that
flag for every worker. Eight tests across master-key/secrets-store/
secrets-sync-passphrase were timing out at exactly the 15s testTimeout
because they constructed MasterKeyManager without injecting a fake
KeytarLike, which made loadKeytar() reach the real OS keychain.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a "Connection" submenu with a "Change Launch Mode…" item that lets
users switch between Run Locally and Connect to Remote after the initial
chooser. The menu sends shell:reset-desktop-mode-request to the renderer;
the dashboard's DesktopLaunchGate listens, calls the new
shell:resetDesktopMode IPC (clears hasCompletedModeSelection, stops the
embedded runtime), strips the cached serverBaseUrl/shellMode query params,
and reloads so the gate re-prompts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap <App /> in a DesktopLaunchGate that runs only inside the Electron shell.
On first run it shows a chooser (Run Locally / Connect Remote). On "local"
it calls setDesktopMode("local") so main starts the embedded runtime, polls
shell:getState until localRuntime.state === "running", then reloads with
?serverBaseUrl=http://127.0.0.1:<port> so the dashboard's API calls route
to the embedded server (file:// origins can't resolve relative /api). On
"remote" it opens the existing connection manager. Replaces the dead-end
"can't reach backend" landing in the packaged desktop app.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In packaged Electron builds, `process.argv[1]` is undefined (Electron loads
the main script via package.json `main`, not via argv), so the bottom-of-file
guard never invoked `run()` and the app started without creating a window.
Also build the dashboard client with `--base ./` so its `file://`-loaded
index.html resolves `./assets/*` from inside the asar instead of the
filesystem root, which was producing a blank white window.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add stale-branch reclaim guards for active executor sessions, recent execution starts, and worktrees with uncommitted changes
- Emit branch:stale-active-reclaim-deferred run-audit telemetry with deferral metadata for self-healing decisions
- Cover reclaim deferral and legitimate reclaim behavior with reliability interaction tests
- Document the new stale active branch deferral contract in AGENTS.md
- Add a patch changeset for the published CLI package
Fusion-Task-Id: FN-4949
Fixed GitHub issue close and delete behavior when tasks are deleted in the dashboard's GitHub tracking state module, with test coverage added for both delete and state tracking scenarios.
Fusion-Task-Id: FN-4941
The in-line branch-cross-contamination auto-recovery in executor.ts had
two related bugs that produced transient "no-worktree-no-merge-confirmed"
stall signals in the dashboard while a live worktree was still mapped
on disk:
1. autoRecoverCrossContamination was called with repoDir=this.rootDir.
The recovery does: git checkout --detach <baseSha> → cherry-pick
wanted commits → git update-ref → git checkout <branch>. When the
branch is checked out in a worktree (the normal case), that final
recheckout in rootDir is blocked by git with "branch already used
by worktree at ...", so the in-line happy path silently failed for
every contaminated task that had a real worktree. Pass the task's
worktree as repoDir when available so the operations stay internal
to the worktree and the recheckout succeeds.
2. The successful-recovery branch called
moveTask(taskId, 'todo', { preserveResumeState: true })
without preserveWorktree:true. moveTask defaults to nulling
task.worktree on requeue. The worktree directory and git mapping
were still live — the dashboard's in-review-stall classifier
(no-worktree-no-merge-confirmed) and TaskChangesTab both keyed off
task.worktree being null and lied about the worktree being gone.
Sibling recovery paths (auto-recovery-handlers/contamination.ts,
tryBootstrapMisbindingRecovery, self-healing.ts:1639) all already
pass preserveWorktree:true; this site was inconsistent.
Updated the existing FN-4428 regression test and added a new
FN-4939 test asserting repoDir uses task.worktree (with fallback
to rootDir when the task has no worktree pointer).
Refs: packages/core/src/in-review-stall.ts:116
Adds a title-id drift detection and reconciliation system to prevent duplicate tasks when task titles change after initial creation. Core adds the `task-title-id-drift.ts` module with `markTitleIdStable` and `resolveTitleIdDrift` logic, wired through `db.ts`, `store.ts`, and `archive-db.ts`, with co
Fusion-Task-Id: FN-4898
The dashboard server cached index.html and the Vite view-chunk manifest
forever with no invalidation. When the on-disk files changed (release
upgrade, rebuild) the server kept serving stale HTML referencing chunk
hashes that no longer existed, leaving the browser stuck on a blank
white page until the server was restarted.
Both caches now key on file mtime and refresh automatically. The
serveIndexHtml catch path also logs the failure and clears the
templated cache so the next request can recover instead of silently
404ing until restart.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add a dedicated `fn pr create <task-id>` help section in the CLI usage output
- Recast `fn task pr-create` in help text as an alias of the new PR command
- Add a changeset describing the dashboard Create-PR entry points and CLI command rollout
Fusion-Task-Id: FN-4758