@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 +338 -2
- package/dist/acceptance-report.html +5622 -0
- package/dist/index.js +585065 -0
- package/dist/maintenanceWorker.mjs +97 -0
- package/man/man1/lh.1 +223 -0
- package/man/man1/lobe.1 +1 -0
- package/man/man1/lobehub.1 +1 -0
- package/package.json +78 -4
package/README.md
CHANGED
|
@@ -1,3 +1,339 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @pengfengagent/cli
|
|
2
2
|
|
|
3
|
-
|
|
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.
|