fix(pairing): accept positional provider args
This commit is contained in:
@@ -2,10 +2,11 @@ import { Command } from "commander";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const listProviderPairingRequests = vi.fn();
|
||||
const approveProviderPairingCode = vi.fn();
|
||||
|
||||
vi.mock("../pairing/pairing-store.js", () => ({
|
||||
listProviderPairingRequests,
|
||||
approveProviderPairingCode: vi.fn(),
|
||||
approveProviderPairingCode,
|
||||
}));
|
||||
|
||||
vi.mock("../telegram/send.js", () => ({
|
||||
@@ -61,6 +62,18 @@ describe("pairing cli", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts provider as positional for list", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
listProviderPairingRequests.mockResolvedValueOnce([]);
|
||||
|
||||
const program = new Command();
|
||||
program.name("test");
|
||||
registerPairingCli(program);
|
||||
await program.parseAsync(["pairing", "list", "telegram"], { from: "user" });
|
||||
|
||||
expect(listProviderPairingRequests).toHaveBeenCalledWith("telegram");
|
||||
});
|
||||
|
||||
it("labels Discord ids as discordUserId", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
listProviderPairingRequests.mockResolvedValueOnce([
|
||||
@@ -84,4 +97,31 @@ describe("pairing cli", () => {
|
||||
expect.stringContaining("discordUserId=999"),
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts provider as positional for approve (npm-run compatible)", async () => {
|
||||
const { registerPairingCli } = await import("./pairing-cli.js");
|
||||
approveProviderPairingCode.mockResolvedValueOnce({
|
||||
id: "123",
|
||||
entry: {
|
||||
id: "123",
|
||||
code: "ABCDEFGH",
|
||||
createdAt: "2026-01-08T00:00:00Z",
|
||||
lastSeenAt: "2026-01-08T00:00:00Z",
|
||||
},
|
||||
});
|
||||
|
||||
const log = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
const program = new Command();
|
||||
program.name("test");
|
||||
registerPairingCli(program);
|
||||
await program.parseAsync(["pairing", "approve", "telegram", "ABCDEFGH"], {
|
||||
from: "user",
|
||||
});
|
||||
|
||||
expect(approveProviderPairingCode).toHaveBeenCalledWith({
|
||||
provider: "telegram",
|
||||
code: "ABCDEFGH",
|
||||
});
|
||||
expect(log).toHaveBeenCalledWith(expect.stringContaining("Approved"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,13 +83,17 @@ export function registerPairingCli(program: Command) {
|
||||
pairing
|
||||
.command("list")
|
||||
.description("List pending pairing requests")
|
||||
.requiredOption(
|
||||
"--provider <provider>",
|
||||
`Provider (${PROVIDERS.join(", ")})`,
|
||||
)
|
||||
.option("--provider <provider>", `Provider (${PROVIDERS.join(", ")})`)
|
||||
.argument("[provider]", `Provider (${PROVIDERS.join(", ")})`)
|
||||
.option("--json", "Print JSON", false)
|
||||
.action(async (opts) => {
|
||||
const provider = parseProvider(opts.provider);
|
||||
.action(async (providerArg, opts) => {
|
||||
const providerRaw = opts.provider ?? providerArg;
|
||||
if (!providerRaw) {
|
||||
throw new Error(
|
||||
`Provider required. Use --provider <provider> or pass it as the first argument (expected one of: ${PROVIDERS.join(", ")})`,
|
||||
);
|
||||
}
|
||||
const provider = parseProvider(providerRaw);
|
||||
const requests = await listProviderPairingRequests(provider);
|
||||
if (opts.json) {
|
||||
console.log(JSON.stringify({ provider, requests }, null, 2));
|
||||
@@ -111,20 +115,35 @@ export function registerPairingCli(program: Command) {
|
||||
pairing
|
||||
.command("approve")
|
||||
.description("Approve a pairing code and allow that sender")
|
||||
.requiredOption(
|
||||
"--provider <provider>",
|
||||
`Provider (${PROVIDERS.join(", ")})`,
|
||||
.option("--provider <provider>", `Provider (${PROVIDERS.join(", ")})`)
|
||||
.argument(
|
||||
"<codeOrProvider>",
|
||||
"Pairing code (or provider when using 2 args)",
|
||||
)
|
||||
.argument("<code>", "Pairing code (shown to the requester)")
|
||||
.argument("[code]", "Pairing code (when provider is passed as the 1st arg)")
|
||||
.option("--notify", "Notify the requester on the same provider", false)
|
||||
.action(async (code, opts) => {
|
||||
const provider = parseProvider(opts.provider);
|
||||
.action(async (codeOrProvider, code, opts) => {
|
||||
const providerRaw = opts.provider ?? codeOrProvider;
|
||||
const resolvedCode = opts.provider ? codeOrProvider : code;
|
||||
if (!opts.provider && !code) {
|
||||
throw new Error(
|
||||
`Usage: clawdbot pairing approve <provider> <code> (or: clawdbot pairing approve --provider <provider> <code>)`,
|
||||
);
|
||||
}
|
||||
if (opts.provider && code != null) {
|
||||
throw new Error(
|
||||
`Too many arguments. Use: clawdbot pairing approve --provider <provider> <code>`,
|
||||
);
|
||||
}
|
||||
const provider = parseProvider(providerRaw);
|
||||
const approved = await approveProviderPairingCode({
|
||||
provider,
|
||||
code: String(code),
|
||||
code: String(resolvedCode),
|
||||
});
|
||||
if (!approved) {
|
||||
throw new Error(`No pending pairing request found for code: ${code}`);
|
||||
throw new Error(
|
||||
`No pending pairing request found for code: ${String(resolvedCode)}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`Approved ${provider} sender ${approved.id}.`);
|
||||
|
||||
@@ -115,7 +115,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
`- Telegram DMs: locked (telegram.dmPolicy="${dmPolicy}") with no allowlist; unknown senders will be blocked / get a pairing code.`,
|
||||
);
|
||||
warnings.push(
|
||||
` Approve via: clawdbot pairing list --provider telegram / clawdbot pairing approve --provider telegram <code>`,
|
||||
` Approve via: clawdbot pairing list telegram / clawdbot pairing approve telegram <code>`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
allowFrom: cfg.discord?.dm?.allowFrom ?? [],
|
||||
allowFromPath: "discord.dm.",
|
||||
approveHint:
|
||||
"Approve via: clawdbot pairing list --provider discord / clawdbot pairing approve --provider discord <code>",
|
||||
"Approve via: clawdbot pairing list discord / clawdbot pairing approve discord <code>",
|
||||
normalizeEntry: (raw) =>
|
||||
raw.replace(/^(discord|user):/i, "").replace(/^<@!?(\d+)>$/, "$1"),
|
||||
});
|
||||
@@ -151,7 +151,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
allowFrom: cfg.slack?.dm?.allowFrom ?? [],
|
||||
allowFromPath: "slack.dm.",
|
||||
approveHint:
|
||||
"Approve via: clawdbot pairing list --provider slack / clawdbot pairing approve --provider slack <code>",
|
||||
"Approve via: clawdbot pairing list slack / clawdbot pairing approve slack <code>",
|
||||
normalizeEntry: (raw) => raw.replace(/^(slack|user):/i, ""),
|
||||
});
|
||||
}
|
||||
@@ -164,7 +164,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
allowFrom: cfg.signal?.allowFrom ?? [],
|
||||
allowFromPath: "signal.",
|
||||
approveHint:
|
||||
"Approve via: clawdbot pairing list --provider signal / clawdbot pairing approve --provider signal <code>",
|
||||
"Approve via: clawdbot pairing list signal / clawdbot pairing approve signal <code>",
|
||||
normalizeEntry: (raw) =>
|
||||
normalizeE164(raw.replace(/^signal:/i, "").trim()),
|
||||
});
|
||||
@@ -178,7 +178,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
allowFrom: cfg.imessage?.allowFrom ?? [],
|
||||
allowFromPath: "imessage.",
|
||||
approveHint:
|
||||
"Approve via: clawdbot pairing list --provider imessage / clawdbot pairing approve --provider imessage <code>",
|
||||
"Approve via: clawdbot pairing list imessage / clawdbot pairing approve imessage <code>",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ export async function noteSecurityWarnings(cfg: ClawdbotConfig) {
|
||||
allowFrom: cfg.whatsapp?.allowFrom ?? [],
|
||||
allowFromPath: "whatsapp.",
|
||||
approveHint:
|
||||
"Approve via: clawdbot pairing list --provider whatsapp / clawdbot pairing approve --provider whatsapp <code>",
|
||||
"Approve via: clawdbot pairing list whatsapp / clawdbot pairing approve whatsapp <code>",
|
||||
normalizeEntry: (raw) => normalizeE164(raw),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ async function noteProviderPrimer(prompter: WizardPrompter): Promise<void> {
|
||||
await prompter.note(
|
||||
[
|
||||
"DM security: default is pairing; unknown DMs get a pairing code.",
|
||||
"Approve with: clawdbot pairing approve --provider <provider> <code>",
|
||||
"Approve with: clawdbot pairing approve <provider> <code>",
|
||||
'Public DMs require dmPolicy="open" + allowFrom=["*"].',
|
||||
`Docs: ${formatDocsLink("/start/pairing", "start/pairing")}`,
|
||||
"",
|
||||
@@ -401,7 +401,7 @@ async function maybeConfigureDmPolicies(params: {
|
||||
await prompter.note(
|
||||
[
|
||||
"Default: pairing (unknown DMs get a pairing code).",
|
||||
`Approve: clawdbot pairing approve --provider ${params.provider} <code>`,
|
||||
`Approve: clawdbot pairing approve ${params.provider} <code>`,
|
||||
`Public DMs: ${params.policyKey}="open" + ${params.allowFromKey} includes "*".`,
|
||||
`Docs: ${formatDocsLink("/start/pairing", "start/pairing")}`,
|
||||
].join("\n"),
|
||||
|
||||
@@ -37,7 +37,7 @@ describe("buildPairingReply", () => {
|
||||
expect(text).toContain(testCase.idLine);
|
||||
expect(text).toContain(`Pairing code: ${testCase.code}`);
|
||||
expect(text).toContain(
|
||||
`clawdbot pairing approve --provider ${testCase.provider} <code>`,
|
||||
`clawdbot pairing approve ${testCase.provider} <code>`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@ export function buildPairingReply(params: {
|
||||
`Pairing code: ${code}`,
|
||||
"",
|
||||
"Ask the bot owner to approve with:",
|
||||
`clawdbot pairing approve --provider ${provider} <code>`,
|
||||
`clawdbot pairing approve ${provider} <code>`,
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
`Pairing code: ${code}`,
|
||||
"",
|
||||
"Ask the bot owner to approve with:",
|
||||
"clawdbot pairing approve --provider telegram <code>",
|
||||
"clawdbot pairing approve telegram <code>",
|
||||
].join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user