fix(cli): remove unset config keys from every layered config file - #12687
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (5 files)
Traced the propagation logic end-to-end ( Reviewed by claude-sonnet-5 · Input: 30 · Output: 9.9K · Cached: 825.7K Review guidance: REVIEW.md from base branch |
fix(cli): remove unset config keys from every layered config file
Clearing a setting back to "not set" in the Settings UI (or via the config API) did not stick when more than one config file existed. Kilo reads and deep-merges every config file in a scope (global:
config.json,kilo.json,kilo.jsonc,opencode.json,opencode.jsonc; project: the same names in the project root and config directories), but writes only patched the single primary target file. An unset deleted the key fromkilo.jsonc, and when the value actually lived inkilo.jsonor a legacy file, the delete was a no-op there, the merged read kept resolving the old value, and the setting snapped back after save. Setting a value worked, which made this look intermittent: sets shadow lower-precedence files, unsets did not.With this change, delete sentinels are removed from every layered config file that contains the key, in both the global and project scopes. Files that do not contain the key are not touched (no byte-level rewrites), comments in
.jsoncfiles are preserved, and sets keep their existing single-target behavior. The propagation runs inside the global config file lock and counts toward the change flag, so cache invalidation and instance disposal still fire when only a sibling file changed.The same patch fixes a second latent crash in this path: deleting a nested key whose parent object is absent from the target file (for example clearing
agent.explore.modelin a file without anagentsection) threwCan not delete in empty documentfrom jsonc-parser. Absent paths are now skipped.The settings docs now also state that layered config files are merged and that clearing a setting removes it from every file that contains it.
Related: #11484 documents the opposite direction of the same read/write mismatch (sets can be silently overridden because read precedence favors legacy
opencode.*files). This PR does not change set behavior or read precedence; it makes unsets robust regardless of that ordering.