其他
需要从 wiki-export 输出导入 wiki 到当前…
适用于用户要求 import wiki、从 export 导入、加载 graph.json、导入 vault、导入 OKF bundle/OKF/markdown bundle、执行 /wiki-import,或用 wiki-export 输出在 vault 间迁移页面的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
需要从 wiki-export 输出导入特定
解决思路
- 在生成或重写自然语言 Markdown 前,读取并应用 `llm-wiki/SKILL.md` 中的 `Writing Profile Resolution` 部分;框架 schema、provenance、安全、操作特定要求优先。
- 保留导入来源的原始 prose;只对新生成的 metadata 或 stubs 应用 `WRITING.md` 偏好。
- 解析 config:遵循 `llm-wiki/SKILL.md` 的 Config Resolution Protocol(inline `@name` override → 向上遍历 CWD 找 `.env` → 全局配置 → 提示 setup),得到 `OBSIDIAN_VAULT_PATH`。
- 若 `$OBSIDIAN_VAULT_PATH/AGENTS.md` 存在则读取,应用 owner-specific conventions。
- 定位导入来源:若用户提供路径参数则直接使用;否则按顺序自动检测 `./wiki-export/okf/`(目录)→ `./wiki-export/graph.json`(文件);都不存在则询问用户路径。
- 检测来源类型:路径是 `.json` 文件 → graph.json 导入(校验后走 Step 3 + Step 4-Graph)。
- 路径是目录且含带 OKF frontmatter(有 `type:` key)的 `.md` 文件,和/或根 `index.md` 含 `okf_version` → OKF bundle 导入(跳过 Step 3,走 Step 4-OKF)。
- 其他情况 → 报告问题并停止。
- 校验 graph.json:必须是合法 JSON;必须有顶层 keys `nodes`(array)、`links`(array)、`graph`(object);至少 1 个 node;失败则报告并停止。
- 校验 OKF bundle:必须至少 1 个非保留 `.md` 文件(即不是 `index.md`/`log.md`),且可解析 YAML frontmatter 含非空 `type`;无 frontmatter 或无 `type` 的 `.md` 跳过并计数,不致命(OKF consumers 按 OKF §9 宽松处理)。
- 导入前显示 preview:graph.json 用格式 `Import preview (graph.json — stubs)`,含 `Source: <path> (exported at <graph.exported_at>)`、`Nodes: N total (...)`、`Links: M edges (...)`、`Target: $OBSIDIAN_VAULT_PATH`。
- 导入前显示 preview:OKF bundle 用格式 `Import preview (OKF bundle — full pages)`,含 `Source: <dir> (okf_version <ver if present>)`、`Pages: N total (...)`、`Target: $OBSIDIAN_VAULT_PATH`。
- 读取用户措辞确定冲突模式,默认 `merge`。
- `merge`:已有页面更新 frontmatter 的 tags/summary/relationships 并添加缺失 wikilinks;新页面创建 stub(OKF 为 full page)。
- `skip`:触发词 `skip existing`、`don't overwrite`、`only new pages`;完全不动已有页面,只创建不存在的页面。
- `overwrite`:触发词 `overwrite`、`replace existing`、`force import`;替换所有匹配页面;graph 来源写成 freshly reconstructed stubs,OKF 来源写 full page,不管已有内容。
- 仅 graph.json:写任何内容前,从 `links` 数组构建 adjacency map:对每个 node id 收集所有 neighbour ids(边任方向),例如 `adjacency["concepts/transformers"] = [...]`。
- 仅 graph.json:构建 typed edge map:对每个 node id 只收集 outgoing typed edges(`typed: true`),例如 `typed_edges["concepts/transformers"] = [{target: "concepts/lstm", relation: "contradicts"}]`。
- graph.json:记录 counts `created = 0`, `skipped = 0`, `merged = 0`。
- graph.json:对 `nodes` 中每个 node,计算 `page_path = $VAULT/<node.id>.md`。
- graph.json:确保父目录存在(如 `$VAULT/concepts/`)。
- graph.json:检查文件是否已存在,并按模式执行:`merge` + exists → 读已有文件,应用 merge logic,`merged` 加 1;`merge` + 不存在 → 创建 stub,`created` 加 1;`skip` + exists → `skipped` 加 1,继续下一 node;`skip` + 不存在 → 创建 stub,`created` 加 1;`overwrite` + exists → 写入 fresh stub(覆盖),`merged` 加 1;`overwrite` + 不存在 → 创建 stub,`created` 加 1。
- graph.json:按 page template 写入新/覆盖页面:frontmatter 含 `title: <node.label>`、`category: <node.category>`、`tags: <node.tags as YAML list>`、`sources: - 'imported from <graph.json path>'`;若 `node.summary` 存在加 `summary`;若 `typed_edges[node.id]` 非空加 `relationships`,每个 `{target, relation}` 写成 `- target: '[[<target>]]'` 和 `type: <relation>`;再加 `lifecycle: draft`、`lifecycle_changed: <today YYYY-MM-DD>`、`base_confidence: 0.5`、`tier: supporting`、`created: <ISO timestamp>`、`updated: <ISO timestamp>`。
- graph.json:page body 写入 `# <node.label>`;若有 `node.summary` paragraph 则写入,否则省略;若 `adjacency[node.id]` 非空,添加 `## Related`,对每个 neighbour 按字母排序,若边 typed 写 `- [[<neighbour>]] — <relation>`,否则写 `- [[<neighbour>]]`;若 adjacency 为空则完全省略 `## Related`。
- graph.json merge logic:读取已有页面 frontmatter。
- graph.json merge logic:Tags 取已有 tags 与 `node.tags` 的并集,去重,保留已有顺序,追加新 tags。
- graph.json merge logic:若已有页面无 `summary` 字段且 `node.summary` 存在,则添加 summary。
- graph.json merge logic:Relationships 取已有 `relationships:` entries 与 `typed_edges[node.id]` 的并集;跳过相同 `(target, type)` 对已存在的条目。
- graph.json merge logic:设置 `updated` 为当前 ISO timestamp。
- graph.json merge logic:扫描 body 中 `## Related` 段;若存在,追加 `adjacency[node.id]` 中未出现在 body 任何位置的缺失 wikilinks;若不存在,则追加一个含缺失 links 的 `## Related`。
- graph.json merge logic:其余 body 保持不动。
- OKF:记录 counts `created = 0`, `skipped = 0`, `merged = 0`, `unparseable = 0`。
- OKF:遍历 bundle 目录树。对每个非保留 `.md` 文件(不是 `index.md`、`log.md`):解析 YAML frontmatter;若无 frontmatter 或无非空 `type`,`unparseable` 加 1 并跳过。
- OKF:计算 concept id = 文件相对 bundle root 的路径去掉 `.md`(如 `concepts/transformers.md` → `concepts/transformers`);目标页面为 `$VAULT/<concept-id>.md`。
- OKF:reverse-map frontmatter:`title` ← `title`。
- OKF:`category` ← 若存在保留的 `category` extension key 则用之;否则用 concept id 的目录前缀小写(`concepts/…` → `concepts`);否则从 `type` 派生(`Concept`→`concepts`、`Entity`→`entities`、`Skill`→`skills`、`Reference`→`references`、`Synthesis`→`synthesis`、`Project`→`projects`、`Journal`→`journal`)。
- OKF:`tags` ← `tags`。
- OKF:`summary` ← `description`。
- OKF:`updated` ← `timestamp`(缺失则 now)。
- OKF:`created` ← 若存在保留的 `created` extension key 则用之,否则 now。
- OKF:`sources` ← 若存在保留的 `sources` extension key 则用之;否则 `["imported from OKF bundle <bundle path>"]`;若 `resource` URL 存在且尚未在 `sources` 中,则加入。
- OKF:原样 carry through 其他保留的 extension keys(`relationships`、`lifecycle`、`tier`、`base_confidence` 等),以保证 round-trip lossless。
- OKF:reverse-transform body links:指向 `.md` 路径的 markdown links 变成 wikilinks;`[text](../concepts/transformers.md)` 或 `[text](/concepts/transformers.md)` → 解析路径(相对当前文件目录,或 `/` 绝对则相对 bundle-root)得到 concept id → `[[concepts/transformers]]`,当 `text` 与目标 title 不同时写成 `[[concepts/transformers|text]]`;目标 title 来自 bundle 页面(存在时),否则与最后路径段比较。
- OKF:reverse-transform body links 时,先把 markdown target 当 file path 处理:相对于当前文件 normalize `.md` 路径,再从解析后的文件路径去掉末尾 `.md` 恢复 page id;不要在解析完整文件路径前从 directory traversal segments 推断 id。这样保留 folder-note 布局 round-trip,例如 `projects/social-twitter.md` 加 `projects/social-twitter/...`,其中 `../../social-twitter.md` 必须还原为 `projects/social-twitter`。
- OKF:即使目标页面不在 bundle 中,也执行上述转换:指向未写入页面的 path-form link 应 round-trip 回 dangling `[[wikilink]]`(Obsidian 支持;OKF §5.3 如此期望);不要留作 markdown link。
- OKF:当 config 中有 `OBSIDIAN_LINK_FORMAT=markdown`,保留 markdown links(只重写为 vault-relative 路径);不要转成 wikilinks。
- OKF:保持外部 `http(s)://` links 和 `# Citations` 段不动。
- OKF:按 Step 2 冲突模式写页面:`merge` + exists → reverse-map frontmatter 并 merge 到已有页面(union `tags`;仅在缺失时填 `summary`/`sources`;union `relationships`;刷新 `updated`);body 方面 OKF 有真实 body:仅当已有页面是 stub(body 只是 heading + `## Related`)时用 bundle body 替换已有 body;否则保留已有 body,并追加 bundle 中已有 body 没有的 `# Citations` / 新 `##` sections;`merged` 加 1。`merge` + 不存在 → 写 full page(frontmatter + full bundle body);`created` 加 1。`skip` + exists → `skipped` 加 1,继续。`skip` + 不存在 → 写 full page;`created` 加 1。`overwrite` + exists → 写 full page,替换已有;`merged` 加 1(summary 中标注 `Replaced`)。`overwrite` + 不存在 → 写 full page;`created` 加 1。
- OKF:写之前确保父目录(`$VAULT/concepts/` 等)存在。
- OKF:与 graph.json 路径不同,不要生成 `## Related` stub section,因为 bundle body 已含真实 cross-links。
- 更新 `.manifest.json`:新增 entry,key 为 source 的 canonical/absolute path(graph.json 文件或 bundle directory);value 含 `ingested_at: <ISO timestamp>`、`source_type`、`pages_created`、`pages_updated`;graph.json 用 `source_type: wiki-export`,OKF bundle 用 `source_type: okf-bundle`。
- 更新 `.manifest.json`:`stats.total_sources_ingested` 加 1;`stats.total_pages` 加上实际 created 页面数(不含 skipped/merged)。
- 若 `.manifest.json` 不存在,创建标准结构:`stats` 含 `total_sources_ingested: 1`、`total_pages: <created count>`,再含 source key 的 entry。
- 更新 `index.md`:对每个 created 或 merged 页面,在其 category section 下添加/更新 entry,格式 `- [[<id>]] — <summary or title> ( #tag1 #tag2)`;注意 `(` 前有空格,即 `description ( #tag)` 不是 `description(#tag)`;category sections 按字母排序;不存在 category section 则创建。
- 更新 `log.md`:追加一行 `- [<ISO timestamp>] IMPORT source="<graph.json path>" pages_created=<N> pages_skipped=<K> pages_merged=<M>`。
- 更新 `hot.md`:重写 `Recent Activity` 段,把本次 import 作为最新 entry:`- [<timestamp>] IMPORT from <graph.json path> — created X, merged Z pages`;更新 `updated:` frontmatter timestamp;除非刚创建的页面被引用,否则保持其他 hot.md sections(Active Threads、Key Takeaways)不变,被引用时加简短 mentions。
- 打印 summary:`Wiki import complete → $OBSIDIAN_VAULT_PATH`,含 Source path 与类型、graph 的 exported_at/N nodes/M links 或 OKF 的 N pages/okf_version、Created X、Merged Z、Skipped Y。
- summary 中仅当显式请求 `skip` 模式时显示 `Skipped` 行;若用 `overwrite`,把 merged 页面标为 `Replaced`;OKF 导入且 `U > 0` 时额外报告 `Unparseable: <U> files (no frontmatter/type, skipped)`。
- 注意 stub vs full pages:graph.json 导入产生 stubs(结构和 wikilinks 但无 body,是后续 ingestion 起点);OKF bundle 导入产生带真实 body 的 full pages,是无损路径,适合 vault-to-vault transfer。
- 注意 re-running 安全:默认 `merge` 模式幂等——对未变 export 重跑只会更新 timestamps,不会破坏内容;仅在想完全把页面重置为 stubs 时用 `overwrite`。
- 注意目录创建:写页面前总是创建缺失的 category directories。
- 注意 broken wikilinks:因为页面从同一 export 一起创建,大多 links 会 resolve;任何在 `links` 中被引用但不在 `nodes` 中的 node(原 export 已 broken)仍会作为 wikilink 出现,只是没有对应 page 文件,这是有效的。
- 注意 filtered exports:若源 `graph.json` 由 visibility filtering 产生(记录在 `graph.metadata`),导入页面只反映 filtered set;若 `graph.graph` 含 `filtered` key,在 summary 中注明。
适用边界 · 注意事项
- 源文件不是由 `wiki-export` 产出的 `graph.json` 或 OKF bundle 时,不适用。
- 目标不是 Obsidian vault,或未配置 `OBSIDIAN_VAULT_PATH` / 缺少 `llm-wiki` 技能约定时,不适用。
- 需要无损迁移页面正文时不要只导入 `graph.json`,因为它只重建 stub;应改用 OKF bundle。