协作办公
在 Obsidian wiki…
扫描 Obsidian wiki 的页面级身份冲突(如 RSC 与 React Server Components),按审计/合并模式确认后合并重复页。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Obsidian wiki 中出现同特定
解决思路
- 开始前先应用写作配置:在起草或重写自然语言 Markdown 前,读取并应用 `llm-wiki/SKILL.md` 的 `Writing Profile Resolution` 部分;框架 schema、provenance、安全及操作特定要求优先;`WRITING.md` 偏好仅用于新起草或重写的自然语言 Markdown,保留源内容与结构化记录。
- 解析配置:按 `llm-wiki/SKILL.md` 的 Config Resolution Protocol 执行(内联 `@name` 覆盖 → 从 CWD 向上查找 `.env` → 全局配置 → 提示设置),得到 `OBSIDIAN_VAULT_PATH` 和 `OBSIDIAN_LINK_FORMAT`。
- 读取 `index.md` 获取完整页面清单及一句话描述和标签。
- 简要读取 `log.md`;若刚发生过 dedup,记录已合并内容。
- 选择模式:默认 Audit 只报告候选不写入;`--merge` 显示每个确认对并在合并前询问;`--auto` 非交互合并所有高置信度对(`score ≥ 0.90`)。若用户未指定,先运行 Audit 并展示结果后再询问是否继续。
- 构建页面注册表:glob vault 中所有 `.md` 文件,排除 `_archives/`、`_raw/`、`.obsidian/`、`index.md`、`log.md`、`hot.md`、`_insights.md`,以及 frontmatter 中含 `redirects_to:` 的文件(已合并的重定向存根)。
- 对每个剩余页面从 frontmatter 提取 `node_id`(相对 vault 根路径去掉 `.md`)、`title`、`aliases`、`tags`、`category`(目录前缀);建立 `node_id → {title, aliases, tags, category, summary}` 查找表。
- 候选对检测:对注册表中每对页面计算相似度分数。
- 标题相似信号:Token overlap:标题小写词元(按空格、连字符、下划线、标点切分)的 Jaccard 相似度,最大贡献 0.65。
- 标题相似信号:Edit distance:小写标题的归一化编辑距离 `1 - (edits / max(len_a, len_b))`,最大贡献 0.40。
- 标题相似信号:Substring containment:一个标题是另一个的子串(如 RSC ⊂ React Server Components),最大贡献 0.50。
- 标题相似信号:Alias cross-match:页面 A 的标题出现在页面 B 的 `aliases` 中或反之,最大贡献 0.65。
- 组合标题分数 = `min(max(token_overlap, edit_distance, substring), 0.65) + alias_cross_bonus`;无需精确算术,做出可信相似度判断。
- 标题提取注意:有些页面使用 YAML 块标量(`title: >-` 或 `title: |`);当 `title:` 值为 `>-`、`>`、`|`、`|-` 时,实际标题在下一缩进行,从那里读取;绝不要把字面字符串 `>-` 当标题比较。
- 语义信号(廉价遍历):同 `category` 目录 +0.10。
- 语义信号:共享标签 ≥ 3 个 +0.15。
- 语义信号:共享标签 ≥ 2 个 +0.05。
- 语义信号:相同首个标签(主导标签)+0.05。
- 阈值:组合分数 ≥ 0.75 标为候选;≥ 0.90 为高置信度。
- 分数区间标签:≥ 0.90 为 HIGH(几乎肯定是同一概念);0.75–0.89 为 MEDIUM(可能相同,需验证);0.60–0.74 为 LOW(可能是缩写或特化;除非用户要求否则跳过)。只将 HIGH 和 MEDIUM 候选带入 Step 3。
- 快速退出规则:vault 少于 10 页时跳过配对循环并报告 vault too small to have meaningful duplicates;超过 500 页时按 50 对一批处理候选,批次间暂停并报告进度。
- 语义裁决:对每个候选对(按分数降序)读取两页全文(候选池小,全文读取合理)。
- 判断两页是否覆盖同一概念,还是不同。
- 分配三种裁决之一:`merge` = 同一概念的不同名称、缩写、别名或意外重复,可安全合并;`keep-separate` = 相关但不同,例如 Server Actions 与 Server Components 是相关 React 特性而非重复;`needs-review` = 模糊,有大量重叠但也有有意义差异,标记让用户决定。
- 为每个裁决附加一句简短原因,出现在报告和日志中。
- 始终生成审计报告,即使在 merge/auto-merge 模式也生成,让用户看到将发生什么。
- 报告格式包含:标题 `## Wiki Dedup Report`;`### High-Confidence Candidates (score ≥ 0.90): N pairs` 表格列 Score, Page A, Page B, Verdict, Reason;`### Medium-Confidence Candidates (score 0.75–0.89): N pairs` 同表;`### Needs Human Review: N pairs` 表格列 Score, Page A, Page B, Reason;`### Summary` 列出 Pages scanned、Candidate pairs found、Recommended merges、Keep separate、Needs review。
- 在 Audit 模式到此停止并询问:Run `--merge` to interactively merge the recommended pairs, or `--auto` to merge all high-confidence ones automatically?
- 合并前写快照:在首次写文件前,检查 vault 本身是否为 Git 仓库根;仅是更大仓库的子目录不合格,因为 `git add -A` 可能捕获无关文件。若 vault 不是独立 Git 仓库,静默跳过,不反复提示,不建议 `git init`。使用给定 bash 逻辑:解析 `VAULT_REAL_PATH` 与 `VAULT_GIT_ROOT`,仅在两者相等且仓库干净时取 `HEAD`;否则 `git add -A` 并 `git commit -m "pre-wiki-dedup snapshot" --quiet`,失败则中止不写 vault 文件;`SNAPSHOT_SHA` 非空且写入文件时在最终报告包含 SHA。丢弃整次运行可在确认无后续需保留更改后执行 `git -C "$OBSIDIAN_VAULT_PATH" reset --hard "$SNAPSHOT_SHA"` 和 `git -C "$OBSIDIAN_VAULT_PATH" clean -fd`。
- 对每个 `merge` 裁决对(在 merge 或 auto-merge 模式):merge 模式显示对和裁决,然后询问 Merge `[Page A]` into `[Page B]`? (yes/skip/review);除 yes 外跳过。auto-merge 模式只处理 HIGH-confidence(`score ≥ 0.90`)合并,不提示。
- 选择规范页:按顺序应用 tiebreakers 直到一个胜出:1) 更多入站 wikilink——grep vault 中 `[[node_id]]` 引用,数量高者胜;2) 内容更丰富——正文更长(行数更多)者胜;3) 来源更多——`sources:` 列表更大者胜;4) 标题长度——更长更描述性的标题胜(如 React Server Components 胜过 RSC);5) 字母顺序——标题更早者胜。规范页是 survivor;另一页成为 secondary(被合并进去,然后替换为重定向存根)。
- 将内容合并到规范页:读取两页,更新规范页。
- 合并 `aliases:`:加入 secondary 页标题及其所有 aliases(去重)。
- 合并 `tags:`:合并两个标签列表(去重,最多 5 个领域标签 + 系统标签)。
- 合并 `sources:`:合并两个来源列表(去重)。
- 合并 `relationships:`:合并两个关系列表(按 target 去重,优先带类型条目而非无类型)。
- 重新计算 `base_confidence`:用 sources 并集和 `llm-wiki/SKILL.md` 公式。
- 设置 `updated` 为当前时间。
- 重写 `summary:`:若 secondary 页增加新领域,覆盖合并后的范围。
- 合并正文:合并 secondary 页的独特章节和项目符号;不要盲目追加,要整合内容;避免重复规范页已有声明;需要综合时使用 `^[inferred]` 标记。
- 合并后重新计算 `provenance:`。
- 在 secondary 页路径写重定向存根,包含 frontmatter:`title: <secondary page title>`、`redirects_to: "[[<canonical node_id>]]"`、`aliases: [<secondary aliases>]`、`category: <secondary category>`、`tags: []`、`created: <secondary original created>`、`updated: <ISO timestamp now>`;正文为 `This page has been merged into [[<canonical page title>]].`;`redirects_to:` 字段告诉读取此页的技能跟随重定向而不是当内容处理。
- vault 范围重写 wikilinks:grep 整个 vault 中指向 secondary slug 的链接;`[[secondary-slug]]` → `[[canonical-slug]]`;`[[secondary-slug|display text]]` → `[[canonical-slug|display text]]`;若 `OBSIDIAN_LINK_FORMAT=markdown`,`[text](../path/to/secondary.md)` → `[text](../path/to/canonical.md)`。
- 重写安全规则:绝不在代码块(``` fences 或 `inline code`)内重写;绝不在重定向存根本身内重写(那是旧 slug 唯一应保留可读之处);绝不用 `rm` 或破坏性 shell 操作,只用 Edit/Write 工具;一次重写一个文件,逐个验证后再继续;若文件零出现,跳过。
- 更新跟踪文件:`index.md` 移除 secondary 页条目;用合并后 summary 更新规范页条目。
- `.manifest.json`:对 secondary 页的来源条目添加 `merged_into: <canonical node_id>`;对规范页合并 secondary 的 `pages_created` 和 `pages_updated` 列表。
- `hot.md`:更新 Recent Activity:Merged N duplicate pairs; canonical pages updated.
- 最终检查:所有合并后,grep vault 中任何剩余 `[[secondary-slug]]` 引用(非存根文件);若仍有残留,报告,重写步骤可能漏掉非标准链接格式。
- 记录日志:向 `log.md` 追加 `- [TIMESTAMP] DEDUP mode=audit|merge|auto-merge pages_scanned=N pairs_found=M merged=X kept_separate=Y needs_review=Z wikilinks_rewritten=W`。
- 重定向存根处理:其他技能应如此处理:`wiki-export` 跳过 frontmatter 含 `redirects_to:` 的页面,它们不是内容节点;`wiki-query` 若搜索命中重定向存根,跟随 `redirects_to:` 读取规范页;`wiki-lint` 验证每个 `redirects_to:` wikilink 解析到存在且非存根的页面(存根指向存根的重定向链是错误);`cross-linker` 将重定向存根视为非目标,绝不新增指向存根页的 `[[wikilink]]`。
- Tips:永远先审计;即使在 auto-merge 模式也显示审计报告,信任结果前先读。
- Tips:最后检查 `needs-review`;这些是困难案例,不要与明显合并批量处理。
- Tips:缩写是最常见情况。GPT / GPT-4 / GPT4,RSC / React Server Components,LLM / Large Language Models 在 substring containment 上得分高,几乎总可安全合并。
- Tips:不同版本不是重复。GPT-3 和 GPT-4 相关但不同;fine-tuning 和 fine-tuning-llms 可能不同(技术 vs 特定应用)。
- Tips:dedup 后运行 `cross-linker`;重定向存根会让图略不一致,Cross-linker 会收紧。
- Vault 写入后刷新 QMD:QMD 是搜索索引,不是真相来源。若 `$QMD_WIKI_COLLECTION` 为空或未设置,跳过此步。仅在本技能写入或重写 vault markdown 后运行。若 QMD 刷新失败,不要回滚 vault 更改;单独报告 QMD 状态。
- 使用 `$QMD_CLI`(若设置),否则使用 `qmd`。运行 `${QMD_CLI:-qmd} update`。若输出说需要 vectors 或 embeddings 可能过期,运行 `${QMD_CLI:-qmd} embed`。用 `${QMD_CLI:-qmd} ls "$QMD_WIKI_COLLECTION"` 或已知页面路径时 `${QMD_CLI:-qmd} get "qmd://$QMD_WIKI_COLLECTION/<page>.md" -l 5` 验证 collection。
- 记录 QMD 状态之一:`QMD refreshed: update + embed + verified`;`QMD refreshed: update only + verified`;`QMD skipped: QMD_WIKI_COLLECTION unset`;`QMD skipped: qmd CLI unavailable`;`QMD failed: <short error summary>`。
- 遵循 `llm-wiki/SKILL.md` 中的 Retrieval Primitives table;候选检测只用 frontmatter 和 titles(低成本),仅对确认候选对打开完整页面正文。
- 与其他技能区别:不同于 `wiki-lint`(检查结构)和 `cross-linker`(添加链接);本技能进行破坏性页面级合并,需谨慎确认。
适用边界 · 注意事项
- 不适用于非 Obsidian wiki,或页面没有 frontmatter、index.md、log.md、redirects_to 等约定结构时。
- 只想做结构检查或补链接时不用;应使用 wiki-lint 或 cross-linker,而不是做破坏性页面级合并。
- 无法承受不可自动撤销的页面合并、无法确认合并对或无法提供 Git 快照回退时,不应进入 merge/auto-merge 模式。