Merge 9ed0f1be56 into fa9ec6e854
This commit is contained in:
commit
48008a1e73
@ -40,6 +40,27 @@ openclaw channels login --channel whatsapp
|
|||||||
openclaw channels logout --channel whatsapp
|
openclaw channels logout --channel whatsapp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### JSON mode (programmatic)
|
||||||
|
|
||||||
|
For programmatic use (e.g., web dashboards, hosting platforms), use `--json` to get QR data as JSON instead of terminal output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
moltbot channels login --channel whatsapp --json --timeout 60000
|
||||||
|
```
|
||||||
|
|
||||||
|
This outputs two JSON objects:
|
||||||
|
1. Initial response with QR data:
|
||||||
|
```json
|
||||||
|
{"status":"pending","qrDataUrl":"data:image/png;base64,...","message":"Scan this QR...","accountId":"default","channel":"whatsapp"}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Final response after scan (or timeout):
|
||||||
|
```json
|
||||||
|
{"status":"connected","connected":true,"message":"✅ Linked!","accountId":"default","channel":"whatsapp"}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `qrDataUrl` is a base64-encoded PNG that can be displayed directly in an `<img>` tag.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- Run `openclaw status --deep` for a broad probe.
|
- Run `openclaw status --deep` for a broad probe.
|
||||||
|
|||||||
@ -9,6 +9,8 @@ type ChannelAuthOptions = {
|
|||||||
channel?: string;
|
channel?: string;
|
||||||
account?: string;
|
account?: string;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
json?: boolean;
|
||||||
|
timeoutMs?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function runChannelLogin(
|
export async function runChannelLogin(
|
||||||
@ -21,6 +23,54 @@ export async function runChannelLogin(
|
|||||||
throw new Error(`Unsupported channel: ${channelInput}`);
|
throw new Error(`Unsupported channel: ${channelInput}`);
|
||||||
}
|
}
|
||||||
const plugin = getChannelPlugin(channelId);
|
const plugin = getChannelPlugin(channelId);
|
||||||
|
|
||||||
|
// JSON mode: use gateway QR login methods for programmatic access
|
||||||
|
if (opts.json) {
|
||||||
|
if (!plugin?.gateway?.loginWithQrStart || !plugin?.gateway?.loginWithQrWait) {
|
||||||
|
throw new Error(`Channel ${channelId} does not support JSON login mode`);
|
||||||
|
}
|
||||||
|
setVerbose(Boolean(opts.verbose));
|
||||||
|
const cfg = loadConfig();
|
||||||
|
const accountId = opts.account?.trim() || resolveChannelDefaultAccountId({ plugin, cfg });
|
||||||
|
const timeoutMs = opts.timeoutMs ?? 60000;
|
||||||
|
|
||||||
|
// Start QR login and get QR data
|
||||||
|
const startResult = await plugin.gateway.loginWithQrStart({
|
||||||
|
accountId,
|
||||||
|
force: false,
|
||||||
|
timeoutMs,
|
||||||
|
verbose: Boolean(opts.verbose),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Output QR data as JSON
|
||||||
|
const output = {
|
||||||
|
status: "pending",
|
||||||
|
qrDataUrl: startResult.qrDataUrl ?? null,
|
||||||
|
message: startResult.message,
|
||||||
|
accountId,
|
||||||
|
channel: channelId,
|
||||||
|
};
|
||||||
|
runtime.log(JSON.stringify(output));
|
||||||
|
|
||||||
|
// Wait for connection
|
||||||
|
const waitResult = await plugin.gateway.loginWithQrWait({
|
||||||
|
accountId,
|
||||||
|
timeoutMs,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Output final result
|
||||||
|
const finalOutput = {
|
||||||
|
status: waitResult.connected ? "connected" : "failed",
|
||||||
|
connected: waitResult.connected,
|
||||||
|
message: waitResult.message,
|
||||||
|
accountId,
|
||||||
|
channel: channelId,
|
||||||
|
};
|
||||||
|
runtime.log(JSON.stringify(finalOutput));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard interactive mode
|
||||||
if (!plugin?.auth?.login) {
|
if (!plugin?.auth?.login) {
|
||||||
throw new Error(`Channel ${channelId} does not support login`);
|
throw new Error(`Channel ${channelId} does not support login`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -215,6 +215,8 @@ export function registerChannelsCli(program: Command) {
|
|||||||
.option("--channel <channel>", "Channel alias (default: whatsapp)")
|
.option("--channel <channel>", "Channel alias (default: whatsapp)")
|
||||||
.option("--account <id>", "Account id (accountId)")
|
.option("--account <id>", "Account id (accountId)")
|
||||||
.option("--verbose", "Verbose connection logs", false)
|
.option("--verbose", "Verbose connection logs", false)
|
||||||
|
.option("--json", "Output QR data as JSON (for programmatic use)", false)
|
||||||
|
.option("--timeout <ms>", "Timeout for QR generation in ms", "60000")
|
||||||
.action(async (opts) => {
|
.action(async (opts) => {
|
||||||
await runChannelsCommandWithDanger(async () => {
|
await runChannelsCommandWithDanger(async () => {
|
||||||
await runChannelLogin(
|
await runChannelLogin(
|
||||||
@ -222,6 +224,8 @@ export function registerChannelsCli(program: Command) {
|
|||||||
channel: opts.channel as string | undefined,
|
channel: opts.channel as string | undefined,
|
||||||
account: opts.account as string | undefined,
|
account: opts.account as string | undefined,
|
||||||
verbose: Boolean(opts.verbose),
|
verbose: Boolean(opts.verbose),
|
||||||
|
json: Boolean(opts.json),
|
||||||
|
timeoutMs: parseInt(String(opts.timeout), 10) || 60000,
|
||||||
},
|
},
|
||||||
defaultRuntime,
|
defaultRuntime,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -208,7 +208,7 @@ describe("cli program (smoke)", () => {
|
|||||||
from: "user",
|
from: "user",
|
||||||
});
|
});
|
||||||
expect(runChannelLogin).toHaveBeenCalledWith(
|
expect(runChannelLogin).toHaveBeenCalledWith(
|
||||||
{ channel: undefined, account: "work", verbose: false },
|
{ channel: undefined, account: "work", verbose: false, json: false, timeoutMs: 60000 },
|
||||||
runtime,
|
runtime,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user