@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.
- package/LICENSE +21 -0
- package/README.md +169 -2
- package/THIRD_PARTY_NOTICES.txt +38904 -0
- package/cordis.patch.yml +3 -0
- package/npm/README.dsh.md +49 -0
- package/npm/acceptance-report.cjs +53 -0
- package/npm/dsh-integration.mjs +159 -0
- package/npm/dsh-test-support.mjs +55 -0
- package/npm/dsh.mjs +31 -0
- package/npm/install.cjs +140 -0
- package/npm/package-lib.cjs +274 -0
- package/npm/run.cjs +39 -0
- package/package.json +46 -4
- package/skill/LICENSE +21 -0
- package/skill/SKILL.md +143 -0
- package/skill/THIRD_PARTY_NOTICES.txt +38904 -0
- package/skill/bin/trim-cli-darwin-arm64 +0 -0
- package/skill/bin/trim-cli-darwin-x64 +0 -0
- package/skill/bin/trim-cli-linux-arm64 +0 -0
- package/skill/bin/trim-cli-linux-x64 +0 -0
- package/skill/bin/trim-cli-windows-arm64.exe +0 -0
- package/skill/bin/trim-cli-windows-x64.exe +0 -0
- package/skill/build-provenance.json +44 -0
- package/skill/entries/trim-app.md +63 -0
- package/skill/entries/trim-baidu-netdisk.md +42 -0
- package/skill/entries/trim-docker.md +35 -0
- package/skill/entries/trim-download.md +38 -0
- package/skill/entries/trim-file.md +30 -0
- package/skill/entries/trim-log.md +32 -0
- package/skill/entries/trim-monitor.md +41 -0
- package/skill/entries/trim-network.md +22 -0
- package/skill/entries/trim-photos.md +32 -0
- package/skill/entries/trim-shared.md +54 -0
- package/skill/entries/trim-storage.md +34 -0
- package/skill/entries/trim-system.md +59 -0
- package/skill/entries/trim-user.md +28 -0
- package/skill/manifest.json +43 -0
- package/skill/reference/_conventions.md +76 -0
- package/skill/reference/_index.md +78 -0
- package/skill/reference/app-center.md +234 -0
- package/skill/reference/baidu-netdisk.md +221 -0
- package/skill/reference/dockermgr.md +244 -0
- package/skill/reference/download.md +357 -0
- package/skill/reference/file.md +752 -0
- package/skill/reference/log.md +224 -0
- package/skill/reference/network.md +41 -0
- package/skill/reference/oauth.md +51 -0
- package/skill/reference/photos.md +158 -0
- package/skill/reference/power.md +34 -0
- package/skill/reference/resmon.md +160 -0
- package/skill/reference/stor.md +525 -0
- package/skill/reference/sysinfo.md +133 -0
- package/skill/reference/user.md +139 -0
- package/skill/reference/workflows/device-validation.md +66 -0
- package/skill/reference/workflows/file-routing.md +44 -0
- package/skill/reference/workflows/file-upload-validation.md +63 -0
- package/skill/reference/workflows/photos-routing.md +83 -0
- package/skill/reference/workflows/storage-dangerous-ops.md +53 -0
- package/skill/scripts/fnos-cli +63 -0
- package/skill/scripts/fnos-cli.cmd +36 -0
- package/skill/scripts/fnos-cli.ps1 +31 -0
- package/skill/scripts/trim-cli +63 -0
- package/skill/scripts/trim-cli.cmd +36 -0
- package/skill/scripts/trim-cli.ps1 +31 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# 用户与认证参考
|
|
2
|
+
|
|
3
|
+
## OAuth 登录
|
|
4
|
+
|
|
5
|
+
fnos-cli 使用 OAuth 2.0 Authorization Code + PKCE 建立代理 session,不使用 NAS 用户名密码、
|
|
6
|
+
2FA 登录或旧 token 恢复链。CLI 按用户、文件读写、下载、应用中心、相册、系统、日志、存储和
|
|
7
|
+
Docker 模块申请 `trim.*` scope;完整列表见 `oauth.md`。
|
|
8
|
+
|
|
9
|
+
生产环境只使用交互式登录:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
fnos-cli --profile home --host <host> --port <port> login
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
CLI 输出授权链接并在当前 profile 保存一次性 PKCE verifier,然后保持运行并等待
|
|
16
|
+
`Authorization code`。用户自行在浏览器输入账号密码、确认授权、复制页面显示的 code,再粘贴
|
|
17
|
+
到 CLI 提示。不要自动填写账号密码、点击授权或读取页面 code,也不要把 code 放进命令参数。
|
|
18
|
+
无法自动打开浏览器时添加 `--no-open`。授权 URL 不包含 `redirect_uri`,不要自行追加;token
|
|
19
|
+
交换成功后一次性 PKCE 文件会被删除。
|
|
20
|
+
|
|
21
|
+
Session 保存以下认证信息:
|
|
22
|
+
|
|
23
|
+
| Field | Meaning |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `accessToken` | 代理业务请求的 Bearer token |
|
|
26
|
+
| `refreshToken` | access token 刷新凭据 |
|
|
27
|
+
| `accessTokenExpiresAt` | access token 的 Unix 秒过期时间 |
|
|
28
|
+
| `oauthClientId` | CLI 使用的 OAuth client id |
|
|
29
|
+
| `oauthDeviceId` | 本机持久化的 OAuth device id |
|
|
30
|
+
| `oauthScope` | 已授权 scope |
|
|
31
|
+
|
|
32
|
+
普通已认证命令会在 access token 临近过期时自动调用 refresh。也可以显式执行:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
fnos-cli --profile home login --refresh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
refresh 响应没有返回新 refresh token 时,CLI 保留已有 refresh token。刷新前会先确认当前
|
|
39
|
+
profile 的 session 存储可写;预检失败时停止当前命令,不发送 refresh,也不静默切换到用户名
|
|
40
|
+
密码登录。多个进程同时恢复时,CLI 会复用已写入的新 session,不覆盖较新的 token。
|
|
41
|
+
|
|
42
|
+
`logout` 只清除当前 profile 的本地 session,不表示服务端 token 已撤销:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
fnos-cli --profile home logout
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 当前用户与列表
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
fnos-cli user info
|
|
52
|
+
fnos-cli user list
|
|
53
|
+
fnos-cli user list --mode group --group Users
|
|
54
|
+
fnos-cli user request user.list --json '{"limit":100,"offset":0}'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| Command | Endpoint | Important output |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `user info` | `user.info` | `userInfo.user`、`uid`、`admin` |
|
|
60
|
+
| `user list` | `user.list` | 用户数组、总数和分页字段 |
|
|
61
|
+
| `user list --mode group` | `user.listUG` | 指定组中的用户 |
|
|
62
|
+
|
|
63
|
+
`user request` 的 endpoint 必须以 `user.` 开头;`--json` 必须是 JSON object,且不能手工提供
|
|
64
|
+
`req` 或 `reqid`。通用 `user request` 无法从 endpoint 名称可靠判断读写属性,因此默认要求确认;
|
|
65
|
+
自动化时需明确传 `--yes`。已封装的 `user info`、`user list` 等专用只读命令不需要该参数。
|
|
66
|
+
|
|
67
|
+
## 用户写操作
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
fnos-cli user add <user> [--password <initial-password>] [--groups Users] [--set-admin] --yes
|
|
71
|
+
fnos-cli user mod <user> [--new-name <name>] [--password <new-password>] [--groups Users] --yes
|
|
72
|
+
fnos-cli user del <user> --yes
|
|
73
|
+
fnos-cli user change-password <user> --yes
|
|
74
|
+
fnos-cli user unfreeze <user> --yes
|
|
75
|
+
fnos-cli user set-admin <user> --admin true --yes
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
| Command | Endpoint | Main request fields |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `user add` | `user.add` | `user`、`password`、`groups`、可选联系信息和管理员标记 |
|
|
81
|
+
| `user mod` | `user.mod` | `user` 加显式提供的变更字段 |
|
|
82
|
+
| `user del` | `user.del` | `user` |
|
|
83
|
+
| `user change-password` | `user.changePassword` | `user`、交互输入的新密码 |
|
|
84
|
+
| `user unfreeze` | `user.unfreeze` | `user` |
|
|
85
|
+
| `user set-admin` | `user.setAdmin` | `user`、`admin` |
|
|
86
|
+
|
|
87
|
+
这里的 `--password` 是创建用户或修改目标用户密码,不是 CLI 登录凭据。不要把用户管理密码
|
|
88
|
+
改写成登录参数。密码不要出现在回复、日志或长期保存的命令记录中;省略可交互输入的密码参数。
|
|
89
|
+
|
|
90
|
+
删除用户、修改管理员权限、改密码和解冻属于写操作,未得到用户明确授权时不要执行。
|
|
91
|
+
|
|
92
|
+
## 用户组
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
fnos-cli user group list
|
|
96
|
+
fnos-cli user group info <group>
|
|
97
|
+
fnos-cli user group users <group>
|
|
98
|
+
fnos-cli user group add <group> [--comment <text>] --yes
|
|
99
|
+
fnos-cli user group mod <group> [--new-name <name>] [--comment <text>] --yes
|
|
100
|
+
fnos-cli user group del <group> --yes
|
|
101
|
+
fnos-cli user group set-users <group> --users <user> --yes
|
|
102
|
+
fnos-cli user group add-users <group> --users <user> --yes
|
|
103
|
+
fnos-cli user group del-users <group> --users <user> --yes
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Command | Endpoint | Main request fields |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| `group list` | `user.groupList` | 无 |
|
|
109
|
+
| `group info` | `user.groupInfo` | `group` |
|
|
110
|
+
| `group users` | `user.groupUsers` | `group` |
|
|
111
|
+
| `group add` | `user.groupAdd` | `group`、可选 `comment` |
|
|
112
|
+
| `group mod` | `user.groupMod` | `group`、可选新名称和备注 |
|
|
113
|
+
| `group del` | `user.groupDel` | `group` |
|
|
114
|
+
| `group set-users` | `user.groupSetUsers` | `group`、`users` |
|
|
115
|
+
| `group add-users` | `user.groupAddUsers` | `group`、`users` |
|
|
116
|
+
| `group del-users` | `user.groupDelUsers` | `group`、`users` |
|
|
117
|
+
|
|
118
|
+
`--users` 和 `--groups` 支持重复参数或逗号分隔值。空列表、控制字符和明显非法名称会在发请求
|
|
119
|
+
前被拒绝。
|
|
120
|
+
|
|
121
|
+
## 登录设备
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
fnos-cli user login-devices
|
|
125
|
+
fnos-cli user request user.listLoginDevice
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
登录设备列表是用户管理数据,不参与 CLI 的 OAuth PKCE 登录。不要根据设备列表尝试旧的
|
|
129
|
+
trusted-device/2FA 登录流程。
|
|
130
|
+
|
|
131
|
+
## 错误处理
|
|
132
|
+
|
|
133
|
+
- `saved proxy session is required`:先完成 OAuth 登录。
|
|
134
|
+
- OAuth pending 缺失或过期:重新运行完整的交互式 `login`,不要单独拼装兑换命令。
|
|
135
|
+
- refresh 失败或 refresh token 缺失:重新运行 OAuth 登录,不回退到账号密码。
|
|
136
|
+
- refresh 返回后 session 最终写入失败:不要盲目复用旧 refresh token;它可能已被轮换,应重新登录。
|
|
137
|
+
- 权限错误:先用 `user info` 确认 `admin`,不要自动提升权限。
|
|
138
|
+
- 写操作未确认:向用户说明目标和影响,得到授权后再传 `--yes`。
|
|
139
|
+
- 响应含业务错误码时原样报告错误语义,不要只依据 HTTP 状态判断成功。
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Device validation
|
|
2
|
+
|
|
3
|
+
Use this workflow for interactive OAuth, minimal probes and read-after-write verification.
|
|
4
|
+
|
|
5
|
+
## 1. User authorization
|
|
6
|
+
|
|
7
|
+
Production validation uses interactive OAuth PKCE:
|
|
8
|
+
|
|
9
|
+
1. The user runs `fnos-cli --profile <profile> --host <host> --port <port> login`
|
|
10
|
+
in their own interactive terminal.
|
|
11
|
+
2. The CLI displays an authorization link and waits.
|
|
12
|
+
3. The user opens the link, signs in and approves access in the browser.
|
|
13
|
+
4. The user copies the one-time code into the CLI's `Authorization code` prompt.
|
|
14
|
+
5. The CLI exchanges the code and saves the selected profile's session.
|
|
15
|
+
|
|
16
|
+
The Agent does not collect credentials, approve access, read browser codes or
|
|
17
|
+
pass codes as arguments. Add `--no-open` if the browser cannot open automatically;
|
|
18
|
+
the remaining steps are unchanged. Authorization URLs omit `redirect_uri`.
|
|
19
|
+
|
|
20
|
+
For DSH, the login terminal must share the DSH Host, system user, configuration
|
|
21
|
+
environment and `--profile`. Remote browsers, SSH shells and containers do not
|
|
22
|
+
automatically inherit that session. macOS background Keychain access may need
|
|
23
|
+
system approval.
|
|
24
|
+
|
|
25
|
+
## 2. Minimal read-only probes
|
|
26
|
+
|
|
27
|
+
Before any write:
|
|
28
|
+
|
|
29
|
+
1. Confirm interactive login established the intended profile's session; do not
|
|
30
|
+
preconfigure or rotate accounts as part of validation.
|
|
31
|
+
2. Run one or two read-only commands for the target module to check connectivity
|
|
32
|
+
and permissions.
|
|
33
|
+
3. For files, prefer `file ls` or a read-only search.
|
|
34
|
+
4. For storage, use `storage pools` / `storage disks`.
|
|
35
|
+
5. For Docker, use `docker stats` or `docker container ls`.
|
|
36
|
+
|
|
37
|
+
Confirm the device target, session and sufficient current-user permissions.
|
|
38
|
+
|
|
39
|
+
## 3. Write sequence
|
|
40
|
+
|
|
41
|
+
1. Probe the closest relevant read-only state.
|
|
42
|
+
2. Perform one authorized, explainable and reversible write.
|
|
43
|
+
3. Immediately read the resulting state.
|
|
44
|
+
4. Clean up temporary resources when appropriate.
|
|
45
|
+
|
|
46
|
+
Keep unrelated writes out of the same validation run.
|
|
47
|
+
|
|
48
|
+
## 4. Read-after-write verification
|
|
49
|
+
|
|
50
|
+
Use at least one relevant check:
|
|
51
|
+
|
|
52
|
+
- Files: `ls`, `search` or `share list`.
|
|
53
|
+
- Storage: `pools`, `disks` or `removable`.
|
|
54
|
+
- Docker: `image ls`, `container ls` or `compose ls`.
|
|
55
|
+
- Users: `user list` or `group list`.
|
|
56
|
+
|
|
57
|
+
Only claim success when the before/after states can be compared objectively.
|
|
58
|
+
|
|
59
|
+
## 5. Stop and ask
|
|
60
|
+
|
|
61
|
+
Stop when OAuth or code exchange fails, the target host is missing, a write may
|
|
62
|
+
affect production data/services, or responses conflict with documented
|
|
63
|
+
constraints and suggest firmware differences.
|
|
64
|
+
|
|
65
|
+
Read the module reference once the command is selected. Resolve unknown
|
|
66
|
+
profiles, permissions and device state before proceeding.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# File paths and shared-directory routing
|
|
2
|
+
|
|
3
|
+
Select the command first, then read `../file.md` for field details.
|
|
4
|
+
|
|
5
|
+
## 1. Match the intent
|
|
6
|
+
|
|
7
|
+
| Intent | Preferred command | Path and semantic rule |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| List currently visible directories | `fnos-cli file ls` | Both no argument and `/` omit `path`; this does not promise all volumes |
|
|
10
|
+
| List a concrete directory | `fnos-cli file ls /vol{n}/...` | Keep aggregate roots separate from canonical paths |
|
|
11
|
+
| Search the current user's files | `fnos-cli file search <key>` | Let the CLI probe and derive the current-user directory |
|
|
12
|
+
| Search a specified directory | `fnos-cli file search <key> /vol{n}/...` | Use concrete canonical paths |
|
|
13
|
+
| Upload a local file | `fnos-cli file upload /vol{n}/... <localFile> --yes` | The remote argument is a directory, not a final filename |
|
|
14
|
+
| Search files shared with me | `fnos-cli file search-others <key>` | Distinct from shared-directory listing |
|
|
15
|
+
| Inspect a shared directory | `fnos-cli file share info <path>` | Not share-link management |
|
|
16
|
+
| List visible shared directories | `fnos-cli file share list [uid]` | Not file search |
|
|
17
|
+
| Inspect ACLs | `fnos-cli file acl get <path>` | Permission data, not shared-directory state |
|
|
18
|
+
| Create/delete/copy/move files | `file mkdir/rm/cp/mv` | Concrete paths and explicit `--yes` |
|
|
19
|
+
|
|
20
|
+
## 2. Resolve paths
|
|
21
|
+
|
|
22
|
+
1. Writes require concrete canonical `/vol{n}/...` paths.
|
|
23
|
+
2. `file ls` and `file ls /` both omit `path`; neither explicitly requests aggregate root `/`.
|
|
24
|
+
3. Search without a path lets the CLI probe the current-user directory via `file.ls`.
|
|
25
|
+
4. Every explicit search path must be `/vol{n}/...`.
|
|
26
|
+
5. For files shared by others, choose `search-others` or `share list-others` as appropriate.
|
|
27
|
+
|
|
28
|
+
## 3. Important distinctions
|
|
29
|
+
|
|
30
|
+
- Shared directories use `file share.*`, not share links.
|
|
31
|
+
- `file search-others` returns matching files, not a shared-directory list.
|
|
32
|
+
- ACL queries report permissions, not share status.
|
|
33
|
+
- `file cp` / `file mv` take a destination directory, not a final filename.
|
|
34
|
+
- Upload `uploadName` is an HTTP upload/resume path, not necessarily the visible filename.
|
|
35
|
+
|
|
36
|
+
## 4. Stop and ask
|
|
37
|
+
|
|
38
|
+
Clarify writes with only `/`, relative or ambiguous paths; requests for share
|
|
39
|
+
links when only shared-directory APIs are documented; mixed noncanonical search
|
|
40
|
+
paths; and assumptions that the current-user directory is a fixed value.
|
|
41
|
+
|
|
42
|
+
For fields read [file.md](../file.md). For uploads read
|
|
43
|
+
[file-upload-validation.md](file-upload-validation.md). Resolve path semantics
|
|
44
|
+
before constructing a payload.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Upload validation
|
|
2
|
+
|
|
3
|
+
Verify small uploads, same-name policies and resumable large uploads.
|
|
4
|
+
|
|
5
|
+
## 1. Prerequisites
|
|
6
|
+
|
|
7
|
+
- A signed-in target NAS.
|
|
8
|
+
- A confirmed writable `/vol{n}/...` directory.
|
|
9
|
+
- An existing local regular file.
|
|
10
|
+
|
|
11
|
+
## 2. Small file
|
|
12
|
+
|
|
13
|
+
1. Create a temporary subdirectory in the confirmed writable directory.
|
|
14
|
+
2. Upload a local file smaller than 20 MiB:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
fnos-cli file upload /vol1/1000/tmp-upload ./demo.txt --overwrite rename --yes
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
3. List the temporary directory:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
fnos-cli file ls /vol1/1000/tmp-upload
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
4. Confirm the CLI reports the requested target path and the directory contains
|
|
27
|
+
the matching filename.
|
|
28
|
+
|
|
29
|
+
## 3. Large file
|
|
30
|
+
|
|
31
|
+
1. Prepare a local file of at least 20 MiB.
|
|
32
|
+
2. Upload it:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
fnos-cli file upload /vol1/1000/tmp-upload ./large.bin --overwrite rename --yes
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
3. List the directory and confirm the original filename exists remotely.
|
|
39
|
+
4. When diagnosing resume, inspect the upload cache in the local configuration
|
|
40
|
+
directory. Its `upload_path` is the backend's `.~#n` upload path, not the final filename.
|
|
41
|
+
5. Resume only when endpoint, profile, signed-in user, remote target, size,
|
|
42
|
+
overwrite policy and local SHA-256 all match. A different same-size file at
|
|
43
|
+
the same local path must begin a new `check-upload`.
|
|
44
|
+
6. Concurrent uploads to the same endpoint and remote target serialize across
|
|
45
|
+
processes; lock waiting does not by itself indicate corrupt cache.
|
|
46
|
+
|
|
47
|
+
## 4. Cleanup
|
|
48
|
+
|
|
49
|
+
After verifying the exact temporary paths, remove the uploaded files and directory:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
fnos-cli file rm /vol1/1000/tmp-upload/demo.txt --yes
|
|
53
|
+
fnos-cli file rm /vol1/1000/tmp-upload/large.bin --yes
|
|
54
|
+
fnos-cli file rm /vol1/1000/tmp-upload --yes
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 5. Completion criteria
|
|
58
|
+
|
|
59
|
+
The successful output uses the requested path, and `file ls` shows the uploaded
|
|
60
|
+
file. Small files do not depend on resume cache. Large files may create cache;
|
|
61
|
+
cache paths support HTTP upload/resume and are not visible result paths.
|
|
62
|
+
Legacy caches, caches missing identity fields and local fingerprint mismatches
|
|
63
|
+
must not resume.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Photo task routing
|
|
2
|
+
|
|
3
|
+
Use for library statistics, filtered search, AI semantic search and sampled previews.
|
|
4
|
+
Read the Photos reference after selecting a command.
|
|
5
|
+
|
|
6
|
+
## 1. Authentication
|
|
7
|
+
|
|
8
|
+
Photos reuses the current profile's proxy session. Without a valid session, the
|
|
9
|
+
user runs interactive `fnos-cli login`, opens the link, signs in, authorizes
|
|
10
|
+
and pastes the one-time code into the CLI. The Agent does not enter credentials,
|
|
11
|
+
approve access or read browser codes.
|
|
12
|
+
|
|
13
|
+
For multiple devices, select `--profile`, `--host` and `--port` explicitly.
|
|
14
|
+
Sessions are not interchangeable across devices.
|
|
15
|
+
|
|
16
|
+
## 2. Scenarios
|
|
17
|
+
|
|
18
|
+
### Library scope and size
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
fnos-cli photos folders
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Summarize returned photo/video counts per scanned folder. Photos indexes only
|
|
25
|
+
folders added to scanning; filesystem image counts are not library index counts.
|
|
26
|
+
|
|
27
|
+
### Filtered search and counts
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
fnos-cli photos search Beijing --limit 20
|
|
31
|
+
fnos-cli photos search IMG --filter file_type=photo --limit 20
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Report the response's `total` as the full match count; `list` is the returned
|
|
35
|
+
sample. For previews, choose a few representative results and call
|
|
36
|
+
`photos preview <id> --size m`, rather than fetching every original.
|
|
37
|
+
|
|
38
|
+
### Natural-language AI search
|
|
39
|
+
|
|
40
|
+
Check readiness before searching:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
fnos-cli photos request post /api/v1/magic-search/ready --yes
|
|
44
|
+
fnos-cli photos request post /api/v1/magic-search/do \
|
|
45
|
+
--json '{"keyword":"sunset at the beach","antiFilters":[]}' --yes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
AI search is a separate endpoint from filtered `photos search`. It usually
|
|
49
|
+
returns `response.data.list` without a stable `total`; report only the number
|
|
50
|
+
returned. If the model is missing, not ready or incompatible with the query
|
|
51
|
+
language, report the business error. A filename-search fallback is not an AI result.
|
|
52
|
+
|
|
53
|
+
`photos request` preserves the raw envelope and can exit 0 even when
|
|
54
|
+
`response.code != 0`. Both calls require `httpStatus` in `200..299` and
|
|
55
|
+
`response.code == 0`. Select result IDs from `response.data.list` for previews.
|
|
56
|
+
|
|
57
|
+
### Sampled previews
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
fnos-cli photos preview <id> --size m
|
|
61
|
+
fnos-cli photos preview <id> --size o
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Prefer medium previews; use `--size o` only when the user asks for originals.
|
|
65
|
+
|
|
66
|
+
## 3. Counts and links
|
|
67
|
+
|
|
68
|
+
| Result | Meaning | Caveat |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| Filtered search `total` | All matches | Not the current `list` length |
|
|
71
|
+
| AI `list` length | Returned count | Not an exact total without `total` |
|
|
72
|
+
| `previewUrl` | Thumbnail, original or video preview | Browser usually needs a signed-in fnOS cookie |
|
|
73
|
+
|
|
74
|
+
Keep secure-store tokens private and preserve the CLI's sensitive-URI redaction.
|
|
75
|
+
|
|
76
|
+
## 4. Stop and clarify
|
|
77
|
+
|
|
78
|
+
Clarify exact-count requests when AI results lack `total`, public-preview
|
|
79
|
+
requests without browser authentication, and preview-only tasks that would
|
|
80
|
+
fetch every original. Stop on non-2xx `httpStatus` or nonzero `response.code`.
|
|
81
|
+
|
|
82
|
+
Read [photos.md](../photos.md) for fields/filters/AI endpoints and
|
|
83
|
+
[device-validation.md](device-validation.md) for device differences.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# High-risk storage operations
|
|
2
|
+
|
|
3
|
+
Probe read-only state before deciding whether a storage write can proceed.
|
|
4
|
+
|
|
5
|
+
## 1. Identify high-risk writes
|
|
6
|
+
|
|
7
|
+
Use this workflow before `storage umount/create/stop/add-disk/remove-disk/replace-disk/resize/extend/format/eject/disk-mount/disk-umount`,
|
|
8
|
+
and before `storage request` unless the endpoint is confirmed read-only.
|
|
9
|
+
|
|
10
|
+
`storage mount` is lower risk but still requires the pool identifier and current
|
|
11
|
+
state. Removable-disk mount/unmount operations require the exact disk target.
|
|
12
|
+
|
|
13
|
+
## 2. Read-only probes
|
|
14
|
+
|
|
15
|
+
1. `fnos-cli storage pools`.
|
|
16
|
+
2. `fnos-cli storage disks`.
|
|
17
|
+
3. Before pool creation, `fnos-cli storage free-disks`.
|
|
18
|
+
4. As needed, `fnos-cli storage health <disk>` or `storage smart <disk>`.
|
|
19
|
+
5. For removable devices, `storage removable` and `storage disk-info <disk>`.
|
|
20
|
+
|
|
21
|
+
Confirm whether the target is a pool UUID/`trim_*` identifier or plain disk
|
|
22
|
+
name, its state and removability. For remaining space on a system disk, use the
|
|
23
|
+
returned `part`, not whole-disk `name`. Keep disk and pool operations distinct.
|
|
24
|
+
|
|
25
|
+
## 3. Password and confirmation policy
|
|
26
|
+
|
|
27
|
+
| Policy | Commands |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Verify and forward password | `umount`, `create`, `stop`, `add-disk`, `remove-disk`, `replace-disk`, `resize` |
|
|
30
|
+
| Verify without forwarding | `extend`, `format`, `eject` |
|
|
31
|
+
| Confirmation without password verification | `mount`, `disk-mount`, `disk-umount` |
|
|
32
|
+
| Generic request | `request` requires confirmation; explicit `--password` is verified and forwarded |
|
|
33
|
+
|
|
34
|
+
Agent/noninteractive writes explicitly pass `--yes`. For the first two rows,
|
|
35
|
+
stop if the required password is unavailable; there is no assumed default.
|
|
36
|
+
Treat potentially mutating `stor.*` requests as high risk.
|
|
37
|
+
|
|
38
|
+
## 4. Distinctions
|
|
39
|
+
|
|
40
|
+
- `mount` is not the inverse of `stop`; check pool state.
|
|
41
|
+
- `extend` and `resize` are different operations.
|
|
42
|
+
- `format` / `eject` target removable devices, not ordinary pools.
|
|
43
|
+
- Pools use UUIDs or `trim_*`, not legacy `name`.
|
|
44
|
+
- Disks use plain names such as `sda` or `nvme0n1`, not `/dev/sda`.
|
|
45
|
+
|
|
46
|
+
## 5. Stop and clarify
|
|
47
|
+
|
|
48
|
+
Stop for ambiguous pool/disk targets, probe results inconsistent with the user's
|
|
49
|
+
description, unavailable required passwords, or stopped/unmounted/non-expandable
|
|
50
|
+
targets and standby/abnormal disks.
|
|
51
|
+
|
|
52
|
+
Once target and order are confirmed, read [stor.md](../stor.md). Otherwise remain
|
|
53
|
+
at the read-only probe stage.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
6
|
+
BIN_DIR="$SCRIPT_DIR/../bin"
|
|
7
|
+
|
|
8
|
+
reject_media_command() {
|
|
9
|
+
skip_value=0
|
|
10
|
+
for arg in "$@"; do
|
|
11
|
+
if [ "$skip_value" -eq 1 ]; then
|
|
12
|
+
skip_value=0
|
|
13
|
+
continue
|
|
14
|
+
fi
|
|
15
|
+
case "$arg" in
|
|
16
|
+
--host|--port|--profile|--scheme)
|
|
17
|
+
skip_value=1
|
|
18
|
+
;;
|
|
19
|
+
--host=*|--port=*|--profile=*|--scheme=*|--allow-insecure-http|--tls-insecure)
|
|
20
|
+
;;
|
|
21
|
+
--*)
|
|
22
|
+
;;
|
|
23
|
+
media)
|
|
24
|
+
echo "Media commands are not available in this skill package." >&2
|
|
25
|
+
exit 2
|
|
26
|
+
;;
|
|
27
|
+
*)
|
|
28
|
+
return
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
reject_media_command "$@"
|
|
35
|
+
|
|
36
|
+
OS=$(uname -s)
|
|
37
|
+
ARCH=$(uname -m)
|
|
38
|
+
|
|
39
|
+
case "$OS:$ARCH" in
|
|
40
|
+
Darwin:arm64)
|
|
41
|
+
TARGET="$BIN_DIR/trim-cli-darwin-arm64"
|
|
42
|
+
;;
|
|
43
|
+
Darwin:x86_64)
|
|
44
|
+
TARGET="$BIN_DIR/trim-cli-darwin-x64"
|
|
45
|
+
;;
|
|
46
|
+
Linux:x86_64)
|
|
47
|
+
TARGET="$BIN_DIR/trim-cli-linux-x64"
|
|
48
|
+
;;
|
|
49
|
+
Linux:aarch64|Linux:arm64)
|
|
50
|
+
TARGET="$BIN_DIR/trim-cli-linux-arm64"
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
echo "Unsupported platform for $0: $OS $ARCH" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
;;
|
|
56
|
+
esac
|
|
57
|
+
|
|
58
|
+
if [ ! -x "$TARGET" ]; then
|
|
59
|
+
echo "Missing packaged binary: $TARGET" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
exec "$TARGET" "$@"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal
|
|
3
|
+
|
|
4
|
+
call :reject_media %*
|
|
5
|
+
if errorlevel 1 exit /b %errorlevel%
|
|
6
|
+
|
|
7
|
+
set "SCRIPT_DIR=%~dp0"
|
|
8
|
+
set "ARCH=%PROCESSOR_ARCHITECTURE%"
|
|
9
|
+
if defined PROCESSOR_ARCHITEW6432 set "ARCH=%PROCESSOR_ARCHITEW6432%"
|
|
10
|
+
if /I "%ARCH%"=="ARM64" (
|
|
11
|
+
set "TARGET=%SCRIPT_DIR%..\bin\trim-cli-windows-arm64.exe"
|
|
12
|
+
) else (
|
|
13
|
+
set "TARGET=%SCRIPT_DIR%..\bin\trim-cli-windows-x64.exe"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if not exist "%TARGET%" (
|
|
17
|
+
echo Missing packaged binary: %TARGET% 1>&2
|
|
18
|
+
exit /b 1
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
"%TARGET%" %*
|
|
22
|
+
exit /b %errorlevel%
|
|
23
|
+
|
|
24
|
+
:reject_media
|
|
25
|
+
if "%~1"=="" exit /b 0
|
|
26
|
+
set "ARG=%~1"
|
|
27
|
+
if /I "%ARG%"=="--host" shift&shift&goto reject_media
|
|
28
|
+
if /I "%ARG%"=="--port" shift&shift&goto reject_media
|
|
29
|
+
if /I "%ARG%"=="--profile" shift&shift&goto reject_media
|
|
30
|
+
if /I "%ARG%"=="--scheme" shift&shift&goto reject_media
|
|
31
|
+
if "%ARG:~0,1%"=="-" shift&goto reject_media
|
|
32
|
+
if /I "%ARG%"=="media" (
|
|
33
|
+
echo Media commands are not available in this skill package. 1>&2
|
|
34
|
+
exit /b 2
|
|
35
|
+
)
|
|
36
|
+
exit /b 0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
$Architecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
|
|
2
|
+
$Platform = if ($Architecture -eq "Arm64") { "windows-arm64" } else { "windows-x64" }
|
|
3
|
+
$Target = Join-Path $PSScriptRoot "..\bin\trim-cli-$Platform.exe"
|
|
4
|
+
|
|
5
|
+
$SkipValue = $false
|
|
6
|
+
foreach ($Argument in $args) {
|
|
7
|
+
if ($SkipValue) {
|
|
8
|
+
$SkipValue = $false
|
|
9
|
+
continue
|
|
10
|
+
}
|
|
11
|
+
if ($Argument -in @("--host", "--port", "--profile", "--scheme")) {
|
|
12
|
+
$SkipValue = $true
|
|
13
|
+
continue
|
|
14
|
+
}
|
|
15
|
+
if ($Argument.StartsWith("-")) {
|
|
16
|
+
continue
|
|
17
|
+
}
|
|
18
|
+
if ($Argument -eq "media") {
|
|
19
|
+
Write-Error "Media commands are not available in this skill package."
|
|
20
|
+
exit 2
|
|
21
|
+
}
|
|
22
|
+
break
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (-not (Test-Path $Target)) {
|
|
26
|
+
Write-Error "Missing packaged binary: $Target"
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
& $Target @args
|
|
31
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
6
|
+
BIN_DIR="$SCRIPT_DIR/../bin"
|
|
7
|
+
|
|
8
|
+
reject_media_command() {
|
|
9
|
+
skip_value=0
|
|
10
|
+
for arg in "$@"; do
|
|
11
|
+
if [ "$skip_value" -eq 1 ]; then
|
|
12
|
+
skip_value=0
|
|
13
|
+
continue
|
|
14
|
+
fi
|
|
15
|
+
case "$arg" in
|
|
16
|
+
--host|--port|--profile|--scheme)
|
|
17
|
+
skip_value=1
|
|
18
|
+
;;
|
|
19
|
+
--host=*|--port=*|--profile=*|--scheme=*|--allow-insecure-http|--tls-insecure)
|
|
20
|
+
;;
|
|
21
|
+
--*)
|
|
22
|
+
;;
|
|
23
|
+
media)
|
|
24
|
+
echo "Media commands are not available in this skill package." >&2
|
|
25
|
+
exit 2
|
|
26
|
+
;;
|
|
27
|
+
*)
|
|
28
|
+
return
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
reject_media_command "$@"
|
|
35
|
+
|
|
36
|
+
OS=$(uname -s)
|
|
37
|
+
ARCH=$(uname -m)
|
|
38
|
+
|
|
39
|
+
case "$OS:$ARCH" in
|
|
40
|
+
Darwin:arm64)
|
|
41
|
+
TARGET="$BIN_DIR/trim-cli-darwin-arm64"
|
|
42
|
+
;;
|
|
43
|
+
Darwin:x86_64)
|
|
44
|
+
TARGET="$BIN_DIR/trim-cli-darwin-x64"
|
|
45
|
+
;;
|
|
46
|
+
Linux:x86_64)
|
|
47
|
+
TARGET="$BIN_DIR/trim-cli-linux-x64"
|
|
48
|
+
;;
|
|
49
|
+
Linux:aarch64|Linux:arm64)
|
|
50
|
+
TARGET="$BIN_DIR/trim-cli-linux-arm64"
|
|
51
|
+
;;
|
|
52
|
+
*)
|
|
53
|
+
echo "Unsupported platform for $0: $OS $ARCH" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
;;
|
|
56
|
+
esac
|
|
57
|
+
|
|
58
|
+
if [ ! -x "$TARGET" ]; then
|
|
59
|
+
echo "Missing packaged binary: $TARGET" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
exec "$TARGET" "$@"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
setlocal
|
|
3
|
+
|
|
4
|
+
call :reject_media %*
|
|
5
|
+
if errorlevel 1 exit /b %errorlevel%
|
|
6
|
+
|
|
7
|
+
set "SCRIPT_DIR=%~dp0"
|
|
8
|
+
set "ARCH=%PROCESSOR_ARCHITECTURE%"
|
|
9
|
+
if defined PROCESSOR_ARCHITEW6432 set "ARCH=%PROCESSOR_ARCHITEW6432%"
|
|
10
|
+
if /I "%ARCH%"=="ARM64" (
|
|
11
|
+
set "TARGET=%SCRIPT_DIR%..\bin\trim-cli-windows-arm64.exe"
|
|
12
|
+
) else (
|
|
13
|
+
set "TARGET=%SCRIPT_DIR%..\bin\trim-cli-windows-x64.exe"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if not exist "%TARGET%" (
|
|
17
|
+
echo Missing packaged binary: %TARGET% 1>&2
|
|
18
|
+
exit /b 1
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
"%TARGET%" %*
|
|
22
|
+
exit /b %errorlevel%
|
|
23
|
+
|
|
24
|
+
:reject_media
|
|
25
|
+
if "%~1"=="" exit /b 0
|
|
26
|
+
set "ARG=%~1"
|
|
27
|
+
if /I "%ARG%"=="--host" shift&shift&goto reject_media
|
|
28
|
+
if /I "%ARG%"=="--port" shift&shift&goto reject_media
|
|
29
|
+
if /I "%ARG%"=="--profile" shift&shift&goto reject_media
|
|
30
|
+
if /I "%ARG%"=="--scheme" shift&shift&goto reject_media
|
|
31
|
+
if "%ARG:~0,1%"=="-" shift&goto reject_media
|
|
32
|
+
if /I "%ARG%"=="media" (
|
|
33
|
+
echo Media commands are not available in this skill package. 1>&2
|
|
34
|
+
exit /b 2
|
|
35
|
+
)
|
|
36
|
+
exit /b 0
|