diff --git a/experimental/dsh-everything-edition/flake.lock b/experimental/dsh-everything-edition/flake.lock index 0f11d13..c6876b6 100644 --- a/experimental/dsh-everything-edition/flake.lock +++ b/experimental/dsh-everything-edition/flake.lock @@ -34,6 +34,23 @@ "type": "github" } }, + "dsh-codex": { + "flake": false, + "locked": { + "lastModified": 1789293989, + "narHash": "sha256-ywNLQlA2cMb6SWOx7RTjkLcFKsPH1H+HzcDPNUI//TU=", + "owner": "Yan-Zero", + "repo": "dsh-codex", + "rev": "acbbe23416694e968f40bfa371a93b7540d885cc", + "type": "github" + }, + "original": { + "owner": "Yan-Zero", + "ref": "v0.3.0", + "repo": "dsh-codex", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -59,7 +76,9 @@ "inputs": { "bun2nix": "bun2nix", "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs", + "nixpkgs": [ + "nixpkgs" + ], "systems": "systems", "treefmt-nix": "treefmt-nix" }, @@ -74,6 +93,7 @@ "original": { "owner": "numtide", "repo": "llm-agents.nix", + "rev": "bcd2a60f193d93655a836d7a2e05fb5f7bd8bdc5", "type": "github" } }, @@ -88,18 +108,16 @@ }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", "repo": "nixpkgs", + "rev": "aff8a0b28396750446e5537a96461bc4facdb287", "type": "github" } }, "root": { "inputs": { + "dsh-codex": "dsh-codex", "llm-agents": "llm-agents", - "nixpkgs": [ - "llm-agents", - "nixpkgs" - ] + "nixpkgs": "nixpkgs" } }, "systems": { diff --git a/experimental/dsh-everything-edition/flake.nix b/experimental/dsh-everything-edition/flake.nix index 5b542b9..1dc62c6 100644 --- a/experimental/dsh-everything-edition/flake.nix +++ b/experimental/dsh-everything-edition/flake.nix @@ -2,14 +2,39 @@ description = "dsh (llm-agents.nix), everything-edition: pnpm+node on PATH, plus a main target that loads this checkout's dsh-plugins"; inputs = { - llm-agents.url = "github:numtide/llm-agents.nix"; - # Reuse llm-agents' nixpkgs so pnpm/node come from the same revision the - # upstream packages were built against. - nixpkgs.follows = "llm-agents/nixpkgs"; + # dsh 0.1.5-rc.1, the last release whose host boot works on aarch64-darwin. + # + # Newer dsh (0.1.7-rc.2) bundles node-addon-require-builtin 0.1.6, whose + # arm64 pattern probe fails here ("arm64 getter is not optional-bti-ldr-x0- + # this-imm-ret") in host preparation, so `dsh web` dies before any plugin + # mounts; 0.1.5-rc.1 ships 0.1.5, which works. That also caps dsh-codex at + # 0.3.0: 0.3.1 requires @deepseek-ai/dsh-agent ^0.1.7-rc.2. Once the addon + # works, bump this to a revision with >= 0.1.7-rc.2 and set codexTag to + # v0.3.1 with its hashes. + llm-agents.url = "github:numtide/llm-agents.nix/bcd2a60f193d93655a836d7a2e05fb5f7bd8bdc5"; + + # Third-party dsh plugin, pinned by the lock. `flake = false` because + # upstream ships no flake.nix; the lock's rev + narHash still pin the tree, + # so `nix flake update dsh-codex` is all a version bump needs. The tree has + # no build output (upstream gitignores `lib/`), so it is used to read the + # release version and to scan the host source for its runtime peers; the + # loadable bytes come from the matching hash-pinned npm tarball below. + dsh-codex = { + url = "github:Yan-Zero/dsh-codex/v0.3.0"; + flake = false; + }; + + # One nixpkgs for everything here, with llm-agents following it. + # + # Pinned rather than tracking llm-agents: this revision provides nodejs + # 24.19.0, the version dsh's native addon is exercised against here. The + # 24.20.0 bump in newer nixpkgs is not known-good with it. + nixpkgs.url = "github:NixOS/nixpkgs/aff8a0b28396750446e5537a96461bc4facdb287"; + llm-agents.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = - { self, nixpkgs, llm-agents }: + { self, nixpkgs, llm-agents, dsh-codex }: let # The systems llm-agents.nix builds for; keep the list aligned with it. systems = [ @@ -26,6 +51,76 @@ inherit (pkgs) lib; upstream = llm-agents.packages.${system}.dsh; + # Third-party plugin, as the artifact `dsh plugin add` installs. + # + # The lock pins the source tree; the shipped bytes come from the npm + # tarball the same release published, since upstream gitignores `lib/`. + # Held at 0.3.0 because 0.3.1 needs @deepseek-ai/dsh-agent + # ^0.1.7-rc.2, which cannot boot here (see the llm-agents note above). + # The version is read from the locked input, so `nix flake update + # dsh-codex` moves it; only the tarball hash is kept by hand, and a + # bump with a stale hash fails loud: + # nix store prefetch-file --json --hash-type sha256 \ + # https://registry.npmjs.org/dsh-codex/-/dsh-codex-.tgz + codexVersion = (builtins.fromJSON (builtins.readFile "${dsh-codex}/package.json")).version; + codexHashes = { + "0.3.0" = "sha256-4v1U5G3jIluvViZnq8UscThUV0QXKAWvwI8ph323Xn0="; + }; + + # This is a bare package directory: no node_modules is grafted on, and + # nothing resolves its dependencies here. Installing it into a profile + # leaves that to pnpm and dsh, which is the only place the correct peer + # versions are knowable — the `@deepseek-ai/dsh-*` services must come + # from the running installation, never from a registry copy. + dsh-codex-src = pkgs.runCommand "dsh-codex-${codexVersion}" { + nativeBuildInputs = [ pkgs.gnutar pkgs.gzip ]; + passthru = { + inherit codexVersion; + entry = "lib/index.js"; + }; + meta = { + description = "dsh-codex ${codexVersion} package: ChatGPT subscription route for dsh (third-party)"; + homepage = "https://github.com/Yan-Zero/dsh-codex"; + license = lib.licenses.asl20; + }; + } '' + mkdir -p $out + tar -xzf ${ + pkgs.fetchurl { + url = "https://registry.npmjs.org/dsh-codex/-/dsh-codex-${codexVersion}.tgz"; + hash = codexHashes.${codexVersion}; + } + } -C $out --strip-components=1 + ''; + + # `dsh plugin --profile add file:`, i.e. the + # supported install path, but with the version decided by this flake + # instead of by "whatever the registry has now". + # + # The install is mutable state in $DSH_HOME, by design: `dsh plugin` + # records the spec and lets pnpm reconcile the profile's bundles, so + # the plugin resolves its services against the dsh that is actually + # running. Re-running with a newer flake revision reinstalls it. + install-to-profile-dsh-codex = pkgs.writeShellApplication { + name = "install-to-profile-dsh-codex"; + runtimeInputs = [ dsh-vanilla-with-pnpm ]; + text = '' + # Only direct args reach this app; nix run's own `--` separator is + # not forwarded. + profile="web" + if [ "$#" -gt 0 ]; then + profile="$1" + shift + fi + exec dsh plugin --profile "$profile" add \ + "file:${dsh-codex-src}" "$@" + ''; + meta = { + mainProgram = "install-to-profile-dsh-codex"; + description = "Install dsh-codex ${codexVersion} into a dsh profile (default: web)"; + }; + }; + # dsh with pnpm + nodejs on PATH, for dsh's own core # # operations (`dsh plugin` shells out to pnpm; plugins run under node). @@ -158,6 +253,15 @@ # `nix run .#main-any-port`: `#main`, but on an OS-assigned free port. main-any-port = dsh-main-any-port; + + # `nix run .#install-to-profile-dsh-codex -- web`: install the pinned + # dsh-codex into the mutable `web` profile. The profile name is + # optional and defaults to web; extra args go to `dsh plugin`. + install-to-profile-dsh-codex = install-to-profile-dsh-codex; + + # `nix build .#dsh-codex-src`: the pinned package directory that the + # installer hands to `dsh plugin add`, for inspection. + dsh-codex-src = dsh-codex-src; } ); };