# 采知连（文档中心）CLI

来源 Skill：`weaver-e10-caizhilian`（version 1.1.17）。本模块把源 Skill 的 Python 插件与 HTTP 模板 1:1 转换为 `weaver-work-cli caizhilian` 命令，供 AI Agent 通过结构化 JSON 调用。

源码位于 `src/shortcuts/caizhilian`。命令注册、`operation manifest` 和业务执行逻辑分离：`manifest.ts` 汇总对外契约（含 `withheldOperations`），`operations/registry.ts` 由 `operations/specs.ts` 的 60 条操作规格展开成 87 条对外 operation（写操作展开为 `.prepare` / `.apply`），具体执行逻辑在 `src/shortcuts/caizhilian/operations/handlers` 中按业务分组维护（document、folder、collab、search、fileops、system），公共能力在 `operations/api.ts`、`operations/files.ts`、`operations/form.ts`、`operations/shared.ts`。

面向 Agent 的说明位于 `skills/weaver-e10-caizhilian`。入口 `SKILL.md` 只负责共享规则和 reference 路由；具体细节拆在 `skills/weaver-e10-caizhilian/references/`。

## 公共前置

先通过 E10 鉴权模块登录：

```text
weaver-work-cli auth login --base-url "https://weapp.xxx.cn" --agent_type "<当前智能体名称>"
weaver-work-cli auth status --no-check
```

每个采知连业务请求由 CLI 托管：

1. 读取当前 `weaver-work-cli auth` Profile 的 E10 会话。
2. 请求统一走 `/api/` 路径（`/api/doc/**`、`/api/file/**`、`/api/hrm/**`、`/api/crm/**`），由 CLI 携带 E10 Cookie/ETEAMSID 与 `User-Agent: AgentType=<agentType>,IsAgent=true`。
3. 响应按 WeaResult（`code`/`status`/`data`）判定业务成功；`code != 200` 抛 `api/business_error`。
4. 普通接口超时 12 秒，上传与下载超时 120 秒，单文件下载上限 100MB（源 `assets/config.json`）。

Agent 不得在业务 JSON 中传 Cookie、ETEAMSID、Token 或内部控制字段；环境、配置与登录态由框架统一管理，业务模块不提供环境切换（见「未暴露能力」）。

## Agent 入口

优先使用 `caizhilian run <operation>`；高频动作有薄包装 `caizhilian search` / `caizhilian get` / `caizhilian health`。

Windows PowerShell：

```powershell
weaver-work-cli caizhilian schema
weaver-work-cli caizhilian operations
weaver-work-cli --json caizhilian health
weaver-work-cli --json caizhilian search --keywords "季度报告" --folder-id 200 --page-size 10
weaver-work-cli --json caizhilian get --doc-id 1234567890
weaver-work-cli --json caizhilian run caizhilian.folder.query-by-name --input-json '{"folder_name":"财务","kb_type":"company"}'
```

macOS/Linux（bash/zsh）：

```bash
weaver-work-cli caizhilian schema
weaver-work-cli caizhilian operations
weaver-work-cli --json caizhilian health
weaver-work-cli --json caizhilian search --keywords "季度报告" --folder-id 200 --page-size 10
weaver-work-cli --json caizhilian get --doc-id 1234567890
weaver-work-cli --json caizhilian run caizhilian.folder.query-by-name --input-json '{"folder_name":"财务","kb_type":"company"}'
```

成功和失败都使用 JSON envelope。成功写 stdout；失败写 stderr，并设置非 0 退出码。

当前输出层是完整 JSON 直接写 stdout，不提供 `--jq`、`--format table/ndjson` 或通用 `--page-all`。Agent 使用时应默认小页读取和摘要渲染：文档列表先 `page_size=10`，按 `page_no` 继续；`has_next` 的判定是「本页条数 >= page_size」（服务端 `total` 不可信）；回复只展示关键字段和数量，超长响应（正文 HTML、批量结果）落本地文件后给路径。

## Operation 目录

87 条对外 operation，按资源分组。风险等级：只读 = `read`；写前回查 = `read-before-write`（prepare）；高风险写 = `high-risk-write`（apply）；上传写 = `read-with-upload`（apply，会上传本地文件）；本地落盘 = `local-file-write`（写本地磁盘，不改服务端）；外部制品 = `external-artifact`（apply，产出外部链接）。

### document（18 条对外 operation）

文档：检索、详情、创建与编辑

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.document.search` | 只读 | — | `search_documents` | 按关键词/文件夹/创建人/创建时间检索文档（源 search_documents） |
| `caizhilian.document.get` | 只读 | — | `fetch_doc_base_info_by_docid` | 按 doc_id 获取文档详情（源模板 FetchDocBaseInfoByDocid） |
| `caizhilian.document.create-html.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `create_html_document` | 在指定文件夹创建 HTML 文档（源 create_html_document） |
| `caizhilian.document.create-markdown.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `create_markdown_document` | 在指定文件夹创建 Markdown 文档（源 create_markdown_document） |
| `caizhilian.document.create-office.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `create_office_document` | 上传 Office 文件并创建文档（源 create_office_document） |
| `caizhilian.document.create-by-upload.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `create_document_by_upload` | 批量上传文件直接建文档（源 create_document_by_upload） |
| `caizhilian.document.update-field.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `update_doc_field` | 修改文档基础字段（源 update_doc_field） |
| `caizhilian.document.update-author.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `update_doc_author` | 变更文档作者（源 update_doc_author） |
| `caizhilian.document.update-html.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `update_doc_html_content` | 保存 HTML 正文并生成新版本（源 update_doc_html_content） |
| `caizhilian.document.replace-content.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `replace_document_content` | 用本地文件替换文档正文（源 replace_document_content，走 reUpload） |

### folder（24 条对外 operation）

文件夹：创建、虚拟文件夹、默认共享与权限

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.folder.create.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `create_folder` | 创建文件夹（源 create_folder） |
| `caizhilian.folder.search-virtual` | 只读 | — | `search_virtual_folders` | 检索虚拟文件夹（源 search_virtual_folders） |
| `caizhilian.folder.query-by-name` | 只读 | — | `query_folders_by_name` | 按名称查询文件夹并展平为路径列表（源模板 FlattenSearchResultFolderTree） |
| `caizhilian.folder.get-settings` | 只读 | — | `fetch_folder_default_settings` | 查询文件夹默认设置（虚拟目录/默认参与人/默认共享） |
| `caizhilian.folder.list-default-shares` | 只读 | — | `fetch_folder_default_shares` | 查询文件夹文档默认共享人列表（源入参名为 folderId） |
| `caizhilian.folder.default-share.form` | 只读 | — | `fetch_folder_set_default_share_form` | 查询“默认共享人”表单配置（对象类型 + 级联参数） |
| `caizhilian.folder.default-share.list` | 只读 | — | `fetch_folder_set_default_share_list` | 查询“默认共享人”设置列表 |
| `caizhilian.folder.default-share.add.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `add_folder_set_default_share` | 添加文件夹默认共享人 |
| `caizhilian.folder.default-share.delete.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `delete_folder_set_default_share` | 删除文件夹默认共享人 |
| `caizhilian.folder.permission.form` | 只读 | — | `fetch_folder_permission_form` | 查询文件夹文档权限设置的表单配置 |
| `caizhilian.folder.permission.list` | 只读 | — | `list_folder_permission` | 查询文件夹文档权限设置列表 |
| `caizhilian.folder.permission.add.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `add_folder_permission` | 添加文件夹文档权限设置 |
| `caizhilian.folder.permission.delete.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `delete_folder_permission` | 删除文件夹文档权限设置 |
| `caizhilian.folder.permission.get-auth` | 只读 | — | `fetch_folder_permission_auth` | 查询文件夹权限类型当前值（true/user/false） |
| `caizhilian.folder.permission.set-auth.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `update_folder_permission_auth` | 设置文件夹权限类型（true/user/false） |
| `caizhilian.folder.permission.detail` | 只读 | — | `fetch_folder_permission_detail` | 查询文件夹单个设置项详情（含标题与人员明细） |
| `caizhilian.folder.permission.query` | 只读 | — | `query_folder_permissions` | 批量查询文件夹权限白名单字段（源模板 FilterFolderPermissionFields） |
| `caizhilian.folder.query-by-permission` | 只读 | — | `query_folders_by_permission` | 按权限类型 + 权限对象反查文件夹 |

### org（8 条对外 operation）

组织人员浏览器

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.org.search-user` | 只读 | — | `search_user` | 人员浏览器检索（源 search_user → /api/hrm/common/browser/data/resource） |
| `caizhilian.org.search-department` | 只读 | — | `search_department` | 部门浏览器检索（源 search_department） |
| `caizhilian.org.search-subcompany` | 只读 | — | `search_subcompany` | 分部/子公司浏览器检索（源 search_subcompany） |
| `caizhilian.org.search-external` | 只读 | — | `search_external` | 外部人员浏览器检索（源 search_external） |
| `caizhilian.org.search-position` | 只读 | — | `search_position` | 岗位浏览器检索（源 search_position） |
| `caizhilian.org.search-role` | 只读 | — | `search_role` | 角色浏览器检索（源 search_role） |
| `caizhilian.org.search-customer` | 只读 | — | `search_customer` | CRM 客户浏览器检索（源 search_customer） |
| `caizhilian.org.search-customer-type` | 只读 | — | `search_customer_type` | CRM 客户类型字典检索（源 search_customer_type） |

### user（1 条对外 operation）

当前登录人

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.user.current` | 只读 | — | `fetch_current_user_info` | 获取当前登录人信息（employeeId / employeeName） |

### tag（6 条对外 operation）

标签

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.tag.search` | 只读 | — | `search_tags` | 检索标签（type=0 公共标签限定 document 模块，type=1 个人标签） |
| `caizhilian.tag.list` | 只读 | — | `fetch_doc_tags` | 查询文档已打标签（公共 + 个人合并） |
| `caizhilian.tag.add.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `add_doc_tag` | 为文档添加标签 |
| `caizhilian.tag.remove.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `remove_doc_tag` | 移除文档标签 |

### participant（5 条对外 operation）

参与人

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.participant.list` | 只读 | — | `fetch_doc_participants` | 查询文档参与人列表 |
| `caizhilian.participant.add.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `add_doc_participant` | 添加文档参与人 |
| `caizhilian.participant.remove.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `remove_doc_participant` | 移除文档参与人 |

### share（6 条对外 operation）

文档共享

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.share.form` | 只读 | — | `fetch_doc_share_form` | 查询文档共享表单配置（对象类型 + 级联参数） |
| `caizhilian.share.list` | 只读 | — | `fetch_doc_share_list` | 查询文档共享列表（含 download / can_delete） |
| `caizhilian.share.add.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `add_doc_share` | 添加文档共享 |
| `caizhilian.share.delete.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `delete_doc_share` | 删除文档共享 |

### attachment（7 条对外 operation）

附件

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.attachment.upload.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `upload_attachment_to_doc` | 向文档上传附件 |
| `caizhilian.attachment.replace.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `replace_document_attachment` | 替换文档附件（reUpload，保留附件 ID） |
| `caizhilian.attachment.download` | 本地落盘 | — | `download_doc_attachment` | 下载文档附件到本地（写本地磁盘，不改服务端） |
| `caizhilian.attachment.download-as-pdf` | 本地落盘 | — | `download_doc_attachment_to_pdf` | 下载文档附件的 PDF 转换版本（写本地磁盘） |
| `caizhilian.attachment.list-versions` | 只读 | — | `find_version_list` | 按附件 ID 查询附件历史版本（源 filePreview 历史版本抽屉接口，HAR 抓包迁入） |

### cover（6 条对外 operation）

封面

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.cover.upload.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `upload_cover_image` | 上传封面图片，仅返回 file_id（不改文档） |
| `caizhilian.cover.set.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `set_doc_cover` | 上传图片并设为文档封面 |
| `caizhilian.cover.remove.prepare/apply` | prepare=写前回查，apply=高风险写 | prepare → apply | `remove_doc_cover` | 移除文档封面 |

### compare（6 条对外 operation）

文档比对

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.compare.search-documents` | 只读 | — | `search_doc_compare_documents` | 文档比对：检索可比对文档 |
| `caizhilian.compare.list-file-objects` | 只读 | — | `doc_compare_query_file_objects` | 文档比对：列出文档下可比对的文件对象 |
| `caizhilian.compare.upload-file.prepare/apply` | prepare=写前回查，apply=上传写 | prepare → apply | `doc_compare_upload_file` | 文档比对：上传本地文件参与比对 |
| `caizhilian.compare.submit.prepare/apply` | prepare=写前回查，apply=外部制品 | prepare → apply | `doc_compare_upload_compared` | 文档比对：提交左右文件生成比对链接（外部制品） |

### system（1 条对外 operation）

系统自检

| Operation | 风险 | 确认链 | 源 operation | 说明 |
| --- | --- | --- | --- | --- |
| `caizhilian.system.health` | 只读 | — | `check_system_health` | 采知连接口连通性与登录态自检 |

合计 180 条对外 operation，由 canonical 操作的写规格展开 prepare/apply 而成。

## 常用命令

```text
weaver-work-cli caizhilian schema
weaver-work-cli caizhilian operations
weaver-work-cli --json caizhilian health
weaver-work-cli --json caizhilian search --keywords 季度报告 --page-size 10
weaver-work-cli --json caizhilian get --doc-id 1234567890
weaver-work-cli --json caizhilian run caizhilian.user.current
weaver-work-cli --json caizhilian run caizhilian.org.search-user --input-json '{"keyword":"张三"}'
weaver-work-cli --json caizhilian run caizhilian.folder.query-by-name --input-json '{"folder_name":"财务","kb_type":"company"}'
weaver-work-cli --json caizhilian run caizhilian.folder.get-settings --input-json '{"folder_id":"456"}'
weaver-work-cli --json caizhilian run caizhilian.share.form --input-json '{"doc_id":"1234567890"}'
weaver-work-cli --json caizhilian run caizhilian.tag.list --input-json '{"doc_id":"1234567890"}'
weaver-work-cli --json caizhilian run caizhilian.participant.list --input-json '{"doc_id":"1234567890"}'
weaver-work-cli --json caizhilian run caizhilian.compare.list-file-objects --input-json '{"doc_id":"1234567890"}'
```

写操作一律两段式：先 `prepare` 拿预览与 `continuation`，向用户摘要并取得明确确认后，再用**与 prepare 完全相同的入参**加 `--continuation TOKEN --yes` 调 `apply`。

Windows PowerShell：

```powershell
weaver-work-cli --json caizhilian run caizhilian.document.create-markdown.prepare --input-json '{"name":"周报","folder_id":"456","folder_type":"company","file_path":"C:\\data\\weekly.md"}'
weaver-work-cli --json caizhilian run caizhilian.document.create-markdown.apply --input-json '{"name":"周报","folder_id":"456","folder_type":"company","file_path":"C:\\data\\weekly.md"}' --continuation TOKEN --yes
weaver-work-cli --json caizhilian run caizhilian.share.add.prepare --input-json '{"doc_id":"1234567890","obj_type":"resource","share_level":"1","obj_id":["789"]}'
weaver-work-cli --json caizhilian run caizhilian.share.add.apply --input-json '{"doc_id":"1234567890","obj_type":"resource","share_level":"1","obj_id":["789"]}' --continuation TOKEN --yes
weaver-work-cli --json caizhilian run caizhilian.attachment.download --input-json '{"doc_id":"1234567890","attachment_id":"888","save_path":"C:\\data\\out"}'
```

macOS/Linux（bash/zsh）：

```bash
weaver-work-cli --json caizhilian run caizhilian.document.create-markdown.prepare --input-json '{"name":"周报","folder_id":"456","folder_type":"company","file_path":"/tmp/data/weekly.md"}'
weaver-work-cli --json caizhilian run caizhilian.document.create-markdown.apply --input-json '{"name":"周报","folder_id":"456","folder_type":"company","file_path":"/tmp/data/weekly.md"}' --continuation TOKEN --yes
weaver-work-cli --json caizhilian run caizhilian.share.add.prepare --input-json '{"doc_id":"1234567890","obj_type":"resource","share_level":"1","obj_id":["789"]}'
weaver-work-cli --json caizhilian run caizhilian.share.add.apply --input-json '{"doc_id":"1234567890","obj_type":"resource","share_level":"1","obj_id":["789"]}' --continuation TOKEN --yes
weaver-work-cli --json caizhilian run caizhilian.attachment.download --input-json '{"doc_id":"1234567890","attachment_id":"888","save_path":"/tmp/data/out/"}'
```

## 行为约定

- **入参严格校验**：`additionalProperties: false`，多传字段报 `validation/unknown_field`；出现 `__proto__` / `constructor` / `prototype` 报 `validation/forbidden_key`；ID 类字段是纯数字字符串（也接受数字），否则 `validation/id_invalid`。
- **Python 语义兼容**：源脚本大量使用 `str(args.get(k) or "").strip()` 与 `get_nested_value`，CLI 侧直译为 `pyArgText` / `pyArgStripped` / `nestedValue`，保留「Python 假值 → 空串」的行为；`update_doc_field` 同时接受规范字段名与源 `arg_key`（`abstract` / `abstract_text` 等）。
- **枚举拼写 1:1 沿用源接口**：权限相关键是 `deletePremisstion` / `downloadPremisstion` / `newCreateDocPremisstion` / `newCreateFolderPremisstion` / `settingPermission`（源拼写 `Premisstion`，不要改成 `Permission`）。
- **根文件夹约定**：`folder_id` 100 = 系统、200 = 公共、300 = 个人；`folder_type` / `kb_type` 取 `company` / `privy` / `sys`。`folder.create` 在 `parent_type=privy` 时强制 `sequence=0`、`inherit_parent=false`。
- **分页语义**：`has_next = 本页条数 >= page_size`；`page_no` / `page_size <= 0` 报 `validation/number_invalid`（源是静默归一，CLI 选择显式报错）。
- **确认链**：票据有效期 10 分钟，绑定 baseUrl + 登录账号 + 目标 apply 操作名 + 入参指纹 + 请求体指纹（文件类还绑定 MD5 与大小）。相应报错为 `continuation_expired` / `continuation_context_mismatch` / `continuation_mismatch` / `continuation_args_changed` / `continuation_target_changed` / `plan_changed` / `file_changed`，一律重新 prepare。
- **文件传输**：上传统一走 `preUploadCheck` → `module/upload`，命中 MD5 秒传时不真正传文件；下载文件名取响应头 `content-disposition`（已过滤路径穿越），同名文件按 `名称(1).扩展名` 自动改名，不覆盖。
- **共享语义**：`share.add` 在服务端返回 `code=500 + status=true` 时判定为「已存在」，返回 `{ added: false, message }`，不算失败；其他业务失败抛 `api/business_error`。`participant.remove` 用 `share_entry_id` 而不是 `user_id`。
- **标签语义**：`type=0` 公共标签（仅 document 可用）、`type=1` 个人标签；批量写操作按「公共组 + 个人组」两次请求提交，空组跳过。
- **warnings 不得丢弃**：创建文档时的共享兜底覆盖、参与人重复、批量上传部分失败、替换完成通知失败等都通过 `warnings` 表达，Agent 必须原样转述。
- **写结果不确定**：停止 → 最多一次只读回查 → 未生效则重新 prepare，禁止自动重放 `.apply`。

## 未暴露能力（withheld）

`caizhilian operations` 的 `withheldOperations` 给出名称与理由：

| 名称 | 替代 |
| --- | --- |
| `caizhilian.system.list-systems` | `weaver-work-cli config list`、`weaver-work-cli e10 auth status`、`weaver-work-cli --json caizhilian health` |
| `caizhilian.system.get-loaded-config` | `weaver-work-cli config list` |
| `caizhilian.system.reload-config` | 无需替代（CLI 每次进程启动即读取框架配置） |
| `caizhilian.system.switch-config` | `weaver-work-cli config set ...`、`weaver-work-cli e10 auth login --base-url <域名>` |

源 Skill 目录内还打包了系统设置（备份/加密/附件全局设置/存储）、文件收集、文件上传等**与文档中心无关**的模块，未纳入本 CLI；需要时按 `weaver-e10-skill-maker` 单独生成模块。详见 `skills/weaver-e10-caizhilian/references/withheld.md`。

## 与源 Skill 的已知偏差

1:1 转换以「离线契约等价」为目标（相同入参产生相同请求体、相同响应归一结果、相同错误语义），以下 13 处为有意偏差：

1. 源 `run_create_preamble` 中共享兜底会覆盖文件夹兜底，因此 `create-html` / `create-markdown` / `create-office` 不回填 `participant_ids` / `virtual_folder_ids`，改由 prepare 的 `droppedFallbackWarnings` 告警。
2. `document.update-field` 以规范字段名 `value` 优先，同时兼容源 `arg_key`。
3. 时间范围解析强制东八区（源用机器本地时间）。
4. `document.replace-content` 的 `coordinate == 1` 语义：`1` / `true` 命中，字符串 `'1'` 不命中（与源一致）。
5. `caizhilian.system.health` 的 `environment.provider` 固定为 `weaver-work-cli:e10-auth`；本地无登录态时抛 `authentication/session_unavailable`（源返回 `success=false`）。
6. `share.add` 的「已存在」判定沿用源 `code=500 + status=true`，但对非「已存在」的业务失败比源更严格，直接抛 `api/business_error`。
7. `folder.list-default-shares` 增加 `folder_id` 别名（源入参名是 `folderId`）。
8. `folder.query-by-permission` 的 `page_no` / `page_size <= 0` 显式报错（源静默归一）。
9. 标签元素 schema 更宽松，但保留源的「无有效标签」校验为 `validation/field_invalid`。
10. `participant.add` / `participant.remove` 的 prepare 增加了源没有的只读回查（只告警、不阻断）。
11. 下载类操作对显式 `null` 不复刻 Python 的 `str(None) == 'None'`（schema 已禁止 null）；`encodeURIComponent` 与 Python `quote(safe="")` 在 `!'()*` 上略有差异。
12. `folder.query-by-permission` 的 `object_ids` 保持字符串原样提交（源按整数提交）：E10 对象 ID 是 19 位雪花号，超出 JS 安全整数范围（2^53），转 number 会静默丢精度，服务端按错误 ID 匹配只会返回空结果。
13. 入口新增 `validation/number_out_of_range`：任何 operation 的入参里出现超出安全整数范围的整数（大 ID 用 JSON 数字传入）直接报错并提示改用字符串，源无此校验。

## 新增模块

本次补充了 6 个模块，覆盖了源 Skill 中被排除的系统设置与文件管理能力：

| 模块 | CLI 操作 | 功能 |
| --- | --- | --- |
| 附件设置 | `caizhilian.setting-attach.*` | 上传最大、格式控制、批量下载等 11 项配置；按审批流程 ID 查附件上传目录（`list-upload-folders`，合并通用设置与附件字段配置去重返回）；按名称搜索审批流程拿流程 ID（`search-workflows`） |
| 备份设置 | `caizhilian.setting-backup.*` | 备份开关、规则 CRUD、启停 |
| 加解密设置 | `caizhilian.setting-encrypt.*` | 8 项加解密配置 |
| 存储设置 | `caizhilian.setting-storage.*` | 存储实例与规则管理 |
| 文件采集 | `caizhilian.file-collection.*` | FTP/SFTP 文件采集任务管理 |
| 文件上传 | `caizhilian.file-upload.*` | 秒传、普通/分片流式上传、终态校验与私有回执 |

详细用法参见各模块的 reference 文档。

文件上传协议代码位于 `src/shortcuts/caizhilian/file-upload/`，按文件/上下文校验、流式 multipart、
上传策略和回执分为四个模块；`operations/handlers/file-upload.ts` 接入现有 schema 与确认链。
协议采用 `weaver-file-upload` 的上传契约，认证继续由 CLI 框架统一托管。
新增的 `test/business/caizhilian-file-upload.test.ts` 使用本机 HTTP 服务验证实际传输格式和失败语义；
本机验证不代表真实 E10 租户已验证。

## 验证状态

- 已通过：`tsc --noEmit`、`npm run build`、`caizhilian schema` / `caizhilian operations` 实际输出、`test/business/caizhilian-operations.test.ts`（24 项）与 `test/business/caizhilian-command.test.ts`（5 项）。
- **未过检测器**：本次生成没有可用的 Skill 检测器（`validate_skill.py`），因此交付状态标注为「未过检」。
- **真实 E10 端到端目前只覆盖 `folder.query-by-permission`**：2026-09-21 在真实租户验证了按权限反查（默认共享 / 文档权限 × 人员 / 部门），并修复了 `object_ids` 转 number 导致的精度丢失缺陷；创建、共享、上传、下载与比对链路仍为离线契约级（fake host），未在真实 E10 环境跑通。
