diff --git a/dotfiles/codex/config.toml b/dotfiles/codex/config.toml index 614a824e..c528c571 100644 --- a/dotfiles/codex/config.toml +++ b/dotfiles/codex/config.toml @@ -5,7 +5,9 @@ personality = "pragmatic" suppress_unstable_features_warning = true # Portable Codex defaults. Machine-local additions are appended from -# dotfiles/codex/config.local.toml by Home Manager. +# dotfiles/codex/config.local.toml by Home Manager. Codex-owned local +# state, including project trust settings, is harvested there before +# this file is regenerated. [mcp_servers.chrome-devtools] command = "npx" diff --git a/nix-shared/home-manager/codex-generated-skills.nix b/nix-shared/home-manager/codex-generated-skills.nix index 8409ee08..e4365538 100644 --- a/nix-shared/home-manager/codex-generated-skills.nix +++ b/nix-shared/home-manager/codex-generated-skills.nix @@ -73,6 +73,8 @@ in { base=${lib.escapeShellArg "${cfg.worktreeCodexDir}/config.toml"} local_config=${lib.escapeShellArg "${cfg.worktreeCodexDir}/config.local.toml"} target="$codex_home/config.toml" + begin_marker="# BEGIN AUTO-GENERATED CODEX MACHINE STATE" + end_marker="# END AUTO-GENERATED CODEX MACHINE STATE" if [ ! -r "$base" ]; then echo "Missing shared Codex config at $base" >&2 @@ -80,6 +82,96 @@ in { fi mkdir -p "$codex_home" + + if [ -r "$target" ]; then + mkdir -p "$(dirname "$local_config")" + local_state="$(mktemp "$codex_home/config.local-state.XXXXXX")" + local_tmp="$(mktemp "$codex_home/config.local.toml.XXXXXX")" + trap 'rm -f "$tmp" "$local_state" "$local_tmp"' EXIT + + ${lib.getExe pkgs.gawk} \ + -v begin_marker="$begin_marker" \ + -v end_marker="$end_marker" ' + FNR == NR { + if ($0 ~ /^\[[^]]+\]$/) { + base_sections[$0] = 1 + } + next + } + + function flush_block() { + if (keep && section != "" && !(section in base_sections)) { + if (printed) { + print "" + } + printf "%s", block + printed = 1 + } + } + + $0 == begin_marker || $0 == end_marker { + next + } + + /^\[[^]]+\]$/ { + flush_block() + section = $0 + keep = ($0 ~ /^\[projects\./ || $0 ~ /^\[tui\./) + block = $0 "\n" + next + } + + section != "" { + block = block $0 "\n" + } + + END { + flush_block() + } + ' "$base" "$target" > "$local_state" + + if [ -s "$local_state" ] || { [ -r "$local_config" ] && grep -Fqx "$begin_marker" "$local_config"; }; then + if [ -r "$local_config" ]; then + ${lib.getExe pkgs.gawk} \ + -v begin_marker="$begin_marker" \ + -v end_marker="$end_marker" ' + $0 == begin_marker { + skip = 1 + next + } + + $0 == end_marker { + skip = 0 + next + } + + !skip { + print + } + ' "$local_config" > "$local_tmp" + else + : > "$local_tmp" + fi + + if [ -s "$local_tmp" ] && [ -s "$local_state" ]; then + printf '\n' >> "$local_tmp" + fi + + if [ -s "$local_state" ]; then + printf '%s\n' "$begin_marker" >> "$local_tmp" + cat "$local_state" >> "$local_tmp" + printf '%s\n' "$end_marker" >> "$local_tmp" + fi + + chmod 600 "$local_tmp" + mv -f "$local_tmp" "$local_config" + else + rm -f "$local_tmp" + fi + + rm -f "$local_state" + fi + tmp="$(mktemp "$codex_home/config.toml.XXXXXX")" trap 'rm -f "$tmp"' EXIT chmod 600 "$tmp"