Files
nexu-io__open-design/flake.nix
PerishFire 3447f60a34 fix packaged payload desktop handoff (#5678)
* fix packaged payload desktop handoff

* fix beta mac full smoke fixture wiring

* fix tools-pack mac payload cold start

* test payload desktop update restart

* fix Nix daemon launcher protocol build

* fix(pack): harden Windows long-jump updates

* fix(pack): harden mac long-jump acceptance

* fix(handoff): defer armed journal writes until spawn and shutdown succeed

Previously executeLegacyPayloadDesktopHandoff wrote the armed handoff
journal, attempt, and runtime state before spawning the payload desktop
and before the old desktop accepted shutdown. When spawn() threw or the
shutdown request failed, the armed journal was stranded on disk, so the
next cold start bailed out of prepareLegacyPayloadDesktopHandoff() with
reason "already-armed" and the install stayed pinned to the old desktop
generation indefinitely.

Move the three writes to after both the payload child has spawned and the
shutdown has been accepted. The old desktop is still alive while it acks
the shutdown, and the payload waits for the old pid to exit before
resuming, so the state still lands before the payload reads it. Add
regression coverage for both the spawn-failed and shutdown-failed paths,
asserting the journal stays "prepared" and a later cold start can retry.

Generated-By: looper 0.10.3 (runner=fixer, agent=claude-code)

* fix(updater): await payload spawn acceptance

* fix(packaged): advance confirmed handoff recovery

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-07-20 02:21:49 +00:00

207 lines
6.3 KiB
Nix

{
description = "Open Design — local-first design product. Daemon (`od` CLI) + Next.js static web frontend.";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
dream2nix = {
url = "github:nix-community/dream2nix";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
flake-utils,
dream2nix,
home-manager,
}: let
filterProjectSource = includePaths:
nixpkgs.lib.cleanSourceWith {
src = self;
filter = path: type: let
root = toString self;
pathStr = toString path;
rel = nixpkgs.lib.removePrefix (root + "/") pathStr;
matches = includePath:
rel == includePath
|| nixpkgs.lib.hasPrefix (includePath + "/") rel
|| (type == "directory" && nixpkgs.lib.hasPrefix (rel + "/") includePath);
in
rel == ""
|| builtins.any matches includePaths;
};
perSystem = flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {inherit system;};
nodejs = pkgs.nodejs_24;
workspacePackageManifests = workspacePaths:
map (workspacePath: "${workspacePath}/package.json") workspacePaths;
# Keep in sync with .github/workflows/ci.yml change_scopes
# nix_validation_required filter.
daemonWorkspacePaths = [
"packages/release"
"packages/contracts"
"packages/registry-protocol"
"packages/agui-adapter"
"packages/plugin-runtime"
"packages/sidecar-proto"
"packages/launcher-proto"
"packages/sidecar"
"packages/platform"
"packages/diagnostics"
"apps/daemon"
];
# Keep in sync with .github/workflows/ci.yml change_scopes
# nix_validation_required filter.
webWorkspacePaths = [
"packages/release"
"packages/components"
"packages/contracts"
"packages/host"
"packages/platform"
"packages/sidecar"
"packages/sidecar-proto"
"apps/web"
];
daemonSrc = filterProjectSource ([
"package.json"
"pnpm-lock.yaml"
"pnpm-workspace.yaml"
"tsconfig.json"
"assets"
"plugins"
"skills"
"design-systems"
"design-templates"
"craft"
"prompt-templates"
]
++ daemonWorkspacePaths);
webSrc = filterProjectSource ([
"package.json"
"pnpm-lock.yaml"
"pnpm-workspace.yaml"
"tsconfig.json"
]
++ webWorkspacePaths);
pnpmDepsBaseInputs = [
"package.json"
"pnpm-lock.yaml"
"pnpm-workspace.yaml"
];
daemonPnpmDepsSrc = filterProjectSource (
pnpmDepsBaseInputs ++ workspacePackageManifests daemonWorkspacePaths
);
webPnpmDepsSrc = filterProjectSource (
pnpmDepsBaseInputs ++ workspacePackageManifests webWorkspacePaths
);
# nixpkgs ships pnpm 10.33.0; the repo's package.json declares
# `engines.pnpm: ">=10.33.2 <11"` and pnpm refuses to install
# against an older binary. Override the upstream tarball to
# the exact version pinned by `packageManager`. Bump the url
# + hash in lockstep with package.json#packageManager.
#
# When bumping versions, run the following to get a new hash:
#
# ```bash
# nix store prefetch-file --hash-type sha256 \
# https://registry.npmjs.org/pnpm/-/pnpm-${NEW_VERSION}.tgz
# ```
pnpm_10 = pkgs.pnpm_10.overrideAttrs (_old: rec {
version = "10.33.2";
src = pkgs.fetchurl {
url = "https://registry.npmjs.org/pnpm/-/pnpm-${version}.tgz";
hash = "sha256-envPE9f2zrOUbAOXg3PZm+n94cr8MAC9/tTE95EWdhA=";
};
});
daemon = pkgs.callPackage ./nix/package-daemon.nix {
inherit dream2nix nixpkgs system nodejs pnpm_10;
src = daemonSrc;
pnpmDepsSrc = daemonPnpmDepsSrc;
workspacePaths = daemonWorkspacePaths;
};
web = pkgs.callPackage ./nix/package-web.nix {
inherit dream2nix nixpkgs system nodejs pnpm_10;
src = webSrc;
pnpmDepsSrc = webPnpmDepsSrc;
workspacePaths = webWorkspacePaths;
};
in {
packages = {
inherit daemon web;
default = daemon;
};
# Wrap `od` with `--no-open` for `nix run`: the daemon package
# builds the daemon workspace only, not `apps/web/out/`, so the
# browser would otherwise auto-open onto an empty static dir.
#
# Set OD_DATA_DIR to a writable location when unset. The Nix store
# is read-only at runtime, so the daemon cannot write to its default
# `<projectRoot>/.od` location under `nix run`.
apps.default = {
type = "app";
program = "${pkgs.writeShellScript "od-nix-run" ''
export OD_DATA_DIR="''${OD_DATA_DIR:-$HOME/.od}"
exec ${daemon}/bin/od --no-open "$@"
''}";
meta.description = "Open Design local daemon (`od`)";
};
devShells.default = pkgs.mkShell {
packages = [
nodejs
pnpm_10
];
shellHook = ''
echo "🎨 Open Design dev shell loaded!"
echo ""
echo "Language runtimes:"
echo " - 🐢 Node.js: $(node --version 2>/dev/null || echo 'not found')"
echo " - 📦 pnpm: $(pnpm --version 2>/dev/null || echo 'not found')"
echo ""
echo "Quick start:"
echo " - 🚀 pnpm install"
echo " - 🚀 pnpm tools-dev # local lifecycle entry point"
echo ""
'';
};
checks = {
daemon = daemon;
web = web;
};
formatter = pkgs.nixpkgs-fmt;
});
moduleCommon = import ./nix/module-common.nix;
in
perSystem
// {
homeManagerModules = rec {
open-design = import ./nix/home-manager.nix {
inherit moduleCommon;
flake = self;
};
default = open-design;
};
nixosModules = rec {
open-design = import ./nix/nixos.nix {
inherit moduleCommon;
flake = self;
};
default = open-design;
};
};
}