mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 12:26:38 -06:00
feat(ui): manage DM pairing requests in Channels (#112401)
* feat(ui): manage DM pairing requests * fix(ui): clear pairing data across auth changes * test(ui): tighten pairing page fixture type * fix(gateway): complete pairing protocol contracts * fix(ui): guard pairing mutations across epochs * fix(ui): restore chat teardown gates * fix(ui): isolate channel auth lifecycles * fix(ui): remove stale chat view export
This commit is contained in:
committed by
GitHub
parent
0d7e870a2b
commit
0c99a4e362
+4
-40
@@ -9,15 +9,8 @@ import { getTerminalTableWidth, renderTable } from "../../packages/terminal-core
|
||||
import { theme } from "../../packages/terminal-core/src/theme.js";
|
||||
import { normalizeChannelId } from "../channels/plugins/index.js";
|
||||
import { listPairingChannels, notifyPairingApproved } from "../channels/plugins/pairing.js";
|
||||
import {
|
||||
formatCommandOwnerFromChannelSender,
|
||||
hasConfiguredCommandOwners,
|
||||
} from "../commands/doctor-command-owner.js";
|
||||
import {
|
||||
getRuntimeConfig,
|
||||
readConfigFileSnapshotForWrite,
|
||||
replaceConfigFile,
|
||||
} from "../config/config.js";
|
||||
import { getRuntimeConfig } from "../config/config.js";
|
||||
import { bootstrapCommandOwnerFromPairing } from "../pairing/command-owner.js";
|
||||
import { resolvePairingIdLabel } from "../pairing/pairing-labels.js";
|
||||
import { approveChannelPairingCode, listChannelPairingRequests } from "../pairing/pairing-store.js";
|
||||
import type { PairingChannel } from "../pairing/pairing-store.types.js";
|
||||
@@ -57,35 +50,6 @@ async function notifyApproved(channel: PairingChannel, id: string, accountId?: s
|
||||
await notifyPairingApproved({ channelId: channel, id, cfg, ...(accountId ? { accountId } : {}) });
|
||||
}
|
||||
|
||||
async function maybeBootstrapCommandOwnerFromPairing(params: {
|
||||
channel: PairingChannel;
|
||||
id: string;
|
||||
}): Promise<{ ownerEntry: string | null; bootstrapped: boolean }> {
|
||||
// First approved pairing can seed ownerAllowFrom so command access is not left open-ended.
|
||||
const ownerEntry = formatCommandOwnerFromChannelSender(params);
|
||||
if (!ownerEntry) {
|
||||
return { ownerEntry: null, bootstrapped: false };
|
||||
}
|
||||
|
||||
const { snapshot, writeOptions } = await readConfigFileSnapshotForWrite();
|
||||
if (hasConfiguredCommandOwners(snapshot.sourceConfig)) {
|
||||
return { ownerEntry, bootstrapped: false };
|
||||
}
|
||||
|
||||
const nextConfig = structuredClone(snapshot.sourceConfig);
|
||||
nextConfig.commands = {
|
||||
...nextConfig.commands,
|
||||
ownerAllowFrom: [ownerEntry],
|
||||
};
|
||||
await replaceConfigFile({
|
||||
nextConfig,
|
||||
snapshot,
|
||||
writeOptions,
|
||||
afterWrite: { mode: "auto" },
|
||||
});
|
||||
return { ownerEntry, bootstrapped: true };
|
||||
}
|
||||
|
||||
export function registerPairingCli(program: Command) {
|
||||
const channels = listPairingChannels();
|
||||
// Avoid rendering a bare "()" enum when no channels are configured.
|
||||
@@ -208,11 +172,11 @@ export function registerPairingCli(program: Command) {
|
||||
defaultRuntime.log(
|
||||
`${theme.success("Approved")} ${theme.muted(channel)} sender ${theme.command(approved.id)}.`,
|
||||
);
|
||||
const ownerBootstrap = await maybeBootstrapCommandOwnerFromPairing({
|
||||
const ownerBootstrap = await bootstrapCommandOwnerFromPairing({
|
||||
channel,
|
||||
id: approved.id,
|
||||
});
|
||||
if (ownerBootstrap.bootstrapped && ownerBootstrap.ownerEntry) {
|
||||
if (ownerBootstrap.status === "configured" && ownerBootstrap.ownerEntry) {
|
||||
defaultRuntime.log(
|
||||
`${theme.success("Command owner configured")} ${theme.command(ownerBootstrap.ownerEntry)} ${theme.muted("(commands.ownerAllowFrom was empty).")}`,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user