mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-01 06:23:41 +00:00
fix(cli): stop pairing list crashing with empty channel enum (#98142)
When no chat DM pairing channels are configured, `openclaw pairing list` (no channel argument) threw `Channel required ... (expected one of: )` with an empty enum that reads like a bug. Users who hit this are usually trying to approve a TUI/device or scope-upgrade request, which lives under `openclaw devices`, not `openclaw pairing` (which only handles chat DM pairing). - Guard the channel hint in help text and errors so an empty channel list no longer renders a bare `()` / `(expected one of: )`. - When no pairing channels exist, redirect to `openclaw devices list` / `openclaw devices approve` instead of failing opaquely. AI-assisted (Claude Code).
This commit is contained in:
@@ -224,6 +224,30 @@ describe("pairing cli", () => {
|
||||
expect(listChannelPairingRequests).toHaveBeenCalledWith("slack");
|
||||
});
|
||||
|
||||
it("redirects to openclaw devices when no pairing channels are configured", async () => {
|
||||
listPairingChannels.mockReturnValueOnce([]);
|
||||
|
||||
const error = await runPairing(["pairing", "list"]).then(
|
||||
() => null,
|
||||
(err: unknown) => err,
|
||||
);
|
||||
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
const message = (error as Error).message;
|
||||
expect(message).toContain("openclaw devices");
|
||||
// Must not leak the empty enum that originally read like a bug.
|
||||
expect(message).not.toContain("expected one of: )");
|
||||
expect(message).not.toContain("()");
|
||||
expect(listChannelPairingRequests).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("lists supported channels when one is required but omitted", async () => {
|
||||
// Multiple channels configured (default mock) + no channel argument.
|
||||
await expect(runPairing(["pairing", "list"])).rejects.toThrow(
|
||||
"expected one of: telegram, discord, imessage",
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts channel as positional for approve (npm-run compatible)", async () => {
|
||||
mockApprovedPairing();
|
||||
|
||||
|
||||
@@ -88,6 +88,8 @@ async function maybeBootstrapCommandOwnerFromPairing(params: {
|
||||
|
||||
export function registerPairingCli(program: Command) {
|
||||
const channels = listPairingChannels();
|
||||
// Avoid rendering a bare "()" enum when no channels are configured.
|
||||
const channelHint = channels.length > 0 ? channels.join(", ") : "none configured";
|
||||
const pairing = program
|
||||
.command("pairing")
|
||||
.description("Secure DM pairing (approve inbound requests)")
|
||||
@@ -100,16 +102,21 @@ export function registerPairingCli(program: Command) {
|
||||
pairing
|
||||
.command("list")
|
||||
.description("List pending pairing requests")
|
||||
.option("--channel <channel>", `Channel (${channels.join(", ")})`)
|
||||
.option("--channel <channel>", `Channel (${channelHint})`)
|
||||
.option("--account <accountId>", "Account id (for multi-account channels)")
|
||||
.argument("[channel]", `Channel (${channels.join(", ")})`)
|
||||
.argument("[channel]", `Channel (${channelHint})`)
|
||||
.option("--json", "Print JSON", false)
|
||||
.action(async (channelArg, opts) => {
|
||||
const channelRaw = opts.channel ?? channelArg ?? (channels.length === 1 ? channels[0] : "");
|
||||
if (!channelRaw) {
|
||||
throw new Error(
|
||||
`Channel required. Use --channel <channel> or pass it as the first argument (expected one of: ${channels.join(", ")})`,
|
||||
);
|
||||
if (channels.length === 0) {
|
||||
// `pairing` is chat DM only; TUI/device approvals live under `openclaw devices`.
|
||||
throw new Error(
|
||||
`No chat DM pairing channels are configured. To approve a TUI or device request, ` +
|
||||
`use ${formatCliCommand("openclaw devices approve")} instead.`,
|
||||
);
|
||||
}
|
||||
throw new Error(`Channel required (expected one of: ${channelHint}).`);
|
||||
}
|
||||
const channel = parseChannel(channelRaw, channels);
|
||||
const accountId = normalizeStringifiedOptionalString(opts.account) ?? "";
|
||||
@@ -151,7 +158,7 @@ export function registerPairingCli(program: Command) {
|
||||
pairing
|
||||
.command("approve")
|
||||
.description("Approve a pairing code and allow that sender")
|
||||
.option("--channel <channel>", `Channel (${channels.join(", ")})`)
|
||||
.option("--channel <channel>", `Channel (${channelHint})`)
|
||||
.option("--account <accountId>", "Account id (for multi-account channels)")
|
||||
.argument("<codeOrChannel>", "Pairing code (or channel when using 2 args)")
|
||||
.argument("[code]", "Pairing code (when channel is passed as the 1st arg)")
|
||||
|
||||
Reference in New Issue
Block a user