Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions config/codex/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ in
"${syncDesktopSettings}"
'';

# Codex caches Desktop preferences in memory and replaces its complete state
# file after activation. Restore managed top-level global-state keys after
# each app-owned rewrite; the synchronizer exits without writing once the
# values already match.
# Codex caches Desktop preferences in its persisted atom state and replaces
# the complete global-state file after activation. Restore managed atom-state
# keys after each app-owned rewrite; the synchronizer exits without writing
# once the values already match.
launchd.agents.codex-desktop-settings-sync = lib.mkIf pkgs.stdenv.isDarwin {
enable = true;
config = {
Expand Down
29 changes: 14 additions & 15 deletions config/codex/sync-desktop-settings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ GLOBAL_STATE="$HOME/.codex/.codex-global-state.json"

mkdir -p "$HOME/.codex"

# Codex stores these preferences as top-level global-state keys. Older Desktop
# builds kept them inside electron-persisted-atom-state, so also require those
# legacy copies to be absent before treating the file as synchronized.
# Codex Desktop stores these preferences in its persisted atom-state object.
# Top-level copies are ignored by the settings UI, so require those stale copies
# to be absent before treating the file as synchronized.
#
# Codex keeps this state in memory and periodically replaces the entire file.
# Avoid a write when the managed values already match so launchd's file watch
# settles after the synchronizer restores an app-owned rewrite.
if [[ -s $GLOBAL_STATE ]] && "$JQ_BIN" -e --slurpfile settings "$DESKTOP_SETTINGS_JSON" '
$settings[0] as $managed
| . as $state
| ($managed | to_entries | all(. as $entry |
$state[$entry.key] == $entry.value))
| (($state["electron-persisted-atom-state"] // {}) as $atoms
| ($managed | to_entries | all(. as $entry |
$atoms[$entry.key] == $entry.value)))
and
((.["electron-persisted-atom-state"] // {}) as $legacy
| ($managed | keys | all(. as $key | $legacy | has($key) | not)))
($managed | keys | all(. as $key | $state | has($key) | not))
' "$GLOBAL_STATE" >/dev/null; then
exit 0
fi
Expand All @@ -34,17 +34,16 @@ trap 'rm -f "$GLOBAL_STATE_TMP"' EXIT
if [[ -s $GLOBAL_STATE ]]; then
"$JQ_BIN" --slurpfile settings "$DESKTOP_SETTINGS_JSON" '
$settings[0] as $managed
| . + $managed
| if (.["electron-persisted-atom-state"] | type) == "object" then
.["electron-persisted-atom-state"] |=
with_entries(select(.key as $key | $managed | has($key) | not))
else
.
end
| (if (.["electron-persisted-atom-state"] | type) == "object"
then .["electron-persisted-atom-state"]
else {}
end) as $atoms
| with_entries(select(.key as $key | $managed | has($key) | not))
| .["electron-persisted-atom-state"] = ($atoms + $managed)
' "$GLOBAL_STATE" >"$GLOBAL_STATE_TMP"
else
"$JQ_BIN" -n --slurpfile settings "$DESKTOP_SETTINGS_JSON" '
$settings[0]
{"electron-persisted-atom-state": $settings[0]}
' >"$GLOBAL_STATE_TMP"
fi

Expand Down
33 changes: 19 additions & 14 deletions spec/activate_config_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ When run grep -qF 'reviewDelivery = "inline"' "$CONFIG_TOML"
The status should be success
End

It 'merges managed top-level Desktop settings without replacing unrelated state'
It 'merges managed Desktop settings into the app-owned atom state without replacing unrelated state'
TMP_HOME="$(mktemp -d)"
mkdir -p "$TMP_HOME/.codex"
cat >"$TMP_HOME/.codex/.codex-global-state.json" <<'JSON'
Expand All @@ -52,16 +52,17 @@ cat >"$TMP_HOME/.codex/.codex-global-state.json" <<'JSON'
}
JSON

When run bash -c 'HOME="$1" bash "$2" "$3" "$4" "$5" "$6" "$7" && jq -r ".[\"unrelated-top-level\"], .[\"electron-persisted-atom-state\"][\"unrelated-setting\"], .[\"git-always-force-push\"], .[\"git-pull-request-merge-method\"], .[\"worktree-keep-count\"]" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SCRIPT" "$CONFIG_TOML" "$HOOKS_JSON" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)" "$SYNC_SCRIPT"
When run bash -c 'HOME="$1" bash "$2" "$3" "$4" "$5" "$6" "$7" && jq -r ".[\"unrelated-top-level\"], .[\"electron-persisted-atom-state\"][\"unrelated-setting\"], .[\"electron-persisted-atom-state\"][\"git-always-force-push\"], .[\"electron-persisted-atom-state\"][\"git-pull-request-merge-method\"], .[\"electron-persisted-atom-state\"][\"worktree-keep-count\"], has(\"worktree-keep-count\")" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SCRIPT" "$CONFIG_TOML" "$HOOKS_JSON" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)" "$SYNC_SCRIPT"
The status should be success
The line 1 should eq 'preserved'
The line 2 should eq '42'
The line 3 should eq 'true'
The line 4 should eq 'squash'
The line 5 should eq '300'
The line 6 should eq 'false'
End

It 'restores managed top-level Desktop settings after the app replaces its state'
It 'restores managed atom-state Desktop settings after the app replaces its state'
TMP_HOME="$(mktemp -d)"
mkdir -p "$TMP_HOME/.codex"
cat >"$TMP_HOME/.codex/.codex-global-state.json" <<'JSON'
Expand All @@ -73,40 +74,44 @@ cat >"$TMP_HOME/.codex/.codex-global-state.json" <<'JSON'
}
JSON

When run bash -c 'HOME="$1" bash "$2" "$3" "$4" && jq -r ".[\"unrelated-top-level\"], .[\"electron-persisted-atom-state\"][\"unrelated-setting\"], .[\"git-branch-prefix\"], .[\"worktree-keep-count\"]" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SYNC_SCRIPT" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)"
When run bash -c 'HOME="$1" bash "$2" "$3" "$4" && jq -r ".[\"unrelated-top-level\"], .[\"electron-persisted-atom-state\"][\"unrelated-setting\"], .[\"electron-persisted-atom-state\"][\"git-branch-prefix\"], .[\"electron-persisted-atom-state\"][\"worktree-keep-count\"], has(\"worktree-keep-count\")" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SYNC_SCRIPT" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)"
The status should be success
The line 1 should eq 'preserved'
The line 2 should eq '42'
The line 3 should eq 'codex/'
The line 4 should eq '300'
The line 5 should eq 'false'
End

It 'removes legacy nested copies of managed Desktop settings'
It 'removes stale top-level copies of managed Desktop settings'
TMP_HOME="$(mktemp -d)"
mkdir -p "$TMP_HOME/.codex"
cat >"$TMP_HOME/.codex/.codex-global-state.json" <<'JSON'
{
"git-branch-prefix": "stale/",
"worktree-keep-count": 15,
"electron-persisted-atom-state": {
"unrelated-setting": 42,
"git-branch-prefix": "legacy/",
"worktree-keep-count": 15
"unrelated-setting": 42
}
}
JSON

When run bash -c 'HOME="$1" bash "$2" "$3" "$4" && jq -r ".[\"electron-persisted-atom-state\"][\"unrelated-setting\"], (.[\"electron-persisted-atom-state\"] | has(\"git-branch-prefix\")), (.[\"electron-persisted-atom-state\"] | has(\"worktree-keep-count\")), .[\"git-branch-prefix\"], .[\"worktree-keep-count\"]" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SYNC_SCRIPT" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)"
When run bash -c 'HOME="$1" bash "$2" "$3" "$4" && jq -r ".[\"electron-persisted-atom-state\"][\"unrelated-setting\"], .[\"electron-persisted-atom-state\"][\"git-branch-prefix\"], .[\"electron-persisted-atom-state\"][\"worktree-keep-count\"], has(\"git-branch-prefix\"), has(\"worktree-keep-count\")" "$1/.codex/.codex-global-state.json"' _ "$TMP_HOME" "$SYNC_SCRIPT" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)"
The status should be success
The line 1 should eq '42'
The line 2 should eq 'false'
The line 3 should eq 'false'
The line 4 should eq 'codex/'
The line 5 should eq '300'
The line 2 should eq 'codex/'
The line 3 should eq '300'
The line 4 should eq 'false'
The line 5 should eq 'false'
End

It 'does not rewrite state when managed Desktop settings already match'
TMP_HOME="$(mktemp -d)"
mkdir -p "$TMP_HOME/.codex"
cp -f "$DESKTOP_SETTINGS_JSON" "$TMP_HOME/.codex/.codex-global-state.json"
jq -n --slurpfile settings "$DESKTOP_SETTINGS_JSON" '{
"unrelated-top-level": "preserved",
"electron-persisted-atom-state": $settings[0]
}' >"$TMP_HOME/.codex/.codex-global-state.json"

When run bash -c 'HOME="$1" bash "$2" "$3" "$4" && before=$(ls -di "$1/.codex/.codex-global-state.json") && before=${before%% *} && HOME="$1" bash "$2" "$3" "$4" && after=$(ls -di "$1/.codex/.codex-global-state.json") && after=${after%% *} && test "$before" = "$after" && printf "%s\\n" unchanged' _ "$TMP_HOME" "$SYNC_SCRIPT" "$DESKTOP_SETTINGS_JSON" "$(command -v jq)"
The status should be success
Expand Down
Loading