mirror of
https://github.com/elwrcl/copnix.git
synced 2026-10-31 06:18:03 +03:00
klaud
This commit is contained in:
1 parent
cfa4aa4969
commit
79f69416f5
3 files changed
+469
No files matched your search
@@ -71,6 +71,8 @@ in
|
|||||||
config.flake.homeModules.home-jujutsu-watchman
|
config.flake.homeModules.home-jujutsu-watchman
|
||||||
config.flake.homeModules.home-gh
|
config.flake.homeModules.home-gh
|
||||||
config.flake.homeModules.home-radicle
|
config.flake.homeModules.home-radicle
|
||||||
|
config.flake.homeModules.home-agents
|
||||||
|
config.flake.homeModules.home-agents-claude
|
||||||
config.flake.homeModules.home-zsh
|
config.flake.homeModules.home-zsh
|
||||||
config.flake.homeModules.home-zsh-nu-handoff
|
config.flake.homeModules.home-zsh-nu-handoff
|
||||||
config.flake.homeModules.home-shell-tools
|
config.flake.homeModules.home-shell-tools
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
flake.homeModules.home-agents = {
|
||||||
|
imports = [
|
||||||
|
config.flake.homeModules.home-agents-claude
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,459 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
flake.homeModules.home-agents-claude =
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib.lists) concatMap singleton;
|
||||||
|
inherit (lib.strings) concatLines;
|
||||||
|
inherit (lib.generators) toJSON;
|
||||||
|
inherit (lib.meta) getExe;
|
||||||
|
allowed.commands = [
|
||||||
|
"rg*"
|
||||||
|
"ls*"
|
||||||
|
|
||||||
|
"jj bookmark list*"
|
||||||
|
"jj config get*"
|
||||||
|
"jj config list*"
|
||||||
|
"jj config path*"
|
||||||
|
"jj diff*"
|
||||||
|
"jj evolog*"
|
||||||
|
"jj file annotate*"
|
||||||
|
"jj file list*"
|
||||||
|
"jj file search*"
|
||||||
|
"jj file show*"
|
||||||
|
"jj file track*"
|
||||||
|
"jj git colocation status*"
|
||||||
|
"jj git remote list*"
|
||||||
|
"jj git root*"
|
||||||
|
"jj help*"
|
||||||
|
"jj interdiff*"
|
||||||
|
"jj log*"
|
||||||
|
"jj op diff*"
|
||||||
|
"jj op log*"
|
||||||
|
"jj op show*"
|
||||||
|
"jj operation diff*"
|
||||||
|
"jj operation log*"
|
||||||
|
"jj operation show*"
|
||||||
|
"jj resolve --list"
|
||||||
|
"jj root*"
|
||||||
|
"jj show*"
|
||||||
|
"jj sparse list*"
|
||||||
|
"jj st*"
|
||||||
|
"jj status*"
|
||||||
|
"jj tag list*"
|
||||||
|
"jj util completion*"
|
||||||
|
"jj util config-schema*"
|
||||||
|
"jj util markdown-help*"
|
||||||
|
"jj version*"
|
||||||
|
"jj workspace list*"
|
||||||
|
"jj workspace root*"
|
||||||
|
|
||||||
|
"gh auth status*"
|
||||||
|
"gh cache list*"
|
||||||
|
"gh gist list*"
|
||||||
|
"gh gist view*"
|
||||||
|
"gh issue list*"
|
||||||
|
"gh issue status*"
|
||||||
|
"gh issue view*"
|
||||||
|
"gh label list*"
|
||||||
|
"gh pr checks*"
|
||||||
|
"gh pr diff*"
|
||||||
|
"gh pr list*"
|
||||||
|
"gh pr status*"
|
||||||
|
"gh pr view*"
|
||||||
|
"gh release list*"
|
||||||
|
"gh release view*"
|
||||||
|
"gh repo list*"
|
||||||
|
"gh repo view*"
|
||||||
|
"gh run list*"
|
||||||
|
"gh run view*"
|
||||||
|
"gh status*"
|
||||||
|
"gh workflow list*"
|
||||||
|
"gh workflow view*"
|
||||||
|
|
||||||
|
"nix build*"
|
||||||
|
"nix develop*"
|
||||||
|
"nix eval*"
|
||||||
|
"nix flake archive*"
|
||||||
|
"nix flake check*"
|
||||||
|
"nix flake metadata*"
|
||||||
|
"nix flake show*"
|
||||||
|
"nix path-info*"
|
||||||
|
"nixfmt*"
|
||||||
|
|
||||||
|
"cargo clippy*"
|
||||||
|
"cargo nextest*"
|
||||||
|
];
|
||||||
|
|
||||||
|
forbidden.rules = [
|
||||||
|
{
|
||||||
|
commands = singleton "git*";
|
||||||
|
justification = "Use `jj` for version control.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
commands = [
|
||||||
|
"nix-build*"
|
||||||
|
"nix-shell*"
|
||||||
|
"nix-instantiate*"
|
||||||
|
"nix-env*"
|
||||||
|
"nix-channel*"
|
||||||
|
];
|
||||||
|
justification = "Use nix3 commands (`nix build`, `nix develop`, `nix flake check`, ...) instead of legacy nix-* commands.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
commands = singleton "cargo check*";
|
||||||
|
justification = "Use `cargo clippy` instead of `cargo check`.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
commands = singleton "cargo test*";
|
||||||
|
justification = "Use `cargo nextest` instead of `cargo test`.";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
commands = [
|
||||||
|
"find /nix/store"
|
||||||
|
"find /nix/store *"
|
||||||
|
"find /nix/store/"
|
||||||
|
"find /nix/store/ *"
|
||||||
|
];
|
||||||
|
justification = "Don't `find` over the entire `/nix/store`. Search specific store paths obtained from the flake instead.";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
instructions =
|
||||||
|
[
|
||||||
|
"Never write a manual `imports = [ ... ]` list in a dendritic (*.ulu.nix) flake; discovery is automatic."
|
||||||
|
"Prefer nix3 commands (`nix build`, `nix flake check`, ...) over nix2/nix1 commands."
|
||||||
|
]
|
||||||
|
++ (forbidden.rules |> map ({ justification, ... }: justification))
|
||||||
|
|> map (instruction: ''
|
||||||
|
- ${instruction}
|
||||||
|
'')
|
||||||
|
|> concatLines;
|
||||||
|
|
||||||
|
allowed.paths = [
|
||||||
|
"/etc/profiles"
|
||||||
|
"/nix/store"
|
||||||
|
];
|
||||||
|
|
||||||
|
# more bittersweet
|
||||||
|
statusLine = pkgs.writers.writeNuBin "claude-code-statusline" /* nu */ ''
|
||||||
|
def format-duration [ms: int] {
|
||||||
|
let total_s = $ms // 1000
|
||||||
|
let h = $total_s // 3600
|
||||||
|
let m = ($total_s mod 3600) // 60
|
||||||
|
let s = $total_s mod 60
|
||||||
|
if $h > 0 {
|
||||||
|
$"($h)h($m | fill -a r -w 2 -c '0')m($s | fill -a r -w 2 -c '0')s"
|
||||||
|
} else if $m > 0 {
|
||||||
|
$"($m)m($s | fill -a r -w 2 -c '0')s"
|
||||||
|
} else {
|
||||||
|
$"($s)s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def color-for-pct [pct: number] {
|
||||||
|
let pct_int = $pct | math floor | into int
|
||||||
|
if $pct_int >= 80 {
|
||||||
|
"\e[31m"
|
||||||
|
} else if $pct_int >= 50 {
|
||||||
|
"\e[33m"
|
||||||
|
} else {
|
||||||
|
"\e[32m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def format-rate-limits [input: record] {
|
||||||
|
let session_pct = try { $input | get rate_limits.five_hour.used_percentage } catch { null }
|
||||||
|
let week_pct = try { $input | get rate_limits.seven_day.used_percentage } catch { null }
|
||||||
|
|
||||||
|
let session_part = if $session_pct != null {
|
||||||
|
let c = color-for-pct $session_pct
|
||||||
|
let v = $session_pct | math round --precision 0 | into int
|
||||||
|
$"session: ($c)($v)%\e[0m"
|
||||||
|
} else { "" }
|
||||||
|
let week_part = if $week_pct != null {
|
||||||
|
let c = color-for-pct $week_pct
|
||||||
|
let v = $week_pct | math round --precision 0 | into int
|
||||||
|
$"week: ($c)($v)%\e[0m"
|
||||||
|
} else { "" }
|
||||||
|
|
||||||
|
[$session_part $week_part] | where {|x| $x | is-not-empty} | str join " "
|
||||||
|
}
|
||||||
|
|
||||||
|
def get-jj-info [] {
|
||||||
|
let root_result = do { jj --ignore-working-copy root } | complete
|
||||||
|
if $root_result.exit_code != 0 { return "" }
|
||||||
|
|
||||||
|
# --ignore-working-copy so a killed render can't leave the working
|
||||||
|
# copy stale; the watchman snapshot trigger keeps the data fresh.
|
||||||
|
let bookmark = (do { jj --ignore-working-copy log -r @ --no-graph -T 'bookmarks.map(|b| b.name()).join(", ")' } | complete | get stdout | str trim)
|
||||||
|
let change = (do { jj --ignore-working-copy log -r @ --no-graph -T 'change_id.shortest(8)' } | complete | get stdout | str trim)
|
||||||
|
let is_empty_str = (do { jj --ignore-working-copy log -r @ --no-graph -T 'empty' } | complete | get stdout | str trim)
|
||||||
|
let dirty = if $is_empty_str == "false" { "*" } else { "" }
|
||||||
|
let has_conflict = (do { jj --ignore-working-copy log -r @ --no-graph -T 'conflict' } | complete | get stdout | str trim)
|
||||||
|
let conflict_marker = if $has_conflict == "true" { " \e[31m!conflict\e[0m" } else { "" }
|
||||||
|
|
||||||
|
let ref_part = if ($bookmark | is-not-empty) {
|
||||||
|
$" | \e[36m($bookmark)($dirty)\e[0m"
|
||||||
|
} else if ($change | is-not-empty) {
|
||||||
|
$" | \e[35m($change)($dirty)\e[0m"
|
||||||
|
} else { "" }
|
||||||
|
|
||||||
|
$"($ref_part)($conflict_marker)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Main ---
|
||||||
|
let input = (^cat | from json)
|
||||||
|
|
||||||
|
let usage_info = format-rate-limits $input
|
||||||
|
|
||||||
|
let model_name = ($input | get model?.display_name? | default ($input | get model?.id? | default "unknown"))
|
||||||
|
let used_pct = ($input | get context_window?.used_percentage? | default null)
|
||||||
|
let total_cost = ($input | get cost?.total_cost_usd? | default 0)
|
||||||
|
let total_input = ($input | get context_window?.s_in? | default ($input | get context_window?.total_input_tokens? | default 0))
|
||||||
|
let total_output = ($input | get context_window?.s_out? | default ($input | get context_window?.total_output_tokens? | default 0))
|
||||||
|
let duration_ms = ($input | get cost?.total_duration_ms? | default 0)
|
||||||
|
let api_duration_ms = ($input | get cost?.total_api_duration_ms? | default 0)
|
||||||
|
let lines_added = ($input | get cost?.total_lines_added? | default 0)
|
||||||
|
let lines_removed = ($input | get cost?.total_lines_removed? | default 0)
|
||||||
|
let exceeds_200k = ($input | get exceeds_200k_tokens? | default false)
|
||||||
|
|
||||||
|
let cache_read = ($input | get context_window?.cache_read_tokens? | default 0)
|
||||||
|
let cache_create = ($input | get context_window?.cache_creation_tokens? | default 0)
|
||||||
|
|
||||||
|
let total_tokens = $total_input + $total_output
|
||||||
|
|
||||||
|
def format-tokens [n: int] {
|
||||||
|
if $n >= 1_000_000 {
|
||||||
|
$"($n / 1_000_000.0 | math round --precision 1)M"
|
||||||
|
} else if $n >= 1_000 {
|
||||||
|
$"($n / 1_000.0 | math round --precision 1)k"
|
||||||
|
} else {
|
||||||
|
$"($n)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let in_display = (format-tokens ($total_input | into int))
|
||||||
|
let out_display = (format-tokens ($total_output | into int))
|
||||||
|
let tok_display = $"($in_display)/($out_display)"
|
||||||
|
|
||||||
|
let cache_total = $cache_read + $cache_create
|
||||||
|
let cache_display = if $cache_total > 0 {
|
||||||
|
let cache_pct = ($cache_read * 100 / $cache_total | math round --precision 0 | into int)
|
||||||
|
let cache_color = if $cache_pct >= 70 {
|
||||||
|
"\e[32m"
|
||||||
|
} else if $cache_pct >= 40 {
|
||||||
|
"\e[33m"
|
||||||
|
} else {
|
||||||
|
"\e[31m"
|
||||||
|
}
|
||||||
|
$" cache:($cache_color)($cache_pct)%\e[0m"
|
||||||
|
} else { "" }
|
||||||
|
|
||||||
|
let context_display = if $used_pct != null {
|
||||||
|
let color = color-for-pct $used_pct
|
||||||
|
let pct_str = $used_pct | math round --precision 1
|
||||||
|
$"($color)($pct_str)%\e[0m"
|
||||||
|
} else { "--" }
|
||||||
|
|
||||||
|
let cost_cents = ($total_cost * 100 | math round | into int)
|
||||||
|
let cost_dollars = $cost_cents // 100
|
||||||
|
let cost_frac = ($cost_cents mod 100 | math abs | into string | fill -a r -w 2 -c '0')
|
||||||
|
let cost_display = $"$($cost_dollars).($cost_frac)"
|
||||||
|
let elapsed_display = (format-duration ($duration_ms | into int))
|
||||||
|
let wait_display = (format-duration ($api_duration_ms | into int))
|
||||||
|
let churn_display = $"\e[32m+($lines_added)\e[0m/\e[31m-($lines_removed)\e[0m"
|
||||||
|
let marker_200k = if $exceeds_200k { " | \e[31m!200k\e[0m" } else { "" }
|
||||||
|
def format-cwd [dir: string] {
|
||||||
|
if ($dir | is-empty) { return "" }
|
||||||
|
let jj_root = try { do { cd $dir; jj workspace root } | complete } catch { {exit_code: 1, stdout: ""} }
|
||||||
|
if $jj_root.exit_code == 0 {
|
||||||
|
let root = ($jj_root.stdout | str trim)
|
||||||
|
let home = ($env.HOME? | default "")
|
||||||
|
let root_display = if ($home | is-not-empty) and ($root | str starts-with $home) {
|
||||||
|
let rel = ($root | str replace $home "" | str trim -l -c '/')
|
||||||
|
$"~/($rel)"
|
||||||
|
} else {
|
||||||
|
$root
|
||||||
|
}
|
||||||
|
let root_parts = ($root_display | split row "/")
|
||||||
|
let base = if ($root_parts | length) <= 5 {
|
||||||
|
$root_display
|
||||||
|
} else {
|
||||||
|
let tail = ($root_parts | last 5 | str join "/")
|
||||||
|
$"…/($tail)"
|
||||||
|
}
|
||||||
|
let subpath = if ($dir | str starts-with $root) {
|
||||||
|
$dir | str replace $root "" | str trim -l -c '/'
|
||||||
|
} else { "" }
|
||||||
|
if ($subpath | is-not-empty) {
|
||||||
|
$"\e[36m($base)\e[0m → \e[34m($subpath)\e[0m"
|
||||||
|
} else {
|
||||||
|
$"\e[36m($base)\e[0m"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let home = ($env.HOME? | default "")
|
||||||
|
let display = if ($home | is-not-empty) and ($dir | str starts-with $home) {
|
||||||
|
let rel = ($dir | str replace $home "" | str trim -l -c '/')
|
||||||
|
$"~/($rel)"
|
||||||
|
} else {
|
||||||
|
$dir
|
||||||
|
}
|
||||||
|
let parts = ($display | split row "/")
|
||||||
|
let shortened = if ($parts | length) <= 5 {
|
||||||
|
$display
|
||||||
|
} else {
|
||||||
|
let tail = ($parts | last 5 | str join "/")
|
||||||
|
$"…/($tail)"
|
||||||
|
}
|
||||||
|
$shortened
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cwd_raw = ($input | get workspace?.current_dir? | default "")
|
||||||
|
let cwd_display = if ($cwd_raw | is-not-empty) {
|
||||||
|
let formatted = (format-cwd $cwd_raw)
|
||||||
|
$" | ($formatted)"
|
||||||
|
} else { "" }
|
||||||
|
let jj_info = get-jj-info
|
||||||
|
let quota_section = if ($usage_info | is-not-empty) {
|
||||||
|
" | (usage) " + $usage_info
|
||||||
|
} else { "" }
|
||||||
|
|
||||||
|
print -n $"($model_name) | Ctx: ($context_display) | ($tok_display)($cache_display) | ($cost_display) | t:($elapsed_display) w:($wait_display) | ($churn_display)($marker_200k)($jj_info)($quota_section)($cwd_display)"
|
||||||
|
'';
|
||||||
|
|
||||||
|
settingsPath = "${config.home.homeDirectory}/.claude/settings.json";
|
||||||
|
managedSettings =
|
||||||
|
pkgs.writeText "claude-code-settings.json"
|
||||||
|
<| toJSON { } {
|
||||||
|
"$schema" = "https://json.schemastore.org/claude-code-settings.json";
|
||||||
|
|
||||||
|
cleanupPeriodDays = 365 * 1000;
|
||||||
|
permissions.allow =
|
||||||
|
[ ]
|
||||||
|
++ map (cmd: "Bash(${cmd})") allowed.commands
|
||||||
|
++ map (path: "Read(${path}/**)") allowed.paths
|
||||||
|
++ [
|
||||||
|
"Glob"
|
||||||
|
"Grep"
|
||||||
|
"LSP"
|
||||||
|
"WebFetch"
|
||||||
|
"WebSearch"
|
||||||
|
"TaskCreate"
|
||||||
|
"TaskUpdate"
|
||||||
|
"TaskGet"
|
||||||
|
"TaskList"
|
||||||
|
"TaskOutput"
|
||||||
|
"TaskStop"
|
||||||
|
];
|
||||||
|
permissions.deny =
|
||||||
|
forbidden.rules |> concatMap (rule: rule.commands |> map (command: "Bash(${command})"));
|
||||||
|
|
||||||
|
env.CLAUDE_BASH_NO_LOGIN = "1";
|
||||||
|
env.CLAUDE_CODE_EAGER_FLUSH = "1";
|
||||||
|
env.CLAUDE_CODE_FORCE_GLOBAL_CACHE = "1";
|
||||||
|
env.MCP_CONNECTION_NONBLOCKING = "1";
|
||||||
|
env.USE_BUILTIN_RIPGREP = "0";
|
||||||
|
|
||||||
|
# bittersweet
|
||||||
|
alwaysThinkingEnabled = true;
|
||||||
|
env.CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING = "1";
|
||||||
|
env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
||||||
|
env.CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY = "20";
|
||||||
|
env.CLAUDE_CODE_PLAN_V2_AGENT_COUNT = "5";
|
||||||
|
env.CLAUDE_CODE_PLAN_V2_EXPLORE_AGENT_COUNT = "5";
|
||||||
|
env.DISABLE_AUTO_COMPACT = "1";
|
||||||
|
env.ENABLE_MCP_LARGE_OUTPUT_FILES = "1";
|
||||||
|
env.ENABLE_TOOL_SEARCH = "auto:5";
|
||||||
|
env.MAX_THINKING_TOKENS = "31999";
|
||||||
|
|
||||||
|
# less slops unfortunately
|
||||||
|
skipWebFetchPreflight = true;
|
||||||
|
env.CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY = "1";
|
||||||
|
env.DISABLE_AUTOUPDATER = "1";
|
||||||
|
env.DISABLE_ERROR_REPORTING = "1";
|
||||||
|
env.DISABLE_INSTALLATION_CHECKS = "1";
|
||||||
|
# env.DISABLE_TELEMETRY = "1";
|
||||||
|
|
||||||
|
# tools: jj workspaces track claude-code's own git-style worktrees.
|
||||||
|
hooks.WorktreeCreate = singleton {
|
||||||
|
hooks = singleton {
|
||||||
|
type = "command";
|
||||||
|
command = /* bash */ ''jj workspace add "$(cat /dev/stdin | jq '.name' --raw-output)"'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
hooks.WorktreeRemove = singleton {
|
||||||
|
hooks = singleton {
|
||||||
|
type = "command";
|
||||||
|
command = /* bash */ ''jj workspace forget "$(cat /dev/stdin | jq '.worktree_path' --raw-output)"'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enabledPlugins."code-review@claude-plugins-official" = true;
|
||||||
|
enabledPlugins."code-simplifier@claude-plugins-official" = true;
|
||||||
|
enabledPlugins."ralph-loop@claude-plugins-official" = true;
|
||||||
|
|
||||||
|
# visuals
|
||||||
|
attribution.commit = "";
|
||||||
|
attribution.pr = "";
|
||||||
|
|
||||||
|
env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE = "1";
|
||||||
|
env.CLAUDE_CODE_HIDE_ACCOUNT_INFO = "1";
|
||||||
|
env.DISABLE_COST_WARNINGS = "1";
|
||||||
|
|
||||||
|
statusLine.type = "command";
|
||||||
|
statusLine.command = getExe statusLine;
|
||||||
|
|
||||||
|
spinnerVerbs.mode = "replace";
|
||||||
|
spinnerVerbs.verbs = [
|
||||||
|
"Redeeming"
|
||||||
|
"Clodding"
|
||||||
|
"Burningtokens"
|
||||||
|
"Slopping"
|
||||||
|
"Clanking"
|
||||||
|
"Flushing"
|
||||||
|
"4get'ing"
|
||||||
|
"Plundering"
|
||||||
|
"Ignoring"
|
||||||
|
"Increasing ram prices"
|
||||||
|
"Making shit up"
|
||||||
|
"Hallucinating"
|
||||||
|
"Esef thinking"
|
||||||
|
"Doing something"
|
||||||
|
"Bain mode"
|
||||||
|
"Hyprland sucks"
|
||||||
|
"Stealing big one"
|
||||||
|
"Selling your data"
|
||||||
|
"Outsourcing to Nürburgring Betriebsgesellschaft mbH Otto-Flimm-Straße 53520 Nürburg"
|
||||||
|
"Compiling Earth"
|
||||||
|
"Absolute Cinema"
|
||||||
|
"Trvth Nvke"
|
||||||
|
"Glory to Caledonia"
|
||||||
|
"Mohamed Salah hat-trick"
|
||||||
|
"Sebasitan Vettel ring ding ding ding"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
home.file.".claude/CLAUDE.md".text = instructions;
|
||||||
|
home.activation.claudeCodeWritableSettings = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
|
_target="${settingsPath}"
|
||||||
|
_jq="${getExe pkgs.jq}"
|
||||||
|
run mkdir -p "$(dirname "$_target")"
|
||||||
|
if [ -s "$_target" ] && "$_jq" empty "$_target" 2>/dev/null; then
|
||||||
|
_merged="$(mktemp)"
|
||||||
|
"$_jq" --slurp '.[0] * .[1]' "$_target" ${managedSettings} > "$_merged"
|
||||||
|
run install -m 0644 "$_merged" "$_target"
|
||||||
|
rm -f "$_merged"
|
||||||
|
else
|
||||||
|
run install -m 0644 ${managedSettings} "$_target"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in new issue
Block a user