diff --git a/modules/claude.nix b/modules/claude.nix index 6f74615..bb0bff6 100644 --- a/modules/claude.nix +++ b/modules/claude.nix @@ -1,5 +1,23 @@ -{ config, ... }: +{ + config, + lib, + pkgs, + ... +}: +let + # writeShellApplication shellchecks both scripts at build time and pins jq. + statusline = pkgs.writeShellApplication { + name = "statusline-command"; + runtimeInputs = [ pkgs.jq ]; + text = builtins.readFile ./claude/statusline-command.sh; + }; + blockDangerousGit = pkgs.writeShellApplication { + name = "block-dangerous-git"; + runtimeInputs = [ pkgs.jq ]; + text = builtins.readFile ./claude/block-dangerous-git.sh; + }; +in { imports = [ ./agents.nix ]; @@ -11,16 +29,7 @@ home.file.".claude/settings.json".source = config.lib.file.mkOutOfStoreSymlink "${config.my.dotfilesDir}/config/claude/settings.json"; - # Static statusLine script referenced by settings.json; in-store since Claude - # never rewrites it. executable so the settings.json command can exec it. - home.file.".claude/statusline-command.sh" = { - source = ../config/claude/statusline-command.sh; - executable = true; - }; - - # PreToolUse hook blocking dangerous git commands; referenced by settings.json. - home.file.".claude/hooks/block-dangerous-git.sh" = { - source = ../config/claude/hooks/block-dangerous-git.sh; - executable = true; - }; + # Static scripts referenced by settings.json under stable ~/.claude paths. + home.file.".claude/statusline-command.sh".source = lib.getExe statusline; + home.file.".claude/hooks/block-dangerous-git.sh".source = lib.getExe blockDangerousGit; } diff --git a/config/claude/hooks/block-dangerous-git.sh b/modules/claude/block-dangerous-git.sh similarity index 85% rename from config/claude/hooks/block-dangerous-git.sh rename to modules/claude/block-dangerous-git.sh index 37e5eda..7c2e67f 100755 --- a/config/claude/hooks/block-dangerous-git.sh +++ b/modules/claude/block-dangerous-git.sh @@ -1,5 +1,5 @@ -#!/bin/bash - +# Runs under writeShellApplication (set -euo pipefail), hence the +# `|| true` guard where failing is fine (outside a repo). INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') @@ -14,7 +14,7 @@ if echo "$COMMAND" | grep -qE '(^|[[:space:]&|;(])git[[:space:]]+push'; then if echo "$COMMAND" | grep -qE '(^|[[:space:]])(-f|--force|--force-with-lease)([[:space:]=]|$)'; then block "is a force push." fi - current=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + current=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || true if [[ "$current" == master || "$current" == main ]] || echo "$COMMAND" | grep -qwE 'master|main'; then block "pushes a protected branch." fi diff --git a/config/claude/statusline-command.sh b/modules/claude/statusline-command.sh similarity index 93% rename from config/claude/statusline-command.sh rename to modules/claude/statusline-command.sh index d63d309..30543e3 100755 --- a/config/claude/statusline-command.sh +++ b/modules/claude/statusline-command.sh @@ -1,6 +1,7 @@ -#!/usr/bin/env bash # Mirrors the Hydro fish prompt: dim path with bold last segment, # git branch + dirty/ahead/behind markers, active model. +# Runs under writeShellApplication (set -euo pipefail), hence the +# `|| true` guards on assignments from commands allowed to fail. input=$(cat) @@ -43,7 +44,7 @@ git_out="" if git -C "$cwd" --no-optional-locks rev-parse --show-toplevel >/dev/null 2>&1; then branch=$(git -C "$cwd" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null \ || git -C "$cwd" --no-optional-locks describe --tags --exact-match HEAD 2>/dev/null \ - || git -C "$cwd" --no-optional-locks rev-parse --short HEAD 2>/dev/null | sed 's/^/@/') + || git -C "$cwd" --no-optional-locks rev-parse --short HEAD 2>/dev/null | sed 's/^/@/') || true dirty="" if ! git -C "$cwd" --no-optional-locks diff-index --quiet HEAD 2>/dev/null \ @@ -52,7 +53,7 @@ if git -C "$cwd" --no-optional-locks rev-parse --show-toplevel >/dev/null 2>&1; fi upstream="" - counts=$(git -C "$cwd" --no-optional-locks rev-list --count --left-right '@{upstream}...@' 2>/dev/null) + counts=$(git -C "$cwd" --no-optional-locks rev-list --count --left-right '@{upstream}...@' 2>/dev/null) || true if [ -n "$counts" ]; then behind=$(echo "$counts" | cut -f1) ahead=$(echo "$counts" | cut -f2)