Skip to content

feat(desktop): native one-click installer with bundled PostgreSQL 17 + pgvector (macOS/Linux/Windows)#355

Merged
Weegy merged 10 commits into
mainfrom
feat/desktop-embedded-postgres
Jun 22, 2026
Merged

feat(desktop): native one-click installer with bundled PostgreSQL 17 + pgvector (macOS/Linux/Windows)#355
Weegy merged 10 commits into
mainfrom
feat/desktop-embedded-postgres

Conversation

@Weegy

@Weegy Weegy commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

Ships the native one-click desktop installer for omadia (macOS / Linux / Windows) — an Electron shell that bundles and supervises the existing middleware kernel + web-ui plus a bundled native PostgreSQL 17 + pgvector, with no Docker and no separate Node runtime. Once merged, auto-release.yml builds and attaches the installers to every release automatically (the desktop-apps reusable-workflow job).

Why native Postgres (not PGlite)

The first iteration embedded PGlite (Postgres compiled to WASM) over pglite-socket. It booted, but the WASM engine crashed (RuntimeError: unreachable) under the kernel's real query load and is single-connection. This PR replaces it with a real bundled PostgreSQL 17: full SQL compatibility (no WASM traps) and normal connection pooling. The DB engine is driven directly via initdb/postgres child processes (loopback-TCP, trust auth), staged as extraResources so it is executable on disk (never trapped in the asar).

Platforms (all CI-green — run on this branch)

OS pgvector source Status
macOS arm64 Homebrew postgresql@17 build green + boot-tested end-to-end
Linux x64 pgdg apt postgresql-17-pgvector build green + artifact structurally verified
Windows x64 MSVC nmake build from pgvector source (Chocolatey PG17 for headers) build green + artifact structurally verified

Validation

  • macOS packaged .app boot-tested: /api/v1/auth/providers + /health → 200, 25/25 sustained queries, CREATE EXTENSION vector (0.8.3) loads and computes, graceful shutdown.
  • Port-drift fix proven end-to-end: the kernel read database_url only from the vault (frozen at first boot), so a changed embedded-DB port would crash-loop boot. Gated OMADIA_EMBEDDED_DB=1 makes the live env DSN authoritative on desktop (cloud unchanged). Verified: forced the frozen port busy → app drifted to a new port → graph reconnected, no crash.
  • CI-artifact boot-test caught a real portability bug a green build hid: staged engine dylib symlinks were rewritten to absolute build-machine paths (resolve locally, dangle on CI / end-user machines → dyld: Library not loaded). Fixed by restoring relative in-tree symlinks from the engine's pg-symlinks.json manifest. Re-verified: CI artifact boots on a different machine than the one that built it.
  • Linux + Windows artifacts structurally verified (their engines can't run on the macOS dev box): correct vector.so / vector.dll placement per platform layout, relative (not absolute) symlinks, valid PE32+/ELF arch.

Signing (fail-soft)

Unsigned/ad-hoc without secrets; the build still produces installers. macOS reuses the proven _HIGH5 Apple secret names (Developer ID + notarization). Windows Authenticode is optional (WINDOWS_CSC_*).

Known limitations / follow-ups

  • Runtime boot of the Linux AppImage and Windows installer on those actual OSes is not yet done (only macOS can be booted on the dev box). The bundling is verified; the vector.so/vector.dll load is the same PG17 ABI bet proven on macOS.
  • macOS is arm64 only for v1 (Intel runners queue for hours; extraResources can't be arch-split). Intel x64 is a tracked follow-up.
  • Signed/notarized artifacts require the Apple/Windows signing secrets on the repo.

Weegy added 10 commits June 19, 2026 16:49
Builds the native installer end-to-end on macOS+Linux (Windows non-blocking),
wires it to run in-run from auto-release.yml (GITHUB_TOKEN releases don't fire
the release event), renames build/ -> buildResources/ (was gitignored so the
signing hook was never committed), and folds in third-pass review fixes
(embeddedDb lock leak, secrets fail-closed cache, supervisor supersession,
updater snapshot quiescing).
argon2 + sharp are N-API (ABI-stable, no rebuild needed). Only better-sqlite3 is
non-N-API; it publishes Electron prebuilds, so prebuild-install fetches one
(no Visual Studio / node-gyp), with a source-rebuild fallback. Should unblock
the Windows leg, which couldn't compile argon2/better-sqlite3 via node-gyp.
better-sqlite3 prebuild + N-API argon2/sharp make the Windows leg pass reliably
(run all-green), so drop continue-on-error; keep the 30min timeout.
…tion)

The provision step rebuilds only better-sqlite3; argon2/sharp are assumed N-API
(ABI-stable, prebuilds reused). Require all three under ELECTRON_RUN_AS_NODE so a
wrong assumption fails CI instead of crashing the kernel at boot.
…dules)

extraResources native modules are copied verbatim into every arch's DMG, so a
single arm64 runner produced an x64 DMG with an arm64 better_sqlite3.node that
crashes on Intel Macs. Build macOS per-arch on matching runners (macos-latest=
arm64 --arm64, macos-13=Intel --x64); each provisions its own arch's prebuild.
Also: move run-artifact upload after notarize/verify (final stapled installers),
and delete the temp signing keychain in teardown.
The per-arch split was correct but GitHub's macos-13 (Intel) runners queue for
hours, blocking releases. Ship Apple-Silicon-only DMG/zip for v1 (the vast
majority of active Macs); an arm64 DMG is honest where the broken x64 one wasn't.
Intel x64 tracked as a follow-up (cross-compile x64 prebuilds on the arm64 runner).
The packaged app crashed at kernel boot (ERR_MODULE_NOT_FOUND @omadia/*): the npm
workspace symlinks node_modules/@omadia/* -> packages/* are ABSOLUTE on CI runners
and fs.cpSync({dereference:true}) left them as dangling symlinks to the build
machine. stage-runtime now replaces each @Omadia symlink with a real copy of its
resolved package. Verified locally: kernel activates all @Omadia plugins, 0
module-resolution errors (only the green CI build hid this — caught by booting the
actual packaged artifact).
PGlite (Postgres-in-WASM, exposed over pglite-socket) booted but crashed
under the kernel's real query load (RuntimeError: unreachable) and is
single-connection. Replace it with a real bundled PostgreSQL 17 + pgvector:
full SQL compatibility (no WASM traps) and normal connection pooling.

- embeddedDb.ts: drive initdb/postgres child procs directly (the
  embedded-postgres npm wrapper is asar-unaware). Loopback-TCP only,
  -A trust loopback-only, locale C. `stopping` flag so a deliberate
  shutdown is not logged as a crash.
- supervisor.ts: drop GRAPH_POOL_MAX=1 (native PG pools normally); add
  OMADIA_EMBEDDED_DB=1 so the kernel treats the live DATABASE_URL as
  authoritative over the first-boot value frozen in the vault.
- knowledge-graph-neon plugin: prefer env DATABASE_URL when
  OMADIA_EMBEDDED_DB=1, else keep vault precedence (cloud unchanged).
  Fixes a boot crash-loop when the embedded Postgres port drifts between
  launches (collision -> new port) while the vault holds the old port.
- stage-runtime.mjs: stage the @embedded-postgres native tree to
  runtime/omadia-pg; pgvector gate now requires control + module + SQL.
- electron-builder.yml: ship omadia-pg as extraResources, exclude
  embedded-postgres from the asar, mac arm64-only.
- afterPack.js: detect Mach-O by magic bytes (PG binaries are
  extensionless); sign both omadia/ and omadia-pg/ trees.
- desktop-apps.yml: provision pgvector for PG17 (brew) into the engine;
  matrix mac-only until Linux/Windows pgvector provisioning is wired.

Validated on the packaged .app: auth/providers + health 200, 25/25
sustained, CREATE EXTENSION vector (0.8.3) loads, graceful shutdown,
and a real port-drift boot recovers (55671 busy -> 55772, graph ready).
…engine

The CI-built .app failed to launch initdb/postgres:
  dyld: Library not loaded: @loader_path/../lib/libicudata.68.dylib
because fs.cpSync({dereference:true}) does not preserve the engine's
relative same-dir symlinks (libicudata.68.dylib -> libicudata.68.2.dylib).
It rewrites them into ABSOLUTE links pointing at the build machine's
node_modules, which resolve locally (masking the bug) but dangle on CI
(/Users/runner/work/...) and on every end-user machine.

After staging, recreate each of the engine's relative symlinks verbatim
from the source tree (all 17 are relative + in-tree), so the dylib chain
resolves wherever the installer lands. Same class of bug as the @Omadia
workspace-symlink materialisation already handled above.

Verified: packaged .app now boots, cluster inits, "database system is
ready", no dyld errors.
macOS proved the bundled-native-Postgres engine end-to-end; bring back the
other two platforms, each provisioning a PG17 pgvector for its embedded
engine before staging:
- Linux: install postgresql-17-pgvector from the pgdg APT repo and copy
  vector.so + control + SQL into the linux-x64 engine (lib/postgresql,
  share/postgresql/extension — same layout as macOS).
- Windows: no prebuilt exists, so build vector.dll from source with MSVC
  (nmake /F Makefile.win) against a Chocolatey PG17 (headers + lib), then
  copy into the windows-x64 engine. Windows layout is FLAT: module in lib/,
  control + SQL in share/extension/.

stage-runtime.mjs made platform-aware:
- pgvector gate now checks the correct module/share paths per OS (Windows
  flat lib/ + share/extension; Unix nested under postgresql/).
- engine symlinks restored from the @embedded-postgres pg-symlinks.json
  manifest (relative, in-tree) instead of walking real fs symlinks. The
  tarballs ship zero real symlinks (postinstall materialises them), so
  reading the manifest is robust regardless of postinstall timing and is
  required for Linux's versioned .so chain. macOS output unchanged (still
  17 relative links); Windows manifest is empty (flat DLLs).

macOS re-verified locally (0 absolute links, gate passes). Linux/Windows
are CI-validated only — their engines can't run on the macOS dev box.
@Weegy Weegy merged commit 7f5ca7e into main Jun 22, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant