语雀 Lakebook 导出 将一个或多个语雀 文件导出为本地 Markdown 目录,并优先适配 Obsidian。 何时使用 当用户需要以下能力时使用本技能: - 导出一个或多个语雀 - 将语雀知识库转换为 Markdown - 将语雀内容迁移到 Obsidian - 修复语雀导出后的图片、裁剪图、内部链接、目录层级、表格渲染问题 不要使用 不要将本技能用于: - 与语雀或 无关的普通 Markdown 编辑 - 网页抓取任务 - 非语雀来源的导出转换任务 使用说明 1. 优先使用非交互模式,便于 Agent 稳定执行。 2. Agent 在执行任何非交互导出前,必须先向用户确认输出根目录,不能自行决定输出目录。 3. 如果用户还没有明确给出输出目录,就先用一句简短问题询问,等用户答复后再执行导出。 4. 统一优先使用 ,不要在任务目录里临时创建 、 这类环境。 5. 在执行任何 命令前,先检查当前环境是否可用 。 6. 如果 未安装,或者不在 中,Agent 必须先征求用户确认是否安装 ,不能直接静默安装。 7. 在执行 或 前,必须先切换到当前已安装 skill 的工具目录,也就是包含本 、 、 和 的那个目录。不要在 所在目录、目标输出目录、或用户当前工作区根目录直接执行这些命令。 8. Agent 执行时使用下面这个入口: 9. 首次使用前同步依赖: 10. 推荐执行…

)\nTABLE_ROW_RE = re.compile(r'^\\s*\\|.*\\|\\s*

语雀 Lakebook 导出 将一个或多个语雀 文件导出为本地 Markdown 目录,并优先适配 Obsidian。 何时使用 当用户需要以下能力时使用本技能: - 导出一个或多个语雀 - 将语雀知识库转换为 Markdown - 将语雀内容迁移到 Obsidian - 修复语雀导出后的图片、裁剪图、内部链接、目录层级、表格渲染问题 不要使用 不要将本技能用于: - 与语雀或 无关的普通 Markdown 编辑 - 网页抓取任务 - 非语雀来源的导出转换任务 使用说明 1. 优先使用非交互模式,便于 Agent 稳定执行。 2. Agent 在执行任何非交互导出前,必须先向用户确认输出根目录,不能自行决定输出目录。 3. 如果用户还没有明确给出输出目录,就先用一句简短问题询问,等用户答复后再执行导出。 4. 统一优先使用 ,不要在任务目录里临时创建 、 这类环境。 5. 在执行任何 命令前,先检查当前环境是否可用 。 6. 如果 未安装,或者不在 中,Agent 必须先征求用户确认是否安装 ,不能直接静默安装。 7. 在执行 或 前,必须先切换到当前已安装 skill 的工具目录,也就是包含本 、 、 和 的那个目录。不要在 所在目录、目标输出目录、或用户当前工作区根目录直接执行这些命令。 8. Agent 执行时使用下面这个入口: 9. 首次使用前同步依赖: 10. 推荐执行…

)\nLIST_RE = re.compile(r'^\\s*(?:[-+*]|\\d+\\.)\\s+')\nLAKE_DOCTYPE_RE = re.compile(r'^\\ufeff?(?:\u003c!doctype\\s+lake>\\s*)?', re.IGNORECASE)\n\n\ndef strip_lake_prefix_artifact(text):\n normalized = text.lstrip(\"\\ufeff\")\n normalized = LAKE_DOCTYPE_RE.sub(\"\", normalized, count=1)\n if not normalized[:4].lower() == \"lake\":\n return normalized\n\n remainder = normalized[4:]\n stripped_remainder = remainder.lstrip()\n if not stripped_remainder:\n return \"\"\n\n marker = stripped_remainder[0]\n if (\n marker.isupper()\n or not marker.isascii()\n or marker in {\"!\", \"#\", \"*\", \"-\", \"_\", \"`\", \"~\", \">\", \"[\", \"(\", \"{\", \"|\", \":\"}\n ):\n return stripped_remainder\n\n return normalized\n\n\ndef normalize_markdown(text):\n \"\"\"\n 统一整理块级元素之间的空行,提升 Obsidian 等 Markdown 渲染兼容性。\n \"\"\"\n text = strip_lake_prefix_artifact(text)\n lines = text.splitlines()\n if not lines:\n return text\n\n normalized = []\n in_fence = False\n\n def is_blank(value):\n return value.strip() == \"\"\n\n def is_fence(value):\n stripped = value.strip()\n return stripped.startswith(\"```\") or stripped.startswith(\"~~~\")\n\n def is_heading(value):\n return bool(HEADING_RE.match(value))\n\n def is_hr(value):\n return bool(HR_RE.match(value))\n\n def is_table_row(value):\n return bool(TABLE_ROW_RE.match(value))\n\n def previous_nonblank():\n for item in reversed(normalized):\n if not is_blank(item):\n return item\n return None\n\n for index, line in enumerate(lines):\n stripped = line.rstrip()\n next_line = lines[index + 1] if index + 1 \u003c len(lines) else \"\"\n prev = previous_nonblank()\n current_is_fence = is_fence(stripped)\n current_is_heading = is_heading(stripped)\n current_is_hr = is_hr(stripped)\n current_is_table = is_table_row(stripped)\n next_is_table = is_table_row(next_line)\n\n if not in_fence:\n should_prepend_blank = False\n if current_is_heading or current_is_hr or current_is_fence:\n should_prepend_blank = prev is not None\n elif current_is_table and prev is not None and not is_table_row(prev):\n should_prepend_blank = True\n\n if should_prepend_blank and normalized and not is_blank(normalized[-1]):\n normalized.append(\"\")\n\n normalized.append(stripped)\n\n if current_is_fence:\n in_fence = not in_fence\n if not in_fence and next_line and next_line.strip() and not is_blank(next_line):\n if not is_blank(normalized[-1]):\n normalized.append(\"\")\n continue\n\n if in_fence:\n continue\n\n if current_is_table and not next_is_table:\n if next_line and next_line.strip():\n normalized.append(\"\")\n elif (current_is_heading or current_is_hr) and next_line and next_line.strip():\n normalized.append(\"\")\n\n collapsed = []\n blank_count = 0\n for line in normalized:\n if is_blank(line):\n blank_count += 1\n if blank_count > 1:\n continue\n else:\n blank_count = 0\n collapsed.append(line)\n\n result = \"\\n\".join(collapsed).strip() + \"\\n\"\n return result\n\n\n# from lxml import etree\ndef load_meta_json(global_context: GlobalContext):\n \"\"\"\n 解析meta.json中标注的文件关系\n :return:\n \"\"\"\n full_path = \"/\".join([global_context.root_path, \"$meta.json\"])\n fp = open(full_path, 'r', encoding='utf-8')\n json_obj = json.load(fp)\n meta = json_obj['meta']\n # print(meta)\n meta_obj = json.loads(meta)\n book_yml = meta_obj['book']['tocYml']\n # print(book_yml)\n # with open('meta_book_yml.yaml', 'w+', encoding='utf-8') as yaml_fp:\n # yaml_fp.write(book_yml)\n # yaml_fp.flush()\n books = yaml.load(book_yml, yaml.Loader)\n for book in books:\n if book.get('uuid'):\n global_context.id_and_book[book['uuid']] = book\n if book['type'] == 'META':\n continue\n if book['parent_uuid'] == '':\n global_context.root_books.append(book)\n continue\n parent_uuid = book['parent_uuid']\n if global_context.parent_id_and_child.get(parent_uuid):\n global_context.parent_id_and_child[parent_uuid].append(book)\n else:\n global_context.parent_id_and_child[parent_uuid] = []\n global_context.parent_id_and_child[parent_uuid].append(book)\n # print(books)\n global_context.file_total = len(global_context.id_and_book)\n global_context.total = len(global_context.id_and_book)\n\n\ndef create_tree_dir(global_context, parent_dir, book):\n \"\"\"\n 根据解析出的关系创建文档的目录树\n :param parent_dir: 当前文档所在的父目录\n :param book: 当前book对象\n :param global_context 上下文\n :return:\n \"\"\"\n if book is None:\n return\n uuid = book['uuid']\n name = sanitize_path_segment(book['title'])\n file_url = book['url']\n book_children = global_context.parent_id_and_child.get(uuid)\n has_children = bool(book_children)\n current_dir = parent_dir\n\n if has_children or file_url == '':\n current_dir = remove_invalid_characters(os.path.join(parent_dir, name))\n if not os.path.exists(current_dir):\n os.makedirs(current_dir, exist_ok=True)\n\n global_context.all_file_count += 1\n if file_url != '':\n ltm = LakeToMd(\n os.path.join(global_context.root_path, \"{}.json\".format(file_url)),\n target=os.path.join(current_dir if has_children else parent_dir, name)\n )\n ltm.to_md(global_context)\n global_context.failure_image_download_list += ltm.image_download_failure\n global_context.file_count += 1\n # print(\"\\r\", end=\"\")\n # i = (file_count // file_total) * 100\n print(\"\\rprocess progress: {}/{}/{}. \".format(global_context.file_count, global_context.all_file_count,\n global_context.file_total), end=\"\")\n # sys.stdout.flush()\n # time.sleep(0.05)\n if not book_children:\n return\n for child in book_children:\n create_tree_dir(global_context, current_dir, child)\n\n\ndef register_doc_paths(global_context, parent_dir, book):\n \"\"\"\n 预先计算所有导出 markdown 路径,供内部文档链接转相对路径使用。\n \"\"\"\n if book is None:\n return\n uuid = book['uuid']\n name = sanitize_path_segment(book['title'])\n file_url = book['url']\n book_children = global_context.parent_id_and_child.get(uuid)\n has_children = bool(book_children)\n current_dir = parent_dir\n\n if has_children or file_url == '':\n current_dir = remove_invalid_characters(os.path.join(parent_dir, name))\n\n if file_url != '':\n target_base = os.path.join(current_dir if has_children else parent_dir, name)\n target_md_path = remove_invalid_characters(target_base) + \".md\"\n global_context.doc_path_map[uuid] = target_md_path\n global_context.doc_path_map[file_url] = target_md_path\n if book.get('doc_id') is not None:\n global_context.doc_path_map[str(book['doc_id'])] = target_md_path\n\n if not book_children:\n return\n for child in book_children:\n register_doc_paths(global_context, current_dir, child)\n\n\nclass LakeToMd:\n body_html = None\n image_download_failure = []\n\n def __init__(self, filename, target):\n self.filename = filename\n self.target = target\n self.__body_html()\n\n def __body_html(self):\n fp = open(file=self.filename, mode='r', encoding='utf-8')\n file_json = json.load(fp)\n fp.close()\n self.body_html = self._extract_body(file_json)\n\n @staticmethod\n def _extract_body(file_json):\n doc_json = file_json.get(\"doc\") or {}\n body_fields = (\n \"body_draft_asl\",\n \"body_asl\",\n \"body_draft\",\n \"body\",\n )\n for field in body_fields:\n body = doc_json.get(field)\n if isinstance(body, str) and body.strip():\n return LakeToMd._normalize_body(body)\n return \"\"\n\n @staticmethod\n def _normalize_body(body):\n \"\"\"\n 某些 lakebook 文档正文会把语雀 Lake 格式标记残留在开头,例如 `lake\u003ch2>...`。\n 这里在保留原有 ASL/Lake 解析能力的前提下,去掉这个误前缀,避免导出 `lake##`。\n \"\"\"\n return strip_lake_prefix_artifact(body)\n\n def to_md(self, global_context):\n mp = MyParser(self.body_html)\n name = os.path.basename(self.target)\n short_target = os.path.dirname(self.target)\n current_file_path = remove_invalid_characters(self.target) + \".md\"\n if short_target and not os.path.exists(short_target):\n os.makedirs(short_target, exist_ok=True)\n context = MyContext(\n filename=name,\n image_target=short_target,\n download_image=global_context.download_image,\n skip_existing=global_context.skip_existing,\n current_file_path=current_file_path,\n doc_path_map=global_context.doc_path_map\n )\n res = mp.handle_descent(mp.soup, context)\n res = normalize_markdown(res)\n self.image_download_failure += context.failure_images\n self.target = remove_invalid_characters(self.target)\n if not res.strip():\n print(f\"\\n警告: 文档导出结果为空 -> {self.filename}\")\n with open(self.target + \".md\", 'w+', encoding='utf-8') as fp:\n fp.writelines(res)\n fp.flush()\n\n\ndef convert_to_md(global_context, file_path, open_output=False):\n output_path = file_path\n if not os.path.exists(output_path):\n os.makedirs(output_path, exist_ok=True)\n global_context.doc_path_map = {}\n for root_book in global_context.root_books:\n register_doc_paths(global_context, output_path, root_book)\n for root_book in global_context.root_books:\n create_tree_dir(global_context, output_path, root_book)\n print(\"\\n>>> markdown 转换完成\")\n if open_output:\n # 根据操作系统选择合适的命令打开文件夹\n import platform\n system = platform.system()\n if system == 'Windows':\n os.system(\"explorer \" + output_path)\n elif system == 'Darwin': # macOS\n os.system(\"open \" + output_path)\n elif system == 'Linux':\n os.system(\"xdg-open \" + output_path)\n else:\n print(\"未识别的操作系统,无法自动打开输出文件夹\")\n\n\ndef start_convert(meta, lake_book, output, download_image_of_in, skip_existing=False, open_output=False):\n global_context = GlobalContext()\n temp_dir = tempfile.mkdtemp(prefix=\"yuque_export_\")\n result = {\n \"success\": False,\n \"file_count\": 0,\n \"output\": os.path.abspath(output) if output else output,\n \"error\": None,\n \"failure_images\": []\n }\n if lake_book:\n global_context.root_path = unpack_lake_book_file(lake_book, temp_dir)\n print(\">>> lake文件抽取完成\")\n else:\n global_context.root_path = meta\n if not global_context.root_path:\n print(\"参数校验失败!-i或者-l二者必须有一个\")\n result[\"error\"] = \"参数校验失败!-i或者-l二者必须有一个\"\n return result\n try:\n load_meta_json(global_context)\n print(\">>> meta json解析完成\")\n global_context.download_image = download_image_of_in\n global_context.skip_existing = skip_existing\n abspath = os.path.abspath(output)\n print(\">>> 开始进行markdown转换\")\n convert_to_md(global_context, abspath, open_output=open_output)\n print(\"共导出%s个文件\" % global_context.file_count)\n\n print(\"图片下载错误列表:\")\n print(' list: ', global_context.failure_image_download_list)\n print(' count:', len(global_context.failure_image_download_list))\n result[\"success\"] = True\n result[\"file_count\"] = global_context.file_count\n result[\"failure_images\"] = list(global_context.failure_image_download_list)\n if os.path.exists(temp_dir):\n shutil.rmtree(temp_dir)\n except Exception as e:\n if os.path.exists(temp_dir):\n shutil.rmtree(temp_dir)\n print(e)\n result[\"error\"] = str(e)\n result[\"traceback\"] = traceback.format_exc()\n return result\n# \"\"\"\n# 已经完成到根据meta生成目录了\n# \"\"\"\n# if __name__ == '__main__':\n# load_meta_json('data/$.meta.json')\n# file_total = len(id_and_book)\n# total = len(id_and_book)\n# abspath = os.path.abspath(\"test\")\n# convert_to_md(abspath)\n# print(\"共导出%s个文件\" % file_count)\n#\n# print(\"图片下载错误列表:\")\n# print(failure_image_download_list)\n# parse_failure_result(failure_image_download_list)\n","content_type":"text/x-python; charset=utf-8","language":"python","size":14044,"content_sha256":"ec889f3bd40caefc8522fa40602ba4973f9b2b6e91609817c5098f3b0f29b8af"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"语雀 Lakebook 导出","type":"text"}]},{"type":"paragraph","content":[{"text":"将一个或多个语雀 ","type":"text"},{"text":".lakebook","type":"text","marks":[{"type":"code_inline"}]},{"text":" 文件导出为本地 Markdown 目录,并优先适配 Obsidian。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"何时使用","type":"text"}]},{"type":"paragraph","content":[{"text":"当用户需要以下能力时使用本技能:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"导出一个或多个语雀 ","type":"text"},{"text":".lakebook","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"将语雀知识库转换为 Markdown","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"将语雀内容迁移到 Obsidian","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"修复语雀导出后的图片、裁剪图、内部链接、目录层级、表格渲染问题","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"不要使用","type":"text"}]},{"type":"paragraph","content":[{"text":"不要将本技能用于:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"与语雀或 ","type":"text"},{"text":".lakebook","type":"text","marks":[{"type":"code_inline"}]},{"text":" 无关的普通 Markdown 编辑","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"网页抓取任务","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"非语雀来源的导出转换任务","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"使用说明","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"优先使用非交互模式,便于 Agent 稳定执行。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Agent 在执行任何非交互导出前,必须先向用户确认输出根目录,不能自行决定输出目录。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果用户还没有明确给出输出目录,就先用一句简短问题询问,等用户答复后再执行导出。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"统一优先使用 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":",不要在任务目录里临时创建 ","type":"text"},{"text":".venv","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":".yuque-export-venv","type":"text","marks":[{"type":"code_inline"}]},{"text":" 这类环境。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"在执行任何 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":" 命令前,先检查当前环境是否可用 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":" 未安装,或者不在 ","type":"text"},{"text":"PATH","type":"text","marks":[{"type":"code_inline"}]},{"text":" 中,Agent 必须先征求用户确认是否安装 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":",不能直接静默安装。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"在执行 ","type":"text"},{"text":"uv sync","type":"text","marks":[{"type":"code_inline"}]},{"text":" 或 ","type":"text"},{"text":"uv run python scripts/cli.py ...","type":"text","marks":[{"type":"code_inline"}]},{"text":" 前,必须先切换到当前已安装 skill 的工具目录,也就是包含本 ","type":"text"},{"text":"SKILL.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"pyproject.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":"、","type":"text"},{"text":"uv.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"scripts/","type":"text","marks":[{"type":"code_inline"}]},{"text":" 的那个目录。不要在 ","type":"text"},{"text":".lakebook","type":"text","marks":[{"type":"code_inline"}]},{"text":" 所在目录、目标输出目录、或用户当前工作区根目录直接执行这些命令。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Agent 执行时使用下面这个入口:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv run python scripts/cli.py","type":"text"}]},{"type":"ordered_list","attrs":{"order":9,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"首次使用前同步依赖:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv sync","type":"text"}]},{"type":"ordered_list","attrs":{"order":10,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"推荐执行顺序:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cd /path/to/installed-skill-root\nuv sync\nuv run python scripts/cli.py ...","type":"text"}]},{"type":"ordered_list","attrs":{"order":11,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"单文件执行:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv run python scripts/cli.py -l \"/path/to/your_file.lakebook\" -o \"/target/root\"","type":"text"}]},{"type":"ordered_list","attrs":{"order":12,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"批量执行:","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv run python scripts/cli.py -l \"/path/to/your_file_1.lakebook\" \"/path/to/your_file_2.lakebook\" -o \"/target/root\"","type":"text"}]},{"type":"ordered_list","attrs":{"order":13,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"虽然 ","type":"text"},{"text":"scripts/cli.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" 仍然保留了给人类终端手工使用的交互选择能力,但 Agent 不应依赖交互模式,因为无法稳定获取终端交互状态。执行时始终显式传入 ","type":"text"},{"text":"-l","type":"text","marks":[{"type":"code_inline"}]},{"text":" 和 ","type":"text"},{"text":"-o","type":"text","marks":[{"type":"code_inline"}]},{"text":" 参数。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"不要在当前工作目录、用户下载目录、或任意任务目录里手动创建临时虚拟环境;依赖应由 skill 工具目录中的 ","type":"text"},{"text":"uv","type":"text","marks":[{"type":"code_inline"}]},{"text":" 环境统一管理。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"已知有些语雀导出的文档正文会包含 ","type":"text"},{"text":"\u003c!doctype lake>","type":"text","marks":[{"type":"code_inline"}]},{"text":",旧实现可能导出成 ","type":"text"},{"text":"lake## 标题","type":"text","marks":[{"type":"code_inline"}]},{"text":";当前技能内置实现已经处理这个问题。","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"导出完成后检查:","type":"text"}]}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":".md","type":"text","marks":[{"type":"code_inline"}]},{"text":" 文件是否生成","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"同名 ","type":"text"},{"text":".assets","type":"text","marks":[{"type":"code_inline"}]},{"text":" 目录是否生成","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"内部链接是否转为相对 Markdown 路径","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"图片是否能在 Obsidian 中正常显示","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"文档首行是否存在异常的 ","type":"text"},{"text":"lake##","type":"text","marks":[{"type":"code_inline"}]},{"text":" 前缀","type":"text"}]}]}]},{"type":"ordered_list","attrs":{"order":17,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"如果导出失败,优先查看输入 ","type":"text"},{"text":".lakebook","type":"text","marks":[{"type":"code_inline"}]},{"text":" 同目录下生成的批量日志。","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"详细行为、输出规则和排查说明见 ","type":"text"},{"text":"references/usage.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"。","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"yuque-lakebook-export-cn","author":"@skillopedia","source":{"stars":9,"repo_name":"awesome-agent-skills","origin_url":"https://github.com/yangsonhung/awesome-agent-skills/blob/HEAD/skills/zh-cn/yuque-lakebook-export-cn/SKILL.md","repo_owner":"yangsonhung","body_sha256":"21936a28efcdbe5f770d2d8ba58fc2a1702fa8dc2f9b6c7c1a106e5141d6509c","cluster_key":"9846c2ae85c4b9cfd833ed63a14ad89ddfcb062d8c5aca322d3d81edde5ee1c9","clean_bundle":{"format":"clean-skill-bundle-v1","source":"yangsonhung/awesome-agent-skills/skills/zh-cn/yuque-lakebook-export-cn/SKILL.md","attachments":[{"id":"264d8d15-f468-566b-bb1e-a728f7bcf552","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/264d8d15-f468-566b-bb1e-a728f7bcf552/attachment.toml","path":"pyproject.toml","size":247,"sha256":"01d2e4e3929e476e5cd74fae56b8786de7e200a7a9294ec6d17ae37f9112d91f","contentType":"text/plain; charset=utf-8"},{"id":"9112fbf6-7344-50b2-b9f5-61104ff6c2d6","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9112fbf6-7344-50b2-b9f5-61104ff6c2d6/attachment.md","path":"references/usage.md","size":1439,"sha256":"583be36880f3aea28868d3cfed91937c5bd7fd58985ef9abfcd27a288212f3f9","contentType":"text/markdown; charset=utf-8"},{"id":"0fd37fc5-d9b6-500d-8e56-80a2489efbaa","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0fd37fc5-d9b6-500d-8e56-80a2489efbaa/attachment.py","path":"scripts/cli.py","size":15250,"sha256":"7687ddc6748c1d359b146100de5cbf1934a5d8e3f3e52b58099985a04c155508","contentType":"text/x-python; charset=utf-8"},{"id":"3058fcdb-2e09-5461-918a-e450a2078925","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3058fcdb-2e09-5461-918a-e450a2078925/attachment.py","path":"scripts/yuque_lakebook_export/__init__.py","size":66,"sha256":"44f870e87b5edda8f3bfd8c2a03bddf034ae45e6aeaaecbde0f602bf9bfdc155","contentType":"text/x-python; charset=utf-8"},{"id":"0e832a43-b680-5ebe-84db-8c13b75ad1d8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0e832a43-b680-5ebe-84db-8c13b75ad1d8/attachment.py","path":"scripts/yuque_lakebook_export/lake_handle.py","size":21789,"sha256":"9c2ca1f6b285754215104286c192947fb6af3caf660d5ed3767947f21da571c2","contentType":"text/x-python; charset=utf-8"},{"id":"30a2e561-5158-5e39-8106-79868ebc91de","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/30a2e561-5158-5e39-8106-79868ebc91de/attachment.py","path":"scripts/yuque_lakebook_export/lake_reader.py","size":1139,"sha256":"66958bf86b0832bfa3def86706fd9ef29b0dd285ec0b7fc2a37a9e94118c8055","contentType":"text/x-python; charset=utf-8"},{"id":"608ae8d1-83ed-58c8-b6da-e100da0f1f0a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/608ae8d1-83ed-58c8-b6da-e100da0f1f0a/attachment.py","path":"scripts/yuque_lakebook_export/lake_setup.py","size":14044,"sha256":"ec889f3bd40caefc8522fa40602ba4973f9b2b6e91609817c5098f3b0f29b8af","contentType":"text/x-python; charset=utf-8"},{"id":"b38e942f-d9f8-54b9-b287-88f876f01990","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b38e942f-d9f8-54b9-b287-88f876f01990/attachment.lock","path":"uv.lock","size":22048,"sha256":"1b38105443cb844b94334dd23a9b1cffe556be8ef2d6656e87e977578409074d","contentType":"text/plain; charset=utf-8"}],"bundle_sha256":"371feccefca3d728ada5df34b9d05b4d6a0158c31801e8f2ba6f382cba7cb389","attachment_count":8,"text_attachments":8,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/zh-cn/yuque-lakebook-export-cn/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"general","category_label":"General"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"general","import_tag":"clean-skills-v1","description":"将语雀知识库、语雀文档或 .lakebook 文件导出并转换为本地 Markdown 目录,适配 Obsidian 使用。适用于导出语雀、把 lakebook 转成 Markdown、迁移语雀知识库到 Obsidian、批量转换多个 .lakebook、处理语雀导出后的图片与附件、裁剪图片、内部文档链接、目录结构、Markdown 表格渲染等问题。当用户提到 语雀、lakebook、导出 Markdown、导入 Obsidian、知识库迁移、批量转换、图片不显示、链接丢失、裁剪失效、目录层级不对、表格显示异常 等场景时触发。"}},"renderedAt":1782981711622}

语雀 Lakebook 导出 将一个或多个语雀 文件导出为本地 Markdown 目录,并优先适配 Obsidian。 何时使用 当用户需要以下能力时使用本技能: - 导出一个或多个语雀 - 将语雀知识库转换为 Markdown - 将语雀内容迁移到 Obsidian - 修复语雀导出后的图片、裁剪图、内部链接、目录层级、表格渲染问题 不要使用 不要将本技能用于: - 与语雀或 无关的普通 Markdown 编辑 - 网页抓取任务 - 非语雀来源的导出转换任务 使用说明 1. 优先使用非交互模式,便于 Agent 稳定执行。 2. Agent 在执行任何非交互导出前,必须先向用户确认输出根目录,不能自行决定输出目录。 3. 如果用户还没有明确给出输出目录,就先用一句简短问题询问,等用户答复后再执行导出。 4. 统一优先使用 ,不要在任务目录里临时创建 、 这类环境。 5. 在执行任何 命令前,先检查当前环境是否可用 。 6. 如果 未安装,或者不在 中,Agent 必须先征求用户确认是否安装 ,不能直接静默安装。 7. 在执行 或 前,必须先切换到当前已安装 skill 的工具目录,也就是包含本 、 、 和 的那个目录。不要在 所在目录、目标输出目录、或用户当前工作区根目录直接执行这些命令。 8. Agent 执行时使用下面这个入口: 9. 首次使用前同步依赖: 10. 推荐执行…