diff --git a/paperforge/commands/sync.py b/paperforge/commands/sync.py index 6d22cdf9..3f3122c1 100644 --- a/paperforge/commands/sync.py +++ b/paperforge/commands/sync.py @@ -64,17 +64,46 @@ def run(args: argparse.Namespace) -> int: result = svc.run(verbose=verbose, json_output=json_output, selection_only=selection_only, index_only=index_only, prune=prune_flag, prune_force=prune_force) - # Auto-build memory DB after successful sync so search works immediately - if result.ok and not dry_run: - try: - from paperforge.memory.builder import build_from_index - counts = build_from_index(vault) - logger.info("Memory DB built: %s papers indexed", counts.get("papers_indexed", 0)) - except Exception as e: - logger.warning("Memory DB build skipped: %s", e) - if json_output: print(result.to_json()) + if result.ok and not dry_run: + try: + from paperforge.memory.builder import build_from_index + build_from_index(vault) + except Exception: + pass + try: + import subprocess, sys + subprocess.Popen( + [sys.executable, "-m", "paperforge", "embed", "build", "--resume"], + cwd=str(vault), + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0, + ) + except Exception: + pass return 0 - return 0 if result.ok else 1 + if not result.ok: + return 1 + + # best-effort: rebuild memory DB for immediate search + try: + from paperforge.memory.builder import build_from_index + counts = build_from_index(vault) + print(f"memory: {counts.get('papers_indexed', 0)} papers indexed") + except Exception as e: + print(f"memory: deferred ({e})") + + # best-effort: trigger vector resume in background + try: + import subprocess, sys + subprocess.Popen( + [sys.executable, "-m", "paperforge", "embed", "build", "--resume"], + cwd=str(vault), + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if sys.platform == "win32" else 0, + ) + print("vector: resume started in background") + except Exception as e: + print(f"vector: deferred ({e})") + + return 0 diff --git a/paperforge/services/sync_service.py b/paperforge/services/sync_service.py index bb026c49..54797a17 100644 --- a/paperforge/services/sync_service.py +++ b/paperforge/services/sync_service.py @@ -248,7 +248,6 @@ class SyncService: index_count = 0 orphaned = 0 flat_cleaned = 0 - memory_rebuild_error: Exception | None = None if not selection_only: from paperforge.worker._domain import load_domain_config @@ -283,15 +282,14 @@ class SyncService: if orphaned > 0 or flat_cleaned > 0: index_count = asset_index.build_index(self.vault, verbose) + # ├─ best-effort: rebuild memory DB (does not affect sync result) try: from paperforge.memory.builder import build_from_index from paperforge.memory.db import get_memory_db_path - if get_memory_db_path(self.vault).exists(): build_from_index(self.vault) except Exception as exc: - memory_rebuild_error = exc - logger.error("Failed to rebuild memory DB after sync: %s", exc) + logger.warning("memory rebuild deferred: %s", exc) # ── Phase 4: Prune orphans ── prune_result = None @@ -319,10 +317,7 @@ class SyncService: total = sum(1 for _ in paths["literature"].rglob("*.md")) if paths["literature"].exists() else 0 print(f"index-refresh: {total} formal note(s) in literature") - all_errors = list(selection_result.get("errors", [])) - if memory_rebuild_error is not None: - all_errors.append(f"memory rebuild failed: {memory_rebuild_error}") - is_ok = selection_result.get("failed", 0) == 0 and len(all_errors) == 0 + is_ok = selection_result.get("failed", 0) == 0 and not selection_result.get("errors") result = PFResult( ok=is_ok, @@ -338,18 +333,6 @@ class SyncService: if _export_code != "ok": result.warnings.append(f"BBT exports: {_export_code}") - if memory_rebuild_error is not None: - result.error = PFError( - code=ErrorCode.SYNC_FAILED, - message=f"Sync completed but memory rebuild failed: {memory_rebuild_error}", - details={"phase": "memory_rebuild", "exception_type": type(memory_rebuild_error).__name__}, - suggestions=["Run paperforge memory build to rebuild the memory DB from the cleaned canonical index."], - ) - result.next_actions.append({ - "command": "paperforge memory build", - "reason": "Rebuild memory DB so it matches the cleaned canonical index", - }) - return result def prune(self, paths: dict, fresh_index: dict | None = None, *, dry_run: bool = True) -> dict: diff --git a/paperforge/worker/asset_index.py b/paperforge/worker/asset_index.py index 7912f435..d3b56c94 100644 --- a/paperforge/worker/asset_index.py +++ b/paperforge/worker/asset_index.py @@ -277,10 +277,10 @@ def _build_entry(item: dict, vault: Path, paths: dict, domain: str, zotero_dir: ) from paperforge.worker.ocr import validate_ocr_meta from paperforge.worker.paper_meta import write_paper_meta + from paperforge.adapters.obsidian_frontmatter import has_deep_reading_content from paperforge.worker.sync import ( collection_fields, frontmatter_note, - has_deep_reading_content, obsidian_wikilink_for_path, obsidian_wikilink_for_pdf, ) @@ -488,8 +488,8 @@ def _vec_auto_embed_if_new(vault: Path, entry: dict) -> None: return # Check if vector DB is enabled and set up try: - from paperforge.embedding._config import _read_plugin_settings from paperforge.embedding import embed_paper, get_vector_db_path + from paperforge.embedding._config import _read_plugin_settings from paperforge.memory.chunker import chunk_fulltext settings = _read_plugin_settings(vault) if not settings.get("features", {}).get("vector_db", False):