mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
fix(sync): freeze workspace slug + frontmatter-only update to prevent deep-reading data loss
- Slug freeze: reuse existing workspace dir when title slug changes in Zotero
- Frontmatter-only: for existing notes, replace only YAML block, never touch body
- extract_preserved_deep_reading: match both ##精读 and ##🔍精读 + skip placeholder-only sections
This commit is contained in:
parent
f8c05959ed
commit
a5dd71bb13
2 changed files with 46 additions and 7 deletions
|
|
@ -226,19 +226,35 @@ def generate_review(candidates: list[dict]) -> str:
|
|||
def extract_preserved_deep_reading(text: str) -> str:
|
||||
if not text:
|
||||
return ""
|
||||
match = re.search("^## 🔍 精读\\s*$", text, re.MULTILINE)
|
||||
# Match "## 🔍 精读" or "## 精读" (emoji is optional)
|
||||
match = re.search(r"^##\s*🔍?\s*精读\s*$", text, re.MULTILINE)
|
||||
if not match:
|
||||
return ""
|
||||
start = match.start()
|
||||
preserved = text[start:].strip()
|
||||
# Skip if section body is empty or only contains placeholder text
|
||||
body = re.sub(r"^##\s*🔍?\s*精读\s*$", "", preserved, flags=re.MULTILINE).strip()
|
||||
if not body or _is_placeholder_only(body):
|
||||
return ""
|
||||
return preserved
|
||||
|
||||
|
||||
_PLACEHOLDER_PATTERN = re.compile(r"(待补充)|\(待补充\)|\(TODO\)|\(TBD\)")
|
||||
|
||||
|
||||
def _is_placeholder_only(body: str) -> bool:
|
||||
"""Check if the deep reading body is only placeholder text (no real content)."""
|
||||
cleaned = _PLACEHOLDER_PATTERN.sub("", body).strip()
|
||||
cleaned = re.sub(r"^[-*]\s*$", "", cleaned, flags=re.MULTILINE).strip()
|
||||
return not cleaned
|
||||
|
||||
|
||||
def has_deep_reading_content(text: str) -> bool:
|
||||
preserved = extract_preserved_deep_reading(text)
|
||||
if not preserved:
|
||||
return False
|
||||
body = preserved.replace(DEEP_READING_HEADER, "").strip()
|
||||
# Strip both "## 🔍 精读" and "## 精读" header variants
|
||||
body = re.sub(r"^##\s*🔍?\s*精读\s*$", "", preserved, flags=re.MULTILINE).strip()
|
||||
if not body:
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -262,13 +262,22 @@ def _build_entry(item: dict, vault: Path, paths: dict, domain: str, zotero_dir:
|
|||
write_json(meta_path, meta)
|
||||
title_slug = slugify_filename(item["title"])
|
||||
note_path = paths["literature"] / domain / f"{key} - {title_slug}.md"
|
||||
|
||||
# --- Freeze slug: reuse existing workspace if it exists under a different slug ---
|
||||
workspace_dir = paths["literature"] / domain / f"{key} - {title_slug}"
|
||||
if not workspace_dir.exists():
|
||||
for candidate in (paths["literature"] / domain).glob(f"{key} - *"):
|
||||
if candidate.is_dir():
|
||||
workspace_dir = candidate
|
||||
title_slug = workspace_dir.name.split(" - ", 1)[1] if " - " in workspace_dir.name else title_slug
|
||||
break
|
||||
|
||||
if note_path.parent.exists():
|
||||
for stale_note in note_path.parent.glob(f"{key} - *.md"):
|
||||
if stale_note != note_path:
|
||||
stale_note.unlink()
|
||||
|
||||
# Workspace paths (Phase 26: flat-to-workspace migration)
|
||||
workspace_dir = paths["literature"] / domain / f"{key} - {title_slug}"
|
||||
main_note_path = workspace_dir / f"{key} - {title_slug}.md"
|
||||
deep_reading_file = workspace_dir / "deep-reading.md"
|
||||
target_fulltext = workspace_dir / "fulltext.md"
|
||||
|
|
@ -363,10 +372,24 @@ def _build_entry(item: dict, vault: Path, paths: dict, domain: str, zotero_dir:
|
|||
entry["maturity"] = compute_maturity(entry)
|
||||
entry["next_step"] = compute_next_step(entry)
|
||||
|
||||
# --- Workspace: always create and write to workspace path (Phase 38: no flat fallback) ---
|
||||
existing_text = main_note_path.read_text(encoding="utf-8") if main_note_path.exists() else ""
|
||||
|
||||
main_note_path.write_text(frontmatter_note(entry, existing_text), encoding="utf-8")
|
||||
# Slug already frozen above — for existing notes, update frontmatter only (preserve body)
|
||||
if main_note_path.exists():
|
||||
text = main_note_path.read_text(encoding="utf-8")
|
||||
fm_close = text.find("---\n", 4) # closing --- after opening ---
|
||||
if fm_close != -1:
|
||||
body = text[fm_close + 4:] # everything after frontmatter
|
||||
new_full = frontmatter_note(entry, "")
|
||||
new_fm_close = new_full.find("---\n", 4)
|
||||
if new_fm_close != -1:
|
||||
new_fm = new_full[: new_fm_close + 4] # new frontmatter block with closing ---\n
|
||||
main_note_path.write_text(new_fm + body, encoding="utf-8")
|
||||
else:
|
||||
main_note_path.write_text(new_full, encoding="utf-8")
|
||||
else:
|
||||
main_note_path.write_text(frontmatter_note(entry, text), encoding="utf-8")
|
||||
else:
|
||||
existing_text = note_path.read_text(encoding="utf-8") if note_path.exists() else ""
|
||||
main_note_path.write_text(frontmatter_note(entry, existing_text), encoding="utf-8")
|
||||
|
||||
# Write per-workspace paper-meta.json (Phase 37: internal state outside frontmatter)
|
||||
write_paper_meta(workspace_dir, entry, paperforge_version=PAPERFORGE_VERSION)
|
||||
|
|
|
|||
Loading…
Reference in a new issue