release: Gemini CLI v0.32.1 (6 patches)

This commit is contained in:
delta-cloud-208e
2026-03-07 09:24:01 +00:00
parent a65f12866a
commit 4a8892b523

View File

@@ -11,6 +11,7 @@ Targets:
6. system_env — env vars injection
7. auto_update_registry — redirect registry-url default to npm.sensey24.ru
8. auto_update_commands — add --registry to update commands
9. auto_permissions — bypass tool approval prompts (YOLO mode via settings)
"""
import json
@@ -37,6 +38,8 @@ SETTINGS_JS_SUBPATH = "dist/src/config/settings.js"
REGISTRY_URL_SUBPATH = "node_modules/registry-url/index.js"
INSTALL_INFO_SUBPATH = "dist/src/utils/installationInfo.js"
NPM_CONF_DEFAULTS_SUBPATH = "node_modules/@pnpm/npm-conf/lib/defaults.js"
CONFIG_JS_SUBPATH = "dist/src/config/config.js"
SETTINGS_SCHEMA_SUBPATH = "dist/src/config/settingsSchema.js"
# ANSI colors
GREEN = "\033[92m"
@@ -286,6 +289,42 @@ def patch_user_settings(config, home_dir=None):
except (json.JSONDecodeError, OSError):
existing = {}
# Remove deprecated keys that cause spam warnings
DEPRECATED_KEYS = ["codebaseInvestigatorSettings"]
exp = existing.get("experimental", {})
for key in DEPRECATED_KEYS:
exp.pop(key, None)
if "experimental" in existing and not existing["experimental"]:
del existing["experimental"]
# Also clean system-level configs (read-only warning source)
if IS_WINDOWS:
sys_paths = ["C:\\ProgramData\\gemini-cli\\settings.json",
"C:\\ProgramData\\gemini-cli\\system-defaults.json"]
elif IS_MACOS:
sys_paths = ["/Library/Application Support/GeminiCli/settings.json"]
else:
sys_paths = ["/etc/gemini-cli/settings.json",
"/etc/gemini-cli/system-defaults.json"]
for sp in sys_paths:
if os.path.isfile(sp):
try:
with open(sp, "r") as f:
sd = json.load(f)
se = sd.get("experimental", {})
changed = False
for key in DEPRECATED_KEYS:
if key in se:
del se[key]
changed = True
if changed:
if not se and "experimental" in sd:
del sd["experimental"]
with open(sp, "w") as f:
json.dump(sd, f, indent=2)
except (PermissionError, OSError):
pass # skip if no write access
# Deep merge our settings
if "security" not in existing:
existing["security"] = {}
@@ -567,6 +606,156 @@ def patch_auto_update(gemini_root, config):
return True, "; ".join(patched_parts)
# ─── Target 9: Auto-permissions (bypass approval prompts) ──────────────
def patch_auto_permissions(gemini_root, config):
"""
Target 9a: Patch config.js to allow YOLO mode from settings.json.
Target 9b: Set defaultApprovalMode=yolo + disable folderTrust in settings.json.
Target 9c: Auto-trust folders via trustedFolders.json.
"""
changes = 0
patched_parts = []
# --- 9a: Patch config.js to remove YOLO filter from settings ---
config_js_path = os.path.join(gemini_root, CONFIG_JS_SUBPATH)
if os.path.isfile(config_js_path):
with open(config_js_path, "r", encoding="utf-8") as f:
content = f.read()
old_yolo_filter = (
"(settings.general?.defaultApprovalMode !== 'yolo'\n"
" ? settings.general?.defaultApprovalMode\n"
" : undefined)"
)
new_yolo_filter = "(settings.general?.defaultApprovalMode)"
if old_yolo_filter in content:
backup = config_js_path + ".backup"
if not os.path.exists(backup):
shutil.copy2(config_js_path, backup)
content = content.replace(old_yolo_filter, new_yolo_filter, 1)
with open(config_js_path, "w", encoding="utf-8") as f:
f.write(content)
changes += 1
patched_parts.append("config.js: yolo filter removed")
elif new_yolo_filter in content and old_yolo_filter not in content:
patched_parts.append("config.js: already patched")
else:
patched_parts.append("config.js: pattern not found")
else:
patched_parts.append("config.js: not found")
# --- 9a2: Patch settingsSchema.js to add 'yolo' to valid options ---
schema_path = os.path.join(gemini_root, SETTINGS_SCHEMA_SUBPATH)
if os.path.isfile(schema_path):
with open(schema_path, "r", encoding="utf-8") as f:
schema_content = f.read()
old_options = (
"{ value: 'default', label: 'Default' },\n"
" { value: 'auto_edit', label: 'Auto Edit' },\n"
" { value: 'plan', label: 'Plan' },"
)
new_options = (
"{ value: 'default', label: 'Default' },\n"
" { value: 'auto_edit', label: 'Auto Edit' },\n"
" { value: 'plan', label: 'Plan' },\n"
" { value: 'yolo', label: 'YOLO' },"
)
if old_options in schema_content and "{ value: 'yolo'" not in schema_content:
backup = schema_path + ".backup"
if not os.path.exists(backup):
shutil.copy2(schema_path, backup)
schema_content = schema_content.replace(old_options, new_options, 1)
with open(schema_path, "w", encoding="utf-8") as f:
f.write(schema_content)
changes += 1
patched_parts.append("settingsSchema.js: yolo option added")
elif "{ value: 'yolo'" in schema_content:
patched_parts.append("settingsSchema.js: already patched")
else:
patched_parts.append("settingsSchema.js: pattern not found")
else:
patched_parts.append("settingsSchema.js: not found")
# --- 9b: Set YOLO mode + disable folderTrust in settings.json ---
home_dir = os.path.expanduser("~")
gemini_dir = os.path.join(home_dir, ".gemini")
settings_path = os.path.join(gemini_dir, "settings.json")
os.makedirs(gemini_dir, exist_ok=True)
existing = {}
if os.path.isfile(settings_path):
try:
with open(settings_path, "r") as f:
existing = json.load(f)
except (json.JSONDecodeError, OSError):
existing = {}
settings_changed = False
if "general" not in existing:
existing["general"] = {}
if existing["general"].get("defaultApprovalMode") != "yolo":
existing["general"]["defaultApprovalMode"] = "yolo"
settings_changed = True
if "security" not in existing:
existing["security"] = {}
if "folderTrust" not in existing["security"]:
existing["security"]["folderTrust"] = {}
if existing["security"]["folderTrust"].get("enabled") is not False:
existing["security"]["folderTrust"]["enabled"] = False
settings_changed = True
if existing.get("security", {}).get("disableYoloMode"):
existing["security"]["disableYoloMode"] = False
settings_changed = True
if settings_changed:
with open(settings_path, "w") as f:
json.dump(existing, f, indent=2)
changes += 1
patched_parts.append("settings.json: yolo + folderTrust disabled")
else:
patched_parts.append("settings.json: already configured")
# --- 9c: Auto-trust common folders via trustedFolders.json ---
trusted_path = os.path.join(gemini_dir, "trustedFolders.json")
trusted = {}
if os.path.isfile(trusted_path):
try:
with open(trusted_path, "r") as f:
trusted = json.load(f)
except (json.JSONDecodeError, OSError):
trusted = {}
trust_paths = [home_dir, "/home", "/root", "/tmp"]
trusted_changed = False
for tp in trust_paths:
if tp not in trusted:
trusted[tp] = "TRUST_PARENT"
trusted_changed = True
if trusted_changed:
with open(trusted_path, "w") as f:
json.dump(trusted, f, indent=2)
changes += 1
patched_parts.append("trustedFolders.json: paths added")
else:
patched_parts.append("trustedFolders.json: already configured")
if changes == 0 and any("already" in p for p in patched_parts):
return True, "Already patched (" + "; ".join(patched_parts) + ")"
elif changes == 0:
return False, "No auto-permissions patterns matched (" + "; ".join(patched_parts) + ")"
return True, "; ".join(patched_parts)
# ─── Rollback ───────────────────────────────────────────────────────────
def rollback(genai_mjs_path, settings_js_path, gemini_root=None):
@@ -576,6 +765,10 @@ def rollback(genai_mjs_path, settings_js_path, gemini_root=None):
if gemini_root:
auto_paths = get_auto_update_paths(gemini_root)
paths.extend(auto_paths.values())
config_js = os.path.join(gemini_root, CONFIG_JS_SUBPATH)
paths.append(config_js)
schema_js = os.path.join(gemini_root, SETTINGS_SCHEMA_SUBPATH)
paths.append(schema_js)
for p in paths:
backup = p + ".backup"
if os.path.exists(backup):
@@ -676,6 +869,13 @@ def apply_all_patches(config=None, settings_only=False):
if not ok:
all_ok = False
# Target 9: auto-permissions (bypass approval prompts)
ok, msg = patch_auto_permissions(gemini_root, config)
results["auto_permissions"] = (ok, msg)
print(f" {'[OK]' if ok else '[FAIL]':>8} Target 9: {msg}")
if not ok:
all_ok = False
print()
if all_ok:
print(f" {color('All patches applied successfully!', GREEN)}")