soia-team/soia-open-cwork-office-skills · Archived

soia-cwork-feishu-doc-git-sync

将飞书知识库或云文档以应用身份只读同步为本地 Markdown,保留目录、来源和同步?

First seen Jul 22, 2026

Installation

$ npx skills add soia-team/soia-open-cwork-office-skills --skill soia-cwork-feishu-doc-git-sync

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from soia-team/soia-open-cwork-office-skills.

npx skills add soia-team/soia-open-cwork-office-skills

Browse all from soia-team/soia-open-cwork-office-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 1
License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.7.3

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 33,615 B
  • docs SUMMARY.md 305 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 3 installs

SKILL.md

soia-cwork-feishu-doc-git-sync

把飞书知识库的内容镜像到一个本地 Markdown 知识库。默认方向是 Feishu → local/Git/Obsidian/VitePress;本技能不默认向飞书写入,双向同步必须先建立文档归属、冲突策略和写权限。

客户可读说明

这个技能可以做什么

客户想要 技能会做 客户能看到
同步飞书知识库到本地 遍历知识空间节点,读取可读文档并生成 Markdown 本地镜像目录、目录层级、来源链接、同步清单
排除指定知识库子树 按稳定节点 ID 或精确标题跳过根节点及全部后代 不读取该子树正文、表格、图片或附件,也不加入侧边栏和重试队列
备份到 Git 将生成内容放入客户指定的 Git 仓库并检查差异 commit/push 回执、文件变更和失败清单
用 Obsidian 查看 在独立 vault 中保存规则、镜像和本地补录 可直接用 Obsidian 打开的 vault
用 VitePress 展示 生成站点侧边栏并构建静态站点 本地开发服务或构建产物
检查表格/多维表格导出能力 解析真实资源类型、权限和可用导出格式 只读探查结果;不会默认生成 Excel 文件
同步独立或内嵌 Sheet 对私有配置明确授权的范围读取 Sheet;可自动覆盖全部独立 Sheet 节点,内嵌 Sheet 从文档 XML 中识别后再读取 有边界的 Markdown 表格快照;不再把已授权的 Sheet 节点写成正文占位
保留 Sheet 公式、样式、批注与图表信息 对已选范围保存单元格、布局、图表和浮动图片元数据快照 Markdown 表格旁的本地保真 JSON;不伪装为可编辑工作簿
初始化完整 Sheet 与报表 经确认后分批导出整个 Sheet 工作簿 .xlsx 保真副本,保留公式、样式、批注、图表、透视和单元格图片
镜像指定多维表格 读取指定 Base 表的字段、限量记录和可选视图,生成 Markdown 与快照 有上限的表格内容、schema/记录快照;默认不读取任何 Base 数据
初始化多维表、多人报表 经确认后分批导出完整 Base;选定表也可读取仪表盘与报表块元数据 .base 保真副本;仪表盘快照写入 JSON,不伪装成交互式网页
本地化资源与导航 经确认后下载文档图片/附件,或下载所选多维表格记录附件,并把文档内部链接和子页面列表改为本地导航 本地资源、相对链接和可选子页面导航
初始化知识库文件 经确认后分批下载 Wiki file 节点的原始二进制 本地链接;ZIP、DMG、EXE 等只保存,绝不执行、挂载或解压
查看同步变更 经配置后生成新增、修改、移动和远端删除的本地变更台账与受限 diff 本次同步的统计、变更清单和差异详情
规划双向同步 区分只读镜像、托管文档和本地补录 冲突/权限风险说明,不自动覆盖飞书

客户如何使用

  1. 确认 soia-cwork-feishu-cli 已完成飞书应用凭证登录,并且机器人可以读取目标知识空间。
  2. 在本机私有配置中填写知识空间 ID、输出目录和来源 URL 模板;不要把 App Secret、token 或企业私有路径提交到公开技能仓库。
  3. 首次使用先执行 dry-run,核对空间、节点数量和目标目录。
  4. 先用单节点隔离试点核对表格、资源和样式快照;--pilot-node-token 只写明确选择的节点到单独试点目录,不会给空目录补齐其他节点占位文件。
  5. 执行镜像同步。默认只写本地文件和同步元数据,不修改飞书内容,也不删除本地历史文件。
  6. 如需排除完整目录树,在私有配置设置 sync.excludesubtrees.enabled: true,并在 roots 中优先填写稳定 nodetoken;首次清理既有 Markdown、完整导出和已下载附件时显式运行一次 --rebuild-tree,本地补录目录永不受影响。
  7. 同步写入后会自动校验 manifest、文件存在性、frontmatter、失败占位、侧边栏覆盖范围、排除子树残留、资源引用、未归档的嵌入式 Sheet、未归档的 Sheet 内嵌 Base、alldocx 模式下尚未完成 XML 语义扫描的历史文档,以及 allnodes 模式下仍未生成真实表格的独立 Sheet;发现 failed/stale 或语义缺口时返回非零结果,不能把空白占位或局部内容当作完整成功。
  8. 如需检查表格导出,先做 drive +inspect/帮助/schema 探查;能力探查不等于授权导出。
  9. 只有客户明确确认导出范围、格式、文件数和本地目录后,才调用 drive +export 或 drive +export-download。
  10. 如需镜像 Sheet,先在私有配置明确范围:全部独立 Sheet 使用 sync.sheets.enabled: true 与 allnodes: true 自动发现每个网格子表,或在 selections 中逐项指定 nodetoken、稳定 sheetid 和有界 A1 range;两种方式都必须设置行列、单元格和返回字符上限。响应达到 maxchars 时必须按 actualrange 下一行续读,不能把截断当成整表失败。混合工作簿还需显式设置 includebitabletabs: true 与记录上限,随后把 Base 子表路由到多维表格读取。文档内嵌 Sheet 启用 sync.embeddedsheets.enabled 后,还须选择 alldocx: true 或 nodetokens。按需开启 sync.sheets.preserve 保存公式、样式、批注、布局和图表等元数据。未启用时必须显示并校验语义缺口,不得静默删除 <sheet> 或把独立 Sheet 占位当成完整归档。
  11. 如需镜像多维表格,逐项指定 sync.bitables.selections 的 nodetoken、tableid 和 maxrecords,再开启 sync.bitables.enabled 或传入 --sync-bitables;附件二进制还需要单独开启 downloadattachments,仪表盘/报表元数据需要 include_dashboards。
  12. 只有用户明确确认来源、格式、文件数、输出目录和 Git 策略后,才能执行完整初始化:Sheet 设置 sync.sheets.workbookexports.enabled=true 与 allnodes=true,Base 设置 sync.bitables.baseexports.enabled=true 与 allnodes=true,Wiki 文件设置 sync.files.downloads.enabled=true 与 allnodes=true。每项必须配置 batchsize,重复执行至 deferred 为零。
  13. 如需离线资源、文档间本地跳转、子页面导航或变更台账,先在私有配置中逐项启用 downloadassets、localizeinternallinks、rendersubpagenavigation、change_ledger;它们默认关闭以兼容已有镜像。
  14. 批量初始化前先以一份代表性范围试点,确认资源数量、失败类别和本地渲染;同步完成后再运行 Git diff、站点构建和必要的人工抽查。

推荐命令:

python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --dry-run
# 试点只写所选节点到独立目录;仍会核验它是否属于当前知识库
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --output-dir <pilot-output-dir> \
  --pilot-node-token <node_token> --incremental
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental
# 没有事件订阅时,按 wiki +node-get 的远端更新时间判断正文是否变化
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental --probe-remote-metadata
# 复用已完整正文,优先补独立 Sheet stub、未扫描的内嵌 Sheet 文档,再退避重试失败项
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --retry-failed
# 事件适配器已经拿到变动 ID 时,只拉对应节点;可重复传入多个 ID
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --changed-node-token <node_token> --changed-obj-token <obj_token>
# 只修复指定节点的本地格式,复用 manifest 中的其他文档,不重试历史失败项
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --rebuild-tree --rebuild-tree-only --only-node-token <node_token> --skip-assets
# 官方 webhook/长连接适配器写入 JSON/NDJSON 后,按事件目标增量拉取
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --event-file <events.ndjson>
# 仅在确认历史生成目录曾经扁平化时执行一次结构迁移
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --retry-failed --rebuild-tree
# 大型知识库遇到限流时分批补偿;重复执行直到 --validate-only 通过
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> \
  --retry-failed --retry-batch-size 100 --skip-assets
# 如果只需要修复本地目录层级、暂时不请求飞书
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --rebuild-tree --rebuild-tree-only
# 从飞书刷新最新目录层级和兄弟节点顺序,但复用现有本地正文
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --rebuild-tree --refresh-tree-only
# 应用私有配置中的整棵子树排除,并清理该子树既有 Markdown、完整导出和已下载附件
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --rebuild-tree --refresh-tree-only --skip-assets
# 下载图片到本地镜像并把正文中的远程 URL 改成相对路径
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --download-assets
# 将私有配置中明确选择的 Sheet 范围渲染为 Markdown 表格
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-sheets
# 将已授权文档中的嵌入式 Sheet 追加为有界 Markdown 表格快照
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-embedded-sheets
# 将私有配置中明确选择的多维表格镜像为 Markdown 与 JSON 快照
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-bitables
# 完整初始化仍使用同一同步命令;私有配置中 workbook_exports/base_exports/files.downloads
# 的 enabled 与 all_nodes 必须都为 true,并按 batch_size 分批重复执行
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --incremental \
  --sync-sheets --sync-bitables
# 只校验最近一次同步生成的本地镜像,不访问飞书
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --validate-only

依赖与安装

装整个域(Claude Code 与 Codex 共用同一份域插件):

claude plugin marketplace add soia-team/soia-open-skills
claude plugin install soia-cwork-office@soia

只装这一个技能:

npx skills add soia-team/soia-open-cwork-office-skills -g -a '*' -s soia-cwork-feishu-doc-git-sync -y

WorkBuddy 的装载单位是角色化专家而不是插件,npx skills add -a '*' 覆盖不到它,需要单独安装,见 docs/install/workbuddy.md。

三种工作模式

  • mirror:默认模式。知识库是来源,本地生成的 10_knowledge-base/ 不应手工编辑。
  • local:只维护本地 20_本地补录/,不会被镜像同步覆盖,也不会自动上传飞书。
  • managed:未来用于明确指定的双向托管文档。必须逐文档确认写入权限、冲突规则和发布动作;当前脚本只提供只读镜像基础,不把它伪装成已经完成的双向同步。

ID 增量同步与事件推送

  • nodetoken 是同步主键,objtoken 是正文读取和事件映射的对象键;标题变化、移动和重名都不应改变这两个 ID。
  • sync.excludesubtrees 必须在私有配置中显式启用;优先按稳定 nodetoken 排除,exact_title 会排除所有精确同名根节点。同步器只在根节点的父级列表中识别它,不再枚举后代,并从正文、Sheet、Base、图片、附件、重试、活跃 manifest 和侧边栏中同时排除整棵子树。
  • 已生成的排除子树内容不会被普通增量同步静默删除;用户明确要求清理后运行 --rebuild-tree,同步器把已知成员记录为 excluded 而不是误报为远端删除,并清理、校验对应 Markdown、目录、exports/ 完整导出和 assets/ 已下载附件均不残留;20_本地补录/ 永不删除。
  • --only-node-token 是单文档修复开关;与 --rebuild-tree-only 一起使用时只从已有 manifest 定位节点,不重新遍历飞书树,也不会因为其他节点历史失败而重试它们。
  • 首次同步建立完整基线,记录 objedittime/remoteupdatedat 和 docs +fetch 返回的 revision_id。
  • 后续 --incremental 仍会先按 parentnodetoken 重建树,但只读取新增、失败、事件命中或远端编辑时间变化的文档正文;未变化节点复用本地 Markdown。
  • 兄弟节点顺序直接保留 wiki +node-list 返回的飞书顺序,不按标题重新排序;因此 VitePress/Obsidian 目录应与飞书知识库的手工排序一致。
  • 没有事件目标时,默认用 wiki +node-get 做元数据探测;这会产生较多轻量元数据请求,但避免重复下载正文。大型空间可改用官方事件订阅并传 --event-file。
  • 事件只提供“哪个对象可能变了”的提示,不能替代 Wiki 树对账;创建、删除、标题变化和未识别事件仍需重新对账节点树。
  • 官方事件订阅、权限和 drive.file. 覆盖边界见 [references/events.yml](references/events.yml)。当前 lark-cli event list 未暴露云文档 drive.file. 事件,因此本脚本不声称已经在 CLI 内常驻监听;外部长连接/webhook 适配器可以把 JSON/NDJSON 交给 --event-file。

依赖与安装

安装本技能及其同仓依赖:

claude plugin marketplace add soia-team/soia-open-skills
claude plugin install soia-cwork-office@soia

只要这一个技能时,可用 npx 路线。注意技能会落进共享真源 ~/.agents/skills;若同时装了插件,同一技能会出现两份索引且各自漂移,建议二选一:

npx skills add soia-team/soia-open-cwork-office-skills -g -a '*' -s soia-cwork-feishu-doc-git-sync -y
依赖 类型 安装 / 配置 缺失时怎么处理
soia-cwork-feishu-cli 强依赖 安装并配置飞书官方 lark-cli 应用凭证 停止,先完成 bot 登录和权限检查
lark-cli 强依赖 参见 soia-cwork-feishu-cli 的安装说明 停止并报告安装命令
Python 3.10+ 强依赖 使用系统 Python 或项目 Python 停止
PyYAML 强依赖 python3 -m pip install pyyaml 停止并报告依赖缺失
Git 可选增强 安装 Git 仍可生成本地镜像,但不能提交/推送
VitePress 可选增强 由目标文档仓库提供 仍可同步到 Obsidian
Obsidian 可选增强 用户本机安装 仍可生成普通 Markdown

私有配置默认位置:

~/.config/soia-skills/soia-cwork-feishu-doc-git-sync/config.yml

也可以使用 SOIACWORKFEISHUDOCGITSYNCCONFIG_FILE 指定配置文件。参考 [assets/config.example.yml](assets/config.example.yml)。

最小配置示例:

version: 1
provider:
  cli: lark-cli
  profile: <configured-cli-profile>
  brand: feishu
  identity: bot
space:
  id: <wiki-space-id>
  source_url_template: https://<tenant>.feishu.cn/wiki/{node_token}
paths:
  output_dir: <git-repository>/docs/feishu-knowledge
  generated_dir: 10_<knowledge-base-name>
sync:
  mode: mirror
  prune: false

权限建议:首轮只申请知识库、文档与 Sheet 只读权限。图片和附件下载是可选增强,涉及云盘/导出权限时单独申请;双向写入权限永不作为默认权限。

同步规则

  • 只使用 --as bot 的应用身份读取,默认不需要用户身份 token。
  • 通过 node token 遍历知识空间,使用文档 token 读取 docx 内容。
  • paths.generateddir 必须使用目标知识库的真实名称或稳定英文名称;例如 10后端技术支持库,不要再嵌套一个泛化的 feishu-knowledge 目录。
  • 如果已有输出目录中只有一个 10* 生成目录而配置未填写 paths.generateddir,技能会复用它;如果发现多个候选目录,会停止并要求先明确配置,避免自动制造重复目录。
  • 每个生成 Markdown 写入来源 URL、space ID、node token、object token、父节点和内容 hash。
  • 使用 sync-state.json 保留 node token 到本地路径的映射;标题变化时尽量保持稳定路径,树位置由最新 parentnodetoken 重新计算。
  • manifest.json 和 sync-state.json 记录 objedittime、remoteupdatedat、revision_id,用于增量选择和审计。
  • 本地单个路径组件最多 48 个字符;超长标题会保留完整标题在 frontmatter/侧边栏,并在文件夹或文件名中追加 node ID 短后缀,避免 Obsidian、macOS 和 VitePress/Rollup 路径过长。
  • 同步器会把飞书导出的自定义 figure/source/grid/callout、媒体 token 和 XML 片段转换为可被 Markdown/VitePress 解析的形式;这只改变本地渲染,不写回飞书。
  • 飞书文档引用会按 nodetoken 优先、objtoken 兜底解析为可点击的飞书 Wiki 链接;用户引用会保留为 @显示名。静态 Markdown 不复制飞书的悬浮卡片和成员头像交互,但不再错误降级为代码样式。
  • 有子节点的飞书节点必须生成一个同名目录,并把正文放在目录内的同名 index Markdown:父目录/节点名/节点名.md;叶子节点才直接生成 节点名.md。不要生成同级的“同名文件 + 同名文件夹”。
  • 如果飞书本身存在同名叶子与可展开节点、父子同名或同级重复可展开节点,目录/文件会追加稳定的 node ID 短后缀;这是为了避免本地文件系统发生同级冲突,manifest 仍以 node_token 区分真实节点。
  • --retry-failed 会复用已有完整正文,并把失败节点、独立 Sheet stub、未完成 XML 语义扫描的历史文档加入补偿队列;适合遇到飞书接口限流或启用新的 Sheet 策略后继续补齐。
  • 历史镜像中如果保留“当前同步器只读取文档正文”一类旧占位,即使飞书节点后来从 Sheet 变成 Docx、manifest 状态仍是 ok,验收也会判定失败,并在 --retry-failed 队列中最高优先级重拉;不能把类型漂移后的旧占位当成成功正文。
  • --retry-batch-size N 仅与 --retry-failed 配合使用,每次最多补偿 N 个失败或语义缺口节点;大型空间应重复执行,并以 --validate-only 的 failedrecords=0、unmirroredsheetnodes=0、unscannedembeddedsheetdocuments=0 为结束条件。
  • --retry-failed 使用上一次 manifest 作为节点清单,不再先对全量文档做元数据探测;启用 Sheet 全量策略时,它会优先补独立 Sheet stub 与缺少语义扫描标记的历史 Docx,再重试普通失败项,并继续受全局节流保护。大型空间配合 --retry-batch-size 重复执行,直到 unmirroredsheetnodes 与 unscannedembeddedsheet_documents 都为 0。
  • 同一输出目录同时只允许一个同步进程;如果上一轮仍在退出或用户重复启动,后续进程会停止并报告,不会并发覆盖 manifest。
  • 全局请求节流和指数退避会跨同步 worker 生效;sync.minrequestinterval_seconds 默认 0.5 秒,避免大知识库并发触发 99991400 限流。
  • 正文读取失败但本地已有旧正文时,节点会标记为 stale 并保留旧正文;下一次增量同步会继续重试,校验不会将其视为成功。
  • 每次非 dry-run 同步结束都会运行本地验收;--validate-only 可单独复核最近一次结果。验收失败时退出码为 2,并在 manifest 的 validation 节点保留机器可读摘要。
  • prune: false 时不删除已消失节点对应的本地文件;节点会在 manifest 中标记为 deleted,避免一次权限或网络异常造成数据丢失。
  • 20本地补录/ 与 90同步元数据/ 不会被知识库同步覆盖。
  • --rebuild-tree 只处理 paths.generateddir 内由同步器生成的旧扁平文件与已排除节点的已知资源,不触碰 20本地补录/。
  • --rebuild-tree-only 仅复用已有 manifest 和生成文件做目录迁移,不发起飞书正文请求;如果同时启用资源本地化,仍可能只为刷新过期媒体 URL 读取含资源的文档。
  • --refresh-tree-only 会重新读取飞书节点树和兄弟顺序,按最新 parentnodetoken 重建本地目录和侧边栏,但复用已有本地正文;启用资源本地化时,会额外刷新仍含未本地化资源的文档;必须与 --rebuild-tree 一起使用。
  • manifest.json/sync-state.json 的 treeorder: feishunode_list 表示目录顺序来源于飞书节点列表,不是标题排序。
  • 图片默认保留远程 URL;设置 sync.downloadassets: true 或传入 --download-assets 后,技能会把正文中的远程图片及 <source token="..."> 媒体块下载到 paths.generateddir/_assets/,并把 Markdown/HTML 引用改写为相对路径。已下载的飞书附件卡片必须进一步改写为标准 Markdown 本地链接;若该链接被单独的 <p> 包裹,必须同时移除该 HTML 容器,确保 Obsidian 和 VitePress 都能点击打开。未下载的卡片仍保留原远程引用并报告失败。
  • 下载资源时,优先按飞书媒体 token 去重;同一附件或图片即使带有不同的短期签名 URL,也只保留一份本地资源。无 token 的资源仍按 URL 内容寻址。
  • sync.localizeinternallinks: true 时,已同步的 Wiki/文档引用会改为相对本地 Markdown 链接;sync.rendersubpage_navigation: true 时,飞书导出的 <sub-page-list> 会改为本地 Markdown 子页面导航。两项均默认关闭,不影响已有外链行为。
  • sync.changeledger: true 时,会在同步元数据下按运行生成新增、修改、移动和远端删除的变更台账;修改项只保留受 changeledgermaxdiff_lines 限制的 diff,不复制文档全文,也不改变生成镜像或本地补录目录。
  • sheet 默认只生成元数据 stub。经用户明确授权全库有界快照后,设置 sync.sheets.enabled: true 与 allnodes: true,同步器会用 sheets +workbook-info 自动发现每个独立 Sheet 的网格子表,再按 maxrows、maxcolumns、maxcells、maxchars 上限调用 sheets +csv-get;响应截断时按 actualrange 分行续读。也可继续用 selections 精确声明单个范围。混合工作簿中的 Base 子表只有在 includebitabletabs: true 时才按 maxbitablerecords 有界读取,否则节点失败,不能静默跳过;若 Base 权限不足,已读出的普通 Sheet 仍落盘,但节点保持 failed 并写入明确缺口标记。allnodes 验收会拒绝任何 metadatastub、缺少真实表格标记的 Sheet 节点或未归档的 Base 子表。完整契约见 [references/sheet-mirroring.yml](references/sheet-mirroring.yml)。
  • 飞书 Markdown 可能只返回 <sheet> 引用而不返回任何单元格。同步器不得删除该引用后仍报告完整成功:未授权下钻时保留可见缺口并使验收失败;仅当 sync.embeddedsheets.enabled 且明确选择 alldocx: true 或 node_tokens 时,才读取文档 XML 并在配置上限内生成“嵌入式表格”快照。首次启用会补扫旧文档;快照不会伪装成交互式原表。完整范围契约见 [references/sheet-mirroring.yml](references/sheet-mirroring.yml)。
  • sync.sheets.preserve.enabled: true 会在同一选定范围另存单元格值、公式、样式、批注,以及工作表布局、图表和浮动图片元数据的 JSON 快照;可额外开启透视、筛选、条件格式和迷你图元数据。它不把图表或图片伪装成原生 Markdown。完整工作簿需在用户明确批准后同时设置 sync.sheets.workbookexports.enabled: true 和 allnodes: true,同步器会用 drive +export 分批生成 .xlsx 并在 Sheet 索引中链接。
  • 异步 Sheet 导出未在首轮轮询完成时,会把导出任务票据保存在生成目录的私有快照中;后续批次只轮询同一任务,并在就绪后使用 drive +export-download 下载,不会反复创建相同工作簿导出任务。manifest.stats.sheetworkbookspending 表示仍在飞书端处理的数量。
  • 图片/附件本地化是显式 opt-in 的本地数据下载;不能因为用户只要求“检查图片”就下载全部素材。持久化配置中的 sync.download_assets: true 只能视为用户此前对该资源范围的明确授权,不得扩展为表格或多维表格导出授权。若先执行 Sheet/Base/文件的结构初始化并使用 --skip-assets 避免输出锁冲突,必须在初始化结束后单独执行资源本地化批次;--skip-assets 不会把图片或附件标记为已下载。
  • bitable 与未授权的 sheet 默认只生成元数据 stub,不读取表内数据;已启用 sync.sheets.allnodes 的独立 Sheet 不允许继续保留 stub。设置 sync.bitables.enabled: true 后,必须逐项声明 nodetoken、tableid 与 maxrecords;同步器以 base +field-list、base +record-list 和可选的 base +view-list/base +dashboard-list/base +dashboard-block-list 生成 Markdown 与 JSON 快照。sync.bitables.downloadattachments: true 是独立的二进制下载授权,使用 base +record-download-attachment 并只处理已选表的已读记录附件。完整 Base 导出仍须在用户明确批准后同时设置 sync.bitables.baseexports.enabled: true 和 all_nodes: true,同步器用 drive +export 分批生成 .base。
  • Wiki file 节点默认只生成元数据 stub;用户明确确认完整初始化后,同时设置 sync.files.downloads.enabled: true 与 all_nodes: true,同步器才会分批调用 drive +download。文件以原始二进制保存,不会执行、挂载、解压或解析 ZIP、DMG、EXE 等格式。
  • 飞书图片 URL 可能很快过期。启用本地化并使用 --refresh-asset-urls 时,会先刷新关联文档的 URL 再下载,不会无条件重拉所有正文;下载后统一写为转义 alt 的本地 HTML <img>,并按文件二进制识别 PNG/JPEG/GIF/WebP/SVG、修正错误缓存后缀。
  • 事件目标、--changed-*-token、--only-node-token 或隔离试点只处理本轮重读文档的资源,不会把整库历史资源重新加入下载队列;完整资源回填则不传目标并按 assetbatchsize 分批执行。
  • 图片下载使用 URL 内容寻址文件名,重复同步会复用已有资源;Markdown 的普通 URL 与 (<https://…>;) 尖括号 URL 都会进入同一下载队列。可通过 assetworkers、assettimeoutseconds、assetdownloadattempts、maxassetbytes 限制并发、超时、媒体重试和单文件大小;单资源默认上限为 50 MiB,可在私有配置中按已确认的下载范围调低或调高。携带飞书媒体 token 的附件遇到短暂或未归类 CLI 失败时会在上限内重试;明确的权限不足、资源不存在或 assettoolarge 不会盲目重试。大型存量镜像可设置正整数 assetbatchsize:每次只请求该数量的尚未落盘资源,已下载资源仍会被本地化改写;assetrefreshedbatchsize 可限制同一批已刷新文档的新链接下载量。重复执行并以 --validate-only 确认完成。manifest 会报告本轮 assetsdeferred。下载失败只保留原 URL,并在 manifest 的 assetsfailed 计数中报告,不把鉴权 URL 写入日志或清单。
  • <source token="..."> 或无 URL 的 <img token="..."> 会调用官方 docs +media-download;远程 URL 不可直接读取时,需要按权限清单补充 docs:document.media:download 或 drive:file:download,并在私有配置中启用本地资源下载。没有下载权限时不得猜测本地资源已经完整。

安全规则

  • 不在公开 skill、Obsidian vault、Markdown、Git 提交、终端输出或最终回复中写入 App Secret、access token、cookie。
  • 终端日志、进度回执和最终回复不得输出本地绝对路径、具体本地文件名、操作系统用户名、用户名、密码、App Secret、access token 或私有下载 URL;统一使用脱敏占位符,只报告状态、数量和错误类别。详见 [references/output-redaction.yml](references/output-redaction.yml)。
  • 不默认调用飞书创建、更新、删除接口。
  • drive +export、drive +export-download、docs +media-download 和附件下载均属于数据导出/下载动作;用户说“看下能否导出”时只做 inspect、help、schema 或 dry-run,不得直接创建本地文件。
  • Sheet 与 Base 值镜像都属于敏感数据落盘:只有用户明确确认需要将选定范围/表同步到本地工作区,并在私有配置中写入有界 sync.sheets.selections 或受限 sync.bitables.selections 后才可启用;该确认不授权任何工作簿导出、未选附件下载或自动 Git 提交。
  • 真实导出前必须明确回执来源、类型、格式、预计文件数、输出目录和 Git 追踪策略;“检查能力”不等于“授权导出”。
  • 导出文件默认放在临时目录或用户明确指定的目录;只有经用户明确确认的完整镜像初始化才能写入生成目录下的 exports/ 或 assets/,并且不得自动提交 Git、自动推送远程或写回飞书。
  • bot 无权访问的个人云盘或私有资源必须报告为不可见,不得切换 user OAuth 代为读取。
  • 不默认覆盖本地补录、删除历史文件或推送远程 Git;这些属于需要明确确认的写入/发布动作。
  • 执行前检查目标仓库、当前分支和远程地址;发现与预期不符时停止并报告。

私密信息与中间数据

  • 把排除节点 ID、知识空间 ID、凭据别名和本地输出位置只写入技能私有配置,不提交公共仓库。
  • 把 active/excluded 节点清单、同步状态、侧边栏和变更台账保存在用户指定镜像的同步元数据目录;排除记录只用于证明未抓取范围,不包含正文。
  • 把临时下载和接口中间结果交给系统临时目录;只把用户授权的 Markdown、表格快照和资源文件写入交付目录。

日志与完成回执

终端和最终回复至少报告:

  • started:空间、身份、配置来源和目标目录(不打印秘密)。
  • processed:节点、文档、跳过和失败数量。
  • created/updated:生成或更新的 Markdown、manifest、sidebar 数量。
  • skipped/failed:失败节点、原因和是否可重试。
  • verification:Git diff、VitePress build、抽样文档和源链接检查结果。
  • next_step:是否需要补权限、确认 Git push 或规划双向同步。
  • 文件变化只报告数量和类别,不列本地路径或文件名;身份只报告 bot identity / user identity 等非敏感状态。

Resources

  • 权限与权限申请分层:[references/permissions.yml](references/permissions.yml)
  • 飞书 CLI 命令与权限申请流程:同仓库 soia-cwork-feishu-cli/references/cli-workflows.md 和 soia-cwork-feishu-cli/references/permissions.md。
  • 事件订阅与增量目标:[references/events.yml](references/events.yml)
  • 同步策略:[references/sync-policy.yml](references/sync-policy.yml)
  • 文档格式转换:[references/block-mapping.yml](references/block-mapping.yml)
  • Sheet 范围镜像:[references/sheet-mirroring.yml](references/sheet-mirroring.yml)
  • 富资源镜像能力与边界:[references/rich-resource-mirroring.yml](references/rich-resource-mirroring.yml)
  • 表格/多维表格导出安全策略:[references/export-policy.yml](references/export-policy.yml)
  • 日志与回复脱敏策略:[references/output-redaction.yml](references/output-redaction.yml)
  • Git 与 VitePress 接入:[references/git-vitepress.yml](references/git-vitepress.yml)
  • 私有配置模板:[assets/config.example.yml](assets/config.example.yml)

Validation

python3 scripts/sync_feishu_wiki.py --help
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --dry-run
python3 scripts/sync_feishu_wiki.py --config <private-config.yml> --validate-only
git diff --check

Forward test

Before a real sync, run a dry-run or a small authorized representative scope and verify the tree, stable node-ID mapping, ordering, incremental selection, asset references, and failure receipt. After every write, require the built-in validation gate to pass; a zero exit code alone is not evidence that the mirror is complete.