Commit Graph

27 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
abd596b700 fix: pack full desktop dependency closure + resolve bun/desktop plugin loading on Windows
Desktop "Local" mode crashed with ERR_MODULE_NOT_FOUND because electron-builder's
pnpm collector drops `deduped` subtrees, so engine's transitive closure
(@modelcontextprotocol/sdk, pi-ai provider SDKs, etc.) was never packed. Stage the
complete flat prod closure with `pnpm deploy --legacy --config.node-linker=hoisted`
and package it via `electron-builder --projectDir deploy`, bypassing the lossy
collector entirely.

Also make the dashboard-imported example plugins loadable under plain Node (the
Electron main runtime): cursor/droid/roadmap now expose compiled `dist` on the
`import` condition (keeping `source`→src for the bun CLI) and are built during the
desktop build. Add `source` conditions to paperclip/agent-browser/even-cards/
even-realities-glasses/whatsapp-chat so the bun `--conditions=source` Windows CLI
compile resolves them from source.

Validated on macOS: @fusion/core|engine|dashboard import cleanly from the staged
deploy; packing yields a complete 705-package asar; bun-windows-x64 cross-compiles
with all plugin dist removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 20:40:02 -07:00
gsxdsm
3aef6dd5cf fix: build @fusion/core and @fusion/engine dist in desktop packaging
The packaged desktop "Local" runtime dynamically imports @fusion/engine, whose
tsc dist is gitignored. desktop-windows.yml built only `@fusion/desktop build`
(no root `pnpm build`), so it packaged an empty engine/dist and the app crashed
on Local mode with ERR_MODULE_NOT_FOUND for app.asar/node_modules/@fusion/engine.

Make the desktop build self-contained (build core then engine before packaging)
and add the parity `pnpm build` step to desktop-windows.yml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 19:34:11 -07:00
gsxdsm
1f3a15ec1c FN-7360: fix Windows desktop runtime packaging
Fix packaged Windows desktop startup by preserving Node-safe runtime dependencies and dashboard registry assets.

- Externalize Electron main/preload npm packages so CommonJS updater dependencies load natively.
- Load the dashboard plugin registry manifest through file IO and copy it into dashboard server dist from all build paths.
- Split Windows NSIS and portable artifact names and verify required Electron runtime resources in CI.
- Cover the packaging/runtime invariants with desktop and dashboard regression tests.

Files changed:
 .changeset/fn-7360-desktop-windows.md              |  7 +++
 .github/workflows/desktop-windows.yml              | 21 ++++++++
 packages/dashboard/package.json                    |  2 +-
 .../src/__tests__/plugin-registry-dist.test.ts     | 32 ++++++++++++
 .../src/__tests__/routes-plugin-registry.test.ts   | 10 ++--
 packages/dashboard/src/plugin-routes.ts            | 27 +++++++++-
 packages/desktop/README.md                         |  5 +-
 packages/desktop/electron-builder.yml              |  9 ++++
 packages/desktop/scripts/build.ts                  | 29 ++++++++--
 packages/desktop/scripts/workspace-tools.ts        |  4 ++
 .../desktop/src/__tests__/build-bundling.test.ts   | 61 ++++++++++++++++++++++
 .../src/__tests__/electron-builder-config.test.ts  | 15 ++++++
 packages/desktop/src/__tests__/ipc.test.ts         | 15 ++++++
 .../desktop/src/__tests__/local-runtime.test.ts    | 20 +++++++
 14 files changed, 247 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-7360

Fusion-Task-Lineage: a2d88130-c24f-43e2-932a-1e174b6afa35

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 08:01:59 -07:00
gsxdsm
8b81cceb17 fix(desktop): externalize @fusion/engine so desktop release builds pass
local-runtime.ts dynamically imports @fusion/engine, but it was missing from the
esbuild externals list (only @fusion/core and @fusion/dashboard were there). esbuild
followed the import and tried to bundle engine's transitive node-pty native .node
binaries, failing with "No loader is configured for .node files" — which broke every
desktop Windows EXE and macOS DMG build leg. Externalize @fusion/engine like the other
workspace packages; it resolves from node_modules at runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 23:38:59 -07:00
gsxdsm
d35f93e1ef FN-6512: refresh mobile PWA icons
Refresh the dashboard launcher artwork so installed mobile PWAs use the Fusion brand mark.

- Generate 192px and 512px dashboard PWA icons from the canonical logo in the desktop icon generator.
- Bump the service-worker cache name so installed PWAs refresh cached icon assets.
- Strengthen PWA tests to validate icon wiring, PNG dimensions, opacity, and non-blank brand content.
- Document the PWA icon regeneration workflow and add a patch changeset.

Files changed:
 .changeset/fn-6512-dashboard-pwa-icons.md        |   5 +
 docs/dashboard-guide.md                          |   4 +
 packages/dashboard/app/__tests__/pwa.test.ts     | 178 ++++++++++++++++++++---
 packages/dashboard/app/public/icons/icon-192.png | Bin 5466 -> 4634 bytes
 packages/dashboard/app/public/icons/icon-512.png | Bin 17687 -> 14826 bytes
 packages/dashboard/app/public/sw.js              |   2 +-
 packages/desktop/scripts/generate-icons.ts       |  75 +++++++---
 7 files changed, 227 insertions(+), 37 deletions(-)

Fusion-Task-Id: FN-6512

Fusion-Task-Lineage: a7a46e0d-fa7d-4ca1-b49c-f083aed92b17
2026-06-16 22:29:07 -07:00
gsxdsm
63f1e097a2 FN-6366: fix desktop Vitest constructor mocks
Stabilize the desktop Vitest suite under Vitest 4.1.8 while keeping dashboard builds complete.

- Convert Electron constructor mocks to constructable function implementations for BrowserWindow, Tray, Notification, and LocalRuntimeManager.\n- Assert local runtime initialization uses the mocked home directory in desktop main-process tests.\n- Build dashboard runtime plugin packages before the desktop dashboard build.

Files changed:\n packages/desktop/scripts/workspace-tools.ts        | 15 ++++++++++++++\n packages/desktop/src/__tests__/deep-link.test.ts   |  4 +++-\n .../desktop/src/__tests__/main-integration.test.ts | 23 ++++++++++++++--------\n .../desktop/src/__tests__/main-local-mode.test.ts  | 19 ++++++++++++++----\n .../desktop/src/__tests__/main.integration.test.ts | 21 ++++++++++++--------\n packages/desktop/src/__tests__/main.test.ts        | 13 +++++++++---\n packages/desktop/src/__tests__/native.test.ts      |  6 ++++--\n 7 files changed, 75 insertions(+), 26 deletions(-)

Fusion-Task-Id: FN-6366

Fusion-Task-Lineage: 4e4ccdbc-845f-47d9-a565-cc5d659cf089
2026-06-13 09:01:39 -07:00
gsxdsm
4148f43ce4 fix(release): honor --publish never, guard Windows signing, fix desktop spawn
Second pass after the cache/arch fix unblocked `pnpm build` and surfaced
later-stage failures:

- Desktop packaging called `pnpm --filter @fusion/desktop dist:mac -- <args>`,
  but pnpm leaks the `--` separator into the script args. electron-builder
  stops parsing at `--`, so `--publish never` was ignored — it auto-published
  to api.github.com/repos/gsxdsm/fusion/releases and 404'd. The same leak
  dropped Linux's `--x64 --arm64`. Switch all four desktop packaging steps to
  `pnpm --filter @fusion/desktop exec electron-builder ...`, which forwards
  args cleanly (verified locally).
- Windows CLI signing now skips when WINDOWS_CERTIFICATE_BASE64 is absent,
  mirroring the macOS guard (was hard-failing the bun-windows-x64 job).
- Desktop build spawns workspace .cmd bins with shell:true on Windows; Node
  rejects .cmd/.bat spawns without a shell (EINVAL) since CVE-2024-27980,
  which broke `@fusion/desktop build` on the Windows runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 00:30:39 -07:00
gsxdsm
b1d1221ba6 fix(desktop): build preload as CJS so contextBridge actually fires
esbuild was emitting preload.js as ESM (format:"esm"), but Electron
loads preload scripts via its sandboxed Node context, which is CJS.
With an ESM preload, the contextBridge.exposeInMainWorld calls
silently no-op, leaving window.fusionShell / window.fusionAPI
undefined in the renderer — which is why the dashboard always fell
through to "Can't reach the Fusion backend" and DesktopLaunchGate
always logged "window.fusionShell unavailable; bypassing".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 23:18:30 -07:00
gsxdsm
e5af9c93ae fix(desktop): packaged macOS app launched with no window / blank white screen
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>
2026-05-17 22:01:51 -07:00
gsxdsm
f84c048fe2 fix(desktop): bundle electron-updater into main.js
esbuild now bundles main.ts with electron-updater (and its transitive
deps) inline, externalizing only electron, workspace packages, and the
native better-sqlite3. This sidesteps the pnpm hoisting issue where
electron-updater's transitive `ms` lived only inside the .pnpm content
store and never landed in the packaged app.asar, leaving the in-app
updater non-functional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 13:07:02 -07:00
gsxdsm
6dde53ff0d fix(desktop): app icon + harden auto-updater loading
Generate a 1024x1024 macOS app icon from the dashboard logo so packaged
builds carry the Fusion brand instead of the default Electron icon, and
load electron-updater dynamically inside a try/catch so packaged builds
tolerate CJS/ESM interop quirks and missing transitive deps. Widen the
electron-builder files whitelist to include electron-updater's
transitive dep tree so they are actually bundled into the asar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 12:51:12 -07:00
Fusion (runfusion.ai)
ae5e292ff9 fix(FN-4750): remove unused desktop build import for lint
Fusion-Task-Id: FN-4750
Fusion-Task-Lineage: 54b3e35f-ef34-469a-aa9f-6d7fe9e79f27
2026-05-16 10:18:40 -07:00
Fusion (runfusion.ai)
477f79f3eb feat(FN-4737): parameterize worktree-escape test to use configured worktree
Adds parameterized test cases to the worktree-liveness test to exercise different configured `worktreesDir` paths, improving coverage of the worktree escape/isolation path.

Fusion-Task-Id: FN-4737

Fusion-Task-Lineage: 40e262ea-2507-461e-b9f5-940b3b4490f9
2026-05-16 09:56:28 -07:00
Fusion
22834e5c4e feat(FN-3404): add local embedded runtime manager to desktop app
Adds a local runtime manager to the desktop app (FN-3404) — an embedded engine process managed via IPC with packaging for bundled dependencies and lifecycle documentation. Also includes project mapping onboarding UI with persistence and rollback (FN-3505), plus related dashboard API and hook updates

Fusion-Task-Id: FN-3404
2026-05-07 23:21:04 -07:00
gsxdsm
ecf0eb6d84 feat(FN-1073): add desktop CLI workflow and packaging support
- Add new `fn desktop` CLI command with argument handling and comprehensive command/bin tests
- Implement desktop build and hot-reload dev scripts and wire package scripts/dependencies for Electron workflows
- Add electron-builder configuration and desktop main-process/integration test coverage to stabilize packaging behavior
- Document desktop development and usage in README files and include a changeset for the published CLI package
2026-04-08 01:40:05 -07:00
gsxdsm
c1fa49c719 feat(FN-1074): add desktop tray and application menu
- Add dedicated desktop tray and menu modules, including platform-aware menu templates and tray status/visibility controls
- Integrate tray setup, app menu initialization, and tray status exports into the Electron main process bootstrap
- Add tray icon assets plus an icon generation script and update desktop package dependencies/lockfile
- Expand desktop test coverage with new menu/tray test suites and main process integration assertions
- Update desktop README with tray and application menu usage/documentation
2026-04-07 23:11:28 -07:00