@pengfengagent/cli 0.0.0-stage → 0.0.76

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/README.md CHANGED
@@ -1,3 +1,339 @@
1
- # Temporary Holding Version
1
+ # @pengfengagent/cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ PengFengAgent command-line interface.
4
+
5
+ ## Update a connected device
6
+
7
+ ```bash
8
+ lh update # Install the latest CLI without restarting a connector
9
+ lh connect status # Connection, running version, and any required action
10
+ lh connect status --verbose # Service metadata and CLI installation paths
11
+
12
+ # Wait for active tasks to finish, then restart the detected connector:
13
+ lh connect restart
14
+ lh connect status # Verify the new running version and connection
15
+ ```
16
+
17
+ Installing an update and activating it are separate steps. `lh update` keeps the
18
+ running connector in place; it reports the installed and running versions separately.
19
+ Restarting disconnects the device and closes its remote terminals. A terminal
20
+ provided by PengFengAgent may close or print `Terminated` before the restart request
21
+ returns. Reconnect before checking status; “Restart requested” is not confirmation
22
+ that the device is already connected.
23
+
24
+ `lh connect restart` detects a CLI daemon or a user/system systemd service. System
25
+ services use `sudo` unless already running as root. When multiple connectors are
26
+ running, select one with `--manager daemon`, `--manager user`, or `--manager system`.
27
+ Service restarts preserve the unit's configuration; daemon connection flags such
28
+ as `--token` cannot override it. `lh connect service restart` remains a user-service
29
+ alias. With no managed connector and no inspection failures, `lh connect restart`
30
+ retains its existing behavior of starting a daemon. Daemon restarts wait for the
31
+ previous process to exit before starting its replacement, including when upgrading
32
+ from an older CLI. If shutdown times out, no replacement is started.
33
+
34
+ A daemon cannot be restarted from a terminal or shell it owns: its shutdown would
35
+ kill the waiting restart command. This is rejected before stopping the connection;
36
+ run `lh connect restart` from a local terminal or an independent SSH session instead.
37
+ If process ancestry cannot be verified, the restart is also rejected without
38
+ stopping the connector. Systemd service restarts still use the service manager.
39
+
40
+ If an older restart lost `daemon.pid`, `lh connect status` can recover it from the
41
+ status record only after verifying that the process is alive and is a daemon, not
42
+ a foreground connection or systemd service. This recovery does not restart the
43
+ connection. Cleanup checks PID ownership; normal restarts also wait for the old
44
+ process to exit before creating new records.
45
+
46
+ If the version still differs after a restart, the status report shows the command's
47
+ CLI entry path and the connector's entry path when available. Different paths mean
48
+ you should update the connector's installation or change its service configuration.
49
+ Diagnostics never dump the service's command line or environment. Older connectors
50
+ on Linux use a conservative `/proc` lookup; an inaccessible or unsupported entry
51
+ is reported as unknown instead of guessed.
52
+
53
+ ## Managed cloud devices
54
+
55
+ A managed cloud device is a device that LobeHub creates and runs for you. The
56
+ platform that runs it starts the agent with:
57
+
58
+ ```bash
59
+ lh connect --managed
60
+ ```
61
+
62
+ Managed mode reads everything from the environment. It does not use a stored
63
+ login, a keychain or a browser, and it writes no credentials to disk, so it runs
64
+ headless in a container. `lh connect service install` is not needed: the
65
+ platform supervises the process and restarts it when it exits.
66
+
67
+ | Variable | Required | Meaning |
68
+ | --------------------------------- | -------- | ----------------------------------------------------------- |
69
+ | `LOBEHUB_MANAGED_DEVICE_ID` | yes | The device id. It replaces the id derived from the machine. |
70
+ | `LOBEHUB_MANAGED_DEVICE_SECRET` | yes | The bootstrap secret. The CLI never prints it. |
71
+ | `LOBEHUB_SERVER` | yes | The LobeHub server URL. |
72
+ | `LOBEHUB_DEVICE_GATEWAY_URL` | yes | The device gateway URL. |
73
+ | `LOBEHUB_DEVICE_ACTIVITY_COMMAND` | no | A JSON array: a command to run while the device does work. |
74
+
75
+ If a required variable is missing, the CLI names it and exits with status 1.
76
+ `LOBEHUB_SERVER` and `LOBEHUB_DEVICE_GATEWAY_URL` must use `https`; `http` is
77
+ accepted only for `localhost` and the loopback addresses `127.0.0.0/8` and
78
+ `::1`. The URLs must not contain a user name, a password, a query or a fragment.
79
+ A path is kept, so `https://example.com/lobehub` sends the token request to
80
+ `https://example.com/lobehub/api/device/managed/token`. `--managed` cannot be used
81
+ with `--token`, `--gateway`, `--device-id`, `--workspace`, `--public` or
82
+ `--daemon`.
83
+
84
+ After the CLI reads the secret, it removes it from its own environment, so the
85
+ processes it starts (tool calls, agent runs) do not inherit it. This does not
86
+ hide the secret from the device: other processes of the same user can still
87
+ read the environment the CLI started with (for example `/proc/<pid>/environ`).
88
+ The secret only gets tokens for this device, and it stops working when the
89
+ device is deleted.
90
+
91
+ **Token.** The CLI sends `POST {LOBEHUB_SERVER}/api/device/managed/token` with
92
+ `{ "deviceId", "secret" }` and gets `{ "token", "expiresAt" }`, where
93
+ `expiresAt` is an RFC 3339 time with `Z` or an offset. The token's
94
+ `workspace_id` claim, when present, makes the device a workspace device;
95
+ otherwise its `sub` is the owning user.
96
+
97
+ - The CLI gets a new token when 80% of the token's lifetime has passed (at least
98
+ 5 s after it got the previous one). The open gateway connection stays up:
99
+ only the next connection uses the new token, so running tool calls, agent
100
+ runs and tunnels continue.
101
+ - On HTTP 408, 429 or 5xx, a network error or an unreadable response, the CLI
102
+ tries again after 1 s, then 2 s, 4 s and so on, up to 60 s between attempts
103
+ (each delay ±20%). It continues until the server answers.
104
+ - On HTTP 401 (wrong secret, or the device was deleted), 404 (the server has no
105
+ managed cloud devices) or another 4xx, the CLI exits with status 1.
106
+ - If the gateway rejects a token, the CLI gets a new token and connects again.
107
+ If the gateway also rejects that token before a connection succeeds, the CLI
108
+ exits with status 1.
109
+
110
+ **Activity command.** When `LOBEHUB_DEVICE_ACTIVITY_COMMAND` is set, the CLI runs
111
+ it while the device serves a tool call, an RPC, an agent run or an open tunnel.
112
+ It runs when the work starts and then every 30 s while work continues, never
113
+ more than once in 30 s and never two at a time. The work does not wait for it.
114
+ A run that takes longer than 10 s is stopped. Failures appear only in the debug
115
+ log (`--verbose`).
116
+
117
+ The value is a JSON array of strings: the program, then its arguments, for
118
+ example `["my-agent","touch"]`. The CLI runs the program directly, without a
119
+ shell, so there is no quoting, `$VAR`, `~` or glob expansion, and `|`, `;`, `&`,
120
+ `>` and `<` are ordinary characters. If the value is not a non-empty JSON array
121
+ of non-empty strings, the CLI exits with status 1 at startup. To use shell
122
+ features, give an explicit shell, for example
123
+ `["sh","-c","my-agent touch >> /var/log/activity"]`. When the CLI stops, it
124
+ also stops a command that is still running.
125
+
126
+ ## Publish local artifacts
127
+
128
+ ```bash
129
+ # Publish ordinary HTML and its referenced local resources
130
+ lh artifact publish ./page.html --root . --json
131
+
132
+ # Read the Canvas component and generation rules
133
+ lh artifact guide canvas
134
+
135
+ # Publish a self-contained Canvas HTML file
136
+ lh artifact publish ./report.html --type canvas --json
137
+
138
+ # The binding remembers the type; subsequent publishes update the same artifact
139
+ lh artifact publish ./report.html --json
140
+
141
+ # Create a separate Canvas and bind future publishes to it
142
+ lh artifact publish ./report.html --new --json
143
+
144
+ # Take a published artifact offline (the deployment and its releases are kept)
145
+ lh artifact unpublish ./report.html --json
146
+ ```
147
+
148
+ Bindings and pending operations live in the project's `.lobehub/artifacts.json`.
149
+ Retry the same command with unchanged input after a failed Canvas save or publish;
150
+ the CLI resumes that operation without creating another Canvas or saved version.
151
+ Restore the original input before retrying if you edited it during recovery.
152
+ An explicit validation or version-conflict rejection releases the pending save,
153
+ so you can correct the file or inspect the latest version before trying again.
154
+ If publication explicitly rejects a slug, correct `--slug` and retry with the same
155
+ content and target; the CLI reuses the saved Canvas and version.
156
+ Canvas bindings are scoped to the authenticated account, server and workspace.
157
+
158
+ Canvas input is a single HTML file with inline styles, scripts and data, subject
159
+ to the Canvas guide's validation and size limits. Publication saves a version in
160
+ PengFengAgent and returns a public URL; it requires a server with Canvas publishing and
161
+ a compatible runtime. JSON errors retain any saved Canvas ID and version.
162
+
163
+ `--slug <name>` requests the readable prefix for a new deployment. Market adds an
164
+ eight-character suffix; both HTML and Canvas use the same rule. Existing deployments
165
+ retain their address when updated, including older records without a stored label.
166
+ JSON `publicUrl` is the direct hosting URL; `shareUrl` is the PengFengAgent product share
167
+ page, and `subdomainLabel` is the actual assigned label when the server returns it.
168
+
169
+ `--deployment <id>` overrides the deployment for this run without changing the
170
+ canonical binding. `--new` and `--deployment` cannot be combined. Changing an
171
+ existing artifact's content type requires `--new`.
172
+
173
+ ## Acceptance skill
174
+
175
+ The acceptance skill is maintained in [lobehub/acceptance](https://github.com/lobehub/acceptance).
176
+ Install from the repository's default branch:
177
+
178
+ ```bash
179
+ lh acceptance install
180
+ ```
181
+
182
+ Update the installed skill:
183
+
184
+ ```bash
185
+ lh acceptance update
186
+ ```
187
+
188
+ Publishing reports to PengFengAgent requires authentication (`lh login`). Without a
189
+ login, acceptance runs locally — see [Local reports](#local-reports).
190
+
191
+ This selects the same source as `npx skills add lobehub/acceptance --skill acceptance`.
192
+ Changes merged into the default branch are available on the next install or
193
+ update, without a tag, GitHub Release, or skill-version bump. Installed files
194
+ remain unchanged until you run an update.
195
+
196
+ `install` skips existing files unless `--force` is passed. `update` replaces the
197
+ materialized files in `.agents/skills/acceptance`, removes stale resources, and
198
+ maintains agent links. The server resolves a commit and downloads the entire
199
+ skill from that snapshot before files are changed. `--json` reports the exact
200
+ source commit and the version declared in `SKILL.md`; that version is a label,
201
+ not the selector for default updates.
202
+
203
+ Use an up-to-date CLI and PengFengAgent server. Older servers may return `401` during
204
+ installation and need to be upgraded.
205
+
206
+ To select an existing version tag explicitly, use `lh acceptance update --skill-version 0.5.0` (requires the updated CLI and server), or the equivalent
207
+ [tagged skill source](https://github.com/lobehub/acceptance/tree/v0.5.0/skills/acceptance)
208
+ with `npx skills add`. A later `lh acceptance update` without `--skill-version`
209
+ returns to the current default-branch source.
210
+
211
+ ## Local reports
212
+
213
+ A machine that has never signed in renders acceptance reports locally instead
214
+ of publishing them; `lh acceptance preflight --json` reports `"mode": "local"`.
215
+
216
+ ```bash
217
+ lh acceptance run render .acceptances/<subject>/<round> --requirement "<business goal>"
218
+ ```
219
+
220
+ This writes `report.html` beside the rounds: the acceptance page, offline — the
221
+ checklist, evidence, before/after pairs, video chapters and round history,
222
+ rendered from every round of that acceptance. Nothing is uploaded. The reader
223
+ can accept or reject checks and circle regions on screenshots there; **Save
224
+ reviews** downloads the decisions, and the next
225
+ `lh acceptance feedback .acceptances/<subject>` (or `view`) files them as
226
+ `reviews.json` and reports them like hosted feedback.
227
+
228
+ Comments, mentions and shared links need PengFengAgent. After `lh login`,
229
+ `lh acceptance publish .acceptances/<subject>` publishes the unpublished rounds
230
+ in order into one acceptance and carries the standing review decisions over;
231
+ running it again publishes only newer rounds.
232
+
233
+ The page is built by `apps/workbench` (`bun run --cwd ../workbench build:report`);
234
+ `bun run build` copies it to `dist/acceptance-report.html` when it exists.
235
+
236
+ ## Local Development
237
+
238
+ | Task | Command |
239
+ | ------------------------------------------ | -------------------------- |
240
+ | Run in dev mode | `bun run dev -- <command>` |
241
+ | Build the CLI | `bun run build` |
242
+ | Link `lh`/`lobe`/`lobehub` into your shell | `bun run cli:link` |
243
+ | Remove the global link | `bun run cli:unlink` |
244
+
245
+ - `bun run build` generates `dist/index.js`, plus `dist/acceptance-report.html` when the local report page is built.
246
+ - To make `lh` available in your shell, run `bun run cli:link`.
247
+ - After linking, if your shell still cannot find `lh`, run `rehash` in `zsh`.
248
+
249
+ ## Custom Server URL
250
+
251
+ By default the CLI connects to `http://llm.hesurwa.com`. To point it at a different server (e.g. a local instance):
252
+
253
+ | Method | Command | Persistence |
254
+ | -------------------- | --------------------------------------------------------------- | ----------------------------------- |
255
+ | Environment variable | `LOBEHUB_SERVER=http://localhost:4000 bun run dev -- <command>` | Current command only |
256
+ | Login flag | `lh login --server http://localhost:4000` | Saved to `~/.lobehub/settings.json` |
257
+
258
+ Priority: `LOBEHUB_SERVER` env var > `settings.json` > default official URL.
259
+
260
+ ## Shell Completion
261
+
262
+ ### Install completion for a linked CLI
263
+
264
+ | Shell | Command |
265
+ | ------ | ------------------------------ |
266
+ | `zsh` | `source <(lh completion zsh)` |
267
+ | `bash` | `source <(lh completion bash)` |
268
+
269
+ ### Use completion during local development
270
+
271
+ | Shell | Command |
272
+ | ------ | -------------------------------------------- |
273
+ | `zsh` | `source <(bun src/index.ts completion zsh)` |
274
+ | `bash` | `source <(bun src/index.ts completion bash)` |
275
+
276
+ - Completion is context-aware. For example, `lh agent <Tab>` shows agent subcommands instead of top-level commands.
277
+ - If you update completion logic locally, re-run the corresponding `source <(...)` command to reload it in the current shell session.
278
+ - Completion only registers shell functions. It does not install the `lh` binary by itself.
279
+
280
+ ## Quick Check
281
+
282
+ ```bash
283
+ which lh
284
+ lh --help
285
+ lh agent <TAB>
286
+ ```
287
+
288
+ ## Tests
289
+
290
+ The default `test` and `test:coverage` scripts run offline unit tests only. Live
291
+ E2E uses a separate config and never replaces or removes your selected CLI home.
292
+ It always runs this checkout's `dist/index.js`, not a globally installed `lh` or
293
+ a caller-supplied `LH_CLI_PATH`.
294
+
295
+ From `apps/cli`, prepare a dedicated test account (never your everyday account):
296
+
297
+ ```bash
298
+ bun run build
299
+ export LOBEHUB_CLI_HOME=.lobehub-e2e
300
+ export LOBEHUB_SERVER=https://your-test-server.example
301
+ node dist/index.js login --server "$LOBEHUB_SERVER"
302
+ node dist/index.js whoami
303
+
304
+ # Explicitly authorize real writes for this test account/server.
305
+ export LOBEHUB_E2E_ALLOW_WRITES=1
306
+ bun run test:e2e e2e/model.e2e.test.ts --testTimeout=60000 --hookTimeout=60000
307
+ ```
308
+
309
+ Without a selected home, server, write opt-in, built CLI, or valid authentication,
310
+ the live setup fails before fixture creation. A directory name does not itself
311
+ isolate server data: sign in with a dedicated test identity. Model tests own a
312
+ temporary provider, including the remote-model clearing case. Other suites may
313
+ create data or consume model credits, so do not run them on a personal account.
314
+ Collection alone (`bunx vitest list --config vitest.e2e.config.mts`) needs no login.
315
+ Signal and VFS tests additionally require their documented Agent ID variables.
316
+ Search fixtures wait up to 60 seconds for asynchronous indexing; a timeout fails
317
+ the suite rather than accepting empty results. The command above supplies a live
318
+ network budget explicitly; this does not change unit-test timeouts or enable retries.
319
+
320
+ ### Native Codex app-server on a connected device
321
+
322
+ A current CLI advertises `codex-app-server-v1` only after its resolved Codex binary
323
+ completes a native app-server handshake. The probe runs once per gateway connection
324
+ (and again after 10 minutes), not once per system-info request. `lh connect capabilities`
325
+ reports that same capability as JSON without logging in, connecting a device, or creating
326
+ a conversation. Desktop gateway connections invoke this command through their bundled
327
+ CLI, so an unrelated global CLI cannot determine support. Missing, incompatible, or
328
+ timed-out binaries do not advertise native support.
329
+
330
+ Codex topics run through `codex exec` unless the user enables the
331
+ **Codex App Server Runtime** Lab. With the Lab on and a capable connection, the server
332
+ runs them through app-server and persists each message's native session and turn IDs.
333
+ These topics keep the `codex exec` recovery: a missing native session is retried fresh
334
+ with the topic transcript.
335
+
336
+ The internal `lh hetero exec --codex-app-server` transport uses a per-operation process
337
+ that owns cancellation and shell identity. This transport rejects unsupported approval
338
+ or sandbox arguments instead of weakening permissions. The richer permission bridge is
339
+ maintained separately.