@fnnas-labs/fnos-cli 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -2
  3. package/THIRD_PARTY_NOTICES.txt +38904 -0
  4. package/cordis.patch.yml +3 -0
  5. package/npm/README.dsh.md +49 -0
  6. package/npm/acceptance-report.cjs +53 -0
  7. package/npm/dsh-integration.mjs +159 -0
  8. package/npm/dsh-test-support.mjs +55 -0
  9. package/npm/dsh.mjs +31 -0
  10. package/npm/install.cjs +140 -0
  11. package/npm/package-lib.cjs +274 -0
  12. package/npm/run.cjs +39 -0
  13. package/package.json +46 -4
  14. package/skill/LICENSE +21 -0
  15. package/skill/SKILL.md +143 -0
  16. package/skill/THIRD_PARTY_NOTICES.txt +38904 -0
  17. package/skill/bin/trim-cli-darwin-arm64 +0 -0
  18. package/skill/bin/trim-cli-darwin-x64 +0 -0
  19. package/skill/bin/trim-cli-linux-arm64 +0 -0
  20. package/skill/bin/trim-cli-linux-x64 +0 -0
  21. package/skill/bin/trim-cli-windows-arm64.exe +0 -0
  22. package/skill/bin/trim-cli-windows-x64.exe +0 -0
  23. package/skill/build-provenance.json +44 -0
  24. package/skill/entries/trim-app.md +63 -0
  25. package/skill/entries/trim-baidu-netdisk.md +42 -0
  26. package/skill/entries/trim-docker.md +35 -0
  27. package/skill/entries/trim-download.md +38 -0
  28. package/skill/entries/trim-file.md +30 -0
  29. package/skill/entries/trim-log.md +32 -0
  30. package/skill/entries/trim-monitor.md +41 -0
  31. package/skill/entries/trim-network.md +22 -0
  32. package/skill/entries/trim-photos.md +32 -0
  33. package/skill/entries/trim-shared.md +54 -0
  34. package/skill/entries/trim-storage.md +34 -0
  35. package/skill/entries/trim-system.md +59 -0
  36. package/skill/entries/trim-user.md +28 -0
  37. package/skill/manifest.json +43 -0
  38. package/skill/reference/_conventions.md +76 -0
  39. package/skill/reference/_index.md +78 -0
  40. package/skill/reference/app-center.md +234 -0
  41. package/skill/reference/baidu-netdisk.md +221 -0
  42. package/skill/reference/dockermgr.md +244 -0
  43. package/skill/reference/download.md +357 -0
  44. package/skill/reference/file.md +752 -0
  45. package/skill/reference/log.md +224 -0
  46. package/skill/reference/network.md +41 -0
  47. package/skill/reference/oauth.md +51 -0
  48. package/skill/reference/photos.md +158 -0
  49. package/skill/reference/power.md +34 -0
  50. package/skill/reference/resmon.md +160 -0
  51. package/skill/reference/stor.md +525 -0
  52. package/skill/reference/sysinfo.md +133 -0
  53. package/skill/reference/user.md +139 -0
  54. package/skill/reference/workflows/device-validation.md +66 -0
  55. package/skill/reference/workflows/file-routing.md +44 -0
  56. package/skill/reference/workflows/file-upload-validation.md +63 -0
  57. package/skill/reference/workflows/photos-routing.md +83 -0
  58. package/skill/reference/workflows/storage-dangerous-ops.md +53 -0
  59. package/skill/scripts/fnos-cli +63 -0
  60. package/skill/scripts/fnos-cli.cmd +36 -0
  61. package/skill/scripts/fnos-cli.ps1 +31 -0
  62. package/skill/scripts/trim-cli +63 -0
  63. package/skill/scripts/trim-cli.cmd +36 -0
  64. package/skill/scripts/trim-cli.ps1 +31 -0
@@ -0,0 +1,76 @@
1
+ # API 文档约定
2
+
3
+ 本目录包含 fnos-cli 支持的 fnOS API 模块参考文档。
4
+
5
+ ## 文档结构
6
+
7
+ 每个模块文档包含:
8
+
9
+ 1. **模块概述**:模块功能和用途
10
+ 2. **模块约定**:模块级别的共享规则和注意事项
11
+ 3. **端点索引**:模块包含的所有端点列表
12
+ 4. **端点详情**:每个端点的完整说明
13
+ 5. **注意事项**:使用中需要关注的行为差异或限制
14
+
15
+ ## 端点详情格式
16
+
17
+ 每个端点包含以下部分(按顺序):
18
+
19
+ ### Endpoint
20
+ 端点的完整名称(如 `appcgi.file.ls`)
21
+
22
+ ### Purpose
23
+ 端点的功能说明
24
+
25
+ ### Trim CLI Mapping
26
+ 对应的 fnos-cli 命令形式;如果未实现则标注 `Not implemented in fnos-cli yet`
27
+
28
+ ### Request
29
+ 请求参数表格:
30
+
31
+ | Field | Location | Required | Type | Meaning | Constraints / Notes | Example |
32
+ | --- | --- | --- | --- | --- | --- | --- |
33
+
34
+ **Location 取值:**
35
+ - `body`:JSON 请求体顶层字段
36
+ - `query`:URL 查询参数
37
+ - `path`:URL 路径变量
38
+ - `header`:协议头字段
39
+ - `wrapped body`:嵌套在请求体内的字段(如 `data.body.*`)
40
+
41
+ ### Response
42
+ 响应字段表格:
43
+
44
+ | Field | Always Present | Type | Meaning | Conditions / Notes | Example |
45
+ | --- | --- | --- | --- | --- | --- |
46
+
47
+ ### Protocol Notes
48
+ 影响自动化的协议行为:
49
+ - 认证要求(token / session / signature)
50
+ - 数据包终止行为(`result`、多包流式响应)
51
+ - 签名格式:当 session 中存在 `secret` 且端点不在直通集合中时,使用 HMAC-SHA256 签名
52
+ - 签名载荷格式:`<base64-hmac-signature><json-body>`
53
+ - 签名密钥:session `secret` 的 base64 解码值
54
+ - 签名前会在 JSON 中注入 `si`(如可用)
55
+ - 特殊封装结构(如嵌套 `data.body`)
56
+
57
+ ### Field Semantics
58
+ 字段语义的详细说明和约束
59
+
60
+ ### Errors
61
+ 常见错误码和错误信息
62
+
63
+ ## 路径约定
64
+
65
+ fnOS 文件路径使用 canonical 格式:`/vol{v}/...`
66
+
67
+ 示例:
68
+ - `/vol1/downloads`
69
+ - `/vol3/1000/media`
70
+
71
+ ## 通用响应信封
72
+
73
+ 大多数端点响应包含以下通用字段:
74
+ - `result`:终态标记,`succ` 或 `fail`
75
+ - `errno`:数值错误码(失败时出现)
76
+ - `errmsg`:错误描述(失败时出现)
@@ -0,0 +1,78 @@
1
+ # fnos-cli 参考索引
2
+
3
+ 本目录既提供模块 reference,也提供面向 Agent 的任务入口。优先按任务找文档;只有当你已经清楚目标模块时,才直接跳到模块表。
4
+
5
+ ## 按任务找文档
6
+
7
+ | 任务 | 先看文档 | 何时继续下钻 |
8
+ | --- | --- | --- |
9
+ | 登录、登出、profile session、连接失败、session 回落 | [user.md](user.md) | 需要用户、用户组、登录设备或 profile/raw 认证细节时继续看 `user.md` |
10
+ | 列目录、判断当前用户目录、搜索文件 | [workflows/file-routing.md](workflows/file-routing.md) | 确认命令方向后,再看 [file.md](file.md) |
11
+ | 验证上传、同名策略或大文件断点续传 | [workflows/file-upload-validation.md](workflows/file-upload-validation.md) | 需要请求字段和缓存语义时,再看 [file.md](file.md) |
12
+ | 看共享目录、ACL、别人共享给我的文件 | [workflows/file-routing.md](workflows/file-routing.md) | 需要 `file share.*` 或 `file.getAcl` 细节时,再看 [file.md](file.md) |
13
+ | 查看下载任务、创建下载任务 | [download.md](download.md) | 下载任务路径仍要遵守 canonical `/vol{n}/...` 规则 |
14
+ | 查看或管理应用中心应用、安装 fpk | [app-center.md](app-center.md) | 写操作需要 `--yes`,复杂依赖/向导转 App Center UI |
15
+ | 搜索照片、查看照片详情或预览地址 | [photos.md](photos.md) | 需要先有有效代理 session |
16
+ | AI 搜图、统计匹配数量或生成照片预览链接 | [workflows/photos-routing.md](workflows/photos-routing.md) | 先区分匹配总数、本次返回条数和预览链接 |
17
+ | 查看系统信息、CPU、内存、日志 | [sysinfo.md](sysinfo.md)、[resmon.md](resmon.md)、[log.md](log.md) | 根据具体目标跳到对应模块 |
18
+ | 发送未封装的已认证请求 | [user.md](user.md) | 先确认 session/profile 是否可用,再决定是否使用 `raw <req>` |
19
+ | 开启或关闭 SSH 服务 | [network.md](network.md) | 启用 SSH 属于安全敏感操作,执行前确认授权 |
20
+ | 重启或关闭 NAS | [power.md](power.md) | 高影响写操作,必须确认目标设备和授权 |
21
+ | 查看 Docker 镜像、容器、Compose,或执行启停/删除 | [dockermgr.md](dockermgr.md) | 长耗时和删除类操作先看模块里的高风险提醒 |
22
+ | 查看存储池、磁盘、SMART | [stor.md](stor.md) | 读操作可直接在模块文档中选命令 |
23
+ | 做挂载、卸载、扩容、替盘、格式化、弹出等存储写操作 | [workflows/storage-dangerous-ops.md](workflows/storage-dangerous-ops.md) | 确认顺序后,再看 [stor.md](stor.md) 的字段和端点约束 |
24
+ | 做真机验证 | [workflows/device-validation.md](workflows/device-validation.md) | 具体接口细节再回对应模块文档 |
25
+
26
+ ## workflow 目录
27
+
28
+ | 文档 | 用途 |
29
+ | --- | --- |
30
+ | [workflows/file-routing.md](workflows/file-routing.md) | 路由文件相关需求,区分 `/`、当前用户目录、具体 `/vol{n}/...`、共享目录和搜索入口 |
31
+ | [workflows/file-upload-validation.md](workflows/file-upload-validation.md) | 验证小文件上传、同名策略、大文件缓存身份和并发续传 |
32
+ | [workflows/photos-routing.md](workflows/photos-routing.md) | 路由相册统计、AI 搜索和抽样预览需求 |
33
+ | [workflows/storage-dangerous-ops.md](workflows/storage-dangerous-ops.md) | 在高风险存储写操作前固定先做只读探测、密码验证和确认 |
34
+ | [workflows/device-validation.md](workflows/device-validation.md) | 统一真机 OAuth、最小探测、写后回归和清理口径 |
35
+
36
+ ## 正式入口目录
37
+
38
+ | 文档 | 用途 |
39
+ | --- | --- |
40
+ | [../entries/trim-shared.md](../entries/trim-shared.md) | 通用连接、session、wrapper、真机验证规则 |
41
+ | [oauth.md](oauth.md) | OAuth PKCE、pending、refresh、存储预检、401 重试和 profile 锁 |
42
+ | [../entries/trim-file.md](../entries/trim-file.md) | 文件、共享目录、ACL、路径路由 |
43
+ | [../entries/trim-storage.md](../entries/trim-storage.md) | 存储池、磁盘、SMART、高风险写操作 |
44
+ | [../entries/trim-docker.md](../entries/trim-docker.md) | Docker 镜像、容器、Compose 和长耗时操作 |
45
+ | [../entries/trim-user.md](../entries/trim-user.md) | 认证、用户、用户组、权限确认 |
46
+ | [../entries/trim-download.md](../entries/trim-download.md) | 下载任务列表/详情、创建、暂停/恢复/重试/删除、路径校验 |
47
+ | [../entries/trim-app.md](../entries/trim-app.md) | 应用中心应用列表、状态、安装、fpk 手动安装、更新、启动、停用、卸载 |
48
+ | [../entries/trim-log.md](../entries/trim-log.md) | 日志列表、模块过滤、清除/导出/归档、老版本接口提醒 |
49
+ | [../entries/trim-system.md](../entries/trim-system.md) | 静态系统信息、机器类型、版本、身份识别 |
50
+ | [../entries/trim-monitor.md](../entries/trim-monitor.md) | 运行态指标(CPU、内存)和 resmon 指标路由 |
51
+ | [../entries/trim-network.md](../entries/trim-network.md) | 网络服务开关,当前覆盖 SSH 服务 |
52
+ | [../entries/trim-photos.md](../entries/trim-photos.md) | 相册目录、搜索、详情和预览链接 |
53
+
54
+ ## 按模块找文档
55
+
56
+ | 模块 | 文件 | 说明 |
57
+ | --- | --- | --- |
58
+ | user | [user.md](user.md) | 认证、用户管理、用户组管理、登录设备 |
59
+ | file | [file.md](file.md) | 文件操作、finder 搜索、共享目录、ACL |
60
+ | download | [download.md](download.md) | 下载任务查询、创建、控制 |
61
+ | app-center | [app-center.md](app-center.md) | 应用中心查询、安装、更新、启动、停用、卸载 |
62
+ | stor | [stor.md](stor.md) | 存储池、磁盘、SMART、挂载/弹出、格式化 |
63
+ | dockermgr | [dockermgr.md](dockermgr.md) | Docker 镜像、容器、网络、Compose 管理 |
64
+ | log | [log.md](log.md) | 日志查询、导出、清除、归档策略 |
65
+ | resmon | [resmon.md](resmon.md) | CPU、内存等资源监控 |
66
+ | sysinfo | [sysinfo.md](sysinfo.md) | 系统信息和机器类型 |
67
+ | network | [network.md](network.md) | 网络服务开关 |
68
+ | power | [power.md](power.md) | 重启或关闭 NAS |
69
+ | photos | [photos.md](photos.md) | Photos 认证、搜索、详情和预览 URL |
70
+
71
+ ## 文档约定
72
+
73
+ 所有模块文档遵循 [_conventions.md](_conventions.md) 定义的统一格式。workflow 文档只负责操作顺序、停手条件和常见误判,不重复完整字段表。
74
+
75
+ 补充约定:
76
+
77
+ - profile/session、`login` / `logout`、`raw` 的共享认证链路统一看 [user.md](user.md)。
78
+ - 输入 guard 遇到控制字符、空值或过长值时会直接报错;skill 示例不要假设 CLI 会帮忙清洗参数。
@@ -0,0 +1,234 @@
1
+ # App Center reference
2
+
3
+ ## Command overview
4
+
5
+ | Command | Purpose | Output |
6
+ | --- | --- | --- |
7
+ | `app list` | List installed App Center apps | JSON |
8
+ | `app status <appName>` | Show one installed app record | JSON |
9
+ | `app base-data` | Read App Center sidebar/source/tag base data | JSON |
10
+ | `app store list` | List cloud App Center packages | JSON |
11
+ | `app store search <keyword>` | Search cloud App Center packages | JSON |
12
+ | `app store detail <appName>` | Show cloud package detail | JSON |
13
+ | `app store latest-release` | List latest release packages | JSON |
14
+ | `app check-update` | Check App Center update availability | JSON |
15
+ | `app check-update --post` | Trigger an App Center update check | Success message |
16
+ | `app common volume` | Read remembered App Center volume | JSON |
17
+ | `app common volume --set <volumeId>` | Set remembered App Center volume | Success message |
18
+ | `app config sys/list/detail/auth-paths/wizard` | Read App Center system and app config | JSON |
19
+ | `app config set-sys --fields <json>` | Update App Center system config fields | Success message |
20
+ | `app config set <appName> --fields <json>` | Update one app config payload | Success message |
21
+ | `app config auto-update <appName>` | Enable or disable app auto update | Success message |
22
+ | `app config proxy-access <appName>` | Allow or deny proxy access | Success message |
23
+ | `app config post-wizard <appName> --fields <json>` | Submit app wizard custom parameters | Success message |
24
+ | `app service list` | List service metadata | JSON |
25
+ | `app entry list` | List available application entries | JSON |
26
+ | `app desktop list` | List the current user's desktop layout and entries | JSON |
27
+ | `app guide check-installed <appName...>` | Check whether guide-required apps are installed | JSON |
28
+ | `app guide batch-download-install <volumeId> <appName...>` | Start guide batch download/install tasks | Success message |
29
+ | `app operation settings` | Read operation settings | JSON |
30
+ | `app openapi app-detail <appName>` | Read OpenAPI app detail for authorization flows | JSON |
31
+ | `app openapi allow-user-auth-paths <appName>` | Read whether users may authorize paths to an app | JSON |
32
+ | `app openapi add-user-auth-path <appName> <path>` | Add current-user authorization path for an app | Success message |
33
+ | `app openapi add-user-auth-inherit-file <appName> <path>` | Add inherited-file authorization for an app | Success message |
34
+ | `app sac app-store-list` | Read SAC App Store entry list | JSON |
35
+ | `app task-status <taskId>` | Query an App Center common task | JSON |
36
+ | `app task-cancel <taskId>` | Cancel an App Center common task | Success message |
37
+ | `app download cancel <downloadTaskId>` | Cancel an App Center download task | Success message |
38
+ | `app install-cancel <taskId>` | Cancel an App Center install task | Success message |
39
+ | `app update-cancel <taskId>` | Cancel an App Center update task | Success message |
40
+ | `app install <appName>` | Download and install an App Center package by name and version | Success message |
41
+ | `app install <appName> --dry-run` | Download and inspect an App Center package without starting install | Success message |
42
+ | `app install-fpk <localFile.fpk>` | Upload and install a local fpk package | Success message |
43
+ | `app install-fpk --remote-path /vol.../*.fpk` | Install an fpk package already stored on the NAS | Success message |
44
+ | `app install-fpk <localFile.fpk> --dry-run` / `--remote-path ... --dry-run` | Inspect an fpk package without starting install | JSON plan |
45
+ | `app update <appName>` | Download and update an installed app to a target version | Success message |
46
+ | `app update <appName> --dry-run` | Download and inspect an App Center update without starting update | Success message |
47
+ | `app start <appName>` | Start an installed app | Success message |
48
+ | `app stop <appName>` | Stop an installed app | Success message |
49
+ | `app restart <appName>` | Restart an installed app | Success message |
50
+ | `app uninstall <appName>` | Uninstall an installed app | Success message |
51
+
52
+ ## Endpoints
53
+
54
+ | Command | Method | Endpoint |
55
+ | --- | --- | --- |
56
+ | `app list` / `app status` | GET | `/app-center/v1/app/installed` |
57
+ | `app base-data` | GET | `/app-center/v2/config/base-data` |
58
+ | `app store list` | GET | `/app-center/v1/app/list` |
59
+ | `app store search` | GET | `/app-center/v1/app/search` |
60
+ | `app store detail` | GET | `/app-center/v1/app/detail` |
61
+ | `app store latest-release` | GET | `/app-center/v1/app/latest-release` |
62
+ | `app check-update` | GET/POST | `/app-center/v1/check-update` |
63
+ | `app common volume` | GET/POST | `/app-center/v1/common/remember-volume` |
64
+ | `app config sys` | GET | `/app-center/v1/sysconfig` |
65
+ | `app config set-sys` | POST | `/app-center/v1/sysconfig` |
66
+ | `app config list/detail/auth-paths/wizard` | GET | `/app-center/v1/config/*` |
67
+ | `app config set` | POST | `/app-center/v1/config` |
68
+ | `app config auto-update` | POST | `/app-center/v1/config/app/auto-update` |
69
+ | `app config proxy-access` | POST | `/app-center/v1/config/proxy-access-allowed` |
70
+ | `app config post-wizard` | POST | `/app-center/v1/config/wizard` |
71
+ | `app service list` | GET | `/app-center/v1/service/list` |
72
+ | `app entry list` | WebSocket CGI | `appcgi.sac.entry.v1.getEntryList` |
73
+ | `app desktop list` | WebSocket CGI | `appcgi.sac.entry.v1.getUserDesktop` |
74
+ | `app guide check-installed` | POST | `/app-center/v1/app/check-installed` |
75
+ | `app guide batch-download-install` | POST | `/app-center/v1/batch-download-install` |
76
+ | `app operation settings` | GET | `/app-center/v1/operation/settings` |
77
+ | `app openapi app-detail` | GET | `/app-center/openapi/v1/app/detail` |
78
+ | `app openapi allow-user-auth-paths` | GET | `/app-center/openapi/v1/app/allow-user-authorization-paths` |
79
+ | `app openapi add-user-auth-path` | POST | `/app-center/openapi/v1/user/authorization-paths` |
80
+ | `app openapi add-user-auth-inherit-file` | POST | `/app-center/openapi/v1/user/authorization-paths/inherit-file` |
81
+ | `app sac app-store-list` | WebSocket CGI | `appcgi.sac.entry.v1.appStoreList` |
82
+ | `app task-status` | POST | `/app-center/v1/common/task-status` |
83
+ | `app task-cancel` | POST | `/app-center/v1/common/task-cancel` |
84
+ | `app download cancel` | POST | `/app-center/v1/download/cancel` |
85
+ | `app install` info | GET | `/app-center/v1/install/info` |
86
+ | `app install` start | POST | `/app-center/v1/install/task` |
87
+ | `app install-cancel` | POST | `/app-center/v1/install/cancel` |
88
+ | `app install-fpk` upload | POST | `/app-center/v1/download/upload` |
89
+ | `app install-fpk --remote-path` package task | POST | `/app-center/v1/download/task` with `packageSourceType=file` and `path` |
90
+ | `app install-fpk` upload status | GET | `/app-center/v1/download/status` |
91
+ | `app update` info | GET | `/app-center/v1/update/info` |
92
+ | `app update` start | POST | `/app-center/v1/update/task` |
93
+ | `app update-cancel` | POST | `/app-center/v1/update/cancel` |
94
+ | `app start` check/start | POST | `/app-center/v1/start/check`, `/app-center/v1/start/start` |
95
+ | `app stop` check/start | POST | `/app-center/v1/stop/check`, `/app-center/v1/stop/start` |
96
+ | `app restart` | POST | `/app-center/v1/restart` |
97
+ | `app uninstall` info/start | GET/POST | `/app-center/v1/uninstall/info`, `/app-center/v1/uninstall/start` |
98
+
99
+ ## Safety behavior
100
+
101
+ All write commands require `--yes`.
102
+
103
+ `app store detail` accepts optional `--source-id` and `--version` when the store result includes a source identifier or a specific version is needed.
104
+
105
+ `app task-cancel` requires `--yes`. The common task status/cancel endpoints use `taskID` in the request body.
106
+
107
+ `app check-update --post`, `app common volume --set`, `app download cancel`, `app install-cancel`, `app update-cancel`, `app restart`, config writes, and guide batch download/install are write operations and require `--yes`.
108
+
109
+ OpenAPI user authorization write commands require `--yes` and require a concrete `/vol...` path. These commands model app/user authorization flows rather than global App Center settings.
110
+
111
+ For config write commands, `--fields` must be a JSON object. `app config set` adds `appName` to that object before sending it. `app config post-wizard` also adds `appName`; include `customParameters` in `--fields`.
112
+
113
+ `app config set-sys` validates common App Center settings before sending:
114
+
115
+ - `downloadAndInstallVolumeID` must be `-1` or a positive integer.
116
+ - `globalAutoUpdate.enabled` must be boolean when present.
117
+ - When global auto update is enabled, or either update time is provided, `updateStartTime` and `updateEndTime` are both required, must use `HH:MM`, and the effective window must be at least 60 minutes.
118
+ - `cloudSecuritySync.enabled` must be boolean when present.
119
+ - When cloud security sync is enabled, or `strategy` is provided, `strategy` must be `strict`, `balanced`, or `lenient`.
120
+ - `autoRunNewApp` must be boolean when present.
121
+ - `autoCreateDesktopIcon` is not sent by the current App Center UI payload. CLI refuses it by default and only sends it when `--allow-desktop-icon-field` is passed; when allowed, it must be boolean.
122
+
123
+ `app install` and `app update` default to `--package-type cloud`. They create and poll an App Center cloud download task before calling install/update info and task endpoints, then wait for the returned install/update task to finish. With `--dry-run`, they still download/parse the cloud package and apply safety guards, but they do not call the install/update task endpoint. `app install-fpk` derives `packageType` from the uploaded or remote package status and commonly uses `file`.
124
+
125
+ `app install`, `app update`, and `app install-fpk` accept explicit wizard inputs:
126
+
127
+ - `--custom-parameters '<jsonArray>'` sends App Center `customParameters`.
128
+ - `--api-scope '<jsonObject>'` sends `systemParameters.apiScope`.
129
+ - `--accept-license` explicitly accepts package license confirmation outside App Center UI.
130
+ - `--cancel-on-failure` attempts the matching install/update cancel endpoint if the install/update task reaches a failed status; the original failure context remains in stderr.
131
+ - If App Center reports that custom wizard parameters are required and `--custom-parameters` is not provided, CLI refuses before starting the install/update task.
132
+
133
+ For `app install`, `app update`, and `app install-fpk`, `--volume-id` is recommended. If omitted, CLI reads App Center sysconfig and uses `downloadAndInstallVolumeID`, with `volumeID` as compatibility fallback. The value must be positive; if no usable default exists, CLI rejects and asks for `--volume-id`.
134
+
135
+ Use `app install-fpk <localFile.fpk> --volume-id <volumeId> --dry-run --yes` before a risky manual install. Dry-run still uploads a local FPK so App Center can parse it, then reads install info and applies CLI safety guards, but it does not call `/app-center/v1/install/task`.
136
+
137
+ Use `app install-fpk --remote-path /vol.../*.fpk --dry-run --yes` for an FPK that is already on the NAS. The path must be a concrete `/vol...` path, must end with `.fpk`, and the remote file size must be no larger than 10GB. CLI checks the remote file property before creating the App Center remote package task.
138
+
139
+ If an install or update task fails, stderr includes the task id plus `appName`, `version`, `packageType`, install/data volume ids, immediate-start flag, status/progress, and any backend `message` or `outputText`. With `--cancel-on-failure`, stderr also says whether the cancel request was attempted or failed.
140
+
141
+ Known storage errors are diagnosed in addition to the raw backend response. For manual FPK upload, `20001` means the selected storage volume is unavailable; choose a mounted, healthy volume id before retrying.
142
+
143
+ If start or stop returns `10500`, App Center reports that the status operation is not supported for the current app state/control data. Inspect `app status` or use App Center UI.
144
+
145
+ For `app install`, pass `--source-id` when the cloud app source identifier is known. `app update` resolves `sourceID` from the installed app list.
146
+
147
+ The CLI refuses cases that require App Center UI decisions:
148
+
149
+ - license confirmation without explicit `--accept-license`
150
+ - custom install/update wizard parameters without explicit `--custom-parameters`
151
+ - custom uninstall wizard parameters
152
+ - unsupported install types other than `volume` or `root`
153
+ - Docker unavailable or uninitialized for install/update
154
+ - OS version mismatch
155
+ - dependency app install/update/start changes
156
+ - running dependent apps for stop/uninstall
157
+
158
+ Root install packages are supported by sending install volume as `0` while keeping data volume as the selected volume, matching App Center behavior.
159
+
160
+ Uninstall waits until the app no longer appears in the installed app list. This avoids starting a follow-up install while the backend is still removing the previous installation.
161
+
162
+ ## Failure handling matrix
163
+
164
+ | Condition | CLI behavior | What to do |
165
+ | --- | --- | --- |
166
+ | License confirmation is required and `--accept-license` is missing | Rejects before install/update task | Pass `--accept-license` only after reviewing the license, or use App Center UI |
167
+ | Custom install/update wizard parameters are required and `--custom-parameters` is missing | Rejects before install/update task | Pass explicit wizard JSON or use App Center UI |
168
+ | Custom uninstall wizard parameters are required | Rejects before uninstall task | Use App Center UI |
169
+ | Unsupported install type | Rejects before install/update task | Use App Center UI |
170
+ | Docker is unavailable or uninitialized | Rejects before install/update task | Fix Docker or use App Center UI |
171
+ | OS version is incompatible | Rejects before install/update/start task | Choose a compatible app or OS version |
172
+ | Dependency app changes are required | Rejects before install/update/start task | Use App Center UI to review dependency operations |
173
+ | Running dependent apps would be affected | Rejects stop/uninstall, and install/update where applicable | Stop/review dependent apps in App Center UI |
174
+ | Cloud download fails | Reports cloud download task id plus app/version/source/volume context | Check sourceID, version, network, and App Center availability |
175
+ | Install/update task fails with `--cancel-on-failure` | Reports task failure context and attempts the matching cancel endpoint | Inspect stderr for cancel result, then verify task state in App Center if needed |
176
+ | Cloud install/update dry-run passes | Prints a success message and does not start install/update task | Review app/version/package/volume before running without `--dry-run` |
177
+ | FPK upload fails | Reports upload task id and upload context | Check package validity and target volume |
178
+ | FPK upload returns `20001` | Reports storage-unavailable diagnostic plus raw response | Check that the selected volume exists, is mounted, and is healthy |
179
+ | FPK dry-run passes | Outputs JSON plan and does not start install task | Review app/version/package/volume before running without `--dry-run` |
180
+ | Remote FPK path or size is invalid | Rejects before App Center download task | Use a concrete `/vol.../*.fpk` path and a file no larger than 10GB |
181
+ | Default install volume is missing | Rejects before download/install task | Pass `--volume-id` or configure App Center default download/install volume |
182
+ | `set-sys` field validation fails | Rejects before network request | Fix the field type, enum, volume id, or update time window |
183
+ | Install/update task fails | Reports task id plus app/version/package/volume/status/progress/backend message | Use the context to identify package, version, volume, or backend script failure |
184
+ | Start/stop returns `10500` | Reports status-operation diagnostic plus raw response | Inspect `app status` or use App Center UI |
185
+ | Uninstall does not disappear from installed list | Times out with the app name | Inspect App Center UI or retry after backend task settles |
186
+
187
+ ## Examples
188
+
189
+ ```bash
190
+ ./scripts/fnos-cli app list
191
+ ./scripts/fnos-cli app status trim.alist
192
+ ./scripts/fnos-cli app store list
193
+ ./scripts/fnos-cli app store search alist
194
+ ./scripts/fnos-cli app store detail trim.alist --source-id 265 --version 3.0.13
195
+ ./scripts/fnos-cli app store latest-release
196
+ ./scripts/fnos-cli app check-update
197
+ ./scripts/fnos-cli app check-update --post --yes
198
+ ./scripts/fnos-cli app common volume
199
+ ./scripts/fnos-cli app common volume --set 2 --yes
200
+ ./scripts/fnos-cli app config sys
201
+ ./scripts/fnos-cli app config detail trim.alist
202
+ ./scripts/fnos-cli app service list
203
+ ./scripts/fnos-cli app entry list --only-hidden
204
+ ./scripts/fnos-cli app desktop list
205
+ ./scripts/fnos-cli app config set-sys --fields '{"autoRunNewApp":true}' --yes
206
+ ./scripts/fnos-cli app config set trim.alist --fields '{"services":[],"extraAuthorizationPath":[]}' --yes
207
+ ./scripts/fnos-cli app config auto-update trim.alist --enable --yes
208
+ ./scripts/fnos-cli app config proxy-access trim.alist --allowed --yes
209
+ ./scripts/fnos-cli app config post-wizard trim.alist --fields '{"customParameters":[]}' --yes
210
+ ./scripts/fnos-cli app guide check-installed trim.media trim.photos
211
+ ./scripts/fnos-cli app guide batch-download-install 2 trim.media trim.photos --yes
212
+ ./scripts/fnos-cli app operation settings
213
+ ./scripts/fnos-cli app openapi app-detail trim.alist
214
+ ./scripts/fnos-cli app openapi allow-user-auth-paths trim.alist
215
+ ./scripts/fnos-cli app openapi add-user-auth-path trim.alist /vol1/1000/docs --yes
216
+ ./scripts/fnos-cli app openapi add-user-auth-inherit-file trim.alist /vol1/1000/docs/file.txt --yes
217
+ ./scripts/fnos-cli app sac app-store-list
218
+ ./scripts/fnos-cli app task-status <taskId>
219
+ ./scripts/fnos-cli app task-cancel <taskId> --yes
220
+ ./scripts/fnos-cli app download cancel <downloadTaskId> --yes
221
+ ./scripts/fnos-cli app install-cancel <taskId> --yes
222
+ ./scripts/fnos-cli app update-cancel <taskId> --yes
223
+ ./scripts/fnos-cli app install trim.alist --version 3.0.13 --source-id 265 --volume-id 2 --dry-run --yes
224
+ ./scripts/fnos-cli app install trim.alist --version 3.0.13 --source-id 265 --volume-id 2 --yes
225
+ ./scripts/fnos-cli app install trim.alist --version 3.0.13 --volume-id 2 --custom-parameters '[{"key":"port","value":8080}]' --api-scope '{"API.User.FileAccess":true}' --yes
226
+ ./scripts/fnos-cli app install trim.alist --version 3.0.13 --volume-id 2 --accept-license --cancel-on-failure --yes
227
+ ./scripts/fnos-cli app install-fpk ~/Downloads/demo.fpk --volume-id 2 --dry-run --yes
228
+ ./scripts/fnos-cli app install-fpk ~/Downloads/demo.fpk --volume-id 2 --yes
229
+ ./scripts/fnos-cli app update trim.alist --version 3.0.14 --volume-id 2 --dry-run --yes
230
+ ./scripts/fnos-cli app update trim.alist --version 3.0.14 --volume-id 2 --yes
231
+ ./scripts/fnos-cli app stop trim.alist --yes
232
+ ./scripts/fnos-cli app start trim.alist --yes
233
+ ./scripts/fnos-cli app uninstall trim.alist --yes
234
+ ```
@@ -0,0 +1,221 @@
1
+ # 百度网盘模块
2
+
3
+ ## 模块概述
4
+
5
+ `baidu-netdisk` 通过 fnOS HTTP API proxy 访问 NAS 上已经安装的百度网盘应用。它覆盖百度账号授权状态、网盘空间、云端文件操作、百度分享链接保存、NAS 与网盘之间的传输任务,以及定时同步任务。
6
+
7
+ fnOS OAuth session 必须包含 `trim.baidu_netdisk.all`。旧 session 缺少该权限时需重新执行
8
+ `login`,refresh token 无法扩大原授权范围。
9
+
10
+ 目标 fnOS 的 OAuth gateway 还必须把 `/app-baidu-netdisk` 的 HTTP 路由登记到该 scope。
11
+ 授权页能勾选百度网盘权限不代表路由已经登记;路由未登记时请求会在到达应用前返回 HTTP 403。
12
+
13
+ CLI 不实现百度 OAuth。百度账号未授权或授权失效时,必须由用户在 NAS 的百度网盘应用登录页完成授权,然后重新运行 `status`。
14
+
15
+ ## 模块约定
16
+
17
+ - 先完成 fnOS 的 `fnos-cli login`,再调用本模块。
18
+ - 百度网盘路径必须以一个 `/` 开头;根路径是 `/`。
19
+ - NAS 写入或读取路径必须是具体 `/vol{n}/...` 路径,不能用聚合根或百度网盘路径代替。
20
+ - 所有写命令都要求 `--yes`。只读命令不要求确认。
21
+ - 后端响应成功条件是 HTTP 2xx 且 `code=0`;百度 XPan 响应成功条件是 HTTP 2xx 且 `errno=0`。
22
+ - 网关刷新重试后仍为 HTTP 401,或响应为 `code=401`、`code=2000`、`errno=-6`,表示百度授权不可用,应回到 NAS 应用登录页处理。
23
+ - HTTP 403 表示 fnOS gateway 拒绝了应用路由。先核对 session 是否含 `trim.baidu_netdisk.all`,再确认设备上的 gateway 版本是否已登记 `/app-baidu-netdisk` 路由;不要误判为百度账号退出。
24
+ - `dlink` 是敏感临时下载 URL,默认输出会脱敏。
25
+
26
+ ## 命令索引
27
+
28
+ | 命令 | 类型 | 用途 |
29
+ | --- | --- | --- |
30
+ | `baidu-netdisk status` | 读 | 检查应用账号、百度账号和设备权益状态 |
31
+ | `baidu-netdisk quota` | 读 | 查看总空间、已用空间和免费空间 |
32
+ | `baidu-netdisk ls [dir]` | 读 | 浏览目录 |
33
+ | `baidu-netdisk search <keyword>` | 读 | 搜索文件 |
34
+ | `baidu-netdisk info <fsid...>` | 读 | 获取文件元数据 |
35
+ | `baidu-netdisk mkdir <path>` | 写 | 创建目录 |
36
+ | `baidu-netdisk rm <path...>` | 写 | 删除文件或目录 |
37
+ | `baidu-netdisk rename <path> <newName>` | 写 | 重命名 |
38
+ | `baidu-netdisk move <path...> <destDir>` | 写 | 移动,最后一个参数是目标目录 |
39
+ | `baidu-netdisk copy <path...> <destDir>` | 写 | 复制,最后一个参数是目标目录 |
40
+ | `baidu-netdisk upload <targetPath> <localPath...>` | 写 | 从 NAS 上传到网盘 |
41
+ | `baidu-netdisk download <targetPath> <fsid...>` | 写 | 从网盘下载到 NAS |
42
+ | `baidu-netdisk share-save <shareUrl> <targetPath>` | 写 | 把百度分享链接内容保存到 NAS |
43
+ | `baidu-netdisk task ...` | 读/写 | 查询和控制传输任务 |
44
+ | `baidu-netdisk sync ...` | 读/写 | 查询和管理同步任务 |
45
+
46
+ ## 授权、空间和文件读取
47
+
48
+ ### `status`
49
+
50
+ ```bash
51
+ fnos-cli baidu-netdisk status
52
+ ```
53
+
54
+ 返回数据包括:
55
+
56
+ | Field | Type | Meaning |
57
+ | --- | --- | --- |
58
+ | `authorized` | boolean | 三段授权状态请求均成功时为 `true` |
59
+ | `authorizationPath` | string | NAS 应用授权入口路径 |
60
+ | `appUser.uk` | number | 应用侧百度用户标识 |
61
+ | `appUser.deviceId` | string | NAS 应用绑定的百度设备 ID |
62
+ | `baiduUser.baidu_name` | string | 百度账号名 |
63
+ | `baiduUser.netdisk_name` | string | 网盘显示名 |
64
+ | `baiduUser.vip_type` | number | `0` 普通、`1` VIP、`2` SVIP |
65
+ | `iot.is_iot_svip` | number | NAS 设备权益状态,`1` 有效、`0` 无效 |
66
+
67
+ ### `quota`
68
+
69
+ ```bash
70
+ fnos-cli baidu-netdisk quota
71
+ ```
72
+
73
+ 响应常见字段:`total`、`used`、`free`,单位均为 byte;`expire` 表示近期容量到期状态。
74
+
75
+ ### `ls`
76
+
77
+ ```bash
78
+ fnos-cli baidu-netdisk ls [dir] [--order name|size|time|ctime|path] [--ascending] [--page N] [--limit N]
79
+ ```
80
+
81
+ | Option | Required | Default | Meaning |
82
+ | --- | --- | --- | --- |
83
+ | `dir` | no | `/` | 百度网盘目录 |
84
+ | `--order` | no | `time` | 排序字段 |
85
+ | `--ascending` | no | false | 升序;缺省为降序 |
86
+ | `--page` | no | `1` | 页码,从 1 开始 |
87
+ | `--limit` | no | `80` | 每页数量,范围 1 到 1000 |
88
+
89
+ 文件条目常见字段:`fs_id`、`path`、`server_filename`、`isdir`、`category`、`size`、`server_mtime`、`server_ctime`、`thumbs`。
90
+
91
+ ### `search`
92
+
93
+ ```bash
94
+ fnos-cli baidu-netdisk search <keyword> [--dir /] [--category video|audio|image|document|application|other|seed] [--recursive] [--limit N]
95
+ ```
96
+
97
+ 响应的 `list[]` 使用与 `ls` 相同的文件字段;`has_more=1` 表示仍有后续结果。
98
+
99
+ ### `info`
100
+
101
+ ```bash
102
+ fnos-cli baidu-netdisk info <fsid...> [--dlink]
103
+ ```
104
+
105
+ `fsid` 必须是正整数。`--dlink` 请求临时下载地址,但 CLI 会对响应中的 `dlink` 值脱敏;该命令适合检查元数据,不适合导出裸下载链接。
106
+
107
+ ## 云端文件写操作
108
+
109
+ ```bash
110
+ fnos-cli baidu-netdisk mkdir <path> --yes
111
+ fnos-cli baidu-netdisk rm <path...> --yes
112
+ fnos-cli baidu-netdisk rename <path> <newName> --yes
113
+ fnos-cli baidu-netdisk move <path...> <destDir> [--ondup fail|newcopy|overwrite|skip] --yes
114
+ fnos-cli baidu-netdisk copy <path...> <destDir> [--ondup fail|newcopy|overwrite|skip] --yes
115
+ ```
116
+
117
+ | Field | Location | Meaning | Constraints |
118
+ | --- | --- | --- | --- |
119
+ | `path` | positional | 源文件或目录 | 绝对网盘路径,不允许 `.` / `..` 段 |
120
+ | `newName` | positional | 新名称 | 单个名称,不能包含 `/` 或 `\\` |
121
+ | `destDir` | final positional | 目标目录 | `move/copy` 的最后一个参数 |
122
+ | `--ondup` | option | 重名策略 | `fail` 失败、`newcopy` 保留副本、`overwrite` 覆盖、`skip` 跳过 |
123
+
124
+ 文件管理响应可能包含 `taskid` 和逐项 `info[]`;即使顶层 `errno=0`,也应检查逐项 `info[].errno`。
125
+
126
+ ## NAS 与网盘传输
127
+
128
+ ### 创建任务
129
+
130
+ ```bash
131
+ fnos-cli baidu-netdisk upload <targetPath> <localPath...> [--conflict fail|rename|overwrite] --yes
132
+ fnos-cli baidu-netdisk download <targetPath> <fsid...> [--conflict fail|rename|overwrite] --yes
133
+ ```
134
+
135
+ | Field | Command | Meaning | Constraints |
136
+ | --- | --- | --- | --- |
137
+ | `targetPath` | upload | 百度网盘目标目录 | `/` 开头的网盘路径 |
138
+ | `localPath` | upload | NAS 源路径 | 一个或多个 `/vol{n}/...` 路径 |
139
+ | `targetPath` | download | NAS 目标目录 | 具体 `/vol{n}/...` 路径 |
140
+ | `fsid` | download | 百度文件 ID | 一个或多个正整数 |
141
+ | `--conflict` | both | 冲突策略 | `fail=0`、`rename=1`、`overwrite=3` |
142
+
143
+ `uploadToCloud` 成功响应按应用合约返回 `data: null`。CLI 会输出结构化的任务提交确认,
144
+ 包括 `accepted: true`、`status: "submitted"`、目标路径、NAS 源路径、冲突策略和后端消息,
145
+ 不会把裸 `null` 当作结果,也不会声称传输已经完成。要查看进度或失败原因,继续执行:
146
+
147
+ ```bash
148
+ fnos-cli baidu-netdisk task list --transfer upload --state running
149
+ fnos-cli baidu-netdisk task list --transfer upload --state completed
150
+ fnos-cli baidu-netdisk task info <taskId> --state completed
151
+ ```
152
+
153
+ `task list/info` 默认查询 `running`。这里的 `running` 是应用定义的“未完成任务组”,会包含排队、等待、进行中、暂停和失败任务,因此返回 `status=6` 不是过滤失效。`completed` 组只包含 `status=5` 的已完成任务。
154
+
155
+ 建议在上传大文件前先执行 `baidu-netdisk quota` 检查剩余空间。任务进入 `status=6` 且
156
+ `failCode=42610` 时,表示百度网盘空间不足;这说明提交接口已经创建任务,但异步传输失败。
157
+ 先释放百度网盘空间或扩容,再重新提交,不要把它误判为 CLI、OAuth 或网关失败。
158
+
159
+ ### 保存百度分享链接
160
+
161
+ ```bash
162
+ fnos-cli baidu-netdisk share-save '<shareUrlWithPassword>' /vol1/1000/downloads --all --yes
163
+ fnos-cli baidu-netdisk share-save '<shareUrl>' /vol1/1000/downloads --password <code> --fsid <id> [--fsid <id>...] --yes
164
+ ```
165
+
166
+ - `shareUrl` 可传百度分享 URL、22 位分享短码,也可粘贴带“提取码: xxxx”的整段文本;URL 中的 `?pwd=xxxx` 也会自动识别。显式 `--password` 优先。
167
+ - 分享域名必须是 `pan.baidu.com` 或 `yun.baidu.com`;NAS 目标必须是具体 `/vol{n}/...` 目录。
168
+ - `--all` 保存分享根目录中的全部条目;若根条目是目录,百度会递归转存。需要精确选择且已知分享 fsid 时,改为重复传 `--fsid`。两种选择模式不能同时使用。
169
+ - 命令先把选中条目转存到百度网盘固定目录 `/我的资源`,轮询完成后再创建下载到 NAS 的任务;百度端重名保留副本,NAS 端重名自动改名。
170
+ - 命令最多等待百度转存 30 分钟。成功只表示 NAS 下载任务已创建,之后用 `baidu-netdisk task list --transfer download` 查看是否完成。
171
+ - 分享短码、提取码、验证后的 `spwd`、分享 fsid 和中间任务 ID 都不会写入正常输出;Agent 也不得在回复或日志中回显这些值。
172
+
173
+ ### 查询任务
174
+
175
+ ```bash
176
+ fnos-cli baidu-netdisk task list --transfer upload|download [--state running|completed] [--page N] [--page-size N] [--sort-by name|size|status] [--ascending]
177
+ fnos-cli baidu-netdisk task info <taskId> [--state running|completed] [--page N] [--page-size N] [--sort-by name|size|status] [--ascending]
178
+ ```
179
+
180
+ 任务字段常见为:`id`、`name`、`targetPath`、`savePath`、`size`、`currentSize`、`speed`、`count`、`status`、`failCode`、`createdAt`、`updatedAt`。状态值:`0` 排队、`1` 等待、`3` 进行中、`4` 暂停、`5` 完成、`6` 失败。失败任务必须同时读取 `failCode`;其中 `42610` 表示百度网盘空间不足。
181
+
182
+ ### 控制任务
183
+
184
+ ```bash
185
+ fnos-cli baidu-netdisk task pause <taskId...> --yes
186
+ fnos-cli baidu-netdisk task resume <taskId...> --yes
187
+ fnos-cli baidu-netdisk task cancel <taskId...> --yes
188
+ fnos-cli baidu-netdisk task clear [--transfer upload|download] --yes
189
+ ```
190
+
191
+ `clear` 只清理已完成任务。未指定 `--transfer` 时,CLI 依次清理上传和下载任务,并分别返回结果。
192
+
193
+ ## 同步任务
194
+
195
+ ```bash
196
+ fnos-cli baidu-netdisk sync list
197
+ fnos-cli baidu-netdisk sync create --direction download|upload --nas-path /vol1/... --netdisk-path /... [--interval 1m|10m|30m] [--conflict fail|rename|overwrite] [--immediate] [--keep-deleted] [--status running|paused] --yes
198
+ fnos-cli baidu-netdisk sync update <id> --status running|paused --interval 1m|10m|30m --conflict fail|rename|overwrite [--immediate] --yes
199
+ fnos-cli baidu-netdisk sync start|pause|delete <id> --yes
200
+ ```
201
+
202
+ | Field | API value | Meaning |
203
+ | --- | --- | --- |
204
+ | `direction=download` | `1` | 百度网盘同步到 NAS |
205
+ | `direction=upload` | `2` | NAS 同步到百度网盘 |
206
+ | `interval=1m/10m/30m` | `1/2/3` | 同步执行频率 |
207
+ | `status=running/paused` | `1/2` | 任务状态 |
208
+ | `--immediate` | `allSyncRightNow=true` | 保存配置后立即全量同步 |
209
+ | `--keep-deleted` | `dontFollowDeleted=true` | 来源删除后保留目的地文件,仅创建时设置 |
210
+
211
+ 同步任务常见响应字段:`id`、`direction`、`nasPath`、`netdiskPath`、`intervalType`、`dontFollowDeleted`、`allSyncRightNow`、`status`、`createdAt`、`updatedAt`。
212
+
213
+ ## 错误与停手条件
214
+
215
+ - fnOS session 缺失或目标 NAS 不匹配:先重新执行 `fnos-cli login`,不要改用百度账号密码。
216
+ - 百度授权错误:让用户在 NAS 百度网盘应用页面重新授权,然后重试只读 `status`。
217
+ - HTTP 502 通常表示 NAS 上的百度网盘应用未安装、未启动或网关上游不可达;这是服务可用性问题,不应重试成空结果。先用 `app list` 确认应用,再检查应用状态。
218
+ - HTTP 非 2xx、后端 `code != 0`、XPan `errno != 0`:保留响应中的 `msg`、`errmsg` 或 `show_msg`,不要只按退出码判断。
219
+ - 路径校验失败:先确认它是百度网盘路径还是 NAS `/vol{n}/...` 路径,不要自动改写。
220
+ - 分享保存失败:不要跳过验证、轮询或直接拼接下载链接;先根据 `errno` 区分链接失效、提取码错误、无权转存、选中文件无效或任务超限。
221
+ - 写操作没有 `--yes`:停下请求确认,不要绕过门禁。