fix(config): preserve unmanaged Codex TOML tables
Keep foreign tables such as mcp_servers and model_providers during config synchronization instead of dropping them; only setup-owned keys are replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1cba8850f9
commit
1a6cc4d46f
4 files changed
+16
-5
No files matched your search
@@ -129,11 +129,9 @@ def merge_toml(current_text, managed_text, statusline_enabled=True):
|
||||
owned_hook = any(re.search(r'(?:flashbang|statusline|record-compact|session-state-pointer)\.(?:ps1|sh)', line, re.I) for line in block)
|
||||
if plugin_table and header in managed_headers:
|
||||
raise ValueError('Cannot merge conflicting managed plugin tables.')
|
||||
if (plugin_table and header not in managed_headers) or (array_table and not owned_hook):
|
||||
if (header not in managed_headers and not array_table) or (array_table and not owned_hook):
|
||||
extras.extend(block)
|
||||
continue
|
||||
if header not in managed_headers:
|
||||
continue
|
||||
if array_table:
|
||||
continue
|
||||
generated_block = next(lines for name, lines in managed_sections if name == header)
|
||||
|
||||
@@ -31,6 +31,19 @@ class InstallOptionsTests(unittest.TestCase):
|
||||
|
||||
self.assertIn(plugin_state, result)
|
||||
|
||||
def test_merge_toml_preserves_unmanaged_tables(self):
|
||||
foreign = ('[mcp_servers.demo]\ncommand = "demo"\n\n[mcp_servers.demo.env]\nTOKEN_NAME = "x"\n\n'
|
||||
'[model_providers.custom]\nname = "Custom"\nbase_url = "https://example.invalid"\n')
|
||||
current = "model = 'old'\n\n[tui]\nstatus_line = ['a']\ntheme = 'dark'\n\n" + foreign
|
||||
managed = "model = 'new'\n\n[tui]\nstatus_line = ['b']\n"
|
||||
|
||||
result = tomllib.loads(OPTIONS.merge_toml(current, managed))
|
||||
|
||||
self.assertEqual(result['model'], 'new')
|
||||
self.assertEqual(result['tui'], {'status_line': ['b'], 'theme': 'dark'})
|
||||
self.assertEqual(result['mcp_servers'], {'demo': {'command': 'demo', 'env': {'TOKEN_NAME': 'x'}}})
|
||||
self.assertEqual(result['model_providers'], {'custom': {'name': 'Custom', 'base_url': 'https://example.invalid'}})
|
||||
|
||||
def test_filter_preserves_other_claude_hooks_and_status(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
path = Path(directory) / 'settings.json'
|
||||
|
||||
@@ -63,7 +63,7 @@ try {
|
||||
$null = Sync-ManagedDestination -Source $source -Destination $destination -Stamp 'plugins'
|
||||
$mergedConfig = [System.IO.File]::ReadAllText($configPath)
|
||||
if (-not ($mergedConfig -replace "`r`n", "`n").Contains(($pluginState -replace "`r`n", "`n"))) { throw 'Updating config.toml must preserve local marketplace and plugin tables, including disabled plugins.' }
|
||||
if (-not $mergedConfig.Contains("model = 'old'") -or -not $mergedConfig.Contains("model_reasoning_effort = 'high'") -or -not $mergedConfig.Contains("approvals_reviewer = 'auto_review'") -or $mergedConfig.Contains("approvals_reviewer = 'user'") -or $mergedConfig.Contains('[other]')) { throw 'Updating config.toml must preserve local model settings and enforce automatic review.' }
|
||||
if (-not $mergedConfig.Contains("model = 'old'") -or -not $mergedConfig.Contains("model_reasoning_effort = 'high'") -or -not $mergedConfig.Contains("approvals_reviewer = 'auto_review'") -or $mergedConfig.Contains("approvals_reviewer = 'user'") -or -not $mergedConfig.Contains('[other]')) { throw 'Updating config.toml must preserve local settings and tables and enforce automatic review.' }
|
||||
if ($mergedConfig.IndexOf("model = 'old'") -gt $mergedConfig.IndexOf('[tui]') -or $mergedConfig.IndexOf("model_reasoning_effort = 'high'") -gt $mergedConfig.IndexOf('[tui]')) { throw 'Model settings must remain in the TOML root table.' }
|
||||
if ([System.IO.File]::ReadAllText((Join-Path $destination 'backups/plugins/config.toml')) -ne $originalConfig) { throw 'Original plugin configuration must be backed up.' }
|
||||
$null = Sync-ManagedDestination -Source $source -Destination $destination -Stamp 'plugins-repeat'
|
||||
|
||||
@@ -74,7 +74,7 @@ merged_config=$(cat "$destination/config.toml")
|
||||
merged_config_normalized=${merged_config//$'\r'/}
|
||||
plugin_state_normalized=${plugin_state//$'\r'/}
|
||||
[[ "$merged_config_normalized" == *"$plugin_state_normalized"* ]] || { printf 'Updating config.toml must preserve local marketplace and plugin tables, including disabled plugins.\n' >&2; exit 1; }
|
||||
[[ "$merged_config" == *"model = 'old'"* && "$merged_config" == *"model_reasoning_effort = 'high'"* && "$merged_config" == *"approvals_reviewer = 'auto_review'"* && "$merged_config" != *"approvals_reviewer = 'user'"* && "$merged_config" != *'[other]'* ]] || { printf 'Updating config.toml must preserve local model settings and enforce automatic review.\n' >&2; exit 1; }
|
||||
[[ "$merged_config" == *"model = 'old'"* && "$merged_config" == *"model_reasoning_effort = 'high'"* && "$merged_config" == *"approvals_reviewer = 'auto_review'"* && "$merged_config" != *"approvals_reviewer = 'user'"* && "$merged_config" == *'[other]'* ]] || { printf 'Updating config.toml must preserve local model settings and enforce automatic review.\n' >&2; exit 1; }
|
||||
[ "$(printf '%s\n' "$merged_config" | grep -n "model = 'old'" | cut -d: -f1)" -lt "$(printf '%s\n' "$merged_config" | grep -n '^\[tui\]$' | cut -d: -f1)" ] || { printf 'Model must remain in TOML root table.\n' >&2; exit 1; }
|
||||
[ "$(printf '%s\n' "$merged_config" | grep -n "model_reasoning_effort = 'high'" | cut -d: -f1)" -lt "$(printf '%s\n' "$merged_config" | grep -n '^\[tui\]$' | cut -d: -f1)" ] || { printf 'Model effort must remain in TOML root table.\n' >&2; exit 1; }
|
||||
[ "$(cat "$destination/backups/plugins/config.toml")" = "$original_config" ] || { printf 'Original plugin configuration must be backed up.\n' >&2; exit 1; }
|
||||
|
||||
Reference in new issue
Block a user