Merge pull request #1104 from arnoldwender/fix/encoding-non-ascii-sweep
fix(encoding): replace non-ASCII symbols in CLI output (#1034)
This commit is contained in:
commit
b4345e84a7
|
|
@ -166,7 +166,7 @@ def _run_pass_zero(project_dir, palace_dir, llm_provider) -> dict:
|
|||
|
||||
samples = _gather_origin_samples(project_dir)
|
||||
if not samples:
|
||||
print(" Skipping corpus-origin detection — no readable samples.")
|
||||
print(" Skipping corpus-origin detection -- no readable samples.")
|
||||
return None
|
||||
|
||||
# Tier 1 — always runs. Cheap regex grep, no API.
|
||||
|
|
@ -431,7 +431,7 @@ def cmd_init(args):
|
|||
registry_path = add_to_known_entities(confirmed, wing=wing)
|
||||
print(f" Registry updated: {registry_path}")
|
||||
else:
|
||||
print(" No entities detected — proceeding with directory-based rooms.")
|
||||
print(" No entities detected -- proceeding with directory-based rooms.")
|
||||
|
||||
# Pass 2: detect rooms from folder structure
|
||||
detect_rooms_local(project_dir=args.dir, yes=getattr(args, "yes", False))
|
||||
|
|
@ -878,7 +878,7 @@ def cmd_sync(args):
|
|||
project_dirs = project_dirs or None
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Sync — Gitignore-aware drawer prune")
|
||||
print(" MemPalace Sync -- Gitignore-aware drawer prune")
|
||||
print(f"{'=' * 55}")
|
||||
print(f" Palace: {palace_path}")
|
||||
if args.wing:
|
||||
|
|
@ -1183,7 +1183,7 @@ def cmd_hallways(args):
|
|||
config=MempalaceConfig(palace_path=palace_path),
|
||||
)
|
||||
if not rows:
|
||||
print("No hallways yet — they are built from drawer entities when you mine.")
|
||||
print("No hallways yet -- they are built from drawer entities when you mine.")
|
||||
return
|
||||
rows.sort(key=lambda h: h.get("co_occurrence_count", 0), reverse=True)
|
||||
print(f" {len(rows)} hallway(s):")
|
||||
|
|
@ -1651,7 +1651,7 @@ def cmd_repair(args):
|
|||
# withholds success until FTS5 rebuild, VACUUM, and quick_check are
|
||||
# clean. Its exception already includes the retained destination
|
||||
# and archive/source recovery paths.
|
||||
print("\n Rebuild cleanup failed — see recovery details above.")
|
||||
print("\n Rebuild cleanup failed -- see recovery details above.")
|
||||
sys.exit(1)
|
||||
# An empty counts dict is rebuild_from_sqlite's documented signal
|
||||
# for a validation refusal (missing source, existing dest,
|
||||
|
|
@ -1985,12 +1985,12 @@ def cmd_serve(args):
|
|||
print(f" palace : {palace_path}")
|
||||
print(f" backend : {(backend or 'default').strip().lower() if backend else 'default'}")
|
||||
print(f" bind : {host}:{port} ({'loopback' if loopback else 'network-exposed'})")
|
||||
print(f" tls : {'on' if tls_cert else 'off (plaintext — terminate TLS at a proxy)'}")
|
||||
print(f" tls : {'on' if tls_cert else 'off (plaintext -- terminate TLS at a proxy)'}")
|
||||
print(f" read-only: {'yes' if args.read_only else 'no'}")
|
||||
if token_created:
|
||||
print("\n A new bearer token was generated and stored 0600 at:")
|
||||
print(f" {_server_token_path(palace_path)}")
|
||||
print(" Store it securely — clients need it to connect:")
|
||||
print(" Store it securely -- clients need it to connect:")
|
||||
print(f" {token}")
|
||||
print("\nConnect a client:")
|
||||
if token:
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ def _mine_convos_impl(
|
|||
files = scan_convos(convo_dir)
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Mine — Conversations")
|
||||
print(" MemPalace Mine -- Conversations")
|
||||
print(f"{'=' * 55}")
|
||||
print(f" Wing: {wing}")
|
||||
print(f" Source: {convo_path}")
|
||||
|
|
@ -897,7 +897,7 @@ def _mine_convos_impl(
|
|||
print(f" Files: {len(files)}{limit_suffix}")
|
||||
print(f" Palace: {palace_path}")
|
||||
if dry_run:
|
||||
print(" DRY RUN — nothing will be filed")
|
||||
print(" DRY RUN -- nothing will be filed")
|
||||
print(f"{'-' * 55}\n")
|
||||
|
||||
collection = _open_convo_collection(
|
||||
|
|
@ -1018,9 +1018,9 @@ def _mine_convos_impl(
|
|||
|
||||
type_counts = Counter(c.get("memory_type", "general") for c in chunks)
|
||||
types_str = ", ".join(f"{t}:{n}" for t, n in type_counts.most_common())
|
||||
print(f" [DRY RUN] {filepath.name} → {len(chunks)} memories ({types_str})")
|
||||
print(f" [DRY RUN] {filepath.name} -> {len(chunks)} memories ({types_str})")
|
||||
else:
|
||||
print(f" [DRY RUN] {filepath.name} → room:{room} ({len(chunks)} drawers)")
|
||||
print(f" [DRY RUN] {filepath.name} -> room:{room} ({len(chunks)} drawers)")
|
||||
total_drawers += len(chunks)
|
||||
# Track room counts
|
||||
if extract_mode == "general":
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ def dedup_palace(
|
|||
print(f" Drawers: {col.count():,}")
|
||||
print(f" Threshold: {threshold}")
|
||||
print(f" Mode: {'DRY RUN' if dry_run else 'LIVE'}")
|
||||
print(f"{'─' * 55}")
|
||||
print(f"{'-' * 55}")
|
||||
|
||||
if wing:
|
||||
print(f" Wing: {wing}")
|
||||
|
|
@ -227,7 +227,7 @@ def dedup_palace(
|
|||
|
||||
elapsed = time.time() - t0
|
||||
|
||||
print(f"\n{'─' * 55}")
|
||||
print(f"\n{'-' * 55}")
|
||||
print(f" Done in {elapsed:.1f}s")
|
||||
print(
|
||||
f" Drawers: {total_kept + total_deleted:,} → {total_kept:,} (-{total_deleted:,} removed)"
|
||||
|
|
|
|||
|
|
@ -1063,7 +1063,7 @@ if __name__ == "__main__":
|
|||
print("=== COMPRESSION STATS ===")
|
||||
print(f"JSON: ~{stats['original_tokens_est']:,} tokens (est)")
|
||||
print(f"AAAK: ~{stats['summary_tokens_est']:,} tokens (est)")
|
||||
print(f"Ratio: {stats['size_ratio']}x (lossy — information is lost)")
|
||||
print(f"Ratio: {stats['size_ratio']}x (lossy -- information is lost)")
|
||||
print()
|
||||
print("=== AAAK DIALECT OUTPUT ===")
|
||||
print(encoded)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def _resolve_providers(device: str) -> tuple[list, str]:
|
|||
requested = _PROVIDER_MAP.get(device)
|
||||
if requested is None:
|
||||
if device not in _WARNED:
|
||||
logger.warning("Unknown embedding_device %r — falling back to cpu", device)
|
||||
logger.warning("Unknown embedding_device %r -- falling back to cpu", device)
|
||||
_WARNED.add(device)
|
||||
return (["CPUExecutionProvider"], "cpu")
|
||||
|
||||
|
|
|
|||
|
|
@ -748,7 +748,7 @@ def _print_entity_list(entities: list, label: str):
|
|||
print(" (none detected)")
|
||||
return
|
||||
for i, e in enumerate(entities):
|
||||
confidence_bar = "●" * int(e["confidence"] * 5) + "○" * (5 - int(e["confidence"] * 5))
|
||||
confidence_bar = "#" * int(e["confidence"] * 5) + "." * (5 - int(e["confidence"] * 5))
|
||||
signals_str = ", ".join(e["signals"][:2]) if e["signals"] else ""
|
||||
print(f" {i + 1:2}. {e['name']:20} [{confidence_bar}] {signals_str}")
|
||||
|
||||
|
|
@ -768,7 +768,7 @@ def confirm_entities(detected: dict, yes: bool = False) -> dict:
|
|||
Pass yes=True to auto-accept all detected entities without prompting.
|
||||
"""
|
||||
print(f"\n{'=' * 58}")
|
||||
print(" MemPalace — Entity Detection")
|
||||
print(" MemPalace -- Entity Detection")
|
||||
print(f"{'=' * 58}")
|
||||
print("\n Scanned your files. Here's what we found:\n")
|
||||
|
||||
|
|
@ -798,7 +798,7 @@ def confirm_entities(detected: dict, yes: bool = False) -> dict:
|
|||
"topics": confirmed_topics,
|
||||
}
|
||||
|
||||
print(f"\n{'─' * 58}")
|
||||
print(f"\n{'-' * 58}")
|
||||
print(" Options:")
|
||||
print(" [enter] Accept all")
|
||||
print(" [edit] Remove wrong entries or reclassify uncertain")
|
||||
|
|
@ -813,9 +813,9 @@ def confirm_entities(detected: dict, yes: bool = False) -> dict:
|
|||
if choice == "edit":
|
||||
# Handle uncertain first
|
||||
if detected["uncertain"]:
|
||||
print("\n Uncertain entities — classify each:")
|
||||
print("\n Uncertain entities -- classify each:")
|
||||
for e in detected["uncertain"]:
|
||||
ans = input(f" {e['name']} — (p)erson, (r)project, or (s)kip? ").strip().lower()
|
||||
ans = input(f" {e['name']} -- (p)erson, (r)project, or (s)kip? ").strip().lower()
|
||||
if ans == "p":
|
||||
confirmed_people.append(e["name"])
|
||||
elif ans == "r":
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ def export_palace(palace_path: str, output_dir: str, format: str = "markdown") -
|
|||
total = col.count()
|
||||
|
||||
if total == 0:
|
||||
print(" Palace is empty — nothing to export.")
|
||||
print(" Palace is empty -- nothing to export.")
|
||||
return {"wings": 0, "rooms": 0, "drawers": 0}
|
||||
|
||||
_reject_symlink(output_dir, "output_dir")
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ def extract_text(
|
|||
logger.info("skip:unreadable (file gone after scan) %s", p)
|
||||
return None, ExtractionStatus.SKIP_UNREADABLE
|
||||
except OSError as exc:
|
||||
logger.info("skip:unreadable %s — %s", p, exc)
|
||||
logger.info("skip:unreadable %s -- %s", p, exc)
|
||||
return None, ExtractionStatus.SKIP_UNREADABLE
|
||||
|
||||
# Fringe Case 5 — empty file. Skip silently.
|
||||
|
|
@ -433,9 +433,9 @@ def extract_text(
|
|||
# Fringe Case 4 vs Case 10: encrypted vs generic crash, by message.
|
||||
msg = str(exc)
|
||||
if _ENCRYPTED_PATTERNS.search(msg):
|
||||
logger.info("skip:encrypted %s — %s", p, msg[:120])
|
||||
logger.info("skip:encrypted %s -- %s", p, msg[:120])
|
||||
return None, ExtractionStatus.SKIP_ENCRYPTED
|
||||
logger.warning("skip:extraction_error %s — %s: %s", p, type(exc).__name__, msg[:200])
|
||||
logger.warning("skip:extraction_error %s -- %s: %s", p, type(exc).__name__, msg[:200])
|
||||
return None, ExtractionStatus.SKIP_EXTRACTION_ERROR
|
||||
|
||||
# Either transformer can legitimately return None / empty (malformed
|
||||
|
|
@ -443,7 +443,7 @@ def extract_text(
|
|||
# so the caller knows to skip rather than file an empty drawer.
|
||||
if not text:
|
||||
transformer = "striprtf" if is_rtf else "markitdown"
|
||||
logger.info("skip:extraction_error %s — %s returned None/empty", p, transformer)
|
||||
logger.info("skip:extraction_error %s -- %s returned None/empty", p, transformer)
|
||||
return None, ExtractionStatus.SKIP_EXTRACTION_ERROR
|
||||
|
||||
return text, ExtractionStatus.OK
|
||||
|
|
@ -803,7 +803,7 @@ def mine_formats(
|
|||
files = scan_formats(format_path)
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Mine — Format extraction")
|
||||
print(" MemPalace Mine -- Format extraction")
|
||||
print(f"{'=' * 55}")
|
||||
print(f" Wing: {wing}")
|
||||
print(f" Source: {format_path}")
|
||||
|
|
@ -811,7 +811,7 @@ def mine_formats(
|
|||
print(f" Files: {len(files)}{limit_suffix}")
|
||||
print(f" Palace: {palace_path}")
|
||||
if dry_run:
|
||||
print(" DRY RUN — nothing will be filed")
|
||||
print(" DRY RUN -- nothing will be filed")
|
||||
print(f"{'-' * 55}\n")
|
||||
|
||||
collection = get_collection(palace_path) if not dry_run else None
|
||||
|
|
@ -876,7 +876,7 @@ def mine_formats(
|
|||
files_with_text += 1
|
||||
|
||||
if dry_run:
|
||||
print(f" [DRY RUN] {filepath.name} → {len(chunks)} drawers")
|
||||
print(f" [DRY RUN] {filepath.name} -> {len(chunks)} drawers")
|
||||
total_drawers += len(chunks)
|
||||
files_mined += 1
|
||||
if limit > 0 and files_mined >= limit:
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ if __name__ == "__main__":
|
|||
import json
|
||||
|
||||
def usage():
|
||||
print("layers.py — 4-Layer Memory Stack")
|
||||
print("layers.py -- 4-Layer Memory Stack")
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" python layers.py wake-up Show L0 + L1")
|
||||
|
|
|
|||
|
|
@ -2950,7 +2950,7 @@ def tool_add_drawer(
|
|||
"The palace index may be stale; run reconnect or repair."
|
||||
)
|
||||
_metadata_cache = None
|
||||
logger.info(f"Filed drawer: {drawer_id} → {wing}/{room}")
|
||||
logger.info(f"Filed drawer: {drawer_id} -> {wing}/{room}")
|
||||
return {
|
||||
"success": True,
|
||||
"drawer_id": drawer_id,
|
||||
|
|
@ -2985,7 +2985,7 @@ def tool_add_drawer(
|
|||
"The palace index may be stale; run reconnect or repair."
|
||||
)
|
||||
_metadata_cache = None
|
||||
logger.info(f"Filed drawer: {drawer_id} → {wing}/{room} ({len(chunk_ids)} chunks)")
|
||||
logger.info(f"Filed drawer: {drawer_id} -> {wing}/{room} ({len(chunk_ids)} chunks)")
|
||||
return {
|
||||
"success": True,
|
||||
"drawer_id": drawer_id,
|
||||
|
|
@ -3883,7 +3883,7 @@ def tool_diary_write(agent_name: str, entry: str, topic: str = "general", wing:
|
|||
documents=[entry],
|
||||
metadatas=[{**base_metadata, "chunk_index": 0}],
|
||||
)
|
||||
logger.info(f"Diary entry: {entry_id} → {wing}/diary/{topic}")
|
||||
logger.info(f"Diary entry: {entry_id} -> {wing}/diary/{topic}")
|
||||
return {
|
||||
"success": True,
|
||||
"entry_id": entry_id,
|
||||
|
|
@ -3931,7 +3931,7 @@ def tool_diary_write(agent_name: str, entry: str, topic: str = "general", wing:
|
|||
}
|
||||
)
|
||||
col.add(ids=chunk_ids, documents=chunk_docs, metadatas=chunk_metas)
|
||||
logger.info(f"Diary entry: {entry_id} → {wing}/diary/{topic} ({len(chunk_ids)} chunks)")
|
||||
logger.info(f"Diary entry: {entry_id} -> {wing}/diary/{topic} ({len(chunk_ids)} chunks)")
|
||||
return {
|
||||
"success": True,
|
||||
"entry_id": entry_id,
|
||||
|
|
@ -7294,10 +7294,10 @@ def _run_stdio_loop() -> None:
|
|||
# clean EOF — same meaning: the client is gone. Never loop on
|
||||
# it: an orphaned stdio server holding the mine_palace flock
|
||||
# blocked all palace writes for hours (2026-07-10 outage).
|
||||
logger.info("stdin read failed (%s) — client disconnected, shutting down", exc)
|
||||
logger.info("stdin read failed (%s) -- client disconnected, shutting down", exc)
|
||||
break
|
||||
if not line:
|
||||
logger.info("stdin EOF — client disconnected, shutting down")
|
||||
logger.info("stdin EOF -- client disconnected, shutting down")
|
||||
break
|
||||
|
||||
line = line.strip()
|
||||
|
|
@ -7327,7 +7327,7 @@ def _run_stdio_loop() -> None:
|
|||
# The client's read end is gone; every future response write
|
||||
# would fail the same way, so treat it like stdin EOF and
|
||||
# shut down instead of swallowing it in the generic handler.
|
||||
logger.info("stdout write failed (%s) — client disconnected, shutting down", exc)
|
||||
logger.info("stdout write failed (%s) -- client disconnected, shutting down", exc)
|
||||
_drop_broken_stdout()
|
||||
break
|
||||
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ def migrate(palace_path: str, dry_run: bool = False, confirm: bool = False):
|
|||
print(f" ROOM: {room:30} {count:5}")
|
||||
|
||||
if dry_run:
|
||||
print("\n DRY RUN — no changes made.")
|
||||
print("\n DRY RUN -- no changes made.")
|
||||
print(f" Would migrate {len(drawers)} drawers.")
|
||||
return True
|
||||
|
||||
|
|
@ -570,7 +570,7 @@ def migrate_wing_names(palace_path: str, dry_run: bool = False, confirm: bool =
|
|||
topic_renames = _plan_topics_by_wing_renames()
|
||||
|
||||
if not d_updates and not c_updates and not topic_renames:
|
||||
print(" All wing names are already normalized — nothing to migrate.")
|
||||
print(" All wing names are already normalized -- nothing to migrate.")
|
||||
return False
|
||||
|
||||
print("\n Wing-name migration plan:")
|
||||
|
|
@ -586,7 +586,7 @@ def migrate_wing_names(palace_path: str, dry_run: bool = False, confirm: bool =
|
|||
print(f" topics_by_wing: {len(topic_renames)} key(s) re-keyed")
|
||||
|
||||
if dry_run:
|
||||
print("\n DRY RUN — no changes made.\n")
|
||||
print("\n DRY RUN -- no changes made.\n")
|
||||
return True
|
||||
|
||||
if not confirm:
|
||||
|
|
|
|||
|
|
@ -1843,7 +1843,7 @@ def _mine_impl(
|
|||
print(f" Palace: {palace_path}")
|
||||
print(f" Device: {describe_device()}")
|
||||
if dry_run:
|
||||
print(" DRY RUN — nothing will be filed")
|
||||
print(" DRY RUN -- nothing will be filed")
|
||||
if not respect_gitignore:
|
||||
print(" .gitignore: DISABLED")
|
||||
if include_ignored:
|
||||
|
|
@ -2183,7 +2183,7 @@ def status(palace_path: str):
|
|||
def _print_status(total: int, wing_rooms: dict[str, dict[str, int]]) -> None:
|
||||
"""Render the wing/room histogram shared by both status code paths."""
|
||||
print(f"\n{'=' * 55}")
|
||||
print(f" MemPalace Status — {total} drawers")
|
||||
print(f" MemPalace Status -- {total} drawers")
|
||||
print(f"{'=' * 55}\n")
|
||||
for wing, rooms in sorted(wing_rooms.items()):
|
||||
print(f" WING: {wing}")
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ DEFAULT_WINGS = {
|
|||
|
||||
|
||||
def _hr():
|
||||
print(f"\n{'─' * 58}")
|
||||
print(f"\n{'-' * 58}")
|
||||
|
||||
|
||||
def _header(text):
|
||||
|
|
@ -121,9 +121,9 @@ def _ask_mode() -> str:
|
|||
""")
|
||||
print(" How are you using MemPalace?")
|
||||
print()
|
||||
print(" [1] Work — notes, projects, clients, colleagues, decisions")
|
||||
print(" [2] Personal — diary, family, health, relationships, reflections")
|
||||
print(" [3] Both — personal and professional mixed")
|
||||
print(" [1] Work -- notes, projects, clients, colleagues, decisions")
|
||||
print(" [2] Personal -- diary, family, health, relationships, reflections")
|
||||
print(" [3] Both -- personal and professional mixed")
|
||||
print()
|
||||
|
||||
while True:
|
||||
|
|
@ -430,7 +430,7 @@ def run_onboarding(
|
|||
print()
|
||||
if _yn(" Add any of these to your registry?"):
|
||||
for e in detected:
|
||||
ans = input(f" {e['name']} — (p)erson, (s)kip? ").strip().lower()
|
||||
ans = input(f" {e['name']} -- (p)erson, (s)kip? ").strip().lower()
|
||||
if ans == "p":
|
||||
rel = input(f" Relationship/role for {e['name']}? ").strip()
|
||||
ctx = (
|
||||
|
|
@ -439,7 +439,7 @@ def run_onboarding(
|
|||
else (
|
||||
"work"
|
||||
if mode == "work"
|
||||
else input(" Context — (p)ersonal or (w)ork? ")
|
||||
else input(" Context -- (p)ersonal or (w)ork? ")
|
||||
.strip()
|
||||
.lower()
|
||||
.replace("w", "work")
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ def prune_corrupt(palace_path=None, confirm=False, collection_name: Optional[str
|
|||
bad_file = os.path.join(palace_path, "corrupt_ids.txt")
|
||||
|
||||
if not os.path.exists(bad_file):
|
||||
print(" No corrupt_ids.txt found — run scan first.")
|
||||
print(" No corrupt_ids.txt found -- run scan first.")
|
||||
return
|
||||
|
||||
with open(bad_file) as f:
|
||||
|
|
@ -539,7 +539,7 @@ def prune_corrupt(palace_path=None, confirm=False, collection_name: Optional[str
|
|||
print(f" {len(bad_ids):,} corrupt IDs queued for deletion")
|
||||
|
||||
if not confirm:
|
||||
print("\n DRY RUN — no deletions performed.")
|
||||
print("\n DRY RUN -- no deletions performed.")
|
||||
print(" Re-run with --confirm to actually delete.")
|
||||
return
|
||||
|
||||
|
|
@ -577,7 +577,7 @@ def prune_corrupt(palace_path=None, confirm=False, collection_name: Optional[str
|
|||
after = col.count()
|
||||
print(f"\n Deleted: {deleted:,}")
|
||||
print(f" Failed: {failed:,}")
|
||||
print(f" Collection size: {before:,} → {after:,}")
|
||||
print(f" Collection size: {before:,} -> {after:,}")
|
||||
|
||||
|
||||
# ChromaDB's ``collection.get()`` enforces an internal default ``limit``
|
||||
|
|
@ -1130,7 +1130,7 @@ def rebuild_index(
|
|||
return
|
||||
|
||||
progress(f"\n{'=' * 55}")
|
||||
progress(" MemPalace Repair — Index Rebuild")
|
||||
progress(" MemPalace Repair -- Index Rebuild")
|
||||
progress(f"{'=' * 55}\n")
|
||||
progress(f" Palace: {palace_path}")
|
||||
|
||||
|
|
@ -1670,7 +1670,7 @@ def rebuild_from_sqlite(
|
|||
in_place = source_palace == dest_palace
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Repair — Rebuild from SQLite")
|
||||
print(" MemPalace Repair -- Rebuild from SQLite")
|
||||
print(f"{'=' * 55}\n")
|
||||
print(f" Source: {source_palace}")
|
||||
print(f" Dest: {dest_palace}")
|
||||
|
|
@ -1765,7 +1765,7 @@ def _preview_rebuild_from_sqlite(
|
|||
Never archives, locks, or writes. Returns ``{}`` if SQLite counts are
|
||||
unreadable so a broken preview cannot look like a successful zero-row plan.
|
||||
"""
|
||||
print("\n DRY RUN — no changes will be made.")
|
||||
print("\n DRY RUN -- no changes will be made.")
|
||||
if in_place:
|
||||
print(
|
||||
f" Would archive {dest_palace} → "
|
||||
|
|
@ -1811,7 +1811,7 @@ def _preview_legacy_repair(
|
|||
Returns ``{}`` when the count is unreadable so a broken preview cannot look
|
||||
like a valid plan (#1654, #2095, #2133).
|
||||
"""
|
||||
print("\n DRY RUN — no changes will be made.")
|
||||
print("\n DRY RUN -- no changes will be made.")
|
||||
n = sqlite_drawer_count(palace_path, collection_name)
|
||||
if n is None:
|
||||
_print_unreadable_count_refusal(collection_name=collection_name, palace_path=palace_path)
|
||||
|
|
@ -1846,8 +1846,8 @@ def _preview_legacy_repair(
|
|||
f" returns fewer than {n} (#1208 truncation guard). It would then, in order:"
|
||||
)
|
||||
if os.path.exists(backup_path):
|
||||
print(f" 1. DELETE the existing backup at {backup_path} — or refuse outright")
|
||||
print(" if it is not a palace — and copy the live palace in its place")
|
||||
print(f" 1. DELETE the existing backup at {backup_path} -- or refuse outright")
|
||||
print(" if it is not a palace -- and copy the live palace in its place")
|
||||
else:
|
||||
print(f" 1. copy the palace directory to {backup_path}")
|
||||
print(f" 2. DELETE the live '{collection_name}' collection and re-file the extracted rows")
|
||||
|
|
@ -1919,7 +1919,7 @@ def _rebuild_from_sqlite_locked(
|
|||
if in_place:
|
||||
ts = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
archive_path = f"{dest_palace}.pre-rebuild-{ts}"
|
||||
print(f" Archiving {dest_palace} → {archive_path}")
|
||||
print(f" Archiving {dest_palace} -> {archive_path}")
|
||||
# os.rename, NOT shutil.move. When any file inside the palace is
|
||||
# held open by another process (MCP server, a running mine, another
|
||||
# harness), renaming the directory fails atomically UP FRONT on
|
||||
|
|
@ -2048,7 +2048,7 @@ def status(palace_path=None, collection_name: Optional[str] = None) -> dict:
|
|||
palace_path = palace_path or _get_palace_path()
|
||||
collection_name = collection_name or _drawers_collection_name()
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Repair — Status")
|
||||
print(" MemPalace Repair -- Status")
|
||||
print(f"{'=' * 55}\n")
|
||||
print(f" Palace: {palace_path}")
|
||||
|
||||
|
|
@ -2265,7 +2265,7 @@ def repair_max_seq_id(
|
|||
}
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Repair — max_seq_id Un-poison")
|
||||
print(" MemPalace Repair -- max_seq_id Un-poison")
|
||||
print(f"{'=' * 55}\n")
|
||||
print(f" Palace: {palace_path}")
|
||||
if segment:
|
||||
|
|
@ -2316,10 +2316,10 @@ def repair_max_seq_id(
|
|||
source = "sidecar" if from_sidecar else "heuristic (collection MAX)"
|
||||
print(f" clean-value source {source}")
|
||||
for seg_id, old_val, new_val in plan:
|
||||
print(f" {seg_id} {old_val} → {new_val}")
|
||||
print(f" {seg_id} {old_val} -> {new_val}")
|
||||
|
||||
if dry_run:
|
||||
print("\n DRY RUN — no rows modified.\n" + "=" * 55 + "\n")
|
||||
print("\n DRY RUN -- no rows modified.\n" + "=" * 55 + "\n")
|
||||
return result
|
||||
|
||||
if not plan:
|
||||
|
|
|
|||
|
|
@ -232,14 +232,14 @@ def detect_rooms_from_files(project_dir: str) -> list:
|
|||
|
||||
def print_proposed_structure(project_name: str, rooms: list, total_files: int, source: str):
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Init — Local setup")
|
||||
print(" MemPalace Init -- Local setup")
|
||||
print(f"{'=' * 55}")
|
||||
print(f"\n WING: {project_name}")
|
||||
print(f" ({total_files} files found, rooms detected from {source})\n")
|
||||
for room in rooms:
|
||||
print(f" ROOM: {room['name']}")
|
||||
print(f" {room['description']}")
|
||||
print(f"\n{'─' * 55}")
|
||||
print(f"\n{'-' * 55}")
|
||||
|
||||
|
||||
def get_user_approval(rooms: list) -> list:
|
||||
|
|
@ -259,7 +259,7 @@ def get_user_approval(rooms: list) -> list:
|
|||
if choice == "edit":
|
||||
print("\n Current rooms:")
|
||||
for i, room in enumerate(rooms):
|
||||
print(f" {i + 1}. {room['name']} — {room['description']}")
|
||||
print(f" {i + 1}. {room['name']} -- {room['description']}")
|
||||
remove = input("\n Room numbers to REMOVE (comma-separated, or enter to skip): ").strip()
|
||||
if remove:
|
||||
to_remove = {int(x.strip()) - 1 for x in remove.split(",") if x.strip().isdigit()}
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ def _print_search_results_bm25_only(
|
|||
for line in (hit.get("text", "") or "").strip().split("\n"):
|
||||
print(f" {line}")
|
||||
print()
|
||||
print(f" {'─' * 56}")
|
||||
print(f" {'-' * 56}")
|
||||
|
||||
print()
|
||||
|
||||
|
|
@ -692,7 +692,7 @@ def search(query: str, palace_path: str, wing: str = None, room: str = None, n_r
|
|||
for line in hit["text"].strip().split("\n"):
|
||||
print(f" {line}")
|
||||
print()
|
||||
print(f" {'─' * 56}")
|
||||
print(f" {'-' * 56}")
|
||||
|
||||
print()
|
||||
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ def run_sync(payload: dict[str, Any]) -> dict[str, Any]:
|
|||
dry_run = bool(payload.get("dry_run", True))
|
||||
|
||||
print(f"\n{'=' * 55}")
|
||||
print(" MemPalace Sync — Gitignore-aware drawer prune")
|
||||
print(" MemPalace Sync -- Gitignore-aware drawer prune")
|
||||
print(f"{'=' * 55}")
|
||||
print(f" Palace: {palace_path}")
|
||||
if payload.get("wing"):
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ def main():
|
|||
return
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f" Mega-file splitter — {'DRY RUN' if args.dry_run else 'SPLITTING'}")
|
||||
print(f" Mega-file splitter -- {'DRY RUN' if args.dry_run else 'SPLITTING'}")
|
||||
print(f"{'=' * 60}")
|
||||
print(f" Source: {src_dir}")
|
||||
print(f" Output: {output_dir or 'same dir as source'}")
|
||||
|
|
@ -307,9 +307,9 @@ def main():
|
|||
|
||||
print(f"{'-' * 60}")
|
||||
if args.dry_run:
|
||||
print(f" DRY RUN — would create {total_written} files from {len(mega_files)} mega-files")
|
||||
print(f" DRY RUN -- would create {total_written} files from {len(mega_files)} mega-files")
|
||||
else:
|
||||
print(f" Done — created {total_written} files from {len(mega_files)} mega-files")
|
||||
print(f" Done -- created {total_written} files from {len(mega_files)} mega-files")
|
||||
print()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1246,7 +1246,7 @@ def test_cmd_repair_default_mode_dry_run_writes_nothing(mock_config_cls, tmp_pat
|
|||
cmd_repair(args)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
assert "DRY RUN — no changes will be made." in out
|
||||
assert "DRY RUN -- no changes will be made." in out
|
||||
assert "holds 2 rows" in out
|
||||
assert "Repair complete" not in out
|
||||
# The count comes from read-only SQLite, never from a chromadb client:
|
||||
|
|
|
|||
|
|
@ -1093,7 +1093,7 @@ def test_status_does_not_cold_load_vector_index(palace_path, seeded_collection,
|
|||
|
||||
sentinel.assert_not_called()
|
||||
out = capsys.readouterr().out
|
||||
assert "MemPalace Status — 4 drawers" in out
|
||||
assert "MemPalace Status -- 4 drawers" in out
|
||||
assert "WING: project" in out
|
||||
assert "WING: notes" in out
|
||||
|
||||
|
|
@ -1128,7 +1128,7 @@ def test_status_falls_back_to_chroma_when_sqlite_unreadable(palace_path, seeded_
|
|||
status(palace_path)
|
||||
|
||||
out = capsys.readouterr().out
|
||||
assert "MemPalace Status — 4 drawers" in out
|
||||
assert "MemPalace Status -- 4 drawers" in out
|
||||
assert "WING: project" in out
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ def test_generate_aaak_bootstrap_no_relationship(tmp_path):
|
|||
def test_hr_prints_line(capsys):
|
||||
_hr()
|
||||
out = capsys.readouterr().out
|
||||
assert "─" in out
|
||||
assert "-" in out
|
||||
|
||||
|
||||
def test_header_prints_banner(capsys):
|
||||
|
|
|
|||
|
|
@ -2481,7 +2481,7 @@ def test_cmd_repair_dry_run_leaves_a_real_palace_byte_identical(tmp_path, capsys
|
|||
out = capsys.readouterr().out
|
||||
assert snapshot() == before
|
||||
assert not (tmp_path / "palace.backup").exists()
|
||||
assert "DRY RUN — no changes will be made." in out
|
||||
assert "DRY RUN -- no changes will be made." in out
|
||||
assert "holds 4 rows" in out
|
||||
assert "Repair complete" not in out
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue