release: v1.2.0 — About+update checker, log viewer, restart button, dup-name fix, stale-file hardening #26

Merged
the_og merged 34 commits from release/v1.2.0 into main 2026-07-08 11:34:35 -04:00
Showing only changes of commit 3c65657d2f - Show all commits
+26 -1
View File
@@ -29,6 +29,7 @@ import threading
import time import time
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import NamedTuple
from urllib.parse import urlparse from urllib.parse import urlparse
CONFIG_FILENAME = "claude_desktop_config.json" CONFIG_FILENAME = "claude_desktop_config.json"
@@ -380,6 +381,30 @@ def config_mtime(path: Path | str) -> float | None:
return None return None
class ConfigStat(NamedTuple):
"""A snapshot of a config file's mtime + size.
Pairing size with mtime hardens stale-file detection beyond bare mtime
equality: a concurrent external write can land within the filesystem's
mtime resolution (e.g. same-second writes on ext4/HFS+) or have its mtime
restored by the writing process, in which case mtime alone would miss the
change. Comparing both fields catches those cases without the cost of a
full content hash.
"""
mtime: float
size: int
def config_fingerprint(path: Path | str) -> ConfigStat | None:
"""Return the file's (mtime, size) snapshot, or None if it does not exist."""
try:
st = Path(path).stat()
except OSError:
return None
return ConfigStat(st.st_mtime, st.st_size)
def external_change_summary(original_cfg: dict, path: Path | str) -> tuple[list[str], str]: def external_change_summary(original_cfg: dict, path: Path | str) -> tuple[list[str], str]:
""" """
Compare original_cfg (what BCC loaded) with the current on-disk state. Compare original_cfg (what BCC loaded) with the current on-disk state.
@@ -474,7 +499,7 @@ def _normalize_unicode(text: str, notes: list[str]) -> str:
out = text out = text
for junk in _JUNK_CHARS: for junk in _JUNK_CHARS:
out = out.replace(junk, "") out = out.replace(junk, "")
out = out.replace(" ", " ") # non-breaking space out = out.replace(" ", " ") # non-breaking space
for smart, ascii_q in _QUOTE_MAP.items(): for smart, ascii_q in _QUOTE_MAP.items():
out = out.replace(smart, ascii_q) out = out.replace(smart, ascii_q)
if out != text: if out != text: