|
|
|
|
@@ -657,44 +657,36 @@ def patch_auto_permissions(gemini_root, config):
|
|
|
|
|
patched_parts.append("config.js: not found")
|
|
|
|
|
|
|
|
|
|
# --- 9a2: Patch settingsSchema.js to add 'yolo' to valid options ---
|
|
|
|
|
# Gemini v0.32.1 used 'auto_edit', v0.35+ uses 'autoEdit' — handle both.
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
if "{ value: 'yolo'" in schema_content:
|
|
|
|
|
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:
|
|
|
|
|
backup_done = False
|
|
|
|
|
patched = False
|
|
|
|
|
for ae_value in ("autoEdit", "auto_edit"):
|
|
|
|
|
old_options = (
|
|
|
|
|
"{ value: 'default', label: 'Default' },\n"
|
|
|
|
|
f" {{ value: '{ae_value}', label: 'Auto Edit' }},\n"
|
|
|
|
|
" { value: 'plan', label: 'Plan' },"
|
|
|
|
|
)
|
|
|
|
|
new_options = (
|
|
|
|
|
"{ value: 'default', label: 'Default' },\n"
|
|
|
|
|
f" {{ value: '{ae_value}', label: 'Auto Edit' }},\n"
|
|
|
|
|
" { value: 'plan', label: 'Plan' },\n"
|
|
|
|
|
" { value: 'yolo', label: 'YOLO' },"
|
|
|
|
|
)
|
|
|
|
|
if old_options in schema_content:
|
|
|
|
|
if not backup_done:
|
|
|
|
|
backup = schema_path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(schema_path, backup)
|
|
|
|
|
backup_done = True
|
|
|
|
|
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(f"settingsSchema.js: yolo option added ({ae_value} variant)")
|
|
|
|
|
patched = True
|
|
|
|
|
break
|
|
|
|
|
if not patched:
|
|
|
|
|
patched_parts.append("settingsSchema.js: pattern not found")
|
|
|
|
|
patched_parts.append("settingsSchema.js: pattern not found")
|
|
|
|
|
else:
|
|
|
|
|
patched_parts.append("settingsSchema.js: not found")
|
|
|
|
|
|
|
|
|
|
@@ -792,25 +784,12 @@ def patch_auto_permissions(gemini_root, config):
|
|
|
|
|
'[[safety_checker]]\n'
|
|
|
|
|
'toolName = "*"\n'
|
|
|
|
|
'priority = 100\n'
|
|
|
|
|
'modes = ["default", "autoEdit", "plan"]\n'
|
|
|
|
|
'modes = ["default", "auto_edit", "plan"]\n'
|
|
|
|
|
'[safety_checker.checker]\n'
|
|
|
|
|
'type = "in-process"\n'
|
|
|
|
|
'name = "conseca"'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Self-heal: if older patcher inserted invalid `auto_edit` enum value, fix it
|
|
|
|
|
if 'modes = ["default", "auto_edit", "plan"]' in conseca_content:
|
|
|
|
|
backup = conseca_path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(conseca_path, backup)
|
|
|
|
|
conseca_content = conseca_content.replace(
|
|
|
|
|
'modes = ["default", "auto_edit", "plan"]',
|
|
|
|
|
'modes = ["default", "autoEdit", "plan"]',
|
|
|
|
|
)
|
|
|
|
|
with open(conseca_path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.write(conseca_content)
|
|
|
|
|
changes += 1
|
|
|
|
|
|
|
|
|
|
if old_conseca in conseca_content and 'modes = ["default"' not in conseca_content:
|
|
|
|
|
backup = conseca_path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
@@ -835,8 +814,46 @@ def patch_auto_permissions(gemini_root, config):
|
|
|
|
|
return True, "; ".join(patched_parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─── Bundled-mode helpers (0.38+) ───────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
def is_bundled_install(gemini_root):
|
|
|
|
|
"""True iff this install uses Gemini CLI 0.38+ bundle/chunk-*.js layout."""
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
return os.path.isdir(bundle_dir)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ─── Target 10: Patch default model constants in models.js ──────────────
|
|
|
|
|
|
|
|
|
|
def _patch_default_models_in_text(content, default_model, flash_model):
|
|
|
|
|
"""Apply Target 10 transformations to a string. Returns (new_content, n_changes)."""
|
|
|
|
|
changes = 0
|
|
|
|
|
|
|
|
|
|
if default_model:
|
|
|
|
|
# Match both 'export const' (legacy) and 'var' (bundled) plus quote variants
|
|
|
|
|
pat = r"((?:export const|var)\s+DEFAULT_GEMINI_MODEL\s*=\s*['\"])gemini-\d+\.\d+[^'\"]*(['\"])"
|
|
|
|
|
content, n = re.subn(pat, rf"\g<1>{default_model}\g<2>", content)
|
|
|
|
|
changes += n
|
|
|
|
|
|
|
|
|
|
if flash_model:
|
|
|
|
|
pat = r"((?:export const|var)\s+DEFAULT_GEMINI_FLASH_MODEL\s*=\s*['\"])gemini-\d+\.\d+[^'\"]*(['\"])"
|
|
|
|
|
content, n = re.subn(pat, rf"\g<1>{flash_model}\g<2>", content)
|
|
|
|
|
changes += n
|
|
|
|
|
|
|
|
|
|
pat = r"((?:export const|var)\s+DEFAULT_GEMINI_FLASH_LITE_MODEL\s*=\s*['\"])gemini-\d+\.\d+[^'\"]*(['\"])"
|
|
|
|
|
content, n = re.subn(pat, rf"\g<1>{flash_model}\g<2>", content)
|
|
|
|
|
changes += n
|
|
|
|
|
|
|
|
|
|
pat = r"((?:export const|var)\s+DEFAULT_GEMINI_MODEL_AUTO\s*=\s*['\"])auto-gemini-\d[^'\"]*(['\"])"
|
|
|
|
|
content, n = re.subn(pat, r"\g<1>auto-gemini-3\g<2>", content)
|
|
|
|
|
changes += n
|
|
|
|
|
|
|
|
|
|
pat = r"(return\s*['\"]Auto \(Gemini )\d[^'\"]*(['\"])"
|
|
|
|
|
content, n = re.subn(pat, r"\g<1>3\g<2>", content)
|
|
|
|
|
changes += n
|
|
|
|
|
|
|
|
|
|
return content, changes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def patch_default_models(gemini_root, config):
|
|
|
|
|
"""
|
|
|
|
|
Target 10: Override DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_FLASH_MODEL,
|
|
|
|
|
@@ -848,6 +865,68 @@ def patch_default_models(gemini_root, config):
|
|
|
|
|
if not default_model and not flash_model:
|
|
|
|
|
return True, "Skipped (no default_model/internal_flash_model in config)"
|
|
|
|
|
|
|
|
|
|
if is_bundled_install(gemini_root):
|
|
|
|
|
from gemini.bundle_finder import find_all_chunks_with_anchors
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
# Strict anchor: 'var DEFAULT_GEMINI_MODEL ' (with trailing space)
|
|
|
|
|
# only matches DEFINITION sites, not USE sites (which look like
|
|
|
|
|
# ', DEFAULT_GEMINI_MODEL,' or 'model: DEFAULT_GEMINI_MODEL').
|
|
|
|
|
anchors = [
|
|
|
|
|
"var DEFAULT_GEMINI_MODEL ",
|
|
|
|
|
"var DEFAULT_GEMINI_FLASH_MODEL ",
|
|
|
|
|
"var DEFAULT_GEMINI_MODEL_AUTO ",
|
|
|
|
|
]
|
|
|
|
|
chunks = find_all_chunks_with_anchors(bundle_dir, anchors)
|
|
|
|
|
# Fallback for legacy-format bundle: 'export const' style
|
|
|
|
|
if not chunks:
|
|
|
|
|
anchors = [
|
|
|
|
|
"export const DEFAULT_GEMINI_MODEL ",
|
|
|
|
|
"export const DEFAULT_GEMINI_FLASH_MODEL ",
|
|
|
|
|
"export const DEFAULT_GEMINI_MODEL_AUTO ",
|
|
|
|
|
]
|
|
|
|
|
chunks = find_all_chunks_with_anchors(bundle_dir, anchors)
|
|
|
|
|
if not chunks:
|
|
|
|
|
return False, "No bundle chunks found defining DEFAULT_GEMINI_MODEL"
|
|
|
|
|
total_changes = 0
|
|
|
|
|
modified = 0
|
|
|
|
|
already = 0
|
|
|
|
|
for path in chunks:
|
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
new_content, n = _patch_default_models_in_text(content, default_model, flash_model)
|
|
|
|
|
if new_content == content:
|
|
|
|
|
# Verify already-patched: definition must point to expected target.
|
|
|
|
|
# If the definition is unchanged from legacy AND we did not
|
|
|
|
|
# change anything, it's a true no-match (anchor was wrong).
|
|
|
|
|
expected_main = (
|
|
|
|
|
f'DEFAULT_GEMINI_MODEL = "{default_model}"' in content
|
|
|
|
|
or f"DEFAULT_GEMINI_MODEL = '{default_model}'" in content
|
|
|
|
|
) if default_model else True
|
|
|
|
|
expected_flash = (
|
|
|
|
|
f'DEFAULT_GEMINI_FLASH_MODEL = "{flash_model}"' in content
|
|
|
|
|
or f"DEFAULT_GEMINI_FLASH_MODEL = '{flash_model}'" in content
|
|
|
|
|
) if flash_model else True
|
|
|
|
|
expected_auto = (
|
|
|
|
|
'DEFAULT_GEMINI_MODEL_AUTO = "auto-gemini-3"' in content
|
|
|
|
|
or "DEFAULT_GEMINI_MODEL_AUTO = 'auto-gemini-3'" in content
|
|
|
|
|
)
|
|
|
|
|
if expected_main and expected_flash and expected_auto:
|
|
|
|
|
already += 1
|
|
|
|
|
# else: silent skip — not counted as already, not as modified
|
|
|
|
|
continue
|
|
|
|
|
backup = path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(path, backup)
|
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.write(new_content)
|
|
|
|
|
modified += 1
|
|
|
|
|
total_changes += n
|
|
|
|
|
if modified == 0 and already == 0:
|
|
|
|
|
return False, "No models.js patterns matched in bundled chunks"
|
|
|
|
|
if modified == 0:
|
|
|
|
|
return True, f"Already patched (models.js, {already} chunk(s))"
|
|
|
|
|
return True, f"Patched {total_changes} constant(s) across {modified} bundled chunk(s)"
|
|
|
|
|
|
|
|
|
|
models_path = os.path.join(gemini_root, MODELS_JS_SUBPATH)
|
|
|
|
|
if not os.path.isfile(models_path):
|
|
|
|
|
return False, f"File not found: {models_path}"
|
|
|
|
|
@@ -950,6 +1029,46 @@ def patch_model_dialog(gemini_root, config):
|
|
|
|
|
"""
|
|
|
|
|
default_model = config.get("default_model", "gemini-2.5-pro")
|
|
|
|
|
flash_model = config.get("internal_flash_model", "gemini-2.5-flash")
|
|
|
|
|
new_desc = f"{default_model}, {flash_model}"
|
|
|
|
|
|
|
|
|
|
if is_bundled_install(gemini_root):
|
|
|
|
|
from gemini.bundle_finder import find_all_chunks_with_anchors
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
# Anchor on the unique-enough literal "dialogDescription" line marker.
|
|
|
|
|
chunks = find_all_chunks_with_anchors(bundle_dir, ["dialogDescription"])
|
|
|
|
|
# Match either the legacy pair (X.Y-pro, X.Y-flash) OR an already-patched
|
|
|
|
|
# config-derived pair (e.g. gemini-3.1-pro-preview, gemini-3-flash-preview).
|
|
|
|
|
legacy_re = re.compile(r"gemini-\d+\.\d+-pro, gemini-\d+\.?\d*-?[a-z]*")
|
|
|
|
|
modified = 0
|
|
|
|
|
already = 0
|
|
|
|
|
seen = 0
|
|
|
|
|
for path in chunks:
|
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
if new_desc in content:
|
|
|
|
|
seen += 1
|
|
|
|
|
already += 1
|
|
|
|
|
continue
|
|
|
|
|
if not legacy_re.search(content):
|
|
|
|
|
continue # this chunk has dialogDescription but not the model-pair string
|
|
|
|
|
seen += 1
|
|
|
|
|
new_content = legacy_re.sub(new_desc, content, count=1)
|
|
|
|
|
if new_content == content:
|
|
|
|
|
already += 1
|
|
|
|
|
continue
|
|
|
|
|
backup = path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(path, backup)
|
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.write(new_content)
|
|
|
|
|
modified += 1
|
|
|
|
|
if seen == 0:
|
|
|
|
|
return False, "No bundle chunks found with model dialog description"
|
|
|
|
|
if modified == 0 and already == seen:
|
|
|
|
|
return True, f"Already patched (ModelDialog, {seen} chunk(s))"
|
|
|
|
|
if modified == 0:
|
|
|
|
|
return False, "No ModelDialog patterns matched in bundled chunks"
|
|
|
|
|
return True, f"Patched ModelDialog in {modified} bundled chunk(s)"
|
|
|
|
|
|
|
|
|
|
dialog_path = os.path.join(gemini_root, MODEL_DIALOG_JS_SUBPATH)
|
|
|
|
|
if not os.path.isfile(dialog_path):
|
|
|
|
|
@@ -990,12 +1109,61 @@ def patch_model_dialog(gemini_root, config):
|
|
|
|
|
|
|
|
|
|
# ─── Target 12: Patch chatCompressionService.js compression aliases ────
|
|
|
|
|
|
|
|
|
|
_COMPRESSION_REGEX_REPLACEMENTS = [
|
|
|
|
|
(r"(case DEFAULT_GEMINI_MODEL:\s*\n\s*return\s+['\"])chat-compression-\d+\.\d+-pro(['\"])",
|
|
|
|
|
r"\g<1>chat-compression-3-pro\g<2>"),
|
|
|
|
|
(r"(case DEFAULT_GEMINI_FLASH_MODEL:\s*\n\s*return\s+['\"])chat-compression-\d+\.\d+-flash(['\"])",
|
|
|
|
|
r"\g<1>chat-compression-3-flash\g<2>"),
|
|
|
|
|
(r"(case DEFAULT_GEMINI_FLASH_LITE_MODEL:\s*\n\s*return\s+['\"])chat-compression-\d+\.\d+-flash[^'\"]*(['\"])",
|
|
|
|
|
r"\g<1>chat-compression-3-flash\g<2>"),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _patch_compression_in_text(content):
|
|
|
|
|
changes = 0
|
|
|
|
|
for pat, repl in _COMPRESSION_REGEX_REPLACEMENTS:
|
|
|
|
|
content, n = re.subn(pat, repl, content)
|
|
|
|
|
changes += n
|
|
|
|
|
return content, changes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def patch_compression_aliases(gemini_root, config):
|
|
|
|
|
"""
|
|
|
|
|
Target 12: Fix compression config aliases in chatCompressionService.js.
|
|
|
|
|
After Target 10, DEFAULT_ constants point to 3.x models but switch/case
|
|
|
|
|
returns 2.5 aliases. Fix to return 3.x aliases.
|
|
|
|
|
"""
|
|
|
|
|
if is_bundled_install(gemini_root):
|
|
|
|
|
from gemini.bundle_finder import find_all_chunks_with_anchors
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
chunks = find_all_chunks_with_anchors(
|
|
|
|
|
bundle_dir, ["case DEFAULT_GEMINI_MODEL:", "chat-compression-"]
|
|
|
|
|
)
|
|
|
|
|
if not chunks:
|
|
|
|
|
return False, "No bundle chunks found with compression switch"
|
|
|
|
|
modified = 0
|
|
|
|
|
already = 0
|
|
|
|
|
total = 0
|
|
|
|
|
for path in chunks:
|
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
new_content, n = _patch_compression_in_text(content)
|
|
|
|
|
if new_content == content:
|
|
|
|
|
already += 1
|
|
|
|
|
continue
|
|
|
|
|
backup = path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(path, backup)
|
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.write(new_content)
|
|
|
|
|
modified += 1
|
|
|
|
|
total += n
|
|
|
|
|
if modified == 0 and already == len(chunks):
|
|
|
|
|
return True, f"Already patched (compression, {len(chunks)} chunk(s))"
|
|
|
|
|
if modified == 0:
|
|
|
|
|
return False, "No compression patterns matched in bundled chunks"
|
|
|
|
|
return True, f"Patched {total} compression alias(es) across {modified} bundled chunk(s)"
|
|
|
|
|
|
|
|
|
|
compress_path = os.path.join(gemini_root, CHAT_COMPRESSION_SUBPATH)
|
|
|
|
|
if not os.path.isfile(compress_path):
|
|
|
|
|
return False, f"File not found: {compress_path}"
|
|
|
|
|
@@ -1057,6 +1225,34 @@ def patch_agent_config_dialog(gemini_root, config):
|
|
|
|
|
Target 13: Fix example model name in AgentConfigDialog.js description.
|
|
|
|
|
"""
|
|
|
|
|
flash_model = config.get("internal_flash_model", "gemini-3-flash-preview")
|
|
|
|
|
old_example = "gemini-2.0-flash"
|
|
|
|
|
|
|
|
|
|
if is_bundled_install(gemini_root):
|
|
|
|
|
from gemini.bundle_finder import find_all_chunks_with_anchors
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
chunks = find_all_chunks_with_anchors(bundle_dir, [old_example])
|
|
|
|
|
if not chunks:
|
|
|
|
|
# Maybe already patched — search for replacement
|
|
|
|
|
patched_chunks = find_all_chunks_with_anchors(bundle_dir, [flash_model])
|
|
|
|
|
if patched_chunks:
|
|
|
|
|
return True, f"Already patched (AgentConfigDialog, {len(patched_chunks)} chunk(s))"
|
|
|
|
|
return False, "No bundle chunks found with AgentConfigDialog example"
|
|
|
|
|
modified = 0
|
|
|
|
|
for path in chunks:
|
|
|
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
new_content = content.replace(old_example, flash_model)
|
|
|
|
|
if new_content == content:
|
|
|
|
|
continue
|
|
|
|
|
backup = path + ".backup"
|
|
|
|
|
if not os.path.exists(backup):
|
|
|
|
|
shutil.copy2(path, backup)
|
|
|
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
|
|
|
f.write(new_content)
|
|
|
|
|
modified += 1
|
|
|
|
|
if modified == 0:
|
|
|
|
|
return False, "No AgentConfigDialog patterns matched in bundled chunks"
|
|
|
|
|
return True, f"Patched AgentConfigDialog example in {modified} bundled chunk(s)"
|
|
|
|
|
|
|
|
|
|
dialog_path = os.path.join(gemini_root, AGENT_CONFIG_DIALOG_SUBPATH)
|
|
|
|
|
if not os.path.isfile(dialog_path):
|
|
|
|
|
@@ -1088,6 +1284,7 @@ def patch_agent_config_dialog(gemini_root, config):
|
|
|
|
|
|
|
|
|
|
def rollback(genai_mjs_path, settings_js_path, gemini_root=None):
|
|
|
|
|
"""Restore backup files."""
|
|
|
|
|
import glob as _glob
|
|
|
|
|
restored = 0
|
|
|
|
|
paths = [genai_mjs_path, settings_js_path]
|
|
|
|
|
if gemini_root:
|
|
|
|
|
@@ -1097,11 +1294,16 @@ def rollback(genai_mjs_path, settings_js_path, gemini_root=None):
|
|
|
|
|
paths.append(config_js)
|
|
|
|
|
schema_js = os.path.join(gemini_root, SETTINGS_SCHEMA_SUBPATH)
|
|
|
|
|
paths.append(schema_js)
|
|
|
|
|
# Targets 10-13
|
|
|
|
|
# Targets 10-13 — legacy paths (pre-0.38)
|
|
|
|
|
paths.append(os.path.join(gemini_root, MODELS_JS_SUBPATH))
|
|
|
|
|
paths.append(os.path.join(gemini_root, MODEL_DIALOG_JS_SUBPATH))
|
|
|
|
|
paths.append(os.path.join(gemini_root, CHAT_COMPRESSION_SUBPATH))
|
|
|
|
|
paths.append(os.path.join(gemini_root, AGENT_CONFIG_DIALOG_SUBPATH))
|
|
|
|
|
# Targets 10-13 — bundled paths (0.38+): every bundle/*.backup
|
|
|
|
|
bundle_dir = os.path.join(gemini_root, "bundle")
|
|
|
|
|
if os.path.isdir(bundle_dir):
|
|
|
|
|
for backup in _glob.glob(os.path.join(bundle_dir, "*.backup")):
|
|
|
|
|
paths.append(backup[:-len(".backup")])
|
|
|
|
|
for p in paths:
|
|
|
|
|
backup = p + ".backup"
|
|
|
|
|
if os.path.exists(backup):
|
|
|
|
|
|