@seeed-studio/solution-cli 0.3.2 → 0.4.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.
@@ -1,89 +1,49 @@
1
1
  # Deploy a solution
2
2
 
3
- Run Step 0 in `SKILL.md` first (engine installed, solutions pulled). Examples
4
- use `--lang en`; use `--lang zh` for a Chinese-speaking user.
3
+ Run Step 0 in `SKILL.md` first. Use `--lang zh` for a Chinese user and `--lang en` for an English user. The examples below use the absolute Engine path injected into the installed Skill; keep that path in place of `sensecraft-engine` when required.
5
4
 
6
5
  ## 1. Find the solution
7
6
 
8
- ```
7
+ ```bash
8
+ solution-cli hub search "<user request>" --limit 5 --json
9
+ solution-cli hub get <reference-design-id> --locale <en|zh|ja> --section deployment --json
9
10
  sensecraft-engine solution list --json
10
11
  ```
11
12
 
12
- Match the user's wording against `name` / `summary`. Confirm the `id` with the
13
- user if more than one fits. `sensecraft-engine solution show <id> --lang en`
14
- prints the full solution if you need more detail.
13
+ The Hub record identifies the business Scenario, its related Tech/RD records,
14
+ the deployment-document mapping, and production links. Match the request to a
15
+ Reference Design first; do not treat a Scenario or Tech page as an executable
16
+ solution. Then use the Engine's local list and `deploy-info` to confirm that
17
+ the mapped `solution_id` and presets are actually installed. If several RDs
18
+ fit, explain the difference and ask which one to use.
15
19
 
16
20
  ## 2. Read what the deployment needs
17
21
 
22
+ ```bash
23
+ sensecraft-engine deploy-info <id> --lang zh
24
+ sensecraft-engine doctor --json
25
+ sensecraft-engine device ports
26
+ sensecraft-engine device scan --timeout 5
18
27
  ```
19
- sensecraft-engine deploy-info <id> --lang en
20
- ```
21
-
22
- - `presets[]` — deployment variants. If there is more than one, ask the user which
23
- one, then run again with `--preset <preset>`. Without `--preset` the template
24
- lists the steps of every preset.
25
- - `steps[]` — each step's `device_id`, `type`, `required`, `connection_type`
26
- (`ssh` / `serial` / `none` / ...), `parameters`, `category` (`deploy` or
27
- `verify`) and `interactive`. Steps with `has_targets: true` (e.g.
28
- `docker_deploy`) list `targets`: `local` = this computer's Docker, `remote` =
29
- a device over SSH.
30
- - Verify steps that need the user carry a ready command list:
31
- `counting_cli`, `face_cli`, `wizard_cli` or `robot_cli` (see `verify.md`).
32
- - `request_template` — a ready request body. Values shaped like
33
- `<REQUIRED: ...>` must be filled in; everything else has a working default.
34
-
35
- Never make up step or device IDs: the keys of `device_connections` and the
36
- entries of `selected_devices` are exactly the ones in `request_template`.
37
-
38
- Optional discovery, to pre-fill values:
39
-
40
- ```
41
- sensecraft-engine device ports # serial ports (USB devices)
42
- sensecraft-engine device scan --timeout 5 # SSH devices on the LAN (mDNS, IPv4)
43
- sensecraft-engine device list # device catalog
44
- sensecraft-engine doctor --json # this computer: serial permission, Docker, disk, network
45
- ```
46
-
47
- ## 3. Fill in and confirm
48
-
49
- Ask the user for every `<REQUIRED: ...>` value (device IP, username, password,
50
- serial port, and any user inputs). Serial steps carry both `port` and
51
- `serial_port` placeholders; fill both with the port name from `device ports`.
52
28
 
53
- For `docker_deploy` steps pick the target with `"target": "<target id>"` **and
54
- set `"target_type"` to that target's own type** (`local` / `remote`) — or
55
- remove `target_type`. Leaving the template's type while switching `target` is
56
- rejected. Each deploy-info target carries `type` (`local` / `remote`) and,
57
- when the target is tied to a board, `device` / `device_name` /
58
- `device_class` (for example `rk3576`, `RK3576`): pick the target whose
59
- `type` and device match the user's hardware, and copy its `type` into
60
- `target_type`. `device` is null for targets that run on any Docker host. On
61
- engine builds whose targets have no `type` yet, the target id suffix (for
62
- example `_local`, `_remote`) is only a hint; confirm the type with `validate`
63
- (§3, dry run) before starting. Remote targets need `host`, `username`
64
- and either `password` or `key_file`:
29
+ Read `presets[]`, `steps[]`, `device_connections`, `selected_devices`, and `request_template` from `deploy-info`. A preset with more than one variant requires the user's choice. Fill every `<REQUIRED: ...>` value from the user or a read-only device check; never invent device IDs, connection keys, SSH credentials, serial ports, or Docker targets.
65
30
 
66
- Windows native `local` Docker is unsupported by both deployers and returns the
67
- platform check failure; use a `remote` target over SSH to a Linux Docker host.
68
- WSL must use the Linux engine binary and is Linux-host evidence, not Windows
69
- native local Docker support. On macOS, the local target uses the literal
70
- `docker` executable visible to the new engine process. If Docker Desktop's CLI
71
- is only in its application bundle, provide that bundle's `bin` directory in a
72
- temporary engine-process `PATH`; do not alter global shell configuration or
73
- assume an already-running instance inherits the path. Docker Desktop being
74
- running is a prerequisite check, not a deployment result.
31
+ For a `docker_deploy` step, use the target listed by `deploy-info` and copy its `type` into `target_type` (`local` or `remote`). Linux local and remote targets may declare `auto_install_docker`; the engine can install Docker/Compose when that option is enabled, but offline installation requires matching packages to be obtainable and usable permissions to already exist. Windows native local Docker is unsupported; use a Linux Docker host over SSH. macOS local Docker requires the user to install and start Docker Desktop first. The CLI does not install Docker Desktop or silently obtain `sudo`.
75
32
 
76
- - Password: `"password": "<the user's password>"`.
77
- - SSH key: `"key_file": "~/.ssh/id_ed25519"` and no `password` field. The key
78
- must be a regular file inside `~/.ssh` (or the engine's data directory); a
79
- relative path is resolved under `~/.ssh`; other locations are refused.
33
+ ## 3. Fill in and confirm (Zero-Plaintext-Password Protocol)
80
34
 
81
- Add `"auto_replace_containers": true` (or the `--replace-existing` flag) only if
82
- the user agrees to replace existing containers with the same name.
35
+ > [!IMPORTANT]
36
+ > **严禁在会话中索要、输出或接收用户的明文 SSH 密码!**(会触发主流大模型安全拒答拦截,且存在凭证泄露与历史污染风险)。
37
+ > - **标准且唯一支持认证方式**:采用 SSH 密钥免密认证 (`key_file: "~/.ssh/id_ed25519"` 或 `~/.ssh/id_rsa`)。
38
+ > - **若用户设备尚未配置免密公钥**:引导用户在其**本地终端**执行一次免密分发:
39
+ > ```bash
40
+ > ssh-copy-id -i ~/.ssh/id_ed25519.pub <user>@<device_ip>
41
+ > ```
42
+ > *(若本地尚无 Ed25519 密钥对,先执行 `ssh-keygen -t ed25519 -N ""` 一键创建)*。
43
+ > 输入密码的交互在用户独立本地终端完成,密码绝不流经大模型上下文,亦不留在会话与历史中。
44
+ > - **部署参数统一使用 `key_file`**:SenseCraft Engine 的部署请求格式要求远程目标通过 `key_file` 进行连接。严禁在聊天框索取明文密码。
83
45
 
84
- Write the filled body to `./.sensecraft-work/body.json` in the current working
85
- directory, not `/tmp` (a file keeps the password out of the process list and
86
- avoids shell quoting problems, notably in PowerShell):
46
+ Write the completed request to `./.sensecraft-work/body.json`, keeping credentials out of the command line:
87
47
 
88
48
  ```json
89
49
  {
@@ -91,210 +51,62 @@ avoids shell quoting problems, notably in PowerShell):
91
51
  "preset_id": "<preset>",
92
52
  "selected_devices": ["<step_id>"],
93
53
  "device_connections": {
94
- "<step_id>": {"target": "<target_id>", "target_type": "remote",
95
- "host": "192.168.1.50", "username": "<user>",
96
- "password": "<password>"}
97
- }
98
- }
99
- ```
100
-
101
- Show the user the body with the password as `<REDACTED>` before starting.
102
-
103
- On Windows PowerShell 5.1, write the JSON as UTF-8 **without a BOM**. The
104
- default `Set-Content -Encoding UTF8` adds a BOM, which the Rust request reader
105
- rejects. Keep the request file under the current workspace and do not print it
106
- when it contains a password:
107
-
108
- ```powershell
109
- $RequestPath = [System.IO.Path]::GetFullPath('.sensecraft-work/body.json')
110
- $RequestDir = [System.IO.Path]::GetDirectoryName($RequestPath)
111
- New-Item -ItemType Directory -Force -Path $RequestDir | Out-Null
112
- $body = @{
113
- solution_id = '<id>'
114
- preset_id = '<preset>'
115
- selected_devices = @('<step_id>')
116
- device_connections = @{
117
- '<step_id>' = @{
118
- target = '<target_id>'
119
- target_type = 'remote'
120
- host = '192.168.1.50'
121
- username = '<user>'
122
- password = '<password>'
54
+ "<step_id>": {
55
+ "target": "<target_id>",
56
+ "target_type": "remote",
57
+ "host": "192.168.1.50",
58
+ "username": "<user>",
59
+ "key_file": "~/.ssh/id_ed25519"
123
60
  }
124
61
  }
125
62
  }
126
- $json = $body | ConvertTo-Json -Depth 50
127
- [System.IO.File]::WriteAllText($RequestPath, $json, [System.Text.UTF8Encoding]::new($false))
128
63
  ```
129
64
 
130
- `-Depth 50` preserves nested `device_connections`; PowerShell's default depth
131
- of 2 is insufficient. Replace placeholders with user-provided values and keep
132
- the file protected; never print the password.
65
+ Remote SSH uses a regular key under `~/.ssh` or the Engine data directory (`id_ed25519` / `id_rsa`). Serial steps need both `port` and `serial_port` when the template contains both. Add `auto_replace_containers: true` only after the user agrees to replace existing containers.
133
66
 
134
- Before a remote deploy, run the dry run (no changes on any device):
67
+ Before a remote deployment, run the no-change validation:
135
68
 
136
- ```
69
+ ```bash
137
70
  sensecraft-engine validate --params ./.sensecraft-work/body.json
138
71
  ```
139
72
 
140
- It reports parameter errors and previews which verify steps will need the user
141
- (`verify_required`). It also lists the changes the deployment may make on each
142
- target beyond the solution's own files and containers, as
143
- `side_effects: {"<step_id>": [{"kind", "what", "when", "decided_in"}, ...]}`:
144
-
145
- | `kind` | Change on the target |
146
- |---|---|
147
- | `sudo` | Commands run with `sudo` (Docker through `sudo docker`, actions marked `sudo`) |
148
- | `daemon_json_write` | Merges `registry-mirrors` into `/etc/docker/daemon.json` (other keys kept) |
149
- | `docker_daemon_restart` | Restarts the Docker daemon (all containers on the device restart with it) |
150
- | `package_install` | Installs packages (Docker / Compose, `.deb`, apt / pip in an action) |
151
- | `system_config` | Changes system settings (`usermod`, `update-alternatives`, services) |
152
- | `reboot` | Reboots the device |
153
- | `firmware_flash` | Flashes firmware |
154
- | `local_script` | Runs a script on this computer |
155
-
156
- `what` says what happens in plain words, `when` the condition: `always`, a
157
- condition the engine checks during the deploy (for example "the device cannot
158
- reach Docker Hub"), or "the action's script decides". `decided_in` points at
159
- engine code; it is for bug reports, not something to read.
160
-
161
- Tell the user what the list contains. If the user forbade a kind that is
162
- listed (Docker restart, daemon.json changes, reboot, package installs) and
163
- has not agreed to it, stop and ask before starting, also when `when` is a
164
- condition: the deploy may meet it. Exception: when the action's script is in
165
- the solution's step file (`devices/<x>.yaml` under `actions` or
166
- `remote_overrides.actions` in `~/.sensecraft/content/solutions/<id>/`, or
167
- `$SC_HOME/content/solutions/<id>/` when `SC_HOME` is set), read
168
- it; if its condition can be checked read-only on the device and is not met,
169
- say so and continue. Actions that come from the engine's built-in device
170
- profile are not in that file: treat them as possible. Builds without a
171
- `side_effects` field: assume a remote Docker deploy may write
172
- `/etc/docker/daemon.json` and ask when the user restricted that.
173
-
174
- Before the deploy, save the target's current Docker daemon config so changes
175
- can be shown and restored:
176
-
177
- ```
178
- ssh <user>@<ip> cat /etc/docker/daemon.json > ./.sensecraft-work/daemon.json.before
179
- ```
180
-
181
- (a missing file is fine: note that it did not exist). After the deploy, `cat`
182
- it again and show the user any difference; restoring it is a change on the
183
- device and needs the user's OK.
73
+ Read `side_effects` and report any `sudo`, Docker daemon configuration or restart, package install, system configuration, reboot, firmware flash, or local script operation. Stop for user approval if a listed effect is outside the agreed scope. Save `/etc/docker/daemon.json` before a remote deployment when it exists so a later restoration can be reviewed separately.
184
74
 
185
75
  ## 4. Start and follow
186
76
 
77
+ ```bash
78
+ sensecraft-engine deploy --params ./.sensecraft-work/body.json --yes --detach --lang zh
79
+ sensecraft-engine status <deployment-id> --json
80
+ sensecraft-engine logs <deployment-id> --since <N>
187
81
  ```
188
- sensecraft-engine deploy --params ./.sensecraft-work/body.json --yes --detach --lang en
189
- ```
190
-
191
- `--detach` prints `{"deployment_id": "...", "log": "..."}` and returns. Keep the
192
- `deployment_id`. Exit code 2 means the request or arguments are invalid. When
193
- the JSON error contains a `missing[]` list, ask for those fields
194
- (`preset_id`, `device_connections.<id>.<key>`); for `bad_request` without
195
- `missing[]`, inspect the solution ID, JSON shape, and parameter spelling before
196
- asking for another value.
197
- Exit code 3 with a 409 means the device is busy with another deployment.
198
-
199
- Follow progress in one of two ways:
200
82
 
201
- - **Poll** (works with any agent's command timeout): every 3–5 seconds run
202
- `sensecraft-engine status <deployment_id> --json`. `status` is `running`
203
- while in progress and ends as `completed`, `failed`, `cancelled` or
204
- `interrupted`; each device and step has its own `status` and `message`.
205
- Exit code: 0 while running or completed, 1 for failed / cancelled /
206
- interrupted.
207
- - **Event stream:** `sensecraft-engine logs <deployment_id> --since <N>`
208
- prints NDJSON events (`{seq, type, ...}`) with `seq > N` and exits; add
209
- `--follow` to keep streaming until the deployment ends (run it in the
210
- background if your command timeout is short). Remember the last `seq` and
211
- pass it as `--since` next time, so you never read the same events twice.
83
+ Keep the returned `deployment_id`. Poll `status` until it is `completed`, `failed`, `cancelled`, or `interrupted`; read `logs` with the last event sequence. `--follow` can stream logs when the command timeout allows it. A request error (exit 2) needs corrected fields; a busy device (exit 3/409) needs the other deployment resolved first.
212
84
 
213
- Event types to act on:
214
-
215
- | `type` | Meaning |
216
- |---|---|
217
- | `log` | `level`, `message`; `error`-level lines are evidence for `diagnose.md` |
218
- | `step_skipped` with `reason: verify_required` | The step needs the user — the `verify_required` event before it has the details |
219
- | `verify_required` | Go to `verify.md` with this event |
220
- | `device_completed` | One device finished |
221
- | `deployment_completed` | Last event; `status` is the final result |
222
-
223
- Read the JSON directly instead of grepping it (no interpreter, see `SKILL.md`
224
- rule 5). Delete `./.sensecraft-work/` afterwards (`body.json` holds a
225
- password).
226
-
227
- Without `--detach`, `deploy --json` streams the same events on stdout and ends
228
- with one `{"type": "result", "deployment_id", "status", "devices"}` line; the
229
- exit code is the deployment's result. Ctrl-C or a killed agent command only
230
- detaches: the deployment keeps running in the engine instance; continue with
231
- `status` / `logs`.
232
-
233
- If `--detach` prints `"backend": "python"`, the desktop app's backend is
234
- running this deployment: `logs` then has `log` and `deployment_completed`
235
- events only, no `verify_required`. Do the guide's verify steps with the user
236
- as described in `verify.md` §1.
85
+ Without `--detach`, `deploy --json` waits for the final result. Interrupting the client only detaches from the running Engine deployment; continue with `status` and `logs`.
237
86
 
238
87
  ## 5. Verify
239
88
 
240
- `completed` is not enough. Check the result is actually usable:
89
+ `completed` is not by itself service verification. Handle every `verify_required` event with `verify.md`, then check the target:
241
90
 
242
- - `verify_required` events: handle each one with `verify.md`.
243
- - Docker steps: on the target the solution's containers have `status`
244
- `running` (and are `(healthy)` in `docker ps` when they define a health
245
- check):
246
- `sensecraft-engine docker ps --json` (this computer),
247
- `sensecraft-engine docker ps --host <ip> --username <user> --key-file ~/.ssh/id_ed25519 --json`
248
- (remote with an SSH key; same path rules as `key_file` in §3), or
249
- `SC_SSH_PASSWORD=<password> sensecraft-engine docker ps --host <ip> --username <user> --json`
250
- (remote with a password; `--password-stdin` reads it from stdin instead).
251
- `docker logs <container> --host ... --key-file ...` takes the same options.
252
- Older engines without `--key-file` accept a password only; with a key-only
253
- device use `ssh <user>@<ip> docker ps`.
254
- - Services with a port: `curl -s -o /dev/null -w "%{http_code}" http://<host>:<port>/`
255
- returns 2xx/3xx.
256
- - Stay running: `completed` can precede a crash loop. CLI deploys already
257
- watch each Docker service for about 60 seconds after its health check
258
- answers and fail the step with `Service <name> is not healthy: ...` when a
259
- container restarts, exits or disappears. Check once more yourself: run `docker ps` once,
260
- wait about 60 seconds, then run it again and read the container restart
261
- count (`docker inspect -f '{{.Name}} {{.RestartCount}} {{.State.Status}}' <container>`
262
- over SSH, or the `Restarting` / `Up Less than a second` status in `docker ps`).
263
- The counts must stay 0 and the verify endpoint (the step's `url`, or the
264
- port check above) must still answer after the wait. If a container restarts
265
- or the endpoint stops answering, report a crash loop, not success, and go to
266
- `diagnose.md`.
267
- - Tell the user the URL to open and anything the guide says to do next.
91
+ - Docker services remain `running` and healthy. Use `sensecraft-engine docker ps --json` locally or the remote form documented by the Engine help.
92
+ - Service endpoints return the expected 2xx/3xx response.
93
+ - For services with a health check, check once more after about 60 seconds and inspect restart counts for a crash loop.
268
94
 
269
- ## 6. If anything failed
95
+ Report the URL, device, deployed solution, and verification evidence. Do not report success when a container restarts, disappears, or its endpoint stops answering.
270
96
 
271
- Go straight to `diagnose.md` with the `deployment_id`. Do not stop to ask.
97
+ ## 6. If anything failed
272
98
 
273
- To retry after a fix, send the same body again — same `preset_id` and
274
- `device_connections` — with `selected_devices` listing only the device(s) that
275
- failed (or `--device <step_id>` for one device); the others are already done.
276
- Leaving manual steps in is harmless (they are skipped).
99
+ Go to `diagnose.md` with the `deployment_id`. Retry only after reading the error. Transient registry or network errors may be retried up to five times with increasing waits; deterministic credential, parameter, disk, port, or container errors require a fix before retry and at most three rounds.
277
100
 
278
- Two kinds of failure, two policies:
101
+ To retry a partial deployment, reuse the same request body and list only failed devices. Do not change the preset or target values while diagnosing a failure. Keep the body file private and remove `./.sensecraft-work/` after the deployment workflow completes.
279
102
 
280
- - **Transient registry or network errors** (image pull answered 401 / 429 /
281
- 500 / 502 / 503 / 504, `TLS handshake timeout`, `i/o timeout`,
282
- `connection reset`, a mirror that flaps): retry the same body without
283
- asking, up to 5 times, waiting 15, 30, 60, 120, 240 seconds between tries.
284
- These retries do not count as fix rounds. If the engine log shows the
285
- mirror changing between tries, that is the same transient case. After the
286
- 5th failure, stop and report the error text, the waits and the registry host.
287
- - **Deterministic failures** (bad parameter or credentials, port taken, disk
288
- full, missing file, a container that exits on start, the same error with the
289
- same text after a fix): stop retrying blindly. First retry after a fix
290
- without asking; later retries need the user's OK; at most 3 rounds, then
291
- report.
103
+ ## Cancel
292
104
 
293
- If you cannot tell which kind it is, treat the second occurrence of the same
294
- error after a wait as deterministic.
105
+ Only after the user approves cancellation:
295
106
 
296
- ## Cancel
107
+ ```bash
108
+ sensecraft-engine cancel <deployment-id>
109
+ sensecraft-engine status <deployment-id> --json
110
+ ```
297
111
 
298
- Only with the user's OK: `sensecraft-engine cancel <deployment_id>`. Then check
299
- `status` until it is `cancelled`, and tell the user which steps had already run:
300
- the device may be half-configured.
112
+ Wait for `cancelled` and report which steps had already run; a cancelled deployment may leave a device partially configured.