mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
* feat(agents): use the shell's own dialect; allow 5 s retry backoff Assisted-by: DeepSeek Harness (deepseek-flash) * feat(dsh): make Nushell the only shell Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): wait for CI in the background Pushes to a PR often start multi-minute CI runs, and an agent that holds the turn open on a foreground watch reports nothing until it ends. Require the pushed head and running checks to be reported first, the watch to run in the background, and the result to be collected after independent work or after ending the turn. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): keep the shell-handoff rule platform-neutral The global rules carry no Windows assumptions: drop the cmd, pwsh, and wsl handoff examples and keep the POSIX forms plus the dsh refusal. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(dsh): keep the shell-swap docs POSIX-only This repository manages Linux and Darwin hosts, not Windows: drop the Windows handoff examples and terminal-backend wording from dsh.md. The home patch also disabled pwsh-sandbox redundantly because dsh-base already disables that row on POSIX; keep only the active bash-sandbox disable and verify the composed rows with --dump-config. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): keep the global rules runtime-neutral Global rules are loaded by every agent CLI, so they must not describe one runtime's behavior. Drop the dsh-specific sentence and wording while keeping the expectation to prefer Nushell structured pipelines and Python. Runtime behavior stays documented in home/base/tui/agents/dsh.md. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): default shell work to Nushell Keep the Nushell preference explicit in the runtime-neutral global rules, and keep runtime behavior in runtime docs. Bash stays a narrow fallback for tasks Nushell cannot do. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): tighten global-rule scope and CI guidance Keep global rules runtime- and project-neutral, and state that boundary in the file. Remove the duplicated CI turn-steering text in favour of the Communication rule, resolve the watch run before watching instead of relying on gh pr checks --watch alone, name the working-directory parameter generically, and distinguish a bounded retry backoff from a fixed completion wait. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): never estimate a CI run's duration A CI run has no predictable length, so do not turn "it looks short" into a reason to wait. The rule is unconditional: report the head and started checks, start a background watch, and end the turn; collect the result on completion. The eval scenario now uses an unknown duration. Assisted-by: DeepSeek Harness (deepseek-flash) * docs(agents): move maintenance guidance to the README The runtime/project boundary is guidance for editing the rules, not a rule agents need loaded every session. The README's Maintaining global rules section already owns that audience; the loaded rules keep only behavior. Assisted-by: DeepSeek Harness (deepseek-flash) * refactor(dsh): render the home patch from a YAML template Move the home-layer cordis patch into dsh-cordis.patch.yml, substitute the bundle and Nushell store paths with replaceVars, and link the rendered file through home.file.source. This module is the only writer of ~/.dsh/cordis.patch.yml, the current host has no such file, and the profile patch is a separate layer. Assisted-by: DeepSeek Harness (deepseek-flash) * refactor(dsh): install the shell plugin through NUR withPlugins Replace the local runCommand bundle, peer symlink, and home-layer YAML file with the plugin package and dsh.withPlugins from ryan4yin/nur-packages#43. The package wrapper adds a generated --patch overlay after the profile layer, so dsh no longer writes or manages ~/.dsh/cordis.patch.yml. The NUR input is temporarily pinned to the PR branch and its commit; point it back at main once the NUR PR merges. Assisted-by: DeepSeek Harness (deepseek-flash) * refactor(nix): expose the NUR package set as nurPkgs Pass one per-system NUR package set through specialArgs instead of repeating nur-ryan4yin.packages.${pkgs.stdenv.hostPlatform.system} at each call site. The agents, rime, and idols-ruby modules now use the short binding. Assisted-by: DeepSeek Harness (deepseek-flash) * refactor(nix): use nurPkgs in package overlays The overlays receive specialArgs too, so they can use the per-system NUR package set instead of rebuilding the long input path from prev. This leaves only the definition in outputs/default.nix. Assisted-by: DeepSeek Harness (deepseek-flash) * refactor(nix): name the per-system NUR set myNurPkgs Leave room for consuming another NUR repository later, and match the existing mylib/myvars naming. Assisted-by: DeepSeek Harness (deepseek-flash) * chore(dsh): consume the merged NUR package set nur-ryan4yin now points at main after ryan4yin/nur-packages#43 was squash merged; the lock records the merge commit. No branch ref remains. Assisted-by: DeepSeek Harness (deepseek-flash) * fix(dsh): pass the web profile explicitly The withPlugins launcher prepends --patch, which historically prevented dsh from auto-expanding "dsh web" into "--profile web". Pass the profile explicitly in the Just recipe and the verification commands so they work with both plain dsh and the wrapper. Assisted-by: DeepSeek Harness (deepseek-flash) * chore(dsh): pick up the wrapped-profile fix Update nur-ryan4yin to the squash merge that keeps an implicit profile name first, so "dsh web" and "just dsh-web" work through the wrapper again. Assisted-by: DeepSeek Harness (deepseek-flash) * chore(dsh): pick up the plugin peer-link fix Update nur-ryan4yin to the squash merge that links the dsh peer tree at node_modules/@deepseek-ai instead of nesting it one level deeper. This is the import failure that stopped nushell-executor from activating after deploy. Assisted-by: DeepSeek Harness (deepseek-flash)
465 lines
14 KiB
Makefile
465 lines
14 KiB
Makefile
# just is a command runner, Justfile is very similar to Makefile, but simpler.
|
|
|
|
# Use nushell for shell commands
|
|
# To use this justfile, you need to enter a shell with just & nushell installed:
|
|
#
|
|
# nix shell nixpkgs#just nixpkgs#nushell
|
|
set shell := ["nu", "-c"]
|
|
|
|
utils_nu := absolute_path("utils.nu")
|
|
|
|
############################################################################
|
|
#
|
|
# Common commands(suitable for all machines)
|
|
#
|
|
############################################################################
|
|
|
|
# List all the just commands
|
|
default:
|
|
@just --list
|
|
|
|
# Run eval tests
|
|
[group('nix')]
|
|
test:
|
|
let result = (nix eval .#evalTests --json --show-trace --print-build-logs --verbose | str trim); if $result != "true" { error make { msg: $"eval tests failed: evalTests returned ($result)" } }
|
|
|
|
# Build and run the runtime security VM test (needs /dev/kvm; not run by just test)
|
|
[linux]
|
|
[group('nix')]
|
|
test-vm:
|
|
nix build --no-link --print-build-logs .#checks.x86_64-linux.security-exporters
|
|
|
|
# Evaluate a NixOS host configuration without building it.
|
|
[group('nix')]
|
|
eval-host host:
|
|
nix eval $".#nixosConfigurations.{{host}}.config.system.build.toplevel.drvPath" --raw --show-trace
|
|
|
|
# Build a NixOS host system closure without changing the current system.
|
|
[group('nix')]
|
|
build-host host:
|
|
nix build $".#nixosConfigurations.{{host}}.config.system.build.toplevel" --no-link --print-build-logs
|
|
|
|
# Build a MicroVM runner locally. microvm-deploy copies the closure to the physical host.
|
|
[group('nix')]
|
|
build-microvm guest:
|
|
nix build $".#nixosConfigurations.{{guest}}.config.microvm.declaredRunner" --no-link --print-build-logs
|
|
|
|
# Update all the flake inputs
|
|
[group('nix')]
|
|
up:
|
|
nix flake update --commit-lock-file
|
|
|
|
# Update specific input
|
|
# Usage: just upp nixpkgs
|
|
[group('nix')]
|
|
upp input:
|
|
nix flake update {{input}} --commit-lock-file
|
|
|
|
# List all generations of the system profile
|
|
[group('nix')]
|
|
history:
|
|
nix profile history --profile /nix/var/nix/profiles/system
|
|
|
|
# Open a nix shell with the flake
|
|
[group('nix')]
|
|
repl:
|
|
nix repl -f flake:nixpkgs
|
|
|
|
# remove all old generations
|
|
# on darwin, you may need to switch to root user to run this command
|
|
[group('nix')]
|
|
clean:
|
|
# Wipe out NixOS's history
|
|
sudo nix profile wipe-history --profile /nix/var/nix/profiles/system
|
|
# Wipe out home-manager's history
|
|
nix profile wipe-history --profile $"($env.XDG_STATE_HOME)/nix/profiles/home-manager"
|
|
|
|
# Garbage collect all unused nix store entries
|
|
[group('nix')]
|
|
gc:
|
|
# garbage collect all unused nix store entries(system-wide)
|
|
sudo nix-collect-garbage --delete-older-than 7d
|
|
# garbage collect all unused nix store entries(for the user - home-manager)
|
|
# https://github.com/NixOS/nix/issues/8508
|
|
nix-collect-garbage --delete-older-than 7d
|
|
|
|
# Enter a shell session which has all the necessary tools for this flake
|
|
[linux]
|
|
[group('nix')]
|
|
shell:
|
|
nix shell nixpkgs#git nixpkgs#neovim nixpkgs#colmena
|
|
|
|
# Enter a shell session which has all the necessary tools for this flake
|
|
[macos]
|
|
[group('nix')]
|
|
shell:
|
|
nix shell nixpkgs#git nixpkgs#neovim
|
|
|
|
# upgrade determinate nix
|
|
[macos]
|
|
[group('nix')]
|
|
nix-upgrade:
|
|
sudo determinate-nixd upgrade
|
|
|
|
[group('nix')]
|
|
fmt:
|
|
# format the nix files in this repo
|
|
# (use external find so symlinked dirs like the `result` build output are not followed)
|
|
^find . -name '*.nix' -not -path './.git/*' | lines | each { |it| nixfmt $it | ignore }
|
|
|
|
# Show all the auto gc roots in the nix store
|
|
[group('nix')]
|
|
gcroot:
|
|
ls -al /nix/var/nix/gcroots/auto/
|
|
|
|
# Verify all the store entries
|
|
# Nix Store can contains corrupted entries if the nix store object has been modified unexpectedly.
|
|
# This command will verify all the store entries,
|
|
# and we need to fix the corrupted entries manually via `sudo nix store delete <store-path-1> <store-path-2> ...`
|
|
[group('nix')]
|
|
verify-store:
|
|
nix store verify --all
|
|
|
|
# Repair Nix Store Objects
|
|
[group('nix')]
|
|
repair-store *paths:
|
|
nix store repair {{paths}}
|
|
|
|
# Update the secondary nixpkgs inputs (the primary `nixpkgs` needs `just up`)
|
|
[group('nix')]
|
|
up-nix:
|
|
nix flake update --commit-lock-file nixpkgs-stable nixpkgs-master nixpkgs-darwin nixpkgs-patched
|
|
|
|
# override nixpkgs's commit hash
|
|
[group('nix')]
|
|
override-pkgs hash:
|
|
nix flake update --commit-lock-file nixpkgs --override-input nixpkgs github:NixOS/nixpkgs/{{hash}}
|
|
|
|
############################################################################
|
|
#
|
|
# NixOS Desktop related commands
|
|
#
|
|
############################################################################
|
|
|
|
# Deploy the nixosConfiguration by hostname match
|
|
[linux]
|
|
[group('homelab')]
|
|
local mode="switch" verbosity="normal":
|
|
#!/usr/bin/env nu
|
|
use {{utils_nu}} *;
|
|
nixos-switch (hostname) {{mode}} {{verbosity}}
|
|
|
|
# Deploy the niri nixosConfiguration by hostname match
|
|
[linux]
|
|
[group('desktop')]
|
|
niri mode="switch" verbosity="normal":
|
|
#!/usr/bin/env nu
|
|
use {{utils_nu}} *;
|
|
nixos-switch $"(hostname)-niri" {{mode}} {{verbosity}}
|
|
|
|
# Pin shoukei's home Wi-Fi to a static IPv4 (run once; the profile persists).
|
|
[linux]
|
|
[group('desktop')]
|
|
shoukei-home-wifi:
|
|
sudo nu {{absolute_path("scripts/shoukei-home-wifi-static.nu")}}
|
|
|
|
############################################################################
|
|
#
|
|
# Darwin related commands
|
|
#
|
|
############################################################################
|
|
|
|
[macos]
|
|
[group('desktop')]
|
|
brew-upgrade:
|
|
brew upgrade --cask --greedy
|
|
|
|
[macos]
|
|
[group('desktop')]
|
|
darwin-rollback:
|
|
#!/usr/bin/env nu
|
|
use {{utils_nu}} *;
|
|
darwin-rollback
|
|
|
|
# Deploy the darwinConfiguration by hostname match
|
|
[macos]
|
|
[group('desktop')]
|
|
local verbosity="normal":
|
|
#!/usr/bin/env nu
|
|
use {{utils_nu}} *;
|
|
darwin-build (hostname) {{verbosity}};
|
|
darwin-switch (hostname) {{verbosity}}
|
|
|
|
|
|
# Reset launchpad to force it to reindex Applications
|
|
[macos]
|
|
[group('desktop')]
|
|
reset-launchpad:
|
|
defaults write com.apple.dock ResetLaunchPad -bool true
|
|
killall Dock
|
|
|
|
############################################################################
|
|
#
|
|
# Homelab - VM host related commands
|
|
#
|
|
############################################################################
|
|
|
|
# Remote deployment via colmena
|
|
[linux]
|
|
[group('homelab')]
|
|
col tag mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@{{tag}}' --verbose --show-trace
|
|
|
|
# Deploy one microVM guest: copy its runner to the physical host, then restart the
|
|
# guest unit there. microvm.nix's sshSwitch step is not used: it switches the guest over
|
|
# SSH and dies on the read-only virtiofs /nix/store (WA-026 in WORKAROUNDS.md).
|
|
# The host is the physical machine running the guest.
|
|
[linux]
|
|
[group('homelab')]
|
|
microvm-deploy guest host:
|
|
nix run $".#nixosConfigurations.{{guest}}.config.microvm.deploy.installOnHost" -- root@{{host}}
|
|
ssh root@{{host}} systemctl restart microvm@{{guest}}
|
|
|
|
# Deploy all the VM hosts (physical machines running the VMs)
|
|
[linux]
|
|
[group('homelab')]
|
|
lab mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@virt-*' --verbose --show-trace
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
shoryu mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@shoryu' --verbose --show-trace
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
shushou mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@shushou' --verbose --show-trace
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
youko mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@youko' --verbose --show-trace
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
aquamarine mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@aquamarine' --verbose --show-trace
|
|
|
|
############################################################################
|
|
#
|
|
# Commands for other Virtual Machines
|
|
#
|
|
############################################################################
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
ruby mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@ruby' --verbose --show-trace
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
kana mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@kana' --verbose --show-trace
|
|
|
|
############################################################################
|
|
#
|
|
# Kubernetes related commands
|
|
#
|
|
############################################################################
|
|
|
|
[linux]
|
|
[group('homelab')]
|
|
k3s-test mode="switch":
|
|
colmena apply {{mode}} --build-on-target --on '@k3s-test-*' --verbose --show-trace
|
|
|
|
# =================================================
|
|
#
|
|
# AI agent commands
|
|
#
|
|
# =================================================
|
|
|
|
# Start the dsh web UI without opening a browser, proxied via mihomo's mixed port.
|
|
[group('agents')]
|
|
dsh-web:
|
|
#!/usr/bin/env nu
|
|
# no_proxy keeps local endpoints out of the proxy; the proxy is here for fake-ip.
|
|
# dsh's web fetch refuses a DNS answer it does not call public and fake-ip answers
|
|
# with 198.18.0.0/15, so a proxied hop makes mihomo resolve the origin instead.
|
|
# That makes mihomo a dependency of every Node fetch the harness makes, so it has
|
|
# to stop at the LAN: without no_proxy the llama-swap endpoint (aquamarine,
|
|
# 192.168.5.101) goes through it too. Node reads only lowercase `no_proxy` and
|
|
# matches exact hosts, not CIDR; curl and Go do honor CIDR.
|
|
with-env {
|
|
HTTPS_PROXY: "http://127.0.0.1:7897"
|
|
HTTP_PROXY: "http://127.0.0.1:7897"
|
|
no_proxy: "localhost,127.0.0.1,::1,[::1],192.168.5.100,192.168.5.101,192.168.5.178,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
|
|
NO_PROXY: "localhost,127.0.0.1,::1,[::1],192.168.5.100,192.168.5.101,192.168.5.178,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
|
|
} { ^dsh --profile web --no-open }
|
|
|
|
# Render the mihomo config from this repo and validate it with the live core.
|
|
[linux]
|
|
[group('services')]
|
|
mihomo-gen:
|
|
#!/usr/bin/env nu
|
|
# ~/.config/mihomo holds only the private sources.yaml and the generated
|
|
# config.yaml. The generator and policy.yaml stay in the repository, so the
|
|
# live directory can never keep a stale copy of them.
|
|
let mod = ("{{ justfile() }}" | path dirname | path join modules nixos desktop networking mihomo)
|
|
nu ($mod | path join generate.nu)
|
|
# Validate with the core the service actually runs; a nixpkgs one may differ.
|
|
let core = (systemctl show mihomo.service -p ExecStart | str trim | split row "path=" | get 1 | split row " " | get 0)
|
|
let check = (^$core -t -f ($env.HOME | path join .config mihomo config.yaml) | complete)
|
|
if $check.exit_code != 0 {
|
|
print --stderr ($check.stderr | str trim)
|
|
exit $check.exit_code
|
|
}
|
|
print "validated -- restart: sudo systemctl restart mihomo.service"
|
|
|
|
# Seed mihomo's geodata into the service's state dir, so a cold start needs no DNS.
|
|
[linux]
|
|
[group('services')]
|
|
mihomo-geo:
|
|
#!/usr/bin/env nu
|
|
# Copy geodata in by hand, so a cold start never has to fetch it. The core
|
|
# fetches it while parsing rules, before its own DNS is up and while the link
|
|
# DNS points at it -- that fetch can only fail.
|
|
let src = ($env.HOME | path join .config mihomo)
|
|
let dst = "/var/lib/private/mihomo"
|
|
sudo mkdir -p $dst
|
|
mut seeded = []
|
|
for f in [GeoSite.dat geoip.metadb ASN.mmdb] {
|
|
let p = ($src | path join $f)
|
|
if ($p | path exists) {
|
|
sudo cp $p $dst
|
|
$seeded = ($seeded | append ($dst | path join $f))
|
|
} else {
|
|
print $"(!) ($f) is not in ($src) -- fetch it first: mihomo -t -d ($src) -f ($src)/config.yaml"
|
|
}
|
|
}
|
|
if ($seeded | is-not-empty) {
|
|
sudo chmod 644 ...$seeded
|
|
let names = ($seeded | path basename | str join ', ')
|
|
print $"seeded ($names) -- restart mihomo to pick them up"
|
|
}
|
|
|
|
# Render the mihomo config into a Clash Verge Rev local profile on macOS.
|
|
# sources.yaml comes from the encrypted dotfiles sync (nix-secrets `just restore`).
|
|
[macos]
|
|
[group('services')]
|
|
mihomo-verge *args:
|
|
#!/usr/bin/env nu
|
|
let mod = ("{{ justfile() }}" | path dirname | path join modules nixos desktop networking mihomo)
|
|
nu ($mod | path join verge-sync.nu) {{ args }}
|
|
|
|
# =================================================
|
|
#
|
|
# Other useful commands
|
|
#
|
|
# =================================================
|
|
|
|
[group('common')]
|
|
path:
|
|
$env.PATH | split row ":"
|
|
|
|
[group('common')]
|
|
trace-access app *args:
|
|
strace -f -t -e trace=file {{app}} {{args}} | complete | $in.stderr | lines | find -v -r "(/nix/store|/newroot|/proc)" | parse --regex '"(/.+)"' | sort | uniq
|
|
|
|
[linux]
|
|
[group('common')]
|
|
penvof pid:
|
|
sudo cat $"/proc/($pid)/environ" | tr '\0' '\n'
|
|
|
|
# Remove all reflog entries and prune unreachable objects
|
|
[group('git')]
|
|
ggc:
|
|
git reflog expire --expire-unreachable=now --all
|
|
git gc --prune=now
|
|
|
|
# Amend the last commit without changing the commit message
|
|
[group('git')]
|
|
game:
|
|
git commit --amend -a --no-edit
|
|
|
|
# Delete all failed pods
|
|
[group('k8s')]
|
|
del-failed:
|
|
kubectl delete pod --all-namespaces --field-selector="status.phase==Failed"
|
|
|
|
# Start PC VR on idols-ai and route desktop audio to the headset.
|
|
[linux]
|
|
[group('vr')]
|
|
vr:
|
|
systemctl --user start wivrn.service
|
|
systemctl --user stop wivrn-audio.service | complete | ignore
|
|
systemd-run --user --collect --unit=wivrn-audio nu {{absolute_path("scripts/wivrn-audio.nu")}} switch --timeout 600
|
|
|
|
# Route audio to a headset that is connected right now.
|
|
[linux]
|
|
[group('vr')]
|
|
vr-audio:
|
|
nu {{absolute_path("scripts/wivrn-audio.nu")}} switch --timeout 60
|
|
|
|
# Stop PC VR when finished and restore the previous audio devices.
|
|
[linux]
|
|
[group('vr')]
|
|
vr-stop:
|
|
systemctl --user stop wivrn-audio.service | complete | ignore
|
|
nu {{absolute_path("scripts/wivrn-audio.nu")}} restore
|
|
systemctl --user stop wivrn.service
|
|
|
|
# Show PC VR service status.
|
|
[linux]
|
|
[group('vr')]
|
|
vr-status:
|
|
systemctl --user status wivrn.service --no-pager
|
|
|
|
# Follow PC VR service logs.
|
|
[linux]
|
|
[group('vr')]
|
|
vr-logs:
|
|
journalctl --user -u wivrn.service -f
|
|
|
|
[linux]
|
|
[group('services')]
|
|
list-inactive:
|
|
systemctl list-units -all --state=inactive
|
|
|
|
[linux]
|
|
[group('services')]
|
|
list-failed:
|
|
systemctl list-units -all --state=failed
|
|
|
|
[linux]
|
|
[group('services')]
|
|
list-systemd:
|
|
systemctl list-units systemd-*
|
|
|
|
|
|
# =================================================
|
|
#
|
|
# GitHub CLI + Nixpkgs Review via Github Action
|
|
# https://github.com/ryan4yin/nixpkgs-review-gha
|
|
#
|
|
# =================================================
|
|
|
|
[group('github')]
|
|
gh-login:
|
|
gh auth login -h github.com --skip-ssh-key --git-protocol ssh
|
|
|
|
# Run nixpkgs-review for PR
|
|
[group('nixpkgs')]
|
|
pkg-review pr:
|
|
gh workflow run review.yml --repo ryan4yin/nixpkgs-review-gha -f x86_64-darwin=no -f post-result=true -f pr={{pr}}
|
|
|
|
# Run package tests for PR
|
|
[group('nixpkgs')]
|
|
pkg-test pr pname:
|
|
gh workflow run review.yml --repo ryan4yin/nixpkgs-review-gha -f x86_64-darwin=no -f post-result=true -f pr={{pr}} -f extra-args="-p {{pname}}.passthru.tests"
|
|
|
|
# View the summary of a workflow
|
|
[group('nixpkgs')]
|
|
pkg-summary:
|
|
gh workflow view review.yml --repo ryan4yin/nixpkgs-review-gha
|