diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index 983ffb5382bd4c8495517ba4c2adb9841a93bf8c..2c6b29d9d8a4eb7f4a3be367c4a3c545d2a8ef6e 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -120,6 +120,10 @@ const zhLocaleThemeConfig = {
text: "专题",
items: [
{ text: "免密登录", link: "/advanced-inject-passwordless-login.md" },
+ {
+ text: "懒猫网盘打开与保存选择器",
+ link: "/advanced-lazycat-drive-open-save-chooser.md",
+ },
{ text: "Skill / MCP 规范", link: "/resource-skill-mcp.md" },
],
},
diff --git a/docs/advanced-lazycat-drive-open-save-chooser.md b/docs/advanced-lazycat-drive-open-save-chooser.md
new file mode 100644
index 0000000000000000000000000000000000000000..d9a11c7855ad64b29a45fae81da8a8242681ef83
--- /dev/null
+++ b/docs/advanced-lazycat-drive-open-save-chooser.md
@@ -0,0 +1,188 @@
+# 懒猫网盘打开与保存选择器
+
+## 目标
+
+本文完成后,你可以在不修改上游前端源码的前提下,为第三方 Web 应用接入懒猫网盘的打开、保存、上传和下载能力。
+
+适合的场景:
+
+1. 应用已经使用浏览器文件 API,例如 `showOpenFilePicker()`、`showSaveFilePicker()` 或 ``。
+2. 应用是第三方容器镜像,不方便重新编译前端。
+3. 希望用户在“本地文件”和“懒猫网盘文件”之间选择。
+
+不适合的场景:
+
+1. 应用完全通过后端 API 管理文件,前端不触发浏览器文件选择能力。
+2. 应用需要服务端直接读写用户网盘目录。此时应优先阅读 [文件访问](./advanced-file.md)。
+
+## 前置条件
+
+1. lzcos 版本满足 inject 功能要求。
+2. 已阅读 [脚本注入(injects)](./advanced-injects.md) 和 [manifest inject 规范](./spec/manifest.md#injects)。
+3. 已掌握 `lzc-build.yml` 的 `contentdir` 字段(见 [lzc-build.yml 规范](./spec/build.md))。
+
+## 示例脚本
+
+本文不在文档站内维护脚本副本。请直接参考已适配应用的 `lazycat-injects` 目录:
+
+- [Excalidraw lazycat-injects](https://gitee.com/lazycatcloud/excalidraw/tree/master/lazycat-injects)
+
+这个目录同时可以作为参考脚本来源和适配应用参考,主要包含:
+
+- `open-save-chooser.js`
+- `vendor/lzc-file-pickers.umd.js`
+- `README.md`
+
+将脚本复制到目标 LPK 项目后,保持以下目录结构:
+
+```text
+content/
+ lazycat-injects/
+ open-save-chooser.js
+ vendor/
+ lzc-file-pickers.umd.js
+```
+
+## 核心思路
+
+通过 browser inject 向目标页面注入两类脚本:
+
+1. `lzc-file-pickers.umd.js`:注册 `` 自定义元素,用来打开懒猫文件选择器。
+2. `open-save-chooser.js`:桥接浏览器文件 API 和懒猫网盘 HTTP 文件接口。
+
+桥接脚本通常处理这些能力:
+
+- `window.showOpenFilePicker()`
+- `window.showSaveFilePicker()`
+- ``
+- 部分 `blob:` 下载链接
+
+## 步骤一:打包注入脚本 {#package-inject-scripts}
+
+目录结构:
+
+```text
+content/
+ lazycat-injects/
+ open-save-chooser.js
+ vendor/
+ lzc-file-pickers.umd.js
+```
+
+`content` 目录需要通过 `lzc-build.yml` 打进 LPK:
+
+```yml
+pkgout: ./
+icon: ./icon.png
+manifest: ./lzc-manifest.yml
+contentdir: ./content
+```
+
+打包后,运行时路径会对应到:
+
+```text
+/lzcapp/pkg/content/lazycat-injects/open-save-chooser.js
+/lzcapp/pkg/content/lazycat-injects/vendor/lzc-file-pickers.umd.js
+```
+
+## 步骤二:在 manifest 中注入 {#inject-in-manifest}
+
+以下仅展示 `lzc-manifest.yml` 中和注入相关的配置:
+
+```yml
+application:
+ injects:
+ - id: open-save-chooser
+ on: browser
+ when:
+ - /*
+ do:
+ - src: file:///lzcapp/pkg/content/lazycat-injects/vendor/lzc-file-pickers.umd.js
+ - src: file:///lzcapp/pkg/content/lazycat-injects/open-save-chooser.js
+```
+
+注意:
+
+1. 顺序不能反。必须先注入 `lzc-file-pickers.umd.js`,再注入 `open-save-chooser.js`。
+2. 正式发布建议使用 `file://` 加载随 LPK 分发的脚本,不建议依赖远程脚本。
+3. `when` 应尽量收窄到需要文件能力的页面。如果应用只有一个入口,可以使用 `/*`。
+
+## `open-save-chooser.js` 的关键配置 {#script-config}
+
+桥接脚本顶部有集中配置:
+
+```js
+const CONFIG = {
+ diskRoot: "/_lzc/files/home",
+ pickerTag: "lzc-file-picker",
+ fallbackMime: "application/octet-stream",
+ hooks: {
+ fileSystemAccess: true,
+ fileInput: true,
+ },
+};
+```
+
+字段说明:
+
+- `diskRoot`:懒猫网盘 HTTP 文件接口根路径。常见值是 `/_lzc/files/home`。
+- `pickerTag`:文件选择器自定义元素标签。常见值是 `lzc-file-picker`。
+- `fallbackMime`:无法从扩展名推断 MIME 时使用的兜底类型。
+- `hooks.fileSystemAccess`:是否接管 `showOpenFilePicker()` 和 `showSaveFilePicker()`。
+- `hooks.fileInput`:是否接管 ``。
+
+## 降级策略
+
+注入脚本应保证“懒猫网盘能力不可用时,不阻断应用原流程”。
+
+建议行为:
+
+1. 如果 `` 没有注册,打开和保存应回退到浏览器原生文件能力。
+2. 如果用户取消选择,应返回与浏览器原生取消一致的结果。
+3. 如果写入懒猫网盘失败,应向调用方返回明确错误,避免静默丢数据。
+
+## 验证
+
+1. 检查脚本语法:
+
+```bash
+node --check content/lazycat-injects/open-save-chooser.js
+```
+
+2. 检查 manifest 和打包配置:
+
+```bash
+lzc-cli project lint .
+```
+
+3. 生成 LPK:
+
+```bash
+lzc-cli project release .
+```
+
+4. 确认静态资源进入包内:
+
+```bash
+tar -tf your-app.lpk
+```
+
+如果顶层包含 `content.tar`,继续展开检查,应能看到:
+
+```text
+lazycat-injects/open-save-chooser.js
+lazycat-injects/vendor/lzc-file-pickers.umd.js
+```
+
+## 常见错误
+
+1. 只写了 `application.injects`,但没有在 `lzc-build.yml` 中配置 `contentdir`,导致运行时 `file:///lzcapp/pkg/content/...` 找不到文件。
+2. 注入顺序写反,桥接脚本执行时 `` 还未注册。
+3. 从示例应用复制了无关的 `file_handler`。只有应用确实需要注册某种文件类型打开方式时,才应配置 `file_handler`。
+4. 目标应用没有使用浏览器文件 API,导致注入成功但看不到效果。
+5. 桥接脚本依赖 Node API。browser inject 运行在真实浏览器页面中,只能使用浏览器 API。
+
+## 下一步
+
+1. 如果应用需要服务端访问用户文件,请继续阅读 [文件访问](./advanced-file.md)。
+2. 如果需要按页面或 hash 路由精确控制注入范围,请继续阅读 [脚本注入(injects)](./advanced-injects.md)。