Ariver
2026-08-25 f82d5d731f7c1439a95dda6e1a14d40d58881d69
X2.Archived/scripts/sync_0inbox.py
@@ -27,7 +27,8 @@
--------------------
- 顶层黑名单 EXCLUDE_TOP 整棵子树不扫:X2.Archived / 00index / X1.Knomo / X.Attachment / P3.bobo
- 仅扫描后缀 SCAN_EXT:.md .markdown .excalidraw .canvas;其它后缀一律跳过
- markdown 同时抽 frontmatter(tags + 关键词字段)与正文 #tag
- markdown 只抽标准 `tags:` frontmatter 与正文 #tag;topic/category/type 等
  元数据字段不再当作标签(避免 copilot 对话、读书笔记的元数据被误建页)
幂等 & 安全
----------
@@ -140,15 +141,18 @@
TAG_RE = re.compile(r"(?<![\w/])#([A-Za-z0-9_\u4e00-\u9fff][\w\u4e00-\u9fff/\-]*)")
SCAN_EXT = {".md", ".markdown", ".excalidraw", ".canvas"}
EXCLUDE_TOP = {"X2.Archived", "00index", "X1.Knomo", "X.Attachment", "P3.bobo"}
# 嵌套路径排除(只排除指定子树,不影响其同级目录)。
# 例:02DS/02copilot 是 Obsidian Copilot 的对话日志,其 topic: 字段与聊天正文
# 不应被当作标签扫描(与 tagfeed 模板的 excludedPaths 保持一致)。
EXCLUDE_PATHS = {"02DS/02copilot"}
INBOX_DIR = "0inbox"
EXCLUDE_DIRS = {".obsidian", ".trash", ".git", ".agents", ".claude",
                ".copilot", ".opencode", ".smart-env", ".workbuddy"}
FM_KEYWORD_KEYS = {
    "aliases", "alias", "keywords", "keyword", "topic", "topics",
    "category", "categories", "subject", "area", "areaOfFocus",
    "people", "person", "project", "projects", "type", "tags",
}
# 只把标准 Obsidian 标签字段 `tags:` 当作标签;不再把 topic/category/subject/
# type/keywords/aliases 等元数据字段误读为标签(否则 copilot 对话的 topic:、
# 读书笔记的 type: 等会被当成标签疯狂建页)。行内 #标签 仍正常扫描。
FM_KEYWORD_KEYS = {"tags"}
def split_fm_value(v) -> list:
@@ -358,10 +362,15 @@
    all_tags = {}
    for root, dirs, files in os.walk(vault):
        dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS and not d.startswith(".")]
        top = os.path.relpath(root, vault).split(os.sep)[0]
        rel = os.path.relpath(root, vault)
        top = rel.split(os.sep)[0]
        if top in EXCLUDE_TOP:
            dirs[:] = []
            continue
        # 嵌套路径排除(如 02DS/02copilot)
        if any(rel == p or rel.startswith(p + os.sep) for p in EXCLUDE_PATHS):
            dirs[:] = []
            continue
        for fn in files:
            if fn.startswith("."):
                continue