dotfiles/modules/home/shell/nushell.nix

202 lines
6.4 KiB
Nix

{
config,
pkgs,
lib,
...
}:
let
profileBin = "${config.home.profileDirectory}/bin";
# System binaries path - same on both NixOS and Darwin
systemBin = "/run/current-system/sw/bin";
defaultBin = "/nix/var/nix/profiles/default/bin";
darwinHomebrewDir = if pkgs.stdenv.hostPlatform.isAarch64 then "/opt/homebrew" else "/usr/local";
homebrewBin = "${darwinHomebrewDir}/bin";
homebrewSbin = "${darwinHomebrewDir}/sbin";
homebrewPaths =
if pkgs.stdenv.hostPlatform.isDarwin then
lib.unique [
homebrewBin
homebrewSbin
]
else
[ ];
# Add common macOS system paths that may contain user-installed CLIs
macosSystemPaths =
if pkgs.stdenv.hostPlatform.isDarwin then
[
"/usr/local/bin"
"/usr/bin"
"/bin"
"/usr/sbin"
"/sbin"
]
else
[ ];
formatPathList = paths: lib.concatMapStrings (path: " \"${path}\"\n") paths;
in
{
imports = [ ./starship ];
programs.nushell.enable = lib.mkDefault true;
programs.nushell.extraConfig = ''
# Dotfiles QA validation command
def dotfiles-qa [] {
let dotfiles_dir = "${config.home.homeDirectory}/Development/dotfiles"
print $"(ansi green_bold)Running dotfiles QA validation...(ansi reset)\n"
# Step 1: Format check
print $"(ansi blue)1. Formatting nix files...(ansi reset)"
cd $dotfiles_dir
nix fmt .
if $env.LAST_EXIT_CODE != 0 {
print $"(ansi red_bold) Formatting failed(ansi reset)"
return
}
print $"(ansi green) Formatting complete(ansi reset)\n"
# Step 2: Flake check
print $"(ansi blue)2. Running flake check...(ansi reset)"
nix flake check
if $env.LAST_EXIT_CODE != 0 {
print $"(ansi red_bold) Flake check failed(ansi reset)"
return
}
print $"(ansi green) Flake check passed(ansi reset)\n"
# Step 3: Build (without activation)
print $"(ansi blue)3. Building darwin configuration (no activation)...(ansi reset)"
darwin-rebuild build --flake $"($dotfiles_dir)#macbook-pro"
if $env.LAST_EXIT_CODE != 0 {
print $"(ansi yellow) Build had warnings, but may still work(ansi reset)\n"
} else {
print $"(ansi green) Build successful(ansi reset)\n"
}
print $"(ansi green_bold) Core QA checks passed!(ansi reset)"
}
# Beads helper functions for AI agent workflows
# Safe Beads initialization with git repository check
def bd-init [] {
if not (".git" | path exists) and not (".git" | path type) == "dir" {
print $"(ansi red_bold)Error: Not in a git repository(ansi reset)"
print "Beads requires a git repository. Initialize git first:"
print " git init"
return
}
if (".beads" | path exists) {
print $"(ansi yellow)Beads already initialized in this project(ansi reset)"
return
}
print $"(ansi green)Initializing Beads...(ansi reset)"
bd init
if $env.LAST_EXIT_CODE == 0 {
print $"(ansi green_bold) Beads initialized successfully(ansi reset)"
print ""
print "Next steps:"
print " bd create --title \"Your task\" --type feature"
print " bd ready"
}
}
# View ready tasks with structured output
def bd-ready [] {
if not (".beads" | path exists) {
print $"(ansi red)Not a Beads project. Run 'bd-init' first.(ansi reset)"
return
}
let ready_tasks = (bd ready --json | from json)
if ($ready_tasks | is-empty) {
print $"(ansi yellow)No ready tasks(ansi reset)"
return
}
print $"(ansi green_bold)Ready Tasks:(ansi reset)\n"
$ready_tasks | each {|task|
print $"(ansi cyan)[$($task.id)](ansi reset) ($task.title)"
print $" Type: ($task.type) | Priority: ($task.priority) | Status: ($task.status)"
if ($task.description? != null) and ($task.description | str length) > 0 {
print $" ($task.description)"
}
print ""
} | ignore
}
# Sync Beads database with git
def bd-sync [] {
if not (".beads" | path exists) {
print $"(ansi red)Not a Beads project(ansi reset)"
return
}
print $"(ansi blue)Syncing Beads database...(ansi reset)"
bd sync
if $env.LAST_EXIT_CODE == 0 {
print $"(ansi green) Sync complete(ansi reset)"
}
}
'';
programs.nushell.envFile.text = ''
# Set XDG Base Directory environment variables
$env.XDG_CONFIG_HOME = "${config.xdg.configHome}"
$env.XDG_DATA_HOME = "${config.xdg.dataHome}"
$env.XDG_CACHE_HOME = "${config.xdg.cacheHome}"
let nix_paths = [
${
formatPathList [
profileBin
systemBin
defaultBin
]
} ]
let homebrew_paths = [
${formatPathList homebrewPaths} ]
let macos_system_paths = [
${formatPathList macosSystemPaths} ]
let path_candidates = ($nix_paths | append $homebrew_paths | append $macos_system_paths | flatten)
if ($env.PATH? == null) {
$env.PATH = $path_candidates
} else {
for path in $path_candidates {
if not ($env.PATH | any {|it| $it == $path}) {
$env.PATH = ($env.PATH | append $path)
}
}
}
$env.NIX_PROFILES = "/run/current-system/sw ${config.home.profileDirectory}"
# Load sops-managed API keys as environment variables
let secrets_dir = "${config.xdg.configHome}/secrets"
def --env load-secret [secret_name: string, env_var: string] {
let secret_file = ($secrets_dir | path join $secret_name)
if ($secret_file | path exists) {
let secret_value = (open --raw $secret_file | str trim)
{} | insert $env_var $secret_value | load-env
}
}
load-secret "zai-api-key" "ZAI_API_KEY"
load-secret "openai-api-key" "OPENAI_API_KEY"
load-secret "openrouter-api-key" "OPENROUTER_API_KEY"
load-secret "moonshot-api-key" "MOONSHOT_API_KEY"
load-secret "anthropic-api-key" "ANTHROPIC_API_KEY"
load-secret "exa-api-key" "EXA_API_KEY"
load-secret "fal-api-key" "FAL_API_KEY"
load-secret "groq-api-key" "GROQ_API_KEY"
load-secret "firecrawl-api-key" "FIRECRAWL_API_KEY"
'';
}