wren-linux / lib / claude-settings.py
"""claude-settings.py add|remove SETTINGS WREN_JSON STATE: puts Wren Linux's
Claude Code settings (WREN_JSON) into your SETTINGS (~/.claude/settings.json)
or takes them out again, for the retired extras/claude-regular.sh (its --remove). Lists get Wren Linux's
items added to yours; a value (like sandbox.enabled) is set only if you haven't
set it yourself. STATE remembers exactly what was added, so remove takes out
that and nothing of yours. Run with python3 -I."""
import json
import os
import sys
def load(path, default):
try:
with open(path) as f:
return json.load(f)
except FileNotFoundError:
return default
def save(path, data, mode=0o600):
os.makedirs(os.path.dirname(path), exist_ok=True)
tmp = path + ".wren-tmp"
with open(tmp, "w") as f:
json.dump(data, f, indent=2)
f.write("\n")
os.chmod(tmp, mode)
os.replace(tmp, path)
def add(mine, ours, path, added):
for key, value in ours.items():
where = path + [key]
if isinstance(value, dict):
if not isinstance(mine.get(key), dict):
if key in mine:
continue # yours is something else: left alone
mine[key] = {}
add(mine[key], value, where, added)
elif isinstance(value, list):
have = mine.setdefault(key, [])
if not isinstance(have, list):
continue
for item in value:
if item not in have:
have.append(item)
added.append({"path": where, "item": item})
elif key not in mine:
mine[key] = value
added.append({"path": where, "value": value})
def remove(mine, added):
for a in added:
node = mine
for key in a["path"][:-1]:
node = node.get(key) if isinstance(node, dict) else None
if node is None:
break
if not isinstance(node, dict):
continue
last = a["path"][-1]
if "item" in a and isinstance(node.get(last), list) and a["item"] in node[last]:
node[last].remove(a["item"])
elif "value" in a and node.get(last) == a["value"]:
del node[last]
prune(mine)
def prune(node):
"""Empty lists and objects Wren Linux's removal left behind go too."""
for key in list(node):
if isinstance(node[key], dict):
prune(node[key])
if node[key] in ({}, []):
del node[key]
def main():
action, settings, ours_path, state = sys.argv[1:5]
mine = load(settings, {})
if not isinstance(mine, dict):
sys.exit("%s isn't a JSON object; leaving it alone." % settings)
if action == "add":
added = load(state, [])
add(mine, load(ours_path, {}), [], added)
save(settings, mine)
save(state, added)
elif action == "remove":
remove(mine, load(state, []))
save(settings, mine)
if os.path.exists(state):
os.remove(state)
else:
sys.exit("usage: claude-settings.py add|remove SETTINGS WREN_JSON STATE")
main()