chore(agents): build dsh-nu from its own flake (#476)

* chore(agents): build dsh-nu from its own flake

NUR now keeps only dsh, so a plugin release needs `nix flake update dsh-nu` instead of a NUR package update.
This commit is contained in:
ryan4yin | 二花 authored and GitHub committed 2026-10-19 01:15:28 +08:00
1 parent 2a792a643f
commit b2673908df
4 files changed
+83 -25

No files matched your search

Generated
+47 -4
View File
@@ -166,6 +166,27 @@
"type": "github"
}
},
"dsh-nu": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"nur-ryan4yin": "nur-ryan4yin"
},
"locked": {
"lastModified": 1792343443,
"narHash": "sha256-5QpExZfeHrb3/crshRpJTdnpu4GdCmPK9YJvWXunzbI=",
"owner": "ryan4yin",
"repo": "dsh-nu",
"rev": "a7af102bf3ef942e09182c10cfee6a8951eed02d",
"type": "github"
},
"original": {
"owner": "ryan4yin",
"repo": "dsh-nu",
"type": "github"
}
},
"fcitx5-vinput": {
"inputs": {
"nixpkgs": [
@@ -1023,15 +1044,36 @@
"nur-ryan4yin": {
"inputs": {
"nixpkgs": [
"dsh-nu",
"nixpkgs"
]
},
"locked": {
"lastModified": 1792330633,
"narHash": "sha256-ICHmCPVtJxn5E2yNzF2+c++AajG4G4YEESxmwbjqVX4=",
"lastModified": 1792342725,
"narHash": "sha256-kalmu6yOiD8HiXoo2ipvQ12L4UXe2kk68ObaMHeVslw=",
"owner": "ryan4yin",
"repo": "nur-packages",
"rev": "b96977d219e9b2dcc30c67f89a698ea961fb68c3",
"rev": "a71fc275ec7dbbbb8b3e9ece422a2df7f55269db",
"type": "github"
},
"original": {
"owner": "ryan4yin",
"repo": "nur-packages",
"type": "github"
}
},
"nur-ryan4yin_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1792342725,
"narHash": "sha256-kalmu6yOiD8HiXoo2ipvQ12L4UXe2kk68ObaMHeVslw=",
"owner": "ryan4yin",
"repo": "nur-packages",
"rev": "a71fc275ec7dbbbb8b3e9ece422a2df7f55269db",
"type": "github"
},
"original": {
@@ -1143,6 +1185,7 @@
"catppuccin": "catppuccin",
"colmena": "colmena",
"disko": "disko",
"dsh-nu": "dsh-nu",
"fcitx5-vinput": "fcitx5-vinput",
"haumea": "haumea",
"home-manager": "home-manager",
@@ -1168,7 +1211,7 @@
"nixpkgs-patched": "nixpkgs-patched",
"nixpkgs-stable": "nixpkgs-stable",
"nu_scripts": "nu_scripts",
"nur-ryan4yin": "nur-ryan4yin",
"nur-ryan4yin": "nur-ryan4yin_2",
"ponytail": "ponytail",
"pre-commit-hooks": "pre-commit-hooks",
"preservation": "preservation",
+7
View File
@@ -230,6 +230,13 @@
inputs.nixpkgs.follows = "nixpkgs";
};
# The Nushell-only shell bundle. Its flake builds the plugin from the
# repository, so a release needs only `nix flake update dsh-nu`.
dsh-nu = {
url = "github:ryan4yin/dsh-nu";
inputs.nixpkgs.follows = "nixpkgs";
};
# Wayland <-> X11 clipboard sync daemon for xwayland-satellite (niri)
pyclipsync = {
url = "github:ryan4yin/pyclipsync/v0.1.3";
+21 -20
View File
@@ -53,31 +53,32 @@ on, `$DSH_AGENTS_HOME/AGENTS.md` — so no patch row is needed; identical conten
## Nushell-only shell
`nur-ryan4yin`'s `dsh.withPlugins [ ...dsh-nu ]` replaces the two first-party shell providers with
Nushell: every `ctx.shell` consumer (model shell tools, background jobs, hook bridges, in-process
callers) runs `nu --no-config-file -c`, and a command that hands execution to another shell is
refused before it spawns. The plugin adds Nushell rules and a syntax guide, and rewrites the
shell-tool descriptions, so the model is told what actually runs. `nu` comes from the NUR package,
so it does not depend on `PATH`.
`dsh-nu`'s flake builds the bundle and `nur-ryan4yin`'s `dsh.withPlugins` applies it: every
`ctx.shell` consumer (model shell tools, background jobs, hook bridges, in-process callers) runs
`nu --no-config-file -c`, and a command that hands execution to another shell is refused before it
spawns. The plugin adds Nushell rules and a syntax guide, and rewrites the shell-tool descriptions,
so the model is told what actually runs. `nu` is the Nixpkgs one, fixed at build time, so it does
not depend on `PATH`.
The source is the `dsh-nu` GitHub release tarball, pinned by `hashes.json` in `nur-packages`;
nix-config locks that package set in its `flake.lock`. `dsh.withPlugins` wraps the binary: each
invocation gets a generated `--patch <file>` overlay after the profile layer, while `dsh plugin`
stays untouched. No `$DSH_HOME/cordis.patch.yml` is written, so there is no home-layer state to
resolve or roll back. Boundaries: preset rows that spawn a shell themselves (`custom-bash.mjs`,
`persistent-shell`) bypass `ctx.shell`. So does `@deepseek-ai/dsh-experimental-terminal-bundle`: its
`terminal_*` tools use a separate `ctx.terminals` seam and run the platform shell (bash on the POSIX
hosts this repository manages), so they coexist with this plugin but stay outside the Nushell-only
guarantee — keep the bundle off for a strict Nu-only machine. Bash hooks now run under Nushell and
need rewriting; remote hosts still run their own POSIX shell. Rollback: install plain `dsh` or pass
an empty plugin list; there is no home file to delete. Tested on Linux; the same package also builds
for Darwin, where it has not been boot-tested.
`home/base/tui/agents/packages.nix` calls `dsh-nu.lib.mkDshNuPackage { inherit pkgs dsh; }` and
passes the result to `withPlugins`; `flake.lock` pins both inputs. `dsh.withPlugins` wraps the
binary: each invocation gets a generated `--patch <file>` overlay after the profile layer, while
`dsh plugin` stays untouched. No `$DSH_HOME/cordis.patch.yml` is written, so there is no home-layer
state to resolve or roll back. Boundaries: preset rows that spawn a shell themselves
(`custom-bash.mjs`, `persistent-shell`) bypass `ctx.shell`. So does
`@deepseek-ai/dsh-experimental-terminal-bundle`: its `terminal_*` tools use a separate
`ctx.terminals` seam and run the platform shell (bash on the POSIX hosts this repository manages),
so they coexist with this plugin but stay outside the Nushell-only guarantee — keep the bundle off
for a strict Nu-only machine. Bash hooks now run under Nushell and need rewriting; remote hosts
still run their own POSIX shell. Rollback: install plain `dsh` or pass an empty plugin list; there
is no home file to delete. Tested on Linux; the same package also builds for Darwin, where it has
not been boot-tested.
Verify after a switch:
```sh
dsh --profile web --dump-config | grep -n "nushell"
# expect the first-party shell rows disabled, nushell-executor and nushell-teaching inserted
dsh --profile web --dump-config | grep -n "nu-executor\|nu-teaching"
# expect the first-party shell rows disabled, nu-executor and nu-teaching inserted
dsh --profile web 2>&1 | grep "disabling profile plugin"
# a dsh bump can disable a row whose manifest no longer matches; nothing prints when healthy
```
+8 -1
View File
@@ -2,10 +2,17 @@
pkgs,
llm-agents,
myNurPkgs,
dsh-nu,
...
}:
let
agentPackages = llm-agents.packages.${pkgs.stdenv.hostPlatform.system};
# dsh-nu's flake builds the plugin from its own checkout; this repository
# supplies the dsh installation it plugs into.
dshNu = dsh-nu.lib.mkDshNuPackage {
inherit pkgs;
dsh = myNurPkgs.dsh;
};
in
{
home.packages = [
@@ -16,7 +23,7 @@ in
# dsh from nur-packages: llm-agents.nix's dsh cannot boot on nixpkgs node
# (node-addon-require-builtin probe), this one shims it. The Nushell-only
# plugin rides in through the package's withPlugins wrapper.
(myNurPkgs.dsh.withPlugins [ myNurPkgs.dsh-nu ])
(myNurPkgs.dsh.withPlugins [ dshNu ])
# Docs lookup CLI behind the find-docs skill (agents/skills/find-docs). The skill's flags are
# written against this package, not against upstream's npx instructions.