mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:10:43 +00:00
Merged via squash.
Prepared head SHA: 9fffdf2ca6
Co-authored-by: luyao618 <17723416+luyao618@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -72,6 +72,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/chat: register chat.send runs in the chat run registry so lifecycle error events reach the client instead of being silently dropped, fixing stuck 'waiting' state and /abort reporting no active run. (#69747) Thanks @wangshu94.
|
||||
- Plugins/QQ Bot: enable the bundled qqbot plugin by default so its runtime dependency `@tencent-connect/qqbot-connector` is installed on first launch, unblocking the QR-code binding flow that dynamically imports the connector before any account is configured. (#71051) Thanks @cxyhhhhh.
|
||||
- Gateway/agent RPC: register active `agent` runs into the chat abort controller map so `chat.abort` and `sessions.abort` can interrupt them, matching `chat.send` behavior and unblocking external runtimes that drive the Gateway through the public `agent` RPC. Fixes #71128. (#71214) Thanks @bitloi.
|
||||
- Matrix/CLI: pass resolved runtime config into verify commands, so `openclaw matrix verify status` and sibling verify subcommands no longer crash before acquiring the Matrix client. Fixes #70992. (#71102) Thanks @luyao618.
|
||||
|
||||
## 2026.4.23
|
||||
|
||||
|
||||
@@ -211,7 +211,9 @@ describe("matrix CLI verification commands", () => {
|
||||
});
|
||||
const program = buildProgram();
|
||||
|
||||
await program.parseAsync(["matrix", "verify", "bootstrap", "--json"], { from: "user" });
|
||||
await program.parseAsync(["matrix", "verify", "bootstrap", "--json"], {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(process.exitCode).toBe(1);
|
||||
});
|
||||
@@ -267,6 +269,76 @@ describe("matrix CLI verification commands", () => {
|
||||
expect(process.exitCode).toBe(1);
|
||||
});
|
||||
|
||||
it("passes loaded cfg to verify status action", async () => {
|
||||
const fakeCfg = { channels: { matrix: {} } };
|
||||
matrixRuntimeLoadConfigMock.mockReturnValue(fakeCfg);
|
||||
mockMatrixVerificationStatus({ recoveryKeyCreatedAt: null });
|
||||
const program = buildProgram();
|
||||
|
||||
await program.parseAsync(["matrix", "verify", "status"], { from: "user" });
|
||||
|
||||
expect(getMatrixVerificationStatusMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
});
|
||||
|
||||
it("passes loaded cfg to all verify subcommands", async () => {
|
||||
const fakeCfg = { channels: { matrix: {} } };
|
||||
matrixRuntimeLoadConfigMock.mockReturnValue(fakeCfg);
|
||||
|
||||
// verify bootstrap
|
||||
const program1 = buildProgram();
|
||||
await program1.parseAsync(["matrix", "verify", "bootstrap"], {
|
||||
from: "user",
|
||||
});
|
||||
expect(bootstrapMatrixVerificationMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
|
||||
// verify device
|
||||
verifyMatrixRecoveryKeyMock.mockResolvedValue({ success: true });
|
||||
const program2 = buildProgram();
|
||||
await program2.parseAsync(["matrix", "verify", "device", "test-key"], {
|
||||
from: "user",
|
||||
});
|
||||
expect(verifyMatrixRecoveryKeyMock).toHaveBeenCalledWith(
|
||||
"test-key",
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
|
||||
// verify backup status
|
||||
getMatrixRoomKeyBackupStatusMock.mockResolvedValue({});
|
||||
const program3 = buildProgram();
|
||||
await program3.parseAsync(["matrix", "verify", "backup", "status"], {
|
||||
from: "user",
|
||||
});
|
||||
expect(getMatrixRoomKeyBackupStatusMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
|
||||
// verify backup reset
|
||||
const program4 = buildProgram();
|
||||
await program4.parseAsync(["matrix", "verify", "backup", "reset", "--yes"], { from: "user" });
|
||||
expect(resetMatrixRoomKeyBackupMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
|
||||
// verify backup restore
|
||||
restoreMatrixRoomKeyBackupMock.mockResolvedValue({
|
||||
success: true,
|
||||
imported: 0,
|
||||
total: 0,
|
||||
backup: {},
|
||||
});
|
||||
const program5 = buildProgram();
|
||||
await program5.parseAsync(["matrix", "verify", "backup", "restore"], {
|
||||
from: "user",
|
||||
});
|
||||
expect(restoreMatrixRoomKeyBackupMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: fakeCfg }),
|
||||
);
|
||||
});
|
||||
|
||||
it("lists matrix devices", async () => {
|
||||
listMatrixOwnDevicesMock.mockResolvedValue([
|
||||
{
|
||||
@@ -332,7 +404,9 @@ describe("matrix CLI verification commands", () => {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(pruneMatrixStaleGatewayDevicesMock).toHaveBeenCalledWith({ accountId: "poe" });
|
||||
expect(pruneMatrixStaleGatewayDevicesMock).toHaveBeenCalledWith({
|
||||
accountId: "poe",
|
||||
});
|
||||
expect(console.log).toHaveBeenCalledWith("Deleted stale OpenClaw devices: BritdXC6iL");
|
||||
expect(console.log).toHaveBeenCalledWith("Current device: A7hWrQ70ea");
|
||||
expect(console.log).toHaveBeenCalledWith("Remaining devices: 1");
|
||||
@@ -452,7 +526,9 @@ describe("matrix CLI verification commands", () => {
|
||||
{ from: "user" },
|
||||
);
|
||||
|
||||
expect(bootstrapMatrixVerificationMock).toHaveBeenCalledWith({ accountId: "ops" });
|
||||
expect(bootstrapMatrixVerificationMock).toHaveBeenCalledWith({
|
||||
accountId: "ops",
|
||||
});
|
||||
expect(console.log).toHaveBeenCalledWith("Matrix verification bootstrap: complete");
|
||||
expect(console.log).toHaveBeenCalledWith(
|
||||
`Recovery key created at: ${formatExpectedLocalTimestamp("2026-03-09T06:00:00.000Z")}`,
|
||||
@@ -705,7 +781,9 @@ describe("matrix CLI verification commands", () => {
|
||||
});
|
||||
const program = buildProgram();
|
||||
|
||||
await program.parseAsync(["matrix", "verify", "bootstrap", "--json"], { from: "user" });
|
||||
await program.parseAsync(["matrix", "verify", "bootstrap", "--json"], {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(process.exitCode).toBe(0);
|
||||
});
|
||||
@@ -715,7 +793,9 @@ describe("matrix CLI verification commands", () => {
|
||||
mockMatrixVerificationStatus({ recoveryKeyCreatedAt: recoveryCreatedAt });
|
||||
const program = buildProgram();
|
||||
|
||||
await program.parseAsync(["matrix", "verify", "status", "--verbose"], { from: "user" });
|
||||
await program.parseAsync(["matrix", "verify", "status", "--verbose"], {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(console.log).toHaveBeenCalledWith(
|
||||
`Recovery key created at: ${formatExpectedLocalTimestamp(recoveryCreatedAt)}`,
|
||||
@@ -920,7 +1000,9 @@ describe("matrix CLI verification commands", () => {
|
||||
it("requires --yes before resetting the Matrix room-key backup", async () => {
|
||||
const program = buildProgram();
|
||||
|
||||
await program.parseAsync(["matrix", "verify", "backup", "reset"], { from: "user" });
|
||||
await program.parseAsync(["matrix", "verify", "backup", "reset"], {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(process.exitCode).toBe(1);
|
||||
expect(resetMatrixRoomKeyBackupMock).not.toHaveBeenCalled();
|
||||
@@ -936,7 +1018,10 @@ describe("matrix CLI verification commands", () => {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(resetMatrixRoomKeyBackupMock).toHaveBeenCalledWith({ accountId: "default" });
|
||||
expect(resetMatrixRoomKeyBackupMock).toHaveBeenCalledWith({
|
||||
accountId: "default",
|
||||
cfg: {},
|
||||
});
|
||||
expect(console.log).toHaveBeenCalledWith("Reset success: yes");
|
||||
expect(console.log).toHaveBeenCalledWith("Previous backup version: 1");
|
||||
expect(console.log).toHaveBeenCalledWith("Deleted backup version: 1");
|
||||
@@ -981,6 +1066,7 @@ describe("matrix CLI verification commands", () => {
|
||||
|
||||
expect(getMatrixVerificationStatusMock).toHaveBeenCalledWith({
|
||||
accountId: "assistant",
|
||||
cfg: {},
|
||||
includeRecoveryKey: false,
|
||||
});
|
||||
expect(console.log).toHaveBeenCalledWith("Account: assistant");
|
||||
|
||||
@@ -96,6 +96,17 @@ function resolveMatrixCliAccountId(accountId?: string): string {
|
||||
return resolveMatrixAuthContext({ cfg, accountId }).accountId;
|
||||
}
|
||||
|
||||
function resolveMatrixCliAccountContext(accountId?: string): {
|
||||
accountId: string;
|
||||
cfg: CoreConfig;
|
||||
} {
|
||||
const cfg = getMatrixRuntime().config.loadConfig() as CoreConfig;
|
||||
return {
|
||||
accountId: resolveMatrixAuthContext({ cfg, accountId }).accountId,
|
||||
cfg,
|
||||
};
|
||||
}
|
||||
|
||||
function formatMatrixCliCommand(command: string, accountId?: string): string {
|
||||
const normalizedAccountId = normalizeAccountId(accountId);
|
||||
const suffix = normalizedAccountId === "default" ? "" : ` --account ${normalizedAccountId}`;
|
||||
@@ -925,13 +936,14 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
includeRecoveryKey?: boolean;
|
||||
json?: boolean;
|
||||
}) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
run: async () =>
|
||||
await getMatrixVerificationStatus({
|
||||
accountId,
|
||||
cfg,
|
||||
includeRecoveryKey: options.includeRecoveryKey === true,
|
||||
}),
|
||||
onText: (status, verbose) => {
|
||||
@@ -952,11 +964,11 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
.option("--verbose", "Show detailed diagnostics")
|
||||
.option("--json", "Output as JSON")
|
||||
.action(async (options: { account?: string; verbose?: boolean; json?: boolean }) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
run: async () => await getMatrixRoomKeyBackupStatus({ accountId }),
|
||||
run: async () => await getMatrixRoomKeyBackupStatus({ accountId, cfg }),
|
||||
onText: (status, verbose) => {
|
||||
printAccountLabel(accountId);
|
||||
printBackupSummary(status);
|
||||
@@ -979,7 +991,7 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
.option("--json", "Output as JSON")
|
||||
.action(
|
||||
async (options: { account?: string; yes?: boolean; verbose?: boolean; json?: boolean }) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
@@ -987,7 +999,7 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
if (options.yes !== true) {
|
||||
throw new Error("Refusing to reset Matrix room-key backup without --yes");
|
||||
}
|
||||
return await resetMatrixRoomKeyBackup({ accountId });
|
||||
return await resetMatrixRoomKeyBackup({ accountId, cfg });
|
||||
},
|
||||
onText: (result, verbose) => {
|
||||
printAccountLabel(accountId);
|
||||
@@ -1025,13 +1037,14 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
verbose?: boolean;
|
||||
json?: boolean;
|
||||
}) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
run: async () =>
|
||||
await restoreMatrixRoomKeyBackup({
|
||||
accountId,
|
||||
cfg,
|
||||
recoveryKey: options.recoveryKey,
|
||||
}),
|
||||
onText: (result, verbose) => {
|
||||
@@ -1074,13 +1087,14 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
verbose?: boolean;
|
||||
json?: boolean;
|
||||
}) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
run: async () =>
|
||||
await bootstrapMatrixVerification({
|
||||
accountId,
|
||||
cfg,
|
||||
recoveryKey: options.recoveryKey,
|
||||
forceResetCrossSigning: options.forceResetCrossSigning === true,
|
||||
}),
|
||||
@@ -1129,11 +1143,11 @@ export function registerMatrixCli(params: { program: Command }): void {
|
||||
.option("--json", "Output as JSON")
|
||||
.action(
|
||||
async (key: string, options: { account?: string; verbose?: boolean; json?: boolean }) => {
|
||||
const accountId = resolveMatrixCliAccountId(options.account);
|
||||
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
|
||||
await runMatrixCliCommand({
|
||||
verbose: options.verbose === true,
|
||||
json: options.json === true,
|
||||
run: async () => await verifyMatrixRecoveryKey(key, { accountId }),
|
||||
run: async () => await verifyMatrixRecoveryKey(key, { accountId, cfg }),
|
||||
onText: (result, verbose) => {
|
||||
printAccountLabel(accountId);
|
||||
if (!result.success) {
|
||||
|
||||
Reference in New Issue
Block a user