Skip to content

Commit fe25ed2

Browse files
committed
refactor(cli): lazy-load devices runtime
1 parent 3fa9658 commit fe25ed2

4 files changed

Lines changed: 867 additions & 740 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Docs: https://docs.openclaw.ai
1414

1515
### Fixes
1616

17-
- CLI: lazy-load model and plugin runtime helpers for command actions so parent/help output renders without importing those runtime paths.
17+
- CLI: lazy-load model, plugin, and device runtime helpers for command actions so parent/help output renders without importing those runtime paths.
1818
- Gateway/session history: carry monotonic transcript message sequence through live updates and refresh SSE history when stale sequence input would otherwise append bad incremental state. (#81474) Thanks @samzong.
1919
- Security/sandbox: include Windows `USERPROFILE` in the sandbox blocked home roots so credential-bearing binds (such as `.codex`, `.openclaw`, or `.ssh` under the Windows user profile) are denied even when `HOME` points at a different shell home. (#63074) Thanks @luoyanglang.
2020
- Models config/auth: stop inferring provider env-var markers from broad `^[A-Z_][A-Z0-9_]*$` strings, and resolve config-backed provider `apiKey` values only through structured env SecretRefs (`secrets.providers[id]` / `secrets.defaults`), so unrelated env vars cannot accidentally become provider credentials. Thanks @sallyom.

src/cli/devices-cli.lazy.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Command } from "commander";
2+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3+
4+
describe("devices cli lazy runtime boundary", () => {
5+
beforeEach(() => {
6+
vi.resetModules();
7+
});
8+
9+
afterEach(() => {
10+
vi.doUnmock("./devices-cli.runtime.js");
11+
vi.resetModules();
12+
});
13+
14+
it("renders parent help without importing the devices runtime", async () => {
15+
const runtimeLoaded = vi.fn();
16+
vi.doMock("./devices-cli.runtime.js", () => {
17+
runtimeLoaded();
18+
return {
19+
runDevicesApproveCommand: vi.fn(),
20+
runDevicesClearCommand: vi.fn(),
21+
runDevicesListCommand: vi.fn(),
22+
runDevicesRejectCommand: vi.fn(),
23+
runDevicesRemoveCommand: vi.fn(),
24+
runDevicesRevokeCommand: vi.fn(),
25+
runDevicesRotateCommand: vi.fn(),
26+
};
27+
});
28+
29+
const { registerDevicesCli } = await import("./devices-cli.js");
30+
const program = new Command();
31+
program.exitOverride();
32+
program.configureOutput({
33+
writeErr: () => {},
34+
writeOut: () => {},
35+
});
36+
registerDevicesCli(program);
37+
38+
await expect(program.parseAsync(["devices", "--help"], { from: "user" })).rejects.toMatchObject(
39+
{
40+
exitCode: 0,
41+
},
42+
);
43+
expect(runtimeLoaded).not.toHaveBeenCalled();
44+
});
45+
46+
it("loads the devices runtime for command actions", async () => {
47+
const runDevicesListCommand = vi.fn().mockResolvedValue(undefined);
48+
const runtimeLoaded = vi.fn();
49+
vi.doMock("./devices-cli.runtime.js", () => {
50+
runtimeLoaded();
51+
return {
52+
runDevicesApproveCommand: vi.fn(),
53+
runDevicesClearCommand: vi.fn(),
54+
runDevicesListCommand,
55+
runDevicesRejectCommand: vi.fn(),
56+
runDevicesRemoveCommand: vi.fn(),
57+
runDevicesRevokeCommand: vi.fn(),
58+
runDevicesRotateCommand: vi.fn(),
59+
};
60+
});
61+
62+
const { registerDevicesCli } = await import("./devices-cli.js");
63+
const program = new Command();
64+
registerDevicesCli(program);
65+
66+
await program.parseAsync(["devices", "list", "--json"], { from: "user" });
67+
68+
expect(runtimeLoaded).toHaveBeenCalledTimes(1);
69+
expect(runDevicesListCommand).toHaveBeenCalledWith(expect.objectContaining({ json: true }));
70+
});
71+
});

0 commit comments

Comments
 (0)