Commit Graph

239 Commits

Author SHA1 Message Date
gsxdsm
5c7ed8b26f chore(release): v0.72.0
Version bump via changesets.
2026-07-18 00:52:59 -07:00
gsxdsm
c4a00d7c37 feat(desktop): Windows close-to-tray option in the close dialog
Windows close previously always meant full shutdown (macOS/Linux hid to
the existing tray icon). The close dialog now defaults to Minimize to
tray — Fusion and the embedded PostgreSQL keep running in the
background, restorable from the tray — alongside the exit choices
(stop or keep PostgreSQL). OS session end still skips dialogs and
performs the full stop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:47:06 -07:00
gsxdsm
68ce5c31da fix: harden onboarding/git/desktop batch per multi-agent review findings
- uninstaller: taskkill only the first, digits-only postmaster.pid line
  (the for /f loop ran taskkill on the port/epoch lines — potential
  unrelated-process kill)
- git-missing dialogs use new ConfirmOptions.alwaysAsk so global
  skip-confirmations cannot silently pick an unseen choice
- Windows quit prompt: embedded-local runtimes only, skipped during OS
  session end (sync dialog blocked Windows shutdown)
- 'leave it running' detaches the embedded lifecycle (disarms its
  process shutdown hook) so Electron exit cannot kill the postmaster
  the operator chose to keep (new detachKeepingEmbedded)
- wizard: ref-based double-submit guard around the async git preflight
- clone route: ENOENT invalidate-and-retry matching runGitCommand
- openExternalUrl: drop the async window.open fallback (always
  popup-blocked); log bridge failures instead
- DirectoryPicker: close the panel when listing the created folder
  fails so Select cannot re-commit the parent
- git status probe bounded to two spawns (PATH + first candidate)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:33:14 -07:00
gsxdsm
755063715a feat(desktop): Windows Postgres lifecycle — quit prompt and uninstaller cleanup
Closing the Windows desktop app now asks whether to also shut down the
embedded PostgreSQL server ('leave it running' keeps serving other
Fusion processes; programmatic restarts never prompt and keep the full
stop). The NSIS uninstaller stops the postmaster from postmaster.pid,
removes materialized runtime binaries, and asks before deleting the
database cluster — silent and auto-update uninstalls never touch data.
build/uninstaller.nsh force-added like entitlements.mac.plist (the
build/ ignore targets generated icons).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:14:54 -07:00
gsxdsm
7bf83bb458 fix(desktop,dashboard): open OAuth URLs via activation-free IPC on desktop
window.open after awaiting /auth/login can outlive Chromium's transient
user activation and get silently popup-blocked in the desktop app — the
OpenAI Codex flow (method select + localhost callback server) crossed
that threshold while Anthropic's faster flow usually didn't, so Codex
login never opened the browser. Add a shell:openExternal IPC bridge
(http/https only), expose it in preload, and route every dashboard
auth-URL open through an openExternalUrl helper that falls back to
window.open on the web.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 00:03:48 -07:00
gsxdsm
1afce9532a fix: green full-suite after product and CI PG drift (#2285)
## Summary
Main Full Suite was red again after release/desktop workflow drift,
engine mock gaps, mission landed-SHA gating, and compound-engineering PG
admin auth on GHA (`USER=runner`).

## Fixes
| Area | Failure | Fix |
|------|---------|-----|
| desktop `release-workflow` | expected old `find artifacts -type f` |
assert pruned collect + `release-files/*` |
| `step-session-executor` | missing
`resolveExecutorFallbackThinkingLevel` | mock export |
| tool-availability tests | empty tools (cascade from above) | fixed by
mock |
| `skill-resolver` | TDZ on `mockFiles` during import | `vi.hoisted`
filesystem state |
| `merge-error-recovery` | enqueue no-op when not started | set
`started=true` |
| mission behavioral posture | `blocked` (no landed SHA / git probe) |
`mergeDetails.commitSha` + staleness stub |
| GraphTaskNode | missing `useOptionalToast` | mock both toast exports |
| CE `pipeline-store.pg` | psql as `runner` | admin via
`FUSION_PG_TEST_URL_BASE` |

## Test plan
- [x] step-session-executor, skill-resolver, merge-error-recovery,
mission-validator-behavioral-posture (203)
- [x] release-workflow (10)
- [x] `pnpm --filter @fusion/engine test:core` (294)
- [ ] Full Suite (non-blocking) after merge

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

- **Bug Fixes**
- Improved desktop release artifact collection by pruning nested
`runtime` and `migrations` directories and consistently staging release
uploads via a dedicated `release-files` mapping.

- **Tests**
- Enhanced engine merge error-recovery coverage and mission validator
behavioral posture setup.
- Improved test reliability by synchronizing mocked filesystem state,
executor fallbacks, and toast hook variants.
- Updated Postgres test harness/admin commands to use a configurable
base URL; refined related Windows changeset description.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-17 23:22:04 -07:00
gsxdsm
7dda1aa3f5 chore(release): v0.71.0
Version bump via changesets.
2026-07-17 20:13:12 -07:00
gsxdsm
0b6c4cd4ca feat(dashboard,desktop): show live database-migration progress during boot
The one-time SQLite→PostgreSQL migration runs inside createTaskStoreForBackend
before any HTTP server listens, so browsers saw "connection refused" and open
tabs failed silently for minutes. Now:

- CLI: a temporary holding server binds the dashboard port for the boot window,
  serving an auto-reloading "Database migration in progress" page and an
  /api/health payload with status "migrating" + structured progress; the port
  is handed off (awaited) to the real app.listen().
- Dashboard SPA: already-open tabs render the new MigrationInProgressBanner
  from the 15s health poll when status is "migrating".
- Desktop: LocalRuntimeManager publishes migration progress on
  DesktopRuntimeStatus via the new core onMigrationProgress option;
  DesktopLaunchGate shows the live label and extends its 30s startup timeout
  while progress advances (2min stall cap), in both boot and first-run flows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 20:09:56 -07:00
gsxdsm
e31223c25f chore(release): v0.70.2
Version bump via changesets.
2026-07-17 19:17:17 -07:00
gsxdsm
eccb115c7e chore(release): v0.70.1
Version bump via changesets.
2026-07-17 18:17:15 -07:00
gsxdsm
6e5bb5d3d5 fix(desktop): stage @fusion/core PG migrations into packaged builds
Bare tsc never copies .sql files into core's dist, and the desktop staging
had no equivalent of the CLI's tsup migrations hook, so every packaged
desktop build shipped without dist/postgres/migrations and Local mode
crashed schema init (ENOENT 0000_initial.sql) after embedded Postgres
started. buildCore() now stages the migrations beside the compiled output,
stageDesktopDeploy() re-stages them into the deployed closure, and
verifyCoreMigrationsStaged() fails the build if the baseline migration is
missing from the stage.

Verified end to end: packed mac-arm64 app boots with isolated home,
embedded PG 15.18 initializes from packaged migrations, /api/health 200.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 18:00:52 -07:00
gsxdsm
f5538e6253 chore(release): v0.70.0
Version bump via changesets.
2026-07-17 17:12:42 -07:00
gsxdsm
adb3eb3a37 FN-8224: add Claude ACP runtime support
Add a bundled Claude Code ACP runtime with model discovery and CLI distribution integration.

- Add the Claude ACP runtime plugin, bridge, tool forwarding, and tests.
- Register Claude model discovery and cached picker support in the dashboard.
- Stage the plugin in CLI and desktop packaging with its pinned dependency.
- Add workspace, lockfile, and release metadata.

Files changed:
 .changeset/fn-8224-claude-acp-runtime.md           |   7 +
 packages/cli/package.json                          |   1 +
 packages/cli/src/__tests__/bundle-output.test.ts   |  32 +-
 .../cli/src/plugins/staged-bundled-plugin-ids.ts   |   1 +
 packages/cli/tsup.config.ts                        |  40 +-
 .../core/src/plugins/bundled-plugin-install.ts     |   2 +
 packages/dashboard/package.json                    |   3 +-
 packages/dashboard/src/claude-model-cache.ts       | 185 +++++++
 packages/dashboard/src/routes.ts                   |   1 +
 .../dashboard/src/routes/register-model-routes.ts  |  11 +
 packages/dashboard/src/runtime-provider-probes.ts  |  15 +
 packages/dashboard/vitest.config.ts                |   4 +
 packages/desktop/scripts/workspace-tools.ts        |   1 +
 plugins/fusion-plugin-claude-runtime/README.md     |   7 +
 plugins/fusion-plugin-claude-runtime/manifest.json |   1 +
 plugins/fusion-plugin-claude-runtime/package.json  |   1 +
 .../src/__tests__/cli-spawn.test.ts                |   3 +
 .../src/__tests__/index.test.ts                    |   3 +
 .../src/__tests__/provider.test.ts                 |   8 +
 .../src/__tests__/runtime-adapter.test.ts          |   7 +
 .../src/__tests__/tool-bridge.test.ts              |  79 +++
 .../src/acp-settings.ts                            |  21 +
 .../src/acp/VENDORED.md                            |  30 ++
 .../src/acp/cli-spawn.ts                           | 188 +++++++
 .../src/acp/control-handler.ts                     | 302 ++++++++++++
 .../src/acp/event-bridge.ts                        | 308 ++++++++++++
 .../src/acp/fs-capabilities.ts                     | 263 ++++++++++
 .../fusion-plugin-claude-runtime/src/acp/index.ts  |  16 +
 .../src/acp/path-jail.ts                           | 229 +++++++++
 .../src/acp/process-manager.ts                     | 177 +++++++
 .../src/acp/prompt-builder.ts                      |  87 ++++
 .../src/acp/provider.ts                            | 542 +++++++++++++++++++++
 .../src/acp/runtime-adapter.ts                     | 190 ++++++++
 .../src/acp/sanitize.ts                            |  81 +++
 .../src/acp/tool-mapping.ts                        |  47 ++
 .../fusion-plugin-claude-runtime/src/acp/types.ts  | 189 +++++++
 .../fusion-plugin-claude-runtime/src/cli-spawn.ts  |  31 ++
 plugins/fusion-plugin-claude-runtime/src/index.ts  |  95 ++++
 .../src/mcp-forwarding.ts                          | 114 +++++
 .../src/mcp-schema-server.cjs                      | 155 ++++++
 plugins/fusion-plugin-claude-runtime/src/probe.ts  |   8 +
 .../fusion-plugin-claude-runtime/src/provider.ts   |   8 +
 .../src/runtime-adapter.ts                         | 424 ++++++++++++++++
 .../src/skill-loader.ts                            | 290 +++++++++++
 .../src/tool-bridge.ts                             | 264 ++++++++++
 plugins/fusion-plugin-claude-runtime/src/types.ts  | 142 ++++++
 plugins/fusion-plugin-claude-runtime/tsconfig.json |  10 +
 .../fusion-plugin-claude-runtime/vitest.config.ts  |  22 +
 pnpm-lock.yaml                                     | 131 ++++-
 pnpm-workspace.yaml                                |   1 +
 50 files changed, 4753 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-8224

Fusion-Task-Lineage: 4e626913-32bb-4baa-a142-816c7f4ee7c4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 12:00:26 -07:00
gsxdsm
6206af8ce9 FN-8146: restore persistent theme selection
Restore the full Settings theme picker while preserving Shadcn Mono selections across reloads.

- Merge the Settings selector into the current-theme row with shared dropdown controls.
- Restore Shadcn Mono across theme metadata, token styles, and dashboard/desktop bootstrap validation.
- Scope Mono light swatches correctly and cover restored options and persistence with tests.

Files changed:
 .changeset/FN-8146-theme-dropdown-current-row.md   |  7 +++
 docs/dashboard-guide.md                            |  5 ++-
 packages/core/src/types/execution-and-ui.ts        |  1 +
 .../dashboard/app/components/ThemeDropdown.css     | 52 ++++++++++++++++++++++
 .../dashboard/app/components/ThemeDropdown.tsx     | 42 ++++++++++++++---
 .../dashboard/app/components/ThemeSelector.css     | 42 +----------------
 .../dashboard/app/components/ThemeSelector.tsx     | 45 +++++--------------
 .../components/__tests__/ThemeDropdown.test.tsx    | 46 ++++++++++++++++---
 .../components/__tests__/ThemeSelector.test.tsx    | 29 ++++++++----
 .../__tests__/CommandCenterControls.test.tsx       | 15 ++++++-
 packages/dashboard/app/components/themeOptions.ts  |  2 +
 .../dashboard/app/hooks/__tests__/useTheme.test.ts |  8 ++--
 packages/dashboard/app/hooks/useTheme.ts           |  8 ++--
 packages/dashboard/app/index.html                  |  5 +--
 packages/dashboard/app/public/theme-data.css       | 16 ++++++-
 packages/desktop/src/renderer/index.html           |  1 +
 16 files changed, 213 insertions(+), 111 deletions(-)

Fusion-Task-Id: FN-8146

Fusion-Task-Lineage: 32ec7f21-ee6b-4459-8e7b-f5a5435c4994

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 00:00:46 -07:00
gsxdsm
07e1ceb860 FN-8151: add Cobalt, Clay, and Moss themes
Add three synchronized color themes across dashboard and desktop surfaces.

- Register Cobalt, Clay, and Moss theme IDs, token palettes, and light/dark swatches.
- Keep dashboard and desktop bootstrap validators aligned with selector metadata.
- Document and test the cross-surface theme registration invariant.

Files changed:
 .changeset/fn-8151-new-themes.md                   |   7 +
 docs/dashboard-guide.md                            |   3 +-
 packages/core/src/types/execution-and-ui.ts        |   4 +
 .../app/__tests__/new-color-themes.test.ts         | 116 ++++++++++++
 .../dashboard/app/components/ThemeSelector.css     |  42 +++++
 packages/dashboard/app/components/themeOptions.ts  |   3 +
 packages/dashboard/app/index.html                  |   2 +-
 packages/dashboard/app/public/theme-data.css       | 202 +++++++++++++++++++++
 packages/desktop/src/renderer/index.html           |   3 +
 9 files changed, 380 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-8151

Fusion-Task-Lineage: d97973a7-3387-4b98-b150-8ac2e838bfa9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 18:18:35 -07:00
gsxdsm
5a60643c0a FN-8142: migrate auth storage and model runtime to pi SDK
Migrate Fusion's credential and model integrations to pi SDK 0.80.8+.

- Replace legacy AuthStorage initialization with a locked Fusion credential store and ModelRuntime-backed registry.
- Wire asynchronous model initialization and refresh through CLI, desktop, dashboard, executor, and provider paths.
- Update provider, routing, and registry tests for the new SDK contracts.

Files changed:
 packages/cli/src/commands/__tests__/daemon.test.ts |   2 +-
 .../cli/src/commands/__tests__/dashboard.test.ts   |   9 +-
 .../cli/src/commands/__tests__/onboard.test.ts     |   1 +
 packages/cli/src/commands/__tests__/serve.test.ts  |   2 +-
 packages/cli/src/commands/daemon.ts                |  19 +-
 packages/cli/src/commands/dashboard.ts             |  20 +-
 packages/cli/src/commands/onboard.ts               |   6 +-
 packages/cli/src/commands/serve.ts                 |  19 +-
 packages/cli/src/commands/startup-model-sync.ts    |   4 +-
 packages/core/src/__tests__/openai-models.test.ts  |  17 +-
 ...-model-routes-openai-codex-supplemental.test.ts |  17 +-
 ...register-model-routes-zai-real-registry.test.ts |  15 +-
 packages/dashboard/src/routes.ts                   |  12 +-
 .../dashboard/src/routes/register-model-routes.ts  |   2 +-
 packages/desktop/src/local-runtime.ts              |   2 +-
 packages/desktop/src/local-server.ts               |   2 +-
 .../custom-providers-openai-completions.test.ts    |  16 +-
 .../custom-providers-openai-responses.test.ts      |  16 +-
 .../engine/src/__tests__/executor-test-helpers.ts  |   2 +-
 .../src/__tests__/pi-create-fn-agent.test.ts       |   8 +-
 .../engine/src/__tests__/pi-layers-wiring.test.ts  |   2 +-
 packages/engine/src/__tests__/pi.test.ts           |  47 ++---
 .../src/__tests__/provider-registration.test.ts    |  17 +-
 packages/engine/src/auth-storage.ts                | 218 ++++++++++++++++++---
 packages/engine/src/custom-provider-registry.ts    |  14 +-
 packages/engine/src/executor.ts                    |  15 +-
 packages/engine/src/pi.ts                          |  50 +++--
 packages/engine/src/provider-auth.ts               |  58 +++---
 packages/engine/src/provider-registration.ts       |  16 +-
 29 files changed, 421 insertions(+), 207 deletions(-)

Fusion-Task-Id: FN-8142

Fusion-Task-Lineage: 8ae79064-7820-4976-9645-9431b5a3129e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 18:13:37 -07:00
gsxdsm
edac617e10 fix(desktop): assert Linux AppImage embeds Postgres packaging (#2131)
## Summary

Verification of the Fusion Linux AppImage + embedded Postgres packaging
surface (follow-on to #2106 Mac packaging and #2117 Windows PG work).

### What we found

1. **Published `v0.60.0` AppImages are broken for Local/embedded
Postgres** (pre-#2106):
- No `embedded-postgres` / `@embedded-postgres/*` in `app.asar` or
`app.asar.unpacked`
- `package.json` `main` is still `dist/main.js` (no
`main-bootstrap.cjs`)
   - No `omp-runtime` packaged
- `asar.unpacked` only has incidental natives (pi-tui, esbuild,
node-pty)

2. **Current main (post-#2106) packaging config is correct** (verified
via mac `--dir` pack on this host):
   - `main` → `dist/main-bootstrap.cjs`
   - Full `asarUnpack` of `embedded-postgres` + `@embedded-postgres/**`
   - Native bins present under `app.asar.unpacked`
   - `omp-runtime` dist present in asar

3. **Linux arm64 native PG binary smoke**
(`@embedded-postgres/linux-arm64` 15.18) in Docker: initdb → start →
create DB → persist across restart → **OK** (requires postinstall soname
symlinks from `hydrate-symlinks.js` / `pg-symlinks.json`).

4. **Host blocker:** this machine is macOS arm64 — cannot produce or
execute a Linux AppImage end-to-end. Linux packaging must run on
`ubuntu-latest` CI.

### Fix in this PR

Release jobs only checked that `*.AppImage` files existed — which is how
v0.60.0 shipped empty of Postgres. Add:

- `scripts/verify-desktop-linux-pg-packaging.mjs` — inspects
`linux-*-unpacked` trees for:
- `app.asar.unpacked` embedded-postgres + `@embedded-postgres/linux-*`
bins
  - `dist/main-bootstrap.cjs` + `package.json` main
  - `omp-runtime` presence
- Wire into `release.yml` + `test-release.yml` after AppImage artifact
checks
- Unit test lock in `release-workflow.test.ts`

## Test plan

- [x] `pnpm --filter @fusion/core test:embedded-postgres` (33/33 with
60s timeout; default 15s flaked under load)
- [x] Desktop packaging unit tests (`electron-builder-config`,
`build-bundling`, `release-workflow`)
- [x] Inspected published `Fusion-0.60.0-linux-arm64.AppImage` (checksum
OK; PG packaging absent)
- [x] Post-#2106 `electron-builder --mac --dir`: asar.unpacked has PG +
bootstrap + omp
- [x] Docker linux-arm64 native binary lifecycle smoke
- [ ] CI `build-desktop-linux` on this PR (runs the new verifier against
real linux-unpacked)

## Gaps remaining (not fixed here)

| Gap | Notes |
|-----|-------|
| Full AppImage launch + `/api/health` on Linux | Needs Linux host/CI
with display or headless Electron |
| No post-#2106 published AppImage yet | Next release will include
packaging fixes; this PR stops empty AppImages |
| README still says `linux-x64.AppImage` | Actual name is
`linux-x86_64.AppImage` (workflow already correct) |
| Windows packaged Local | Tracked by #2117 / verify-desktop |

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

* **Bug Fixes**
* Added verification for Linux AppImage packaging to ensure embedded
Postgres binaries, platform files, symlinks, and runtime assets are
included correctly.
* Confirmed packaged application metadata points to the expected startup
entry point.
* Improved detection of invalid, missing, or incorrectly formatted
packaging artifacts.

* **Tests**
* Added coverage for architecture-specific binaries, exact ASAR paths,
executable files, and symlink metadata.
* Verified packaging checks run after Linux desktop artifacts are
created.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 14:41:05 -07:00
gsxdsm
5caf360a58 fix(desktop): green Windows smoke + Linux AppImage PG packaging checks (#2138)
## Summary
- **Windows CI:** run the embedded Postgres smoke as non-admin
`fusion-pg` (with profile prewarm) so elevated `windows-latest` runners
stop failing with PostgreSQL’s admin-token refusal. Packaging still runs
as the job user.
- **Linux AppImage:** add a packaging content verifier for
`main-bootstrap`, `@embedded-postgres` natives, and `omp-runtime` dist
entrypoints; wire it into `release.yml`, `test-release.yml`, and the
advisory **Desktop packaging** PR lane (after `electron-builder --dir`).
- Fix eslint `no-undef` on bare `URL` in the verifier script (was red on
#2131).

## Context
Desktop packaging on Ubuntu was mostly green; Windows desktop builds and
the AppImage packaging PR (#2131 lint) were the remaining red paths. The
win-pg-diag pivot (run smoke as non-admin) proved green on CI; this
ports that approach without removing main’s elevated-token product path
for end-user “Run as administrator” cases (smoke simply does not take
that path when the process is non-admin).

## Test plan
- [x] `pnpm --filter @fusion/desktop exec vitest run
src/__tests__/release-workflow.test.ts`
- [x] `pnpm exec eslint scripts/verify-desktop-linux-pg-packaging.mjs`
- [ ] Desktop packaging workflow on this PR
- [ ] Desktop Windows Build (workflow_dispatch)
- [ ] Confirm #2131 supersession if this lands the same AppImage checks

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

* **Bug Fixes**
* Strengthened Linux desktop AppImage validation to confirm embedded
PostgreSQL artifacts, required binaries, symlink hydration, and the
expected app entrypoints are present after packaging.
* Improved Windows embedded PostgreSQL smoke testing by running under a
non-administrator helper user with a prewarmed profile environment.

* **Tests**
* Added automated packaging/release workflow verification steps (Linux
and Windows) to catch embedded PostgreSQL content regressions earlier,
including during artifact build and release verification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 13:56:10 -07:00
gsxdsm
a242f1b449 fix(FN-7952): migrate bundled plugins to PostgreSQL (#2111)
## Summary

Bundled plugins now persist shared runtime state in project-scoped
PostgreSQL tables instead of maintaining independent SQLite authority.
Reports, CLI Printing Press, Compound Engineering, Roadmap, Even
Realities, and WhatsApp all follow the same ownership and startup
contract as Fusion core.

## Design decisions

- Plugin schema hooks run through the host’s PostgreSQL owner and
enforce project isolation.
- The SDK exposes the host contract needed by bundled plugins without
importing engine internals.
- Legacy Roadmap ownership fixtures use the supported empty-owner
sentinel, preserving current composite primary/foreign keys while
exercising backfill behavior.
- The lockfile travels with the Even Realities PostgreSQL dependency so
packaged installs remain reproducible.

## Validation

- All six affected plugin builds pass.
- Affected plugin suites pass: 773 tests across Printing Press, Compound
Engineering, Even Realities, Reports, Roadmap, and WhatsApp.
- `pnpm test:gate` passes all 478 gate tests.
- This PR changes 40 files.

## Stack

- Depends on #2110 → #2109 → #2108.
- The documentation/release PR completes the stack.

Related: #2105


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

## Summary by CodeRabbit

* **Breaking Changes**
* PostgreSQL is now required for runtime storage; SQLite files are used
only as one-time migration inputs.
  * The legacy `FUSION_NO_EMBEDDED_PG` fallback has been removed.

* **New Features**
* Added project-isolated PostgreSQL storage for plugins, reports, tasks,
notifications, and other plugin data.
  * Added agent tools for reports and CLI service drafts.
  * Added PostgreSQL schema initialization support for plugin authors.

* **Bug Fixes**
  * Improved migration and recovery of legacy plugin state.
* Prevented cross-project data access and strengthened transactional
schema updates.

* **Documentation**
* Updated storage, migration, deployment, plugin authoring, CLI, and
dashboard guidance for PostgreSQL.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 00:27:59 -07:00
gsxdsm
97172fdcf2 fix(FN-7952): require PostgreSQL in CLI and desktop (#2110)
## Summary

CLI commands, daemon/dashboard startup, packaged desktop startup, and
live-data maintenance scripts now share the mandatory PostgreSQL
lifecycle. Operators no longer risk a command silently reading or
writing a disconnected SQLite shadow when PostgreSQL setup fails.

## Design decisions

- Every startup owner retains and awaits its PostgreSQL shutdown
callback, including partial-startup failure paths.
- CLI project context and lock-retry flows resolve through asynchronous
project stores.
- Maintenance scripts use the shared backend helper; explicit database
migration/inspection remains the only CLI surface allowed to read legacy
SQLite sources.

## Validation

- CLI and Desktop typechecks pass on the stacked branch.
- `pnpm test:gate` passes all 478 gate tests.
- This PR changes 54 files.

## Stack

- Depends on #2109, which depends on #2108.
- Bundled plugins and docs/release follow in later PRs.

Related: #2105


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

## Summary by CodeRabbit

* **New Features**
* PostgreSQL is now the authoritative store for structured project and
task metadata.
* Projects can be recognized and initialized using
`.fusion/project.json`, without creating a legacy SQLite database.
  * CLI commands now retry transient PostgreSQL contention errors.

* **Bug Fixes**
* Improved cleanup when commands complete, fail, or run in the
background, preventing lingering resources.
  * Improved desktop, server, and session shutdown reliability.

* **Documentation**
* Updated storage and standalone binary guidance to reflect PostgreSQL
and legacy SQLite compatibility.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 23:18:55 -07:00
gsxdsm
2e4fcfcaea fix(FN-7952): establish PostgreSQL core authority (#2108)
## Summary

Fusion’s core runtime now treats PostgreSQL as the authoritative
metadata store without leaving current CLI, dashboard, desktop, or
engine composition roots uncompilable between stack layers. This is the
99-file foundation for the larger cutover: subsequent PRs migrate the
remaining consumers, plugins, and operator surfaces.

## Design decisions

- Runtime store construction fails closed when an asynchronous
PostgreSQL layer is unavailable; SQLite remains readable only at
explicit migration and identity-recovery boundaries.
- Project ownership is enforced across active, archived, workflow,
mission, analytics, and plugin-schema data.
- The small set of cross-package files in this layer are
compatibility-critical call sites required for a green intermediate
commit, not the complete consumer migration.
- Schema migration 0008 remains assigned to session-advisor state from
current `main`; mission lineage idempotency advances to 0009 so neither
invariant can be skipped.

## Validation

- All affected package typechecks pass: Core, Engine, Dashboard, CLI,
and Desktop.
- `pnpm test:gate` passes: 478 tests across the engine gate, PostgreSQL
core gate, and CLI workflow shape.
- The PR changes exactly 99 files.

## Stack

This is the base PR. Engine/dashboard, CLI/desktop/ops, plugins, and
docs/release follow as stacked PRs, each below 100 changed files.

Related: #2105


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

## Summary by CodeRabbit

* **New Features**
* PostgreSQL is now the standard runtime backend, with embedded
PostgreSQL enabled by default.
* Added project-scoped storage for tasks, archives, chat sessions,
missions, knowledge pages, and operational data.
* Improved archived-task search, filtering, pagination, and restoration.
* Added safer plugin schema initialization with validation and project
isolation.
* Added PostgreSQL-backed workflow, mission, validator, and dashboard
capabilities.

* **Bug Fixes**
  * Improved startup timeout cancellation and resource cleanup.
* Prevented cross-project data access and phantom reservation cleanup
errors.
* Ensured archived tasks remain read-only and asynchronous writes
complete reliably.
  * Retired SQLite opt-out settings with clear startup errors.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 22:13:30 -07:00
gsxdsm
7568705244 fix(desktop): boot embedded Postgres in packaged app and ship omp dist (#2106)
## Summary

Packaged Fusion desktop Local mode failed after the SQLite→Postgres
cutover:

1. **Embedded Postgres** could not start from `app.asar` — platform
packages resolve `initdb`/`postgres` via `import.meta.url` into the asar
virtual path, and `spawn` fails with `ENOTDIR`.
2. **After Postgres was fixed**, Local mode still fell back to the mode
chooser because `@fusion-plugin-examples/omp-runtime` was never built
into `dist/` (dashboard imports it from `runtime-provider-probes.ts`).

This PR makes packaged Local mode boot embedded Postgres reliably and
keep the dashboard shell up.

### Changes

- **CJS bootstrap** (`main-bootstrap.cjs`) as Electron `main`: patches
`child_process.spawn` / `fs.promises.stat|chmod` before the ESM main
loads so asar binary paths rewrite to real files.
- **Materialize** the full native PG install (`bin` + `lib` + `share`)
under `~/.fusion/embedded-postgres/runtime-bin/<plat-arch>/`.
- **electron-builder**: full `asarUnpack` of embedded-postgres packages;
allowlist PG deps and `@fusion-plugin-examples/**/*` (+ plugin-sdk / ACP
SDK).
- **Build** `fusion-plugin-omp-runtime` with the other dashboard-static
runtime plugins; export `DASHBOARD_RUNTIME_PLUGIN_PACKAGES` for tests.
- Unit coverage for asar path rewrite, packaging allowlists, and omp
build inclusion.

## Test plan

- [x] `pnpm --filter @fusion/core test:embedded-postgres` (23/23)
- [x] Desktop packaging unit tests (`build-bundling`,
`electron-builder-config`)
- [x] Packaged macOS `Fusion.app` Local mode:
  - [x] `embedded postgres: ready on port … (database "fusion")`
  - [x] `desktopMode` stays `"local"` (no chooser fallback)
- [x] `GET /api/health` → `status: ok`, `database.healthy: true`,
`engine.available: true`
- [x] Linux embedded binary lifecycle smoke (Docker aarch64,
`@embedded-postgres/linux-arm64`) — initdb/start/persist/restart
- [ ] CI release desktop jobs (macOS/Linux) when this lands
- [ ] Windows packaged desktop Local + PG (separate agent / host)

## Verification notes

| Platform | Embedded Postgres | Packaged Local shell |
|----------|-------------------|----------------------|
| macOS | Working | Working after this PR |
| Linux | Native binary smoke pass | Full AppImage not built on this
host |
| Windows | Out of scope here | Separate verification |

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

* **Bug Fixes**
* Improved embedded PostgreSQL reliability in Electron-packaged apps by
rewriting bundled `app.asar` binary paths to their unpacked/materialized
locations.
* Ensured embedded PostgreSQL runtime binaries resolve correctly across
platforms/architectures, with best-effort executable permissions and
macOS dylib link normalization.

* **Packaging**
* Updated the desktop Electron entry to use a bootstrap module for
embedded PostgreSQL binary resolution.
* Expanded Electron Builder inclusion and asar-unpack rules for
embedded-postgres and related packages, plus required runtime plugin/sdk
assets.

* **Tests**
* Updated and added checks to match the new packaging and plugin/runtime
expectations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-14 20:44:09 -07:00
gsxdsm
1b9dce22c0 fix(desktop): harden embedded Postgres packaging 2026-07-14 09:47:41 -07:00
gsxdsm
c15c78feeb feat: migrate storage from SQLite to PostgreSQL (#1793)
# Migrate storage from SQLite to PostgreSQL — full dashboard cutover

Migrates Fusion's storage layer to the embedded PostgreSQL
`AsyncDataLayer` (the default backend) and **completes the
satellite-store + feature cutover** so every dashboard and Command
Center surface works in PG mode.

## Status — every surface works in embedded-PG mode

Verified live against a running embedded-Postgres dashboard (all
**200**, zero 5xx) and gate-tested (**23 files / 99 tests** on embedded
PG, plus engine-core 294 and ci-shape 63 in the blocking merge gate;
core/engine/cli/dashboard typecheck clean).

| Area | Surfaces | State |
|---|---|---|
| Satellite stores | workflows, todos, insights, research, missions,
goals, mailbox | ✅ |
| Views | artifacts, documents, evals | ✅ |
| Command Center | activity, productivity, team, tokens, tools,
**workflows**, **github**, **signals**, **plugin-activations**, **live**
(all 10) | ✅ |
| Run execution | insight generation, research run execution | ✅
(store-path; AI step needs a provider) |
| Live updates | SSE push for mission/research/insight events | ✅ |
| Workflow editing | create / update / delete / select (+ id counter) |
✅ |
| Engine | mission autopilot, incident-signal ingestion, regression
storm-guard, agent wake-on-message | ✅ |
| Core | tasks, agents, secrets, automations, memory, chat, usage, PRs,
git | ✅ |

## Approach

Each satellite store gets an `Async<Store>` wrapper exposing the sync
store's method names over the existing `async-*-store.ts` helpers;
`get<Store>Store()` returns a `Sync | Async` union; consumers `await`
(harmless on sync), and engine/CLI paths that can't convert use
`instanceof Sync` graceful fallback. Analytics aggregators branch on
`"ping" in dbOrLayer` to run schema-qualified raw SQL over `project.*`
(snake_case) in PG. Executors/orchestrators/autopilot are
await-converted to drive the union store; the async store wrappers
extend `EventEmitter` so SSE live-push fires in both backends.

Not-yet-ported capabilities degrade gracefully (never 500) and are
individually called out in commits.

## Sync with main

The branch is kept continuously merged with `main` (currently through
FN-7845, 2026-07-12); the earlier "final rebase deferred" note no longer
applies. Use **Create a merge commit** (or squash) to land it — GitHub's
rebase-merge cannot replay a merge-maintained branch.

## Residual Review Findings

Multi-agent code review of the PostgreSQL satellite-store ports (U1–U5)
applied 3 safe fixes (see `fix(review): apply autofix feedback`). The
following are **real but gated** — recorded here as follow-up work
rather than auto-applied. All are SQLite→PostgreSQL
**concurrency/atomicity regressions**: the sync stores were immune only
by SQLite's single-writer, single-threaded-handler execution; the async
ports open multi-await read-modify-write windows. **Reachability is low
today** because the execution engines that generate concurrent same-run
mutations (insight run executor, research orchestrator/dispatcher) are
`instanceof`-gated to sync mode in PG. No process-crash class survived
(all engine fallbacks correctly guard the sync store).

- **[P1] Research `appendResearchEvent` dual-write is non-atomic**
(`packages/core/src/async-research-store.ts`, corroborated: adversarial
+ reliability). The `research_run_events` insert (own transaction) and
the `run.events` jsonb update are separate writes — a crash between
them, or two concurrent appends, splits the table count from the jsonb
array. **Fix:** perform the seq-insert and the jsonb update in one
`layer.transactionImmediate`.
- **[P1] Research run terminal-reversion via stale full-row persist**
(`async-research-store.ts` `persistResearchRun`/`updateResearchStatus`).
Concurrent `PATCH /runs/:id/status` + `POST /runs/:id/events` can revert
a terminal run to `running` by overwriting the whole row, bypassing the
transition guard. **Fix:** scoped column `UPDATE`s with a `WHERE status
…` guard, or optimistic version column.
- **[P2] `updateResearchRun`/`updateInsightRun` read-then-write TOCTOU**
— concurrent PATCHes last-writer-wins on the lifecycle merge. **Fix:**
`SELECT … FOR UPDATE` / enclosing transaction.
- **[P2] `upsertRun`/`createRunOrThrowConflict` check-then-create race**
(`async-insight-store.ts`) — two callers can each create an "active"
run. **Fix:** partial unique index on `(projectId, trigger) WHERE status
IN ('pending','running')`.
- **[P3] `createResearchRetryRun` return-value divergence** — sync
returns the pre-update `queued` snapshot; async returns the reloaded
`retry_waiting` run (persisted state is identical). Pick one side for
cross-backend parity.
- **[P2/perf] Mission `getMissionWithHierarchy`/`getMissionHealth` N+1
fan-out** — O(milestones×slices) sequential round-trips hold one pool
slot per request; can starve the pool for large hierarchies. **Fix:**
batched/joined reads.
- **Testing gaps:** no PG-mode concurrency tests (interleaved
status/event mutations), no sync↔async parity assertion for the
lifecycle-error codes, and no mission status/health rollup parity test
vs the sync `MissionStore`.

~~Out of scope (deferred): AI run *execution* (insight/research) +
mission autopilot + live SSE mission events remain sync-gated/degraded
in PG mode.~~ **Since ported** — insight/research run execution, mission
autopilot, and SSE live push all run on the async layer now, which also
makes the concurrency findings above genuinely reachable; they remain
open follow-ups.







---

## Update — 2026-07-12: production-readiness hardening & live acceptance

Everything below landed on this branch since the description above was
written:

**Production blockers from review — fixed**
- `recoverStaleTransitionPending` ported to the async layer (backend
moves write + clear the crash-safe marker; startup/maintenance sweeps no
longer throw).
- Lost-update class fixed: `atomicWriteTaskJson`/`WithAudit` write
changed columns only (full-row upserts silently resurrected stale fields
across concurrent store instances — the "task stuck unplanned forever"
bug).
- First-boot **auto-migration**: booting the PG backend over a project
with a legacy `fusion.db` migrates it automatically (loud failure,
SQLite kept as backup), and the dashboard shows a one-time **"your data
was migrated" banner** with the backup paths and a Need-help Discord
link.
- `pg_dump`/`pg_restore` discovered from common install locations for
embedded-mode backups.
- The PG suite is part of the blocking merge gate (`test:pg-gate`).

**Multi-project isolation (PR #2007, merged into this branch)**
- `project_id` partition key on tasks / archived tasks / config,
`taskProjectScope` threaded through every scan/claim/count, per-project
config rows, layer bound to the project at startup.
- Review P1 follow-up: the shared cold-storage `archive.archived_tasks`
table is also partitioned and all archived-board reads/counts/searches
are scoped.
- Schema drift self-heal generalized to schema-qualified columns so
existing databases upgrade in place.

**Other changes**
- Node settings sync **removed** in PG mode (409
`settings-sync-disabled-postgres`) — nodes share state by connecting to
the same database; auth sync kept (per-machine file).
- Perf (review findings): `listTasks` pushes column filter + ORDER BY +
LIMIT/OFFSET into SQL; `getConversation` capped to the most recent 200
messages.
- Fixed a false "operator action required" pause-abort log fired on
every successfully auto-merged task.

**Live acceptance — PASSED (2026-07-12)**
A sandboxed instance (isolated HOME, embedded PG, real Opus executor)
ran a task through the complete cycle: create → triage (AI spec) →
execute → in-review → AI squash-merge landed on the project's `main` →
done. A write+read sweep of every data surface (settings, comments,
documents, attachments + artifact bridge + artifact edit, chat with real
generation, goals, missions, agent mail, secrets, workflows, memory, CC
analytics) was green on embedded PG.

**Known remaining work**
- The per-project `config` PK re-key has no upgrade path for
pre-isolation embedded-PG databases (needs a real `DROP
CONSTRAINT`/re-key migration; fresh databases are fine).
- `pg_dump`/`pg_restore` binaries are not yet bundled in release
artifacts (PATH/common-location discovery only).
- The satellite-store concurrency findings listed above.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Phil Larson <hello@phillarson.xyz>
Co-authored-by: fusion-merge <fusion-merge@local>
2026-07-13 19:07:58 -07:00
gsxdsm
1ff83a2735 chore(release): v0.60.0
Version bump via changesets.
2026-07-13 10:32:12 -07:00
gsxdsm
c3c3861efa fix: stale TRANSITIVE_EXTERNALS + dashboard dist/client clean + cross-worker build lock (round 12) (#2065)
## Summary

Fixes shard 3 failures from runs 29258546612 + 29259574946 (FN-7936
drift).

## Fixes

### `package-config.test.ts` — stale TRANSITIVE_EXTERNALS entry
FN-7936 aliased `@fusion/core` to a runtime shim in bundled plugin
outputs; it's no longer a tsup external. Removed the stale allowlist
entry.

### `bundle-output.test.ts` — stale dashboard client hash ENOENT
**Root cause:** Two test files (`bundle-output.test.ts` +
`extension-integration.test.ts`) call
`buildCliWithRealDashboardAssets()` which triggers concurrent vite/tsup
builds. Vitest runs them in parallel (`pool: "forks"`, `fileParallelism:
true`). Without coordination, two builds clean and write `dist/client`
simultaneously, causing `ENOENT` on content-hashed chunk files.

**Fix (3 parts):**
1. **`workspace-tools.ts buildDashboardClient`** — `rm dist/client`
before vite build. Prevents stale content-hash references from previous
builds.
2. **`bundle-output-helpers.ts`** — atomic `mkdirSync` file lock around
`buildCliWithRealDashboardAssets()`. Winner builds; losers poll with
`Atomics.wait`, then re-check `hasBuiltDashboardAssets()`. On timeout,
**throws** (never builds without owning the lock).
3. Lock uses `Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0,
0, 500)` for sync sleep — no child process spawning.

## Verification
- Gate: exit 0 ✅

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved dashboard asset builds by removing stale files before
rebuilding.
* Prevented concurrent builds from producing incomplete or corrupted
dashboard assets.
* Added safeguards to detect stalled asset builds and fail with clearer
errors.

* **Tests**
* Updated package validation checks to reflect current runtime bundling
behavior.
  * Improved reliability of CLI build-related test execution.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-13 08:14:20 -07:00
gsxdsm
502c4c132f chore(release): v0.59.0
Version bump via changesets.
2026-07-13 01:23:43 -07:00
gsxdsm
967f3dd900 FN-7923: align task-card cost badge bottom-right with other footer chips
Narrative: Reworked TaskCard footer/meta layout so the cost badge (and its sibling footer-right chips) render inline at the bottom-right of the card-meta row when the footer has no leading content, instead of always sitting in a separate footer row beside the time badge.

- Extracted the footer-right chip cluster (cost, time, retry, near-duplicate, undo-of, GitHub tracking) into a shared `footerRightCluster` render, computed once instead of duplicated inline.
- Added `footerHasLeadingContent`/`footerRightHasContent`/`placeFooterRightInMeta` derivations so the cluster moves into `.card-meta` (bottom-right, inline with other tags) when there's no files-changed button or GitHub-import leading content, and the meta row is visible; otherwise it keeps the existing `.card-footer-row` placement for in-progress/tracked cards.
- Updated dashboard-guide.md wording to describe the cost badge as appearing 'with the card's other footer/meta chips' rather than 'beside the execution-time badge'.
- Extended TaskCard.test.tsx coverage for the new placement behavior.
- Desktop local-runtime.ts: kept the previously-unused `reason` parameter on `requestRestart` explicitly referenced (void reason) for API parity/lint cleanliness, unrelated cosmetic cleanup carried in the same branch.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/TaskCard.tsx     | 242 +++++++++++----------
 .../app/components/__tests__/TaskCard.test.tsx     |  96 +++++++-
 packages/desktop/src/local-runtime.ts              |   4 +-
 4 files changed, 222 insertions(+), 122 deletions(-)

Fusion-Task-Id: FN-7923

Fusion-Task-Lineage: 7e4c3109-f39e-45c0-af13-358ce54f945c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-12 23:56:13 -07:00
gsxdsm
f1b6a6340c Address review feedback: System panel hardening (#2028)
Correctness/reliability:
- engine restart-all: compensating pause on resume failure so a project
  is never left marked active with a dead engine
- desktop restart: app.quit() (runs before-quit teardown) not app.exit(0)
- supervisor: SIGINT/SIGTERM during crash-backoff exit immediately;
  stopping-latch prevents respawn after intentional shutdown
- coalesce concurrent /system/restart requests (restartScheduled guard)
- rebuild job completion chain given a .catch (no stranded activeJob)

Security:
- same-origin CSRF guard on all mutating /system/* POSTs (safe under
  --no-auth / desktop)
- redact secrets in host-process log history (reuse core redactSecrets)
- report-bug: confirm before including server logs + escape ``` fences
- sanitize restart reason; Object.hasOwn scope-guard (prototype-key 500)

Frontend:
- log tail dedup (drop redundant REST backfill; SSE heartbeat stops 45s
  reconnect churn) + X-Accel-Buffering:no on both SSE routes
- restart-wait 90s timeout re-enables controls
- hydrate buffered rebuild lines on mount (mid-build panel open)

Maintainability + tests:
- engineAvailable reflects centralCore; hoisted systemLogs option; typed
  desktop systemControl DTO
- add tests: SSE routes, exit-86 respawn, compiled-binary respawn,
  engine-restart recovery, log redaction

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:42:09 -07:00
gsxdsm
a227b19a22 feat: add Command Center System panel with rebuild/restart controls, Plugins tab, and supervised-by-default dashboard
- pnpm dev / new pnpm start default to the dashboard command
- fn dashboard (and bare fn/fusion/npx, incl. packaged binaries) now runs
  supervised by default via an attached foreground child (TUI-safe);
  --no-supervise opts out; FUSION_RESTART_EXIT_CODE=86 = intentional restart
- New /api/system routes: info, restart, rebuild jobs with SSE output,
  engine restart, agents restart-all, plugins reload-all, log tail
- System tab: rebuild & restart (source checkouts only, hidden elsewhere),
  restart server/engine/agents, backup DB, live server logs, copy
  diagnostics, report bug; new Plugins tab reusing PluginManager
- Desktop restart via Electron app.relaunch(); DashboardLogSink now keeps a
  bounded history + listener feed for the log viewer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:42:09 -07:00
gsxdsm
f82a3d2840 chore(release): v0.58.0
Version bump via changesets.
2026-07-11 23:50:00 -07:00
gsxdsm
cc901c2b9d FN-7762: expand update-notification test coverage across CLI, dashboard, and desktop surfaces
Broadens regression coverage for the npm-release update-check invariant so it holds across every consuming surface, not just the reported repro.

- Replace the update-check route/service semver spot-checks with a parametrized case matrix (equal, newer, older, prerelease/build metadata, short/long version segments) to close false-positive/false-negative gaps.
- Add dedicated route-level tests asserting the update-check API route surfaces the same invariant.
- Add CLI update command tests covering notification rendering across version-comparison cases.
- Add desktop native update-check tests covering the same invariant on the desktop shell.
- Add dashboard useUpdateCheck hook tests verifying consistent notification behavior for the hook consumers.

Files changed:
 packages/cli/src/commands/__tests__/update.test.ts | 59 ++++++++++++++++++
 .../app/hooks/__tests__/useUpdateCheck.test.ts     | 25 ++++++++
 .../src/__tests__/update-check-route.test.ts       | 71 ++++++++++++++++++++++
 .../dashboard/src/__tests__/update-check.test.ts   | 42 +++++++------
 packages/desktop/src/__tests__/native.test.ts      | 27 ++++++++
 5 files changed, 206 insertions(+), 18 deletions(-)

Fusion-Task-Id: FN-7762

Fusion-Task-Lineage: 6ab34312-fb4e-487a-aefc-2ab133bf79af

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-09 23:46:21 -07:00
gsxdsm
081dae0e0f FN-7705: Add Grok CLI runtime support as a bundled plugin
Adds a new bundled Grok CLI runtime plugin, wiring it end-to-end into settings, auth routes, model discovery, and the dashboard authentication UI.

- New `fusion-plugin-grok-runtime` package with CLI spawn, probe, provider, process-manager, and runtime-adapter modules plus tests
- Bundled-plugin install list (CLI + core) updated to auto-install the grok-cli plugin
- New `useGrokCli`/`grokCliBinaryPath` settings in `settings-schema.ts` and `types.ts`
- Dashboard: `GrokCliProviderCard` component/styles, `ProviderIcon` grok entry, `AuthenticationSection` wiring
- New `grok-model-cache.ts` for caching `grok models` discovery results, registered model/auth routes for `/auth/grok-cli` and `/providers/grok-cli/status`, merged into `/api/models`
- `runtime-provider-probes.ts` extended with Grok CLI probe/model-discovery delegation
- Docs updated (`PLUGIN_AUTHORING.md`, `settings-reference.md`) and changeset added (minor, feature)
- Workspace config (`pnpm-workspace.yaml`, `pnpm-lock.yaml`) updated to register the new plugin package

Files changed:
 .changeset/fn-7705-grok-cli-runtime.md             |   7 +
 docs/PLUGIN_AUTHORING.md                           |   2 +-
 docs/settings-reference.md                         |   4 +
 packages/cli/src/plugins/bundled-plugin-install.ts |   8 +
 .../cli/src/plugins/staged-bundled-plugin-ids.ts   |   1 +
 packages/cli/vitest.config.ts                      |  12 +
 .../core/src/__tests__/grok-cli-settings.test.ts   |  34 +++
 packages/core/src/index.ts                         |   1 +
 .../core/src/plugins/bundled-plugin-install.ts     |  10 +
 packages/core/src/settings-schema.ts               |   6 +
 packages/core/src/types.ts                         |   9 +
 packages/dashboard/app/api/legacy.ts               |  40 ++++
 .../app/components/GrokCliProviderCard.css         |  65 ++++++
 .../app/components/GrokCliProviderCard.tsx         | 204 ++++++++++++++++
 packages/dashboard/app/components/ProviderIcon.tsx |   5 +
 .../__tests__/GrokCliProviderCard.test.tsx         | 105 +++++++++
 .../app/components/__tests__/ProviderIcon.test.tsx |   8 +
 .../settings/sections/AuthenticationSection.tsx    |   8 +-
 packages/dashboard/package.json                    |   1 +
 .../src/__tests__/grok-model-cache.test.ts         | 152 ++++++++++++
 .../register-model-routes-grok-cli.test.ts         | 214 +++++++++++++++++
 .../dashboard/src/__tests__/routes-auth.test.ts    | 258 ++++++++++++++++++++-
 packages/dashboard/src/grok-model-cache.ts         | 166 +++++++++++++
 packages/dashboard/src/routes.ts                   |   1 +
 .../dashboard/src/routes/register-auth-routes.ts   | 134 ++++++++++-
 .../dashboard/src/routes/register-model-routes.ts  |  51 ++++
 packages/dashboard/src/runtime-provider-probes.ts  |  43 ++++
 packages/dashboard/vitest.config.ts                |  12 +
 packages/desktop/scripts/workspace-tools.ts        |   3 +-
 plugins/fusion-plugin-grok-runtime/CHANGELOG.md    |   7 +
 plugins/fusion-plugin-grok-runtime/README.md       |  54 +++++
 plugins/fusion-plugin-grok-runtime/manifest.json   |   6 +
 plugins/fusion-plugin-grok-runtime/package.json    |  40 ++++
 .../src/__tests__/cli-spawn.test.ts                | 103 ++++++++
 .../src/__tests__/index.test.ts                    |  12 +
 .../src/__tests__/probe.test.ts                    | 135 +++++++++++
 .../src/__tests__/process-manager.test.ts          |  96 ++++++++
 .../src/__tests__/provider.test.ts                 |  57 +++++
 .../src/__tests__/runtime-adapter.test.ts          |  21 ++
 .../fusion-plugin-grok-runtime/src/cli-spawn.ts    |  50 ++++
 plugins/fusion-plugin-grok-runtime/src/index.ts    |  74 ++++++
 plugins/fusion-plugin-grok-runtime/src/probe.ts    | 107 +++++++++
 .../src/process-manager.ts                         |  86 +++++++
 plugins/fusion-plugin-grok-runtime/src/provider.ts |  25 ++
 .../src/runtime-adapter.ts                         |  25 ++
 plugins/fusion-plugin-grok-runtime/src/types.ts    |  12 +
 plugins/fusion-plugin-grok-runtime/tsconfig.json   |  10 +
 .../fusion-plugin-grok-runtime/vitest.config.ts    |  22 ++
 pnpm-lock.yaml                                     |  25 ++
 pnpm-workspace.yaml                                |   1 +
 50 files changed, 2525 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-7705

Fusion-Task-Lineage: b8194ea8-c773-4199-a52a-b0e4e7347192

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 23:39:34 -07:00
gsxdsm
400f04530c chore(release): v0.57.0
Version bump via changesets.
2026-07-08 16:27:10 -07:00
gsxdsm
26f22861fa FN-7637: port bundled-plugin auto-install into @fusion/core for the desktop runtime
Move the host-agnostic bundled-plugin auto-install logic (manifest loading, entry-path
resolution, install/update/enable flow) out of the CLI package into @fusion/core so the
desktop embedded runtime can auto-install bundled runtime plugins without depending on
the CLI package; the CLI module becomes a thin adapter that supplies its own bundle-dir
resolution to the shared helper.

- Add packages/core/src/plugins/bundled-plugin-install.ts with the shared, host-agnostic
  ensureBundledPluginInstalled / ensureBundledDependencyGraphPluginInstalled /
  ensureBundledCursorRuntimePluginInstalled implementation and BUNDLED_PLUGIN_IDS/
  isBundledPluginId/resolvePluginEntryPath, exported from @fusion/core's index.
- Slim packages/cli/src/plugins/bundled-plugin-install.ts to a CLI-specific
  candidate-bundle-dir resolver that delegates to @fusion/core and re-exports the same
  public surface dashboard.ts/serve.ts/daemon.ts already depend on.
- Remove the now-redundant packages/cli/src/plugins/__tests__/resolve-plugin-entry-path-sync.test.ts
  (coverage moved with the implementation to @fusion/core).
- Add packages/desktop/src/bundled-plugin-dirs.ts to resolve each bundled plugin's staged
  package directory via import.meta.resolve, mirroring the CLI's dist/plugins/<id> resolver.
- Wire local-runtime.ts and local-server.ts to call ensureBundledPluginInstalled before
  loadAllPlugins() and expose a lazy-install callback for PUT /api/plugins/:id/settings,
  mirroring the CLI dashboard command's startup auto-install pass.
- Update docs/PLUGIN_AUTHORING.md to describe the shared bundled-plugin-install location.

Files changed:
 docs/PLUGIN_AUTHORING.md                           |  11 +
 .../__tests__/bundled-plugin-install.test.ts       | 619 ++-------------------
 .../resolve-plugin-entry-path-sync.test.ts         |  97 ----
 packages/cli/src/plugins/bundled-plugin-install.ts | 250 +--------
 packages/core/src/index.ts                         |   8 +
 .../__tests__/bundled-plugin-install.test.ts       | 391 +++++++++++++
 .../core/src/plugins/bundled-plugin-install.ts     | 186 +++++++
 .../src/__tests__/bundled-plugin-dirs.test.ts      |  59 ++
 .../desktop/src/__tests__/local-runtime.test.ts    | 183 +++++-
 .../desktop/src/__tests__/local-server.test.ts     |  96 +++-
 packages/desktop/src/bundled-plugin-dirs.ts        |  61 ++
 packages/desktop/src/local-runtime.ts              |  66 ++-
 packages/desktop/src/local-server.ts               |  36 +-
 13 files changed, 1171 insertions(+), 892 deletions(-)

Fusion-Task-Id: FN-7637

Fusion-Task-Lineage: 953c5b82-a079-4600-b3af-45c974cd5014

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:06:16 -07:00
gsxdsm
d54ab80395 FN-7623: wire pluginStore/pluginLoader into desktop embedded dashboard server
Fixes the desktop app's plugin subsystem, which was never wired into createServer(), breaking Settings > Plugins Browse registry and plugin install.

- local-runtime.ts: construct a PluginStore + PluginLoader (mirroring the CLI dashboard command), load enabled plugins, run plugin schema-init hooks, and pass pluginStore/pluginLoader/pluginRunner into createServer()
- local-server.ts: apply the same wiring to the legacy desktop local server path for consistency
- Both paths fail soft: a broken plugin subsystem (e.g. corrupt manifest) is logged/traced but no longer blocks embedded dashboard startup
- Extend local-runtime.test.ts and local-server.test.ts to cover plugin wiring and the fail-soft path
- Add changeset (patch) documenting the fix

Files changed:
 .changeset/fn-7623-desktop-plugin-wiring.md        |   7 ++
 .../desktop/src/__tests__/local-runtime.test.ts    | 123 ++++++++++++++++++++-
 .../desktop/src/__tests__/local-server.test.ts     |  69 +++++++++++-
 packages/desktop/src/local-runtime.ts              |  50 ++++++++-
 packages/desktop/src/local-server.ts               |  41 ++++++-
 5 files changed, 286 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-7623

Fusion-Task-Lineage: c6f291fb-e6aa-4ac1-a3f3-4189fc831c60

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:04:53 -07:00
gsxdsm
fe5a595984 FN-7622: unify desktop and CLI provider seeding to fix truncated provider list
The Electron desktop app's in-process dashboard server skipped the CLI's provider seeding sequence, so /api/providers and /api/models returned a truncated catalog (missing built-in API-key providers and user customProviders[]) compared to the identical config on the web build.

- Move provider-auth.ts and custom-provider-registry.ts from @fusion/cli into @fusion/engine as the single shared implementation
- Add engine/src/provider-registration.ts exposing seedDashboardProviders(), mirroring the CLI's exact startup order (built-in Zai provider registration -> wrapAuthStorageWithApiKeyProviders -> model merge/refresh -> registerCustomProviders -> settings:updated resubscription)
- Update desktop/src/local-runtime.ts and local-server.ts to call the shared seedDashboardProviders() helper instead of constructing a raw authStorage/modelRegistry
- Convert packages/cli/src/commands/provider-auth.ts and custom-provider-registry.ts into re-export shims preserving unchanged observable behavior
- Add engine/src/__tests__/provider-registration.test.ts and expand desktop local-runtime/local-server tests to cover the shared seeding path
- Add changeset for @runfusion/fusion (patch)

Files changed:
 .changeset/fn-7622-desktop-provider-parity.md      |   7 +
 .../cli/src/commands/custom-provider-registry.ts   | 122 +----
 packages/cli/src/commands/provider-auth.ts         | 517 +--------------------
 .../desktop/src/__tests__/local-runtime.test.ts    |  93 ++++
 .../desktop/src/__tests__/local-server.test.ts     |  62 ++-
 packages/desktop/src/local-runtime.ts              |  33 +-
 packages/desktop/src/local-server.ts               |  21 +-
 .../src/__tests__/provider-registration.test.ts    | 192 ++++++++
 packages/engine/src/custom-provider-registry.ts    | 117 +++++
 packages/engine/src/index.ts                       |  18 +
 packages/engine/src/provider-auth.ts               | 513 ++++++++++++++++++++
 packages/engine/src/provider-registration.ts       | 105 +++++
 12 files changed, 1172 insertions(+), 628 deletions(-)

Fusion-Task-Id: FN-7622
Fusion-Task-Lineage: fb6fbbf3-745e-4623-b7af-11471e13f138
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:04:51 -07:00
gsxdsm
f87e11387f FN-7617: retry embedded desktop runtime startup to fix transient Windows launch failure
Adds bounded internal retry to the desktop embedded-start path so a transient first-attempt failure self-heals before the operator ever sees the "Couldn't start local Fusion" error screen.

- LocalRuntimeManager.startEmbedded() now retries startEmbeddedAttempt() up to startupRetries (default 3) total attempts with a startupRetryDelayMs (default 150ms) delay between attempts, both overridable via constructor options for deterministic zero-delay tests.
- status.state stays "starting" across retried attempts; only the final attempt's real error sets state "error" and is thrown/surfaced, so genuine failures still report their real message unchanged.
- Only affects the embedded-start path (never external-cli or already-running paths).
- Adds regression tests covering retry-then-success, exhausted-retries-surfaces-final-error, and status transitions across attempts.

Files changed:
 .../desktop/src/__tests__/local-runtime.test.ts    | 158 ++++++++++++++++++++-
 packages/desktop/src/local-runtime.ts              |  76 +++++++++-
 2 files changed, 228 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-7617

Fusion-Task-Lineage: 2baf90f0-052c-42ff-a5b1-bc0b802d0ddc

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-06 19:03:06 -07:00
gsxdsm
eb86555797 chore(release): v0.56.1
Version bump via changesets.
2026-07-05 19:57:09 -07:00
gsxdsm
2025f9d56d chore(release): v0.56.0
Version bump via changesets.
2026-07-05 17:13:36 -07:00
gsxdsm
ced783ea79 FN-7473: open desktop Anthropic OAuth in browser
Route desktop OAuth popups to the system browser while preserving Anthropic subscription login polling.\n\n- Add Electron window-open handling that keeps internal Fusion navigation in-app and external http(s) OAuth URLs in the system browser.\n- Cover Anthropic Subscription polling so login-in-progress states do not show a false incomplete-login toast.\n- Document desktop OAuth browser handoff behavior and add a patch changeset.\n\nFiles changed:\n .../fn-7473-desktop-anthropic-oauth-browser.md     |  7 ++\n docs/dashboard-guide.md                            |  2 +-\n docs/settings-reference.md                         |  2 +-\n .../__tests__/SettingsModal.models-auth.test.tsx   | 76 ++++++++++++++++++++++\n .../desktop/src/__tests__/main-integration.test.ts |  2 +\n .../desktop/src/__tests__/main-local-mode.test.ts  |  3 +-\n .../desktop/src/__tests__/main.integration.test.ts |  2 +\n packages/desktop/src/__tests__/main.test.ts        | 54 ++++++++++++++-\n packages/desktop/src/main.ts                       | 60 +++++++++++++++++-\n 9 files changed, 203 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7473

Fusion-Task-Lineage: 3d6b0acd-536c-4f7d-8c6b-35eb519b46bb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 21:45:21 -07:00
gsxdsm
52dbc0e65e FN-7472: quit Windows desktop runtime on window close
Ensure Windows Desktop treats window close as application shutdown.

- Allow Windows BrowserWindow close events to proceed so Electron emits quit lifecycle hooks.
- Keep non-Windows close-to-tray behavior while documenting platform-specific close semantics.
- Cover native, renderer, tray, and runtime cleanup paths with desktop tests.

Files changed:
 .changeset/fn-7472-windows-desktop-close-quits.md |   7 ++
 packages/desktop/README.md                        |  10 +-
 packages/desktop/src/__tests__/ipc.test.ts        |   9 ++
 packages/desktop/src/__tests__/main.test.ts       |  76 ++++++++++++++-
 packages/desktop/src/__tests__/tray.test.ts       | 110 +++++++++++++++++++++-
 packages/desktop/src/main.ts                      |   8 ++
 packages/desktop/src/tray.ts                      |   4 +
 7 files changed, 214 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-7472
Fusion-Task-Lineage: c007e20f-37b9-435e-861d-1665e2691bc9
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 21:45:21 -07:00
gsxdsm
843f365452 chore(release): v0.55.0
Version bump via changesets.
2026-07-03 13:10:20 -07:00
gsxdsm
da662c41a7 fix(onboarding,desktop): don't error on duplicate first agent; wire Switch-server button
First-run project setup surfaced a blocking "Agent with this name already exists" error when creating
the default CEO. The default first agent can be created from more than one first-run surface (the
unified ModelOnboarding agent step and the project-setup SetupWizard sub-flow), and agent names are
unique per store, so the second create returned 409. The step's goal — a first agent exists — was
already satisfied, so both onboarding surfaces now treat a name collision as success and advance
instead of blocking. The user still creates the agent; they just aren't punished for the flow offering
it twice.

Separately, the desktop header "Desktop local mode / Switch server" button did nothing: main relays
the click as a `shell:open-connection-manager` IPC (webContents.send), but the preload never forwarded
it to the `window` DOM event ShellContext listens for, so the signal was dropped. Add the preload
bridge so the button opens NativeShellConnectionManager (Local/Remote toggle + remote-server profiles),
letting operators switch between running locally, connecting to a remote server, or a different remote.

Regression tests: SetupWizard advances on an already-exists agent; preload dispatches the window event
on the IPC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:54:38 -07:00
gsxdsm
a318267976 build(desktop): allow redirecting staged deploy via FUSION_DESKTOP_DEPLOY_DIR (#1884)
Follow-up to #1878 (merged). While building the Windows desktop
installer locally, `pnpm deploy`'s final temp-dir rename hits `EPERM` on
the orca-managed Windows workspace mount and litters deeply-nested
`deploy_tmp_*` dirs that are painful to remove.

This lets local Windows installer builds redirect the staged production
closure to an external, plain-NTFS path via a new
`FUSION_DESKTOP_DEPLOY_DIR` env var. **CI and the default in-tree
`packages/desktop/deploy` path are unchanged** — the override is opt-in.

Verified locally: with
`FUSION_DESKTOP_DEPLOY_DIR=C:\Users\...\fusion-build\deploy`, `pnpm
--filter @fusion/desktop build` stages the full closure externally
without the EPERM race, and `electron-builder --projectDir <that dir>
--win nsis --x64` produces a signed installer.

🤖 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**
* Desktop deployment staging can now be configured with an environment
variable, making it easier to customize where build files are prepared.
* **Documentation**
* Added notes about updated desktop deployment behavior on Windows,
including common rename and cleanup issues.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-03 09:29:38 -07:00
gsxdsm
08e47d4f0d fix(desktop): migrate userData on relocation, verify packaged assets, harden Windows CI
- Add a one-time copy of the previous default Electron profile into
  ~/.fusion/desktop-user-data (user-data-migration.ts) so upgrading operators
  keep window geometry/session instead of starting fresh (report Issue 8).
- Verify main.js/preload.js/client assets in scripts/build.ts (pre-package
  staging) and in the packaged app.asar via desktop-windows.yml, so an
  incomplete package fails the build/CI instead of dead-ending at runtime with
  a silent missing preload (report Issue 5, recommendation #2).
- Fix two pre-existing stale workflow-assertion tests that expected a bare
  'electron-builder --win' after the scripts moved to '--projectDir deploy'.
- Update the field report with a per-issue resolution matrix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 08:49:43 -07:00
gsxdsm
d97e66a657 fix(desktop): sync lockfile, gate Windows GPU flags, document desktop hardening
- Regenerate pnpm-lock.yaml for the new electron@^33.4.11 CLI dependency so
  --frozen-lockfile stops failing every PR-check job.
- Gate the GPU/sandbox-disabling Electron flags (--no-sandbox, --disable-gpu,
  etc.) to Windows only via os.platform(); applying them on macOS/Linux was a
  security and rendering regression. This also resolves the unused os import
  that failed lint.
- Add FNXC comments for the Windows GPU flags, desktop user-data isolation, and
  CLI dashboard-server reuse per project comment convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 08:13:06 -07:00
gsxdsm
62c1fa14fa build(desktop): allow redirecting staged deploy via FUSION_DESKTOP_DEPLOY_DIR
pnpm deploy's final temp-dir rename hits EPERM on the orca-managed Windows workspace mount and litters
deeply-nested deploy_tmp_* dirs. Let local Windows installer builds redirect the staged closure to an
external plain-NTFS path via FUSION_DESKTOP_DEPLOY_DIR; CI and the default in-tree path are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 07:49:49 -07:00
gsxdsm
6d7715fe9e Merge branch 'main' into desktop-release-issues-report 2026-07-03 07:48:51 -07:00
gsxdsm
00afb22bcb FN-7458: default startup theme mode to system
Default fresh dashboard startup and appearance reset to System mode while keeping Shadcn Ember as the color theme.

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

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

Fusion-Task-Id: FN-7458
Fusion-Task-Lineage: fb6184b4-9a6a-4131-9f97-f8cd12ef904c
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-03 07:47:03 -07:00